Streamlit - Drawable Canvas
This project is best effort. Every now and then I'll add something I need myself and let a coding agent do most of the typing, but I don't have the time to go through bigger issues or pull requests. If there's a larger feature you want, fork away!
Please add a thumbs up HERE if you wish to see a native implementation maintained by the Streamlit team.
Streamlit component which provides a sketching canvas using Fabric.js.
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
Requires Streamlit >= 1.53 and Python >= 3.10 (0.10.0 is built on Streamlit Components v2; see Upgrading from 0.9.x if you're on an older Streamlit).
pip install streamlit-drawable-canvas
return_image_data=True additionally requires Pillow and numpy:
pip install streamlit-drawable-canvas[image]
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,
return_image_data=True,
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.
For reading the returned drawing -- what's in json_data, why a resized shape keeps its
original width, how to map canvas coordinates back to your source image -- see
FAQ.md.
API
st_canvas(
fill_color: str
stroke_width: int
stroke_color: str
background_color: str
background_image: str | Path | bytes | Image
update_streamlit: bool
height: int
width: int
drawing_mode: str
initial_drawing: dict
display_toolbar: bool
point_display_radius: int
return_image_data: bool
key: str
on_change: callable
disabled: bool
background_image_fit: 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 : Image to display behind canvas: an http(s) URL, a
data:URI, a local file path, raw image bytes, or a Pillow Image. 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. Forced off for
drawing_mode="polygon"-- an in-progress multi-click polygon isn't a meaningful intermediate value; the completed polygon still sends once closed with a right-click. When nothing sends automatically, the toolbar stays pinned open instead of appearing on hover, because its send button is then the only discoverable way to commit a drawing. If what you want is "only give me the finished drawing", prefer anst.formoverupdate_streamlit=False-- see FAQ.md. - height : Height of canvas in pixels. Defaults to 400.
- width : Width of canvas in pixels. Defaults to 600.
- drawing_mode : One of
"freedraw","transform","line","rect","circle","point","polygon". Enable free drawing when "freedraw", object manipulation when "transform", otherwise create new objects with the rest. Defaults to "freedraw". Any other value raisesValueError.- 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_dataoutput from another 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/reset toolbar. When shown, it appears on hover as a floating card above the canvas's top-right corner, matching Streamlit's own element toolbars, and takes up no layout space. - return_image_data : If
True, populateimage_dataon the result with the canvas's RGBA pixels.Falseby default -- it PNG-encodes the whole canvas on every send. Requires theimageextra; accessingimage_datawithout both raises. - key : An optional string to use as the unique key for the widget. Assign a key so the component is not remounted on every rerun.
- on_change : Optional callback invoked when the component sends a new drawing.
- background_image_fit : One of
"stretch"(default) or"contain"."stretch"scales each axis independently to fill the canvas exactly, distorting the image when the aspect ratios differ -- this is the historical behaviour."contain"preserves the aspect ratio, fitting the image inside the canvas and centring it, so a canvas larger than its background image gets margins instead of a stretched image. Ignored when nobackground_imageis set. Any other value raisesValueError. - disabled : If
True, render the canvas read-only -- drawing, selection and transforms are all inert, nothing is sent back to Streamlit, and the toolbar is hidden regardless ofdisplay_toolbar.initial_drawingstill renders, so this is how you show a drawing back to someone without letting them change it. Defaults toFalse.
Example:
import streamlit as st
from streamlit_drawable_canvas import st_canvas
canvas_result = st_canvas()
st_canvas(initial_drawing=canvas_result.json_data)
Upgrading from 0.9.x
0.10.0 is a breaking release (Streamlit Components v2, Fabric.js 7). If you're upgrading:
image_dataraisesRuntimeError-- it's now opt-in. Passreturn_image_data=Truetost_canvas(), and install the extra:pip install streamlit-drawable-canvas[image].- Old Streamlit or Python -- 0.10.0 needs Streamlit >= 1.53 and Python >= 3.10. If
you can't upgrade, pin
streamlit-drawable-canvas==0.9.3. - Saved drawings from 0.9.x with Circle or Point objects render as a thin sliver, not
the original shape, when fed back in via
initial_drawing. Fabric 4 wroteCircle.startAngle/endAnglein radians; Fabric 7 reinterprets those same JSON keys as degrees, andloadFromJSONdoesn't consult the JSON'sversionfield to tell the difference. This is declared breaking, with no migration shim. Line, Rect, freedraw, Polygon, and Transform objects are unaffected -- only objects fromcircle/pointdrawing modes carrystartAngle/endAngle.
Development
Tasks are automated with just (see justfile) and uv. Run just (or just --list) to see every recipe.
Install
just setup # uv sync + npm ci (frontend) + pre-commit install
just reinstall # same, but wipes .venv / node_modules / build outputs first
Run the demo app
just demo # uv run streamlit run demo_app.py
For frontend changes, run the Vite watch-rebuild alongside it in another terminal --
it rebuilds frontend/build on every save, which just demo's Streamlit process picks
up on the next rerun:
just dev
Lint, format, test
just lint # ruff check + tsc --noEmit + prettier check
just format # ruff format + prettier write
just test # pytest + Vitest
End-to-end tests (Playwright)
just e2e-setup # one-time: install deps + browsers
just build # E2E needs the built frontend
just e2e # uv run pytest e2e_playwright -n auto
See the justfile (just --list) for the full recipe reference, including
version bumps and publishing.
References
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file streamlit_drawable_canvas-0.10.0.tar.gz.
File metadata
- Download URL: streamlit_drawable_canvas-0.10.0.tar.gz
- Upload date:
- Size: 120.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab9dffbd6e1b7d53de359344661cea9c323cb900815172860ec2a2adfc627cd2
|
|
| MD5 |
551b11c586284a34406d6183964f3b09
|
|
| BLAKE2b-256 |
28449beb2d7ee8096fdbf4c7844979f831a7a728916a1762bc093f9f5a7aa6dc
|
File details
Details for the file streamlit_drawable_canvas-0.10.0-py3-none-any.whl.
File metadata
- Download URL: streamlit_drawable_canvas-0.10.0-py3-none-any.whl
- Upload date:
- Size: 117.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e9abed2eb228b8bbbe4fc45a0c112af5baa0d5593aad616c0618ba7df6a4f25
|
|
| MD5 |
3fb305f14d70f0b59ba9f64931b3a013
|
|
| BLAKE2b-256 |
8897669cb33ca642243d7cf7846b7384ab121b3ddae39afafce29c15d0764023
|