Jupyter front end systems

UX design by underfunded volunteer committee is how I like my data science

2017-02-09 — 2025-08-27

Wherein the Jupyter ecosystem is described as an ecology of kernels and front-ends, and VS Code integration is noted as an alternative that couples notebook execution with a full code editor.

faster pussycat
premature optimization
python
Figure 1

Jupyter, the Python code dev environment, is not monolithic but a whole ecology. Different language back-end kernels talk to various front-end interfaces over a range of protocols for interaction and rendering. I can execute Python code interactively using several different front-ends, each offering a distinct user experience. Because the, er, food web of this ecosystem is complicated, it’s not always easy to know which chunk of code is responsible for which part of the user experience.

The default front-end (either “classic” or “lab”) isn’t my favourite user experience. Notebook classic was a great first draft, although there were some things I didn’t enjoy. Subsequent developments doubled down on the things I don’t like, worsening the user experience.

But there are choices for all tastes, and some of them are not as bad. Let us examine some:

1 Generating Jupyter code via AI

Can Claude et al generate Jupyter notebooks for me? Not natively, because the Jupyter file format is horrible.

I have seen some MCP servers that might make this feasible:

However, I haven’t tested them.

2 Command line

Command line:

jupyter run notebook.ipynb

What is the difference between this and just running normal Python scripts from the command line?, you might ask. For one thing, jupyter wastes more hard disk space and doesn’t version nicely.

If we want to mix the two we can, for example, execute a notebook from the command line and capture the output in a new notebook, which might provide some advantage.

jupyter nbconvert --to notebook --execute my_notebook.ipynb

See the nbconvert executing notebooks manual for more options.

3 Papermill

Papermill takes it a step further — too far for me, in fact — converting a Jupyter notebook into a Python script with a Python command line interface.

papermill is a tool for parameterising, executing, and analysing Jupyter Notebooks.

Papermill lets you:

  • parameterize notebooks
  • execute notebooks

This opens up new opportunities for how notebooks can be used. For example:

  • Perhaps you have a financial report that you wish to run with different values on the first or last day of a month or at the beginning or end of the year, using parameters makes this task easier.
  • Do you want to run a notebook and depending on its results, choose a particular notebook to run next? You can now programmatically execute a workflow without having to copy and paste from notebook to notebook manually.

These are all fine features, but if I were going to build these features, wouldn’t I rather write a script without Jupyter? Nonetheless, it probably makes things easier for some people and certainly beats Excel.

4 Mercury

Mercury allows you to add interactive widgets in Python notebooks, so you can share notebooks as web applications. Forget about rewriting notebooks to web frameworks just to share your results. Mercury offers a set of widgets with simple re-execution of cells.

You can build with Mercury:

  • Turn your notebook into beautiful Web Apps,
  • Create interactive Presentations with widgets, you can recompute slides during the show,
  • Share notebooks as static Websites,
  • Build data-rich Dashboards with widgets,
  • Create Reports with PDF exports, automatic scheduling, and email notifications (coming soon),
  • Serve Python notebooks as REST API endpoints (coming soon).

5 VS Code Jupyter

VS Code’s jupyter integration is good-ish and its support for plain Python is excellent.

A jupyter front-end is already an app we need to install to interact with the code, so why not install a good one instead of a bad one? Further, there are a huge number of benefits to using a proper editor to edit code, instead of jupyter. More benefits than I care to enumerate, but I’ll start.

I do not need to learn new keyboard shortcuts. I do not need to arse around with the various defective reimplementations of text editors from inside the browser. Further, heaps of other things that jupyter can’t even dream of just magically work! Session sharing? No problem. Remote editing? Easy! Type inference! Autocomplete! Debugger injection! Search and replace across a whole project! Style checking! Refactor assistance! Comprehensible documentation.

See VS Code for Python for more details.

Still, if that is not our jam, read on for some onerous alternatives that I dislike and will later say “I told you so” about.

6 Notebook classic

The one that was the recommended one until, I dunno, 2015 or so; I can’t recall. Worth knowing, to set expectations for what all the other front-ends are attempting to emulate.

6.1 Configuring

The location of theming infrastructure, widgets, CSS, etc. has moved recently; check your version number. The current location is ~/.jupyter/custom/custom.css, not the former location ~/.ipython/profile_default/static/custom/custom.css

Julius Schulz’s ultimate setup guide is also a great compilation of pro tips.

6.2 Auto-closing parentheses

