Drawable canvas

@andfanilo , how can I predraw some shapes on @streamlit canvas such as square, rectangle, traingle or some icon(say smartphone icon). I do not want the user to use his mouse to create these shapes on the canvas. Basically I want to draw these shapes automaticaly at random places in the canvas based on some other actions by user such as his age, gender, etc.

1 Like

Thanks for much for your code. I had a quick question. When I look at the output of the rectangular (json), it doesn’t seem to update the width and height if I use the transform function. The rectangular on the images is updated but not the value in the json.

Hey @Alexander_Hexemer,

Interesting :thinking: could you bring a new issue (with some code snippet would be perfect!) to the Github repo? Issues · andfanilo/streamlit-drawable-canvas · GitHub

Thanks a lot!
Fanilo

Hi Fanilo,
Thanks for the super-fast response. I just added a small snippet of code to show my issue. Thanks again for the help.
Cheer,s
Alex

1 Like

Hello @Alexander_Hexemer, responded on the GIthub issue but maybe that could help others:

Under the hood, json_data is a FabricJS object exported in JSON with .toObject.
It seems for a scaled object, you will need to apply the scaleX/scaleY factor to the height/width to retrieve the correct values. FabricJS preserves the original dimensions and applies a ratio independently.

st.text(f"Scaled height: {dic['height'] * dic['scaleY']}")
st.text(f"Scaled width: {dic['width'] * dic['scaleX']}")

doesn’t seem like rotating the rectangle adds more complexity :slight_smile: .

@andfanilo Thanks for this great component!

After playing around with this a while, I’m still trying to figure out if there is a way to pass drawings to the canvas or load a state from Streamlit? Has anyone had any success with this?

Hello @tcfkaj, welcome to the community !

Coming soon :wink:

Cheers
Fanilo

1 Like

Hi im not that familiar with the component yet but id like to know if it is possible to have a jpg as background picture so u can draw above it. oh wait i just found it.

thanks

1 Like

is there a way to remove/make invisible the lower pane from the display? and the table that shows the list of shapes drawn ?

No not yet, as it’s the only way for now to redo/undo/delete changes. Could you open an issue in GitHub - andfanilo/streamlit-drawable-canvas: 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. if you need this? Thanks!

Yes, this is post-processing inside the app.py, you can drop the

if canvas_result.json_data is not None:
    st.dataframe(pd.json_normalize(canvas_result.json_data["objects"]))

part to remove the table.

Fanilo :balloon:

Drawable Canvas Release 0.7.0 :pencil2: with some quick fixes, mostly around loading previous drawings.

  • initial_drawing is now used as the initial canvas state. If None provided then we create one on the Python side. This provokes the following changes:
    • a change in background_color will reset the drawing.
    • background_color will override the background color present in initial_drawing.
    • if background_image is present then background_color is removed from st_canvas call.
  • Upgrade Fabric.js to version 4.4.0.
  • Toolbar is now on the bottom left to account for large canvas width.
  • Add argument to make the toolbar invisible.
  • Make stroke_width the minimum size constraint to create a rectangle and circle. Thanks hiankun for the PR!

App: https://share.streamlit.io/andfanilo/streamlit-drawable-canvas-demo/master/app.py
Code: GitHub - andfanilo/streamlit-drawable-canvas: 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.

There’s a kinda breaking change in that changing background_color now resets drawing, so do tell me if this impacts you.

Happy Streamli-drawing :balloon: ,
Fanilo

Weekend tip!

With a SVG path library like svgpathtools, you can load and manipulate the paths you draw on the canvas. For example you can compute the length in pixels of any drawn arc on the canvas!

If you’re interested in comparing distances by drawing on an image, I’ve added the code snippet to compute arc lengths in the demo app.

Happy drawing in Streamlit :balloon:

1 Like

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.

Hi @ejyuen !

Hmmm thanks for reporting. I created an issue on github: TypeError: string indices must be integers · Issue #57 · andfanilo/streamlit-drawable-canvas · GitHub.

If possible could we continue the discussion there :slight_smile: ? Most notably I’d love to know your version of streamlit-drawable-canvas, if you made a recent upgrade and if it works again by downgrading.

Thanks a lot,
Fanilo

EDIT: linked to component value of type dict is not properly marshalled with streamlit==0.84.0 · Issue #3507 · streamlit/streamlit · GitHub, @ejyuen the bug has been introduced by Streamlit 0.84, if you downgrade to 0.83 it should work. Do you need Drawable Canvas to work with 0.84 immediately?

Hey everyone, this should be fixed with Streamlit 0.84.1 streamlit/streamlit#3507 (comment). I’ve tested on the demo app and it works well, so it should work on your side too!

Fanilo

Hey @andfanilo
I have a small issue I m trying to draw a polygon and use it as the ROI for detections in a video but I am not sure how exactly can I extract the points from the table as I am getting the following error

for this code st.dataframe(pd.json_normalize(canvas_result.json_data["objects"])) in drawing a polygon

ArrowTypeError: ("Expected bytes, got a 'int' object", 'Conversion failed for column path with type object')

2 Likes

I’ve also had the same issue with the st.dataframe function.

Hey @Pavankunchala @aswincandra

Sorry for taking so long to answer, holidays :slight_smile:

Looks like a Streamlit Arrow upgrade problem, does it work if you downgrade Streamlit before version 0.85?

Fanilo

1 Like

TypeError: a bytes-like object is required, not ‘CanvasResult’

I am using 0.88 version

# Create a canvas component
image_data = st_canvas(
    b_width, b_color, bg_color, height=150, drawing_mode=drawing_mode, key="canvas"
)

# Do something interesting with the image data
if image_data is not None:
    st.image(image_data)

and the code is:

1 Like

I have a small issue I m trying to draw a polygon and use it as the ROI for detections in a video but I am not sure how exactly can I extract the points from the table as I am getting the following error for this code st.dataframe(pd.json_normalize(canvas_result.json_data["objects"])) in drawing a polygon ArrowTypeError: ("Expected bytes, got a 'int' object", 'Conversion failed for column path with type object')
I think the explanation is https://discuss.streamlit.io/t/all-in-on-apache-arrow/15342/3:

        if canvas_result.json_data is not None:
            objects = pd.json_normalize(canvas_result.json_data["objects"])
            for col in objects.select_dtypes(include=['object']).columns:
                objects[col] = objects[col].astype("str")
            st.dataframe(objects)
  • or change the serialization from arrow to legacy, by putting in .streamlit/config.toml the following:
[global]
dataFrameSerialization = "legacy"

@BeyondMyself the image is stored in image_data.image_data, the image_data variable contains 2 properties: image_data for the image and json_data for the canvas JSON representation.