Giter Site home page Giter Site logo

andfanilo / streamlit-drawable-canvas Goto Github PK

View Code? Open in Web Editor NEW
524.0 10.0 78.0 9.17 MB

Do you like Quick, Draw? Well what if you could train/predict doodles drawn inside Streamlit? Also draws lines, circles and boxes over background images for annotation.

Home Page: https://drawable-canvas.streamlit.app/

License: MIT License

Python 15.92% HTML 1.78% CSS 1.04% TypeScript 77.06% JavaScript 4.20%
streamlit python react fabric drawing image-annotation

streamlit-drawable-canvas's Introduction

Streamlit - Drawable Canvas

Streamlit component which provides a sketching canvas using Fabric.js.

Streamlit App

PyPI PyPI - Downloads

Buy Me A Coffee

Features

  • Draw freely, lines, circles, boxes and polygons on the canvas, with options on stroke & fill
  • Rotate, skew, scale, move any object of the canvas on demand
  • Select a background color or image to draw on
  • Get image data and every drawn object properties back to Streamlit !
  • Choose to fetch back data in realtime or on demand with a button
  • Undo, Redo or Delete canvas contents
  • Save canvas data as JSON to reuse for another session

Installation

pip install streamlit-drawable-canvas

Example Usage

Copy this code snippet:

import pandas as pd
from PIL import Image
import streamlit as st
from streamlit_drawable_canvas import st_canvas

# Specify canvas parameters in application
drawing_mode = st.sidebar.selectbox(
    "Drawing tool:", ("point", "freedraw", "line", "rect", "circle", "transform")
)

stroke_width = st.sidebar.slider("Stroke width: ", 1, 25, 3)
if drawing_mode == 'point':
    point_display_radius = st.sidebar.slider("Point display radius: ", 1, 25, 3)
stroke_color = st.sidebar.color_picker("Stroke color hex: ")
bg_color = st.sidebar.color_picker("Background color hex: ", "#eee")
bg_image = st.sidebar.file_uploader("Background image:", type=["png", "jpg"])

realtime_update = st.sidebar.checkbox("Update in realtime", True)

    

# Create a canvas component
canvas_result = st_canvas(
    fill_color="rgba(255, 165, 0, 0.3)",  # Fixed fill color with some opacity
    stroke_width=stroke_width,
    stroke_color=stroke_color,
    background_color=bg_color,
    background_image=Image.open(bg_image) if bg_image else None,
    update_streamlit=realtime_update,
    height=150,
    drawing_mode=drawing_mode,
    point_display_radius=point_display_radius if drawing_mode == 'point' else 0,
    key="canvas",
)

# Do something interesting with the image data and paths
if canvas_result.image_data is not None:
    st.image(canvas_result.image_data)
if canvas_result.json_data is not None:
    objects = pd.json_normalize(canvas_result.json_data["objects"]) # need to convert obj to str because PyArrow
    for col in objects.select_dtypes(include=['object']).columns:
        objects[col] = objects[col].astype("str")
    st.dataframe(objects)

You will find more detailed examples on the demo app.

API

st_canvas(
    fill_color: str
    stroke_width: int
    stroke_color: str
    background_color: str
    background_image: Image
    update_streamlit: bool
    height: int
    width: int
    drawing_mode: str
    initial_drawing: dict
    display_toolbar: bool
    point_display_radius: int
    key: str
)
  • fill_color : Color of fill for Rect in CSS color property. Defaults to "#eee".
  • stroke_width : Width of drawing brush in CSS color property. Defaults to 20.
  • stroke_color : Color of drawing brush in hex. Defaults to "black".
  • background_color : Color of canvas background in CSS color property. Defaults to "" which is transparent. Overriden by background_image. Changing background_color will reset the drawing.
  • background_image : Pillow Image to display behind canvas. Automatically resized to canvas dimensions. Being behind the canvas, it is not sent back to Streamlit on mouse event. Overrides background_color. Changes to this will reset canvas contents.
  • update_streamlit : Whenever True, send canvas data to Streamlit when object/selection is updated or mouse up.
  • height : Height of canvas in pixels. Defaults to 400.
  • width : Width of canvas in pixels. Defaults to 600.
  • drawing_mode : Enable free drawing when "freedraw", object manipulation when "transform", otherwise create new objects with "line", "rect", "circle" and "polygon". Defaults to "freedraw".
    • On "polygon" mode, double-clicking will remove the latest point and right-clicking will close the polygon.
  • initial_drawing : Initialize canvas with drawings from here. Should be the json_data output from other canvas. Beware: if you try to import a drawing from a bigger/smaller canvas, no rescaling is done in the canvas and the import could fail.
  • point_display_radius : To make points visible on the canvas, they are drawn as circles. This parameter modifies the radius of the displayed circle.
  • display_toolbar : If False, don't display the undo/redo/delete toolbar.