If I must use jupyter notebook, I kill parenthesis molestation (referred to in the docs as bracket autoclose) with fire. I don’t like having to fight the notebook’s misplaced faith in its ability to read my mind. The setting is tricky to find, because it’s not called “put syntax errors in my code without me asking Y/N”; it’s cm_config.autoCloseBrackets and isn’t in the preference menus. According to a support ticket, the following should work.

# Run this in Python once, it should take effect permanently

from notebook.services.config import ConfigManager
c = ConfigManager()
c.update('notebook', {"CodeCell": {
  "cm_config": {"autoCloseBrackets": False}}})

Or add the following to custom.js:

define([
    'base/js/namespace',
], function(Jupyter) {
    Jupyter.CodeCell.options_default.cm_config.autoCloseBrackets = false;
})

Or maybe create ~/.jupyter/nbconfig/notebook.json with the content

{
  "CodeCell": {
    "cm_config": {
      "autoCloseBrackets": false
    }
  }
}

That doesn’t work with jupyterlab, which is even more righteously convinced it knows better than we do about what we truly want to do with parentheses. Perhaps the following will work? Let’s open Settings --> Advanced Settings Editor and add the following to the User Overrides section:

{
  "codeCellConfig": {
    "autoClosingBrackets": false
  }
}

Or in the file ~/.jupyter/lab/user-settings/@jupyterlab/notebook-extension/tracker.jupyterlab-settings.

Ahhh. Update: it’s easier now.

Figure 2

6.3 Notebook extensions

Jupyter classic is more usable if we install the notebook extensions, which include, e.g., drag-and-drop image support.

$ pip install --upgrade jupyter_contrib_nbextensions
$ jupyter contrib nbextension install --user

For example, if we run nbconvert to generate an HTML file, the image will remain outside the file. We can embed all images by calling nbconvert with the EmbedPostProcessor.

$ jupyter nbconvert --post=embed.EmbedPostProcessor

Update — broken in Jupyter 5.0

Wait, that was still pretty confusing; I need the notebook configurator whatsit.

$ pip install --upgrade jupyter_nbextensions_configurator
$ jupyter nbextensions_configurator enable --user

7 JupyterLab

jupyter lab (sometimes styled jupyterlab) is the current cutting edge according to Jupyter mainline, and reportedly is much nicer to develop plugins for than the notebook interface. From a user perspective, it’s more or less the same thing, but the annoyances differ. It doesn’t strictly dominate notebook in terms of user experience, although I understand it might for plugin developers’ experience.

A pitch targeted at us users explains some practical implications of JupyterLab and claims it’s the one true way and the righteous future, etc. Since we’re not in the future, though, we have to deal with certain friction points in the present, actually-existing JupyterLab.

7.1 JupyterLab UI

The UI, though… The mysterious curse of JavaScript development is that once you’ve tasted it, you can’t resist an uncontrollable urge to reimplement something that already works — but as a jankier JavaScript version. The JupyterLab folks have tasted that forbidden fruit, have SpiderMonkey on their backs, and hunger to reinvent things using JavaScript. So far they’ve reimplemented copy, paste, search/replace, browser tabs and the command line.

Yo dawg I heard you like notebook tabs so I put notebook tabs in your browser notebook tab.

The replacement Jupyter tab system clashes with the browser tab system, keyboard shortcuts and generally confuses the eye. Why do we get a search function that, AFAICT, non-deterministically does regexp matching but then doesn’t search the whole page? Possibly the intention is that it shouldn’t be run in a normal browser but in a custom single-tab embedded browser? Or maybe, for true believers, once we load a Jupyter notebook we like it so much that we never need to browse the web again and we close all the other tabs forever. Whatever the rationale, the learning curve for these weird UI choices is bumpy, and the lessons are not transferable.

Is the learning process worth it? I am not using Jupyter for its artisanal, quirky alternate take on tabs, cut-and-paste etc., but because I want a quick interface to run some shareable code with embedded code and graphics. Does it get me that?

Maybe. If I get in and out fast, do most of my development in a real code editor and leave the Jupyter nonsense for results sharing, I neither need the weird UI nor am I bothered by it. The other features are like that button on the microwave labelled “fish”, which no one has ever needed or intentionally used, but which doesn’t stop the microwave from defrosting things if you use the normal controls.

At the same time, some JupyterLab enthusiasts want to re-implement text editors, which suggests there might be a contagion of NIH fever in the community, and it makes me nervous.

Whether I like the overwrought JupyterLab UX or not, we should allow it a moderate nonsense-baggage allowance if the developer API is truly cleaner and easier to work with. That would be a solid win in delivering features I actually regard as improvements, including, maybe, ultimately, a better UI.

