# ipycanvas: drawing the browser Canvas API from Python

> ipycanvas is a Jupyter widget library that exposes the browser Canvas API to Python, so text, paths, polygons, images and animation can be drawn from a notebook cell. It is aimed at people who want interactive or data-driven drawings rather than a static figure.

**jupyter-widgets-contrib/ipycanvas** — Interactive Canvas in Jupyter

- Repository: https://github.com/jupyter-widgets-contrib/ipycanvas
- Website: https://ipycanvas.readthedocs.io/en/latest/
- Stars: 710 · Forks: 64
- Language: Python
- License: BSD-3-Clause
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/jupyter-widgets-contrib-ipycanvas

## The problem it solves is live drawing, not static figures

ipycanvas is a library that exposes the browser's Canvas API to IPython, and the point of it is interaction rather than rendering a finished plot. The project description calls it a lightweight, fast and stable library that lets you draw simple primitives directly from Python, covering text, lines, polygons, arcs and images, and the README goes further and says this simple toolset allows you to draw literally anything. The audience is therefore the notebook author who wants a drawing surface that reacts: a simulation that animates, a scatter of points that updates as data arrives, or a sketch that accepts drag and drop. The topic tags list canvas, canvas2d, interactive-visualizations, jupyter and jupyterlab, which is an honest description of the scope. The project lives under the jupyter-widgets-contrib organisation and is distributed under BSD-3-Clause, with documentation hosted at ipycanvas.readthedocs.io.

## A widget model: Python state on one side, a browser canvas on the other

The architecture is the standard ipywidgets model, and the dependency list in pyproject.toml makes it explicit. The runtime requirements are `ipywidgets>=7.6.0,<9`, `numpy` and `pillow>=6.0`, so the library sits on top of the widget protocol rather than talking to a browser directly, and NumPy arrays and Pillow images are first class inputs rather than conversions you write yourself. The widget state lives in the kernel, and the front end is a separate TypeScript project that is bundled into two artifacts: a classic notebook extension and a JupyterLab extension. The build in package.json produces both, and pyproject.toml declares where the built assets are installed, placing the nbextension under `share/jupyter/nbextensions/ipycanvas`, the labextension under `share/jupyter/labextensions/ipycanvas`, and a notebook configuration file at `etc/jupyter/nbconfig/notebook.d/ipycanvas.json`. In other words, the same Python API is reachable from a classic notebook and from JupyterLab, and the shipped files decide which one loads.

## Installing with pip, conda, and the extra step for JupyterLab 2

The README gives pip as the primary route, and the command installs the library together with orjson:

```bash
pip install ipycanvas orjson
```

A conda route exists for people managing environments that way:

```bash
conda install -c conda-forge ipycanvas
```

There is a third case, and it is the one that catches people out. If your JupyterLab is version 2 or older, the front end extension has to be installed separately, which the README handles with yarn and the labextension command:

```bash
conda install -c conda-forge yarn
jupyter labextension install @jupyter-widgets/jupyterlab-manager ipycanvas
```

Newer setups do not need that step. The build configuration in pyproject.toml pins `jupyterlab>=3,<5` for the build environment, which tells you which lab versions the project is built against, and the file also keeps a legacy `setup.py` shim for applications that still require one. A development installation guide is linked from the README for anyone building from source.

## Drawing from NumPy arrays and the offscreen canvas

The example notebooks in the repository show the range of use cases, and their filenames are more informative than any claim about capabilities. There is 06.binary_image.ipynb for drawing data directly from a NumPy array, 07.batch_drawing.ipynb for issuing many draw calls together, and 16.offscreen_canvas.ipynb for working with a canvas that is not attached to the visible widget. 09.interaction_during_animation.ipynb is the one to read if you care about responsiveness, since it shows interaction while an animation loop is running, and 11.drag_and_drop_example.ipynb covers pointer input. 18.plot3d.ipynb and 19.3d_monkey.ipynb are 3D experiments, 20.mapping.ipynb and 21.fractals_tree.ipynb cover texture mapping and recursive drawing, and 17.plotting.ipynb is the notebook for people who want to build a plotting library of their own entirely in Python. Two helper abstractions are demonstrated separately: 23.roughcanvas.ipynb for a hand-drawn look and 05.sprites.ipynb for custom sprite animation.

## The front end is a TypeScript project built with webpack and yarn

The repository is a hybrid project, and that has consequences for anyone planning to contribute or to pin a version. The top level contains a `src/` directory, a `tsconfig.json`, `webpack.config.js` and `webpack.lab.config.js`, a `package.json` and a `yarn.lock`, alongside the Python package directory `ipycanvas/`, a `pyproject.toml`, a `setup.py` and a `dev-environment.yml` for conda based development setups. The npm side is version 0.14.3 and the package is published with the `lib` and `dist` outputs, and the licence field in package.json and the LICENSE.txt file agree on BSD-3-Clause. The build scripts in package.json show the split: the TypeScript compiler produces the library, webpack produces the classic notebook extension bundle, and `jupyter labextension build .` produces the JupyterLab extension. Versioning is shared between the two halves, with pyproject.toml deriving the package version from the nodejs source through hatch.

