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.
Why Svelte?
Any modern web framework could be used to create Jupyter Widgets, but Svelte has a few advantages. Primarily, Svelte does not require any new language or syntax, it’s plain HTML and JavaScript with a few extra decorators, meaning developers don’t have to learn a whole new platform. There are various other benefits that can be found here, and the Svelte website has a great interactive tutorial to get started.
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
cd ./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
:
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 example.py
called count
:
Next, we create a new store for count
in 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 jupyter lab.
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
cookiecutter https://github.com/cabreraalex/widget-svelte-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!