Jupyter UI wrangling
What happens inside those notebook cells doesnt stay inside tgose notebook cells
2017-02-09 — 2025-02-13
Wherein the mechanics of the Jupyter user interface are laid out in sober terms, and the procedure for exporting notebooks as reveal.js slides is demonstrated alongside notes on rich display and widgets.
Jupyter is complicated, so I separated information about the UI, rendering, and so on from the main notebook. Here’s the bit on using the Jupyter system to support non-standard user interactions.
1 Generative AI in
Runcell is an example of a Jupyter Notebook extension that integrates generative AI into the notebook interface. In other words, it provides functionality we get for free when we use Python in a modern IDE, but that’s hard to achieve in the hostile Jupyter notebook interface.
2 Presentations using Jupyter
2.1 Basic: export to reveal.js
Jupyter can export a notebook as a browser-based presentation! The easiest is Classic reveal.js mode. tl;dr:
We might want to make various improvements, such as tweaking the reveal.js settings in Jupyter slideshows.
If we aren’t running a coding class, we may want to hide the input cells from our IPython slides by customizing the output templates, or we can suppress all code by using output format hide_code_slides.
These tweaks aren’t too crazy, but some require a copy of the reveal.js source.
As an example, a more comprehensive version using a custom theme and the reveal.js source looks like
2.2 Fancier: integrated slideshows using RISE
Fancier again: interactive slideshows using RISE.
To meet our house-style requirements, it’s usually enough to customize some decorations and alter some CSS.
Major plus: we can execute code while running the slides!
Major minus: I don’t see any way to style cover slides differently, which conflicts with, for example, my university’s style guide.
If I don’t want to show inline input code, I can hide it with hide_code.
Install using pip:
Install using conda:
3 Rich display
We can show Python objects with rich display, for example with IPython.display.Image.
Or you can use Markdown to display a local image.
If we want our objects to display richly, we can implement the appropriate magic methods:
I used this to build a LaTeX renderer called latex_fragment that we should totally check out for rendering inline algorithms or emitting SVG equations.
Alternatively, we can use the inbuilt Jupyter LaTeX renderer:
4 Graphs
Set up inline plots:
Inline SVG:
Graph sizes are controlled by matplotlib. Here’s how we make big graphs:
Interesting-looking other graphing options:
Jupyter lab includes such nifty features as a diagram editor which you can install using jupyter labextension install jupyterlab-drawio
5 Citations and other academic writing in Jupyter
I did this for
my blog — using simple Zotero markdown citation export, which is not great for inline citations but fine for bibliographies, and easy and robust.
my papers — abandoning Jupyter in favour of
Pweave+pandoc, which works amazingly for everything if you use pandoc tricks for your citations.
I couldn’t find a unified approach for these two different use cases which didn’t sound like more work than it was worth. At least, many academics seem to have way more tedious and error-prone workflows than this, so I’m just being a fancypants if I try to tweak it further.
More recently, there has appeared jupyterbook which enables notebook-based blog rendering, including citations. This is built using the ruby site generator jekyll-scholar so is heavy in dependencies but it seems to work. A hyped example of this in action is You Only Write Thrice.
Chris Sewell has produced a script called ipypublish that eases some pain points in producing articles. It’s an impressive piece of work.
My own latex_fragment allows you to insert one-off LaTeX fragments into Jupyter and Pweave (e.g. algorithmic environments or some weird TikZ thing.)
Jean-François Bercher’s jupyter_latex_envs reimplements various LaTeX markup as native Jupyter including \cite.
Sylvain Deville recommends treating Jupyter as a glorified markdown editor and then using pandoc, which is an OK workflow if you are producing a once-off paper, but not for a repeatedly updated blog.
nbconvert has built-in citation support but only for LaTeX output. Citations look like this in markup:
or even
The template defines the bibliography source and looks like this:
And the build looks like this:
As above, it’s helpful to know how the document templates work.
Note that even in the best case we don’t have access to BibTeX-style citations, so auto-year citation styles will look funky.
Speaking of custom templates, the nbconvert setup is customizable for more than just LaTeX.
But how about online? cite2c seems to do this by inserting citations live from Zotero, including author–year details. (Requires Jupyter Notebook 4.2 or later, which might require a pip install --upgrade notebook)
Julius Schulz provides a comprehensive config for this and everything else.
This workflow is smooth for directed citing, but there’s no way to include a bibliography except via citations, so we have to name-check every article. The citation keys it uses are Zotero citation keys, which are nothing like our BibTeX keys, so they can’t really be edited manually.
If you are customizing the output of Jupyter’s nbconvert, be aware that the {% block output_prompt %} override doesn’t actually do anything in the templates I use (slides, HTML, LaTeX). Instead, we need to use a config option:
I had to use the source to discover this.
Here’s what ipyBibtex.ipynb looks like:
So it supports author–year citations, but it’s a small, unmaintained package and therefore risky.
🏗 Work out how Mark Masden got citations working?
6 Interacting
Jupyter supports interactions! For some special cases with backing by a major firm or dev team—like dashboards—this can be an easy way to interact with Python.
In the general case, not so much. For a while I thought building widgets in Jupyter might be useful or convenient, but after many days of effort I concluded my early experiments weren’t convenient. The API changes so frequently that maintaining a UI long‑term would have to be effortless to be viable. These days I regard using Jupyter for interactions as adding extra failure points to an app that would be better off without it.
6.1 Gradio
For Python ML apps, Gradio seems to work in Jupyter, or at least in Colab. TBD
6.2 Dashboards
6.3 Updating progress graphs
6.4 Widgets
Official documentation: ipywidgets.
See also the announcement: The announcement says Jupyter supports interactive JS widgets and discusses the data-binding module in terms of JavaScript UI thingies.
Pro tip: If we want a list of widgets
Then we use them.
6.5 PixieApps
An alternative — or perhaps complementary — system is PixieApps:
PixieApps are Python classes used to write UI elements for your analytics, and they run directly in a Jupyter notebook.
PixieApps are designed to be easy to build. Mostly, you’ll only need to write HTML and CSS with some custom attributes, along with some Python for the business logic. Except in rare cases, you won’t have to write JavaScript. The PixieDust JS runtime will automatically listen to key events and manage transactions to the Jupyter kernel appropriately.
The whole kit is rather heavy: it requires Java and installs Scala, which feels OTT.
6.6 External event loops
External event loops are now easy to use and documented. The docs don’t say outright that if we want to use the tornado event loop, we can relax — both the Jupyter server and the IPython kernel already use the pyzmq event loop which subclasses the tornado one.
If we want this to work smoothly without passing ioloops everywhere, make zmq install itself as the default loop:
Now, our asynchronous Python should just work using tornado coroutines.
NB: With the release of the latest asyncio and tornado and various major version incompatibilities, I’m curious how smoothly everything still works.
6.7 JavaScript from Python with Jupyter
As seen in art python.
Here’s how we invoke JavaScript from Jupyter. Here’s the Jupyter JS source and the full Jupyter browser JS manual, and the Jupyter JS extension guide.
