Creating Reactive Jupyter Widgets With Svelte

Alex Cabrera
4 min readNov 10, 2020

--

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.

Examples of Jupyter Widgets. (A) Ipyleaflet renders dynamic maps. (B) QGrid lets users dynamically interact and modify their dataframes. (C) Errudite is a comprehensive system for debugging machine learning models for language tasks

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:

Example Jupyter + Svelte widget

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:

example.py in the widget_svelte_example/ folder. This is the main file for the Python component, which can define variables, listen for changes, and dynamically update.

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 countin 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.

At the bottom of stores.ts we add a new WidgetWritable and new .setModel(model) call

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!

--

--