Example:

import streamlit as st
from streamlit_drawable_canvas import st_canvas

canvas_result = st_canvas()
st_canvas(initial_drawing=canvas_result.json_data)
  • display_toolbar : Display the undo/redo/reset toolbar.
  • key : An optional string to use as the unique key for the widget. Assign a key so the component is not remount every time the script is rerun.

Development

Install

  • JS side
cd frontend
npm install
  • Python side
conda create -n streamlit-drawable-canvas python=3.7
conda activate streamlit-drawable-canvas
pip install -e .

Run

Both webpack dev server and Streamlit should run at the same time.

  • JS side
cd frontend
npm run start
  • Python side
streamlit run app.py

Cypress integration tests

  • Install Cypress: cd e2e; npm i or npx install cypress (with --force if cache problem)
  • Start Streamlit frontend server: cd streamlit_drawable_canvas/frontend; npm run start
  • Start Streamlit test script: streamlit run e2e/app_to_test.py
  • Start Cypress app: cd e2e; npm run cypress:open

References

streamlit-drawable-canvas's People

Contributors

amantik avatar andfanilo avatar andreaferretti avatar arnauddhaene avatar hiankun avatar kapong avatar tconkling avatar whitphx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

streamlit-drawable-canvas's Issues

Snapping

On a mouseevent (like ctrl), enable point snapping

Export canvas as png

I'm working on a front end for a neural search framework to take a user's drawing and match it with the closest looking Pokemon: https://github.com/alexcg1/jina-streamlit-frontend

My goal is to have the user draw on the canvas, then click button to export that drawing into a base64 encoded png, which I then pass to Jina via REST API.

How can I take the np.ndarray generated by the canvas and convert that to a png? I've been trying a few things so far, but all I get is a blank transparent png in the canvas dimensions.

I'm working on the code in the draw branch: https://github.com/alexcg1/jina-streamlit-frontend/tree/draw

Thanks for putting together a cool project. I can't wait to get it working!

Problem with new customizable layouts

The component seems to not work with the new customizable layouts. This reproduced the problem:

import streamlit as st
from streamlit_drawable_canvas import st_canvas

col1, col2 = st.beta_columns(2)

with col1:
    canvas_image = st_canvas(
        fill_color = "rgba(255, 165, 0, 0.3)", 
        stroke_width = 2,
        stroke_color = '#e00',
        drawing_mode = "line",
        key = "canvas",
    )

with col2:
    options = ['U','D','R', 'L']
    lines = [st.selectbox('Select', options, key=x) for x in range(4)]

The page appears correctly, but keeps refreshing constantly.

Containing the canvas in beta columns

Hi,

Thank you for creating this fantastic tool. I'm trying to build a use case for selecting ROIs in 3D radiological images in a Streamlit dashboard.

How could I use the st.beta_columns API to put 3 separate drawable canvases side by side?

Best,
Tom

Dynamically update background image

Is it possible to dynamically update the background image with some numpy array or PIL Image which is generated at runtime without creating a new st_canvas-instance?

canvas resets inside a button and does not work

The canvas becomes unusable if defined inside a button or such. Here is a simple example code:

import pandas as pd
from PIL import Image
import streamlit as st
from streamlit_drawable_canvas import st_canvas