7.2 Collaborative options

Simultaneous users are supported natively in JupyterLab with an OK UI for identifying running notebooks. I think this could be a killer feature of JupyterLab. As implemented, it’s usable, but sometimes calculation output gets lost somewhere in the system.

There is an under-documented project to introduce real-time collaboration in JupyterLab coordinating on notebook content, code, output and backend state, which apparently works, but is barely mentioned in the docs. Maybe the JupyterLab RTC Design Documentation would help there.

If we have a snakepit of different Jupyter sessions running on a machine we’ve just logged in to and want to open the browser to get a UI for them, then we need to work out which are running on that machine so that we can attach to them. The command is (for either Jupyter Notebook or JupyterLab sessions):

jupyter notebook list

7.3 Lab extensions

Related to, inspired by, and maybe conflicting or intersecting with the nbextensions are the labextensions, which add extra functionality to the lab interface rather than the notebook interface (JupyterLab is built on the notebook interface and runs notebooks similarly, but with different moving parts under the hood.)

I try to keep using these to a minimum because I have a possibly irrational foreboding that some complicated death spiral of version clashes is starting between all the different Jupyter kernel, lab and notebook installations I have cluttering up my hard disk, and it can’t improve things to add various versions of lab extensions to the mix, can it? And I really don’t want to have to understand how it works to work out whether that’s true or not, so please don’t explain it to me. I also don’t wish to obsessively update lab extensions everywhere.

Anyway, there are some useful ones, so I live with it by obsessively running install and update commands in every combination of kernel/lab/whatever environment in the hope that something sticks.

Life is easier with jupyterlab-toc which lets us navigate our lab notebooks by Markdown section headings.

jupyter labextension install @jupyterlab/toc

The upgrade command is

jupyter labextension update @jupyterlab/toc

Integrated diagram editor? Someone has integrated drawio as the jupyterlab-drawio extension to prove a point about the developer API.

jupyter labextension install jupyterlab-drawio

LaTeX editor? As flagged, I think this is a terrible idea. It’s even worse than the diagram editor. There are better editors than Jupyter, better means of scientific communication than LaTeX, and better specific LaTeX tooling, but I will concede there’s some kind of situation where this sweet spot of mediocrity might be useful, e.g. as a plot point in a contrived techno-thriller script written by cloistered nerds. If we find ourselves in such dramaturgical straits:

jupyter labextension install @jupyterlab/latex

One nerdy extension is jupyter-matplotlib, confusingly called ipympl, which gives us better interactive plotting inside notebooks.

pip install ipympl
# If using JupyterLab

# Install nodejs: https://nodejs.org/en/download/
jupyter labextension install @jupyter-widgets/jupyterlab-manager
jupyter labextension install jupyter-matplotlib

jupyterlab/jupyterlab-hdf5 provides a UI for HDF5 files.

8 Quarto

Quarto® is an open-source scientific and technical publishing system built on Pandoc

See quarto.

9 Jupyter Book

Special, fancy thing: Jupyter Book is a publishing engine for Jupyter.

10 qtconsole

A classic, i.e. a non-web-browser-based client for Jupyter. No longer fashionable? It seems to work fine but is sometimes difficult to compile and doesn’t support all the fancy client-side extensions.

10.1 Multiple clients connecting to a single kernel

jupyter qtconsole can connect two frontends to the same kernel. This will be loopy, since the two frontends update the same variables (presumably) but, as far as I can tell, not the same notebook content, so we’d need to take care to make sure we are doing what we intend.

%qtconsole

11 Google Colab

A proprietary Google fork/extension, Colaboratory is a Jupyter thingo integrated with some fancy hosting and storage infrastructure, and it gives us free GPUs. It looks like a neat way of sharing things, but all Google wants is our souls. Don’t be fooled, though: claims on the internet that this is a real-time collaborative environment are false. Google killed realtime interaction.

12 nteract

nteract is an Electron desktop app that runs Jupyter notebooks. It could possibly host native-type interactions

nteract is an ecosystem of React components, JavaScript packages, and applications built on top of the Jupyter specification. Together they enhance interactive computing and data science workflows.

What can I do with nteract?

  • Parameterize and execute notebooks with papermill.
  • Build your own interactive notebook application with our React components.
  • Host notebooks with commuter.

13 Hydrogen

Hydrogen, a plugin for the atom text editor, provides a more unified coding experience in a regular code editor. See the intro blog post. Discontinued.

14 Pweave

pweave is like knitr for Python. It can also execute Jupyter kernels. The emphasis isn’t on interactivity but on reproducible documents.