Creating Reactive Jupyter Widgets With Svelte
TL;DR — You can use the Svelte Widget Cookiecutter to create Jupyter Widgets with modern, reactive web technologies.
Over the past decade Jupyter Notebooks have become the most popular platform for data science, and their use is only growing. Data scientists are drawn by how modular and interactive notebooks are, making it easy to prototype, modify, and share code and analysis.
One of Jupyter Notebooks’ most powerful features are Jupyter Widgets (also known as ipywidgets): custom, interactive widgets that interface with the Python kernel. Developers have created an amazing array of widgets for notebooks, from embedded maps and interactive data frames to full AI debugging systems.
Unfortunately, authoring widgets can be challenging. The API is centered around early web technologies like the Model-View-Presenter (MVP) framework that makes it tedious to make widgets with more than a couple variables or views. To improve this process, we adapt the widget API to work with a modern, reactive frontend framework, Svelte. With Svelte, we can abstract away the traditional paradigm of listeners and manual state updates and write reactive frontend code.
An Example Widget
Let’s make a Svelte Widget! We’ll start with a baseline template and then add a new variable and feature. First, clone the widget example repository and install it for Jupyter Notebooks/Lab with the following:
git clone https://github.com/cabreraalex/widget-svelte-example
pip install -e .
You can test it out by running
jupyter notebook or
jupyter lab and opening
examples/introduction.ipynb. You should see the following notebook:
What is a Widget?
A widget is made up of two major components: the backend module and the frontend interface. The Python module is found in the
widget_svelte_example/ folder, which has the widget file
example.py. The frontend code is in
src/, with the main component
Widget.svelte. Other files and folders deal with building and packaging the widget.
Let’s explore what’s in each component. In
example.py we find the following:
ExampleWidget extends the
DOMWidget class and is made up of various Traitlets. Traitlets are the bread and butter of Jupyter Widgets, they are type-checked variables that can be synced with the frontend using the
.tag(sync=True) option. In this case we have declared a String (Unicode) Traitlet called
value that we want to sync with the frontend.
Now lets take a look at the frontend, primarily
App.svelte is a Svelte component (learn more about Svelte components here) that has access to the same
value variable described in
example.py in the form of a Svelte store. It then has HTML that displays the value and a button that increments it. And that’s about all it takes! We’ll next look at how you can declare new Traitlets to sync variables between the frontend and backend.
Adding a Units Variable
Lets walk through adding another Traitlet and feature to our widget: a simple number we want to increment.
First, we’ll define a new Integer Traitlet (string) in
Next, we create a new store for
stores.ts and a button to increment it in
Widget.svelte . We use the WidgetWritable constructor to create a synced writable store, and initialize it with the widget model.
To update the widget, use
yarn build to compile the frontend Svelte and TypeScript and run the notebook again with
jupyter notebook or
Creating Your Own Widget
That’s all you need to make a Svelte widget! To make it easier to start a new widget I’ve made a cookiecutter template, which creates a new widget with your information (instead of cloning an existing widget). You can use to quickly set up a new project with the following commands:
pip install cookiecutter
During development, if you update the frontend code just run
yarn build and refresh the Jupyter notebook. You can also use
yarn watch to automatically rebuild on every file change. If you update the Python code, restart the kernel. If you have any issues or suggestions please leave a comment or issue!