# Specify canvas parameters in application
stroke_width = st.sidebar.slider("Stroke width: ", 1, 25, 3)
stroke_color = st.sidebar.color_picker("Stroke color hex: ")
bg_color = st.sidebar.color_picker("Background color hex: ", "#eee")
bg_image = st.sidebar.file_uploader("Background image:", type=["png", "jpg"])
drawing_mode = st.sidebar.selectbox(
    "Drawing tool:", ("freedraw", "line", "rect", "circle", "transform")
)
realtime_update = st.sidebar.checkbox("Update in realtime", True)


if st.button("Next"):
# Create a canvas component
    canvas_result = st_canvas(
        fill_color="rgba(255, 165, 0, 0.3)",  # Fixed fill color with some opacity
        stroke_width=stroke_width,
        stroke_color=stroke_color,
        background_color=bg_color,
        background_image=Image.open(bg_image) if bg_image else None,
        update_streamlit=realtime_update,
        height=150,
        drawing_mode=drawing_mode,
        key="canvas",
    )
    
    # Do something interesting with the image data and paths
    if canvas_result.image_data is not None:
        st.image(canvas_result.image_data)
    if canvas_result.json_data is not None:
        st.dataframe(pd.json_normalize(canvas_result.json_data["objects"]))

Json_data hex color

Hi, Thanks for amazing projects, relly helpful.

In choosing color section, can we choose the output of stroke color is rgb (xxx,xxx,xx) since opencv default is read rgb color.
yup, i know we can converting hex to rgb with python. just asking cause really exciting!

Thanks in advance!

Bug in drawn line

hello
I'm getting this as the jason description of a line drawn on the canvas:
I want to calculate the gradient of the line so was checking x1,y1 x2, y2 and they always come back as negatives of each other.

[{'type': 'line', 'version': '3.6.3', 'originX': 'center', 'originY': 'center', 'left': 130.5, 'top': 213.5, 'width': 89, 'height': 15, 'fill': '#65EA47', 'stroke': '#65EA47', 'strokeWidth': 3, 'strokeDashArray': None, 'strokeLineCap': 'butt', 'strokeDashOffset': 0, 'strokeLineJoin': 'miter', 'strokeMiterLimit': 4, 'scaleX': 1, 'scaleY': 1, 'angle': 0, 'flipX': False, 'flipY': False, 'opacity': 1, 'shadow': None, 'visible': True, 'clipTo': None, 'backgroundColor': '', 'fillRule': 'nonzero', 'paintFirst': 'fill', 'globalCompositeOperation': 'source-over', 'transformMatrix': None, 'skewX': 0, 'skewY': 0, 'x1': -44.5, 'x2': 44.5, 'y1': -7.5, 'y2': 7.5}], 'background': '#eee'

Feature request: tag annotations

I am annotation regions of interest (ROI) and displaying them in a dataframe for a text extraction app. I would like to auto generate an incrementing tag for the regions, e.g. region_1, region_2 etc and have this displayed inside the annotation and also in the dataframe, so that people can associate the data. Is this currently possible, or a feature request?
Cheers and great work!

image

Change width of canvas

Is there a way to change the width of the canvas to custom dimensions!? I'm working on MNIST and it would require inputs with dimensions 28ร—28 pixels. Thanks in advance!

Straight line segments

Hi I was wondering if you can point me to where I can adjust code to only produce straight line segments.

I'm currently going through the repo myself, but I'd appreciate any advice on this!

Best,
Theodore.

Format of canvas image_data

To further proceed with the canvas result, image_data, I need to know its type to work with opencv. Can you suggest a way that will work for opencv functions as well as displaying the image with st.image()

TypeError: string indices must be integers

Reported on https://discuss.streamlit.io/t/drawable-canvas/3671/29