## Where ipycanvas is the wrong tool

Three limits are visible in the project itself. First, the output is a widget, not a file. If you need a PNG of your chart for a paper, a slide or a commit, this library does not give you one, and the workflow of generating figures in a notebook and collecting them later does not fit. Second, the surface you draw on is the Canvas API, which is a 2D immediate mode API. The README lists text, lines, polygons, arcs and images as the primitive set, and anything beyond that, such as axes, ticks or legends, is something you build yourself, as the plotting example illustrates. Third, the browser side is a hard dependency. A notebook executed on a headless server with no browser has nowhere to draw, and the offscreen canvas example shows a canvas detached from the visible widget rather than a path that avoids the browser entirely. The documentation also does not describe how the widget behaves in every notebook front end, so a non standard front end is untested territory.

## Item level drawing against a server rendered figure

The realistic alternative to a canvas widget is a conventional plotting library that renders a figure in the kernel and embeds the result as an image in the notebook output. The difference in approach is where the drawing happens. A server rendered figure is a snapshot: it is produced once, it is portable, it embeds in any notebook viewer and it can be saved or exported with ordinary tooling. A canvas widget keeps a live object in the browser that Python mutates over time, which is what makes animation, drag and drop and incremental data updates possible, and what makes the output dependent on a working browser and on the front end extension being installed. The trade-off runs in both directions. If your need is a repeatable figure for a report, a rasterised figure is simpler and more portable. If your need is a drawing that responds while the kernel is still running, a static image cannot do it at all, and ipycanvas exists for that case. The 17.plotting.ipynb example makes the point from the other direction, showing that a plotting layer can be written entirely in Python on top of the canvas.

## Release cadence and what an upgrade costs

Maintenance is visible in the tag history. The last push was on 2026-07-01, and the three most recent releases are 0.14.3 on 2025-12-11, 0.14.2 on 2025-12-10 and 0.14.1 on 2025-08-01. Two patch versions in consecutive days followed a gap of several months, so the pattern is irregular rather than a steady stream, and a project that depends on a recent ipywidgets release should pin accordingly. The upgrade cost is mostly a dependency question: ipywidgets is constrained to `>=7.6.0,<9`, NumPy and Pillow are required, and the build targets `jupyterlab>=3,<5`. Under BSD-3-Clause the code can be used and modified in commercial and closed contexts, with the requirement that the copyright notice and licence text travel with redistributed copies, though the widget code also sits in a browser front end whose licensing is separate. The project also keeps a CHANGELOG.md and a documentation site that the README points to for questions, and a Gitter channel and GitHub discussions for support.

## Conclusion

ipycanvas fits notebook authors who need a drawing surface that responds to mouse input, streams data or animates, and who accept writing JavaScript-flavored drawing code in Python. It does not fit people who want a standard plot to paste into a paper, since the output is a widget rather than an image. Check first that your environment satisfies the declared dependencies, `ipywidgets>=7.6.0,<9`, `numpy` and `pillow>=6.0`, and that your JupyterLab version is covered by the `jupyterlab>=3,<5` build requirement, because a JupyterLab 2 setup needs the separate labextension install step. The last push was on 2026-07-01 and version 0.14.3 was released on 2025-12-11 under BSD-3-Clause.

## FAQ

### How do I install ipycanvas in a JupyterLab environment?

With pip the README gives `pip install ipycanvas orjson`, and conda users can run `conda install -c conda-forge ipycanvas`. If you run JupyterLab 2 or older, the README also asks for the labextension install step with `jupyter labextension install @jupyter-widgets/jupyterlab-manager ipycanvas`.

### What are the Python dependencies of ipycanvas?

The project metadata lists `ipywidgets>=7.6.0,<9`, `numpy` and `pillow>=6.0` as runtime dependencies, and the build system requires `jupyterlab>=3,<5`.

### Can ipycanvas be used to draw data from a NumPy array?

Yes. The repository includes an example notebook named 06.binary_image.ipynb that draws data directly from a NumPy array, and NumPy is a declared runtime dependency.

## Sources

- [jupyter-widgets-contrib/ipycanvas on GitHub](https://github.com/jupyter-widgets-contrib/ipycanvas)
- [License: BSD-3-Clause](https://github.com/jupyter-widgets-contrib/ipycanvas/blob/master/LICENSE)
- [Project website](https://ipycanvas.readthedocs.io/en/latest/)
- [README](https://github.com/jupyter-widgets-contrib/ipycanvas/blob/master/README.md)
- [Releases](https://github.com/jupyter-widgets-contrib/ipycanvas/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jupyter-widgets-contrib-ipycanvas