Hey there!
It seems like something happened to the Streamlit Drawable Canvas code today. I use streamlit-drawable-canvas for educational purposes.
Earlier today, the canvas was working for my program (it's been working perfectly fine for the past several months). I define the canvas as follows:

canvas_result = st_canvas(
    fill_color="rgba(255, 165, 0, 0.3)",  # Fixed fill color with some opacity
    stroke_width=stroke_width,
    stroke_color=stroke_color,
    background_color= bg_color,
    # background_image=Image.open(bg_image) if bg_image else None,
    update_streamlit=realtime_update,
    width = 500,
    height= 500,
    drawing_mode=drawing_mode,
    key="canvas",
)

and then this afternoon, I get this error:

2021-07-01 23:00:34.341 Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/streamlit/script_runner.py", line 349, in _run_script
    exec(code, module.__dict__)
  File "/content/app.py", line 37, in <module>
    key="canvas"
  File "/usr/local/lib/python3.7/dist-packages/streamlit_drawable_canvas/__init__.py", line 138, in st_canvas
    w = component_value["width"]
TypeError: string indices must be integers

Do you know if any updates might have caused this? I haven't touched this code in a while and then it broke.

Change the size of the canvas dynamically based on screen resolution.

Hello,

Is it possible to adjust the size of the canvas based on screen resolution (something like viewport in html)?

When I run the application on my laptop, the canvas looks pretty normal. But when I try to use it on an ipad or mobile, the canvas looks enlarged and its not so convenient to use it. It would be really great if the canvas could adjust automatically to screens of different resolutions.

Alter canvas toolbar symbols

Hi there, more of a feature request than an issue, but I would love the ability to change the colour of the toolbar at the bottom of a canvas.

As you can see in the image, as the background colour of my app is black, the symbols are not visible unless hovered over. If the colours of the symbols could be changed, or if there was a background colour applied to the toolbar, I'd be much better able to use drawable canvas.

image

Change ordering of objects

As a user I want to be able to put objects in foreground/background or move up/down th object stack.
Maybe through keypresses.

Eraser tool

Feature request: Is there any way to implement an eraser tool? i.e I select a brush which when overlayed with an existing line, removes both (like the rubber tool in MS paint).

TypeError: _lib__WEBPACK_IMPORTED_MODULE_7__.tools[drawingMode] is not a constructor

Hi, I'm trying to locally run an application that uses streamlit-drawable-canvas.

I have followed the procedure for the development mode, but once started in place of the drawing component I get the error reported in the title.

I copy below the entire error log:

TypeError: lib__WEBPACK_IMPORTED_MODULE_7_.tools[drawingMode] is not a constructor
(anonymous function)
C:/WORK/streamlit-drawable-canvas-develop/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx:141

138 | */
139 | useEffect(() => {
140 | // Update canvas events with selected tool
141 | const selectedTool = new toolsdrawingMode as FabricTool
142 | ^ const cleanupToolEvents = selectedTool.configureCanvas({
143 | fillColor: fillColor,
144 | strokeWidth: strokeWidth,

Thank you in advance.

Clean the cache when rerun the function st_canvas()

Hi author,
Awesome work and really helpful to me. Now I realized automatically show photo in canvas and save the image. But I wonder how to clear the canvas when I show a new photo. Could you give me some suggestion?

Clear drawing

Hi there, great work btw! Just wanted to ask whether its possible to clear a drawing without refreshing the entire page. Thanks!

Add canvas width.

As the canvas already has a height , it is logical to add a canvas width?

"initial_drawing" over "background_image" only appears when clicking "Undo" or "Reset Canvas & History"

Hi,

first of all, thank you for this awesome extension to streamlit. I'd really like to make use of the "initial_drawing" capability in order to superimpose bounding boxes on images. However, there seems to be a bug that the background image overlays the drawing (while it should be the other way around). The drawing only appears in the following cases:

  • press "undo". This will prompt the app to show the initial drawing on top of the background image - this is what I want, but it should be like that in the first place without having to press "undo"
  • press "Reset Canvas & History". This will show the initial drawing, but remove the image

My super simple app is as follows:


import json
from pathlib import Path

import streamlit as st
from PIL import Image
from streamlit_drawable_canvas import st_canvas


with open("star_state.json", "r") as f:
    star_state = json.load(f)

canvas_result = st_canvas(
    fill_color="rgba(255, 165, 0, 0.3)",
    background_image=Image.open("img/tennis-balls.jpg"),
    update_streamlit=False,
    height=150,
    initial_drawing=star_state,
    key="full_app",
)

star_state.json and tennis-balls.jpg are from the demo repo.

Thank you for your help.

I cannot see drawable canvas on localhost

Great app,
I was trying to run the streamlit-drawable-canvas locally. However, the drawable canvas is not loading. I wonder if you could look at my issue.

my steps:
-I cloned streamlit-drawable-canvas repository
-run
-opened "Local URL: http://localhost:8501"
-uploaded an image

df

cannot draw anything

thank you in advance
ahmed

Add background image

Add background image. Maybe implies sending only drawing instead of full image data on mouse up

Calculate path length for line and freedraw?

Hi!

Great streamlit component! I want to calculate the path length (ie: total distance in pixels) for the freedraw and line tool. For the line tool, it's pretty straightforward by applying the Pythagorean theorem using the width and height provided. But I'm having a little trouble figuring out the best/most efficient way to do this for the freedraw tool.

Any advice for be greatly appreciated. Thanks!

Jethro

deletion update is 1 step behind

when deleting an object using the transform tool, the update is 1 step behind because the click event (and the update state) happens before the double click event fires.

A suggestion is to save the state after the double click event (a pull request #34).

Drag and Drop Icos/Images from Library into Canvas

The enhancement required is

  1. Ability to have a library for images, icons - which could be pre built or custom - user can load his or her own images, icons in this library or could be pulled from third party open source libraries of icons.
  2. Ability to the user to drag and drop the Icons/images into the Canvas.

Your app is having trouble loading the streamlit_drawable_canvas.st_canvas component.

I get this error message in my app website instead of canvas area,

"Your app is having trouble loading the streamlit_drawable_canvas.st_canvas component.

(The app is attempting to load the component from http://localhost:3001, and hasn't received its "streamlit:componentReady" message.)

If this is a development build, have you started the dev server?
If this is a release build, have you compiled the frontend?
For more troubleshooting help, please see the Streamlit Component docs or visit our forums."

I will be grateful if can help me solve it.

st_canvas displays cropped background image

Hi! Thanks for the super cool package. As the title says st_canvas displays a cropped background image even though the height and width of the canvas are set acc. to the image dimensions.

Here's my code:

    canvas_result = st_canvas(
            stroke_color='#fff',
            stroke_width=stroke_width,
            background_color='#000',
            background_image=image.copy(),
            height = image.size[1],
            width = image.size[0],
            update_streamlit=realtime_update,
            drawing_mode = drawing_mode,
            key = "canvas",
            )

Am I doing something wrong?

JSON update while using transform

I am having a problem in seeing updates in canvas_result.json_data while using transform on rect:

As an example, I am adding a few lines to app.py
If I add a few simple lines the top and left updates while using transform but somehow not width and height while scaling a rect

(this is the last part of app.py)

# Do something interesting with the image data and paths
if canvas_result.image_data is not None:
    st.image(canvas_result.image_data)
if canvas_result.json_data is not None:
    st.dataframe(pd.json_normalize(canvas_result.json_data["objects"]))
    # Just adding a json view of the first rect. 
    dic = canvas_result.json_data["objects"][0]
    st.text('Top value in json =' + str(dic['top']))
    st.text('Left value in json =' + str(dic['left']))
    st.text('Height value in json =' + str(dic['height']))     
    st.text('Width value in json =' + str(dic['width'])) 

Freedraw brush transparency

One more feature request; is it possible to be able to alter the transparency of the brush colour when in freedraw mode? Currently, when I alter the hex value to be semi-transparent, the brush colour is always fully opaque. This feature would be particularly useful when we want to identify two overlapping paths in an image.

Upload new background to existing canvas

I try uploading a new image to the background_image=NEW_IMAGE property while initializing the canvas.
The background is changed, but the new height and weight are not. Which makes this canvas unusable.

Deleting this canvas object and creating a new one doesn't help.

Is there any way to do so?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.