UX Improvements

One of the interesting alternatives to Jupyter Notebook outside of the Jupyter space are Observable notebooks. As these are 100% JS-only, there are some design choices that we could not easily make in the Jupyter ecosystem. However, there are also some features that we could borrow, and some that aren’t inspired by Observable. I’d like to discuss both of these below.

Less Intrusive Hidden Cells

Part of the argument against doing interactive markdown in the kernel is that it’s not that nice to hide code cells in Jupyter. Compare Observable:
Peek 2021-09-09 13-28

with Jupyter
Peek 2021-09-09 13-31-2

The Jupyter implementation leaves a large ellipsis in the notebook view, which interrupts the flow of the prose. Inverting the input-output order would help here, but I think we need to go further — the ellipsis says (to me) this is important, but hidden, whereas the Observable hidden cell is not visible unless you go looking for it.

Inverted Output-Input Order

This is off-topic of “interactive” markdown cells, but worth raising here.

In Observable, cell outputs are rendered above the source that generated them. Given that (all?) modern languages read top-down, if we want to promote narrative within the notebook, then I feel that outputs should come first. In my experience, where both output and cell source are visible, I want to look at the output first, and maybe the source that generated it thereafter. In a hand-wavy sense my thinking is:

What does this graph say?

followed by

How was this graph generated?

Here’s how this looks in Observable:

Note the prose above “New York City weather forecast”, which belongs to a separate cell.

I’d be interested to hear from developers and users as to whether they like these changes, or have other suggestions to make!

2 Likes

Thanks @agoose77 for starting this discussion :+1:

Somehow related to these ideas: a new akernel Python kernel by @davidbrochart, which has a “React Mode” similar to what Observable offers:

2 Likes

I think this one is mostly a non-starter. If you run an input and the output appears above the input I for one would find that super confusing to follow in 95% of cases. I think there’s only one real context in which this UI would make sense:

  • a “static” notebook display (eg the output of nbconvert)
  • cells with chart/image heavy outputs

So one possibility would be to enable this as a per-cell option (via cell metadata or whatever) that affects the nbconvert rendering. However, the opt-in approach has a major pitfall; cells in a notebook could then be heterogeneous in terms of input ← output and output → input layout, which would not be great for readability.

I guess you could maybe get away with a per-notebook opt-in? I struggle to see a use case tho, except maybe a notebook in which almost every cell is plot heavy. And then it still has the downside of negatively impacting the readability of notebooks in general; immediately upon opening any given notebook would a user really be able to reliably intuit the cell i/o layout? Right now the user doesn’t have that problem

Perhaps the input/output order should be a property of the UI, not the notebook? That ensures it’s consistent across all notebooks, and can be chosen by an administrator when setting up a teaching environment.

2 Likes

@manics making it per-server occurred to me too, and makes a bit more sense. But in that case it’s something that would be more appropriate for an extension than for inclusion in jlab core. The reasoning being that it’s something that only a minority of users will want, and also that it can probably be implemented fairly easily as an extension.

We may still need some changes in core in order to facilitate a mix-n-match layout of notebook elements

1 Like

Thanks for the feedback Max!

I’m personally not so worried that this isn’t obvious behaviour. In Observable, for example, the UI makes it clear how things are structured:
image

This associative left-margin pictured above is something that I think we miss in JupyterLab. It might be that just adding something like this (that visually related the cell source and output more distinctly) would be enough to scratch this itch of mine, although I suspect not entirely!

RE mix-and-match of the notebook, I think you’re right on core development needs — it was non-trivial to build-out the prototype for inline markdown variables for this reason!

One other feature of Observable notebooks I’m interested in is the ability to import cells from other notebooks. It raises some questions:

  • what would be the import syntax? In the case of Python, it could be implemented with an IPython magic?
  • how to reference a notebook? Observable notebooks are published “on the web”, so it’s something like a URL. But a Jupyter notebook can live on the local drive, on a GitHub repo, etc.
  • how to reference a cell in a notebook? Here again, maybe an IPython magic could set a name to a cell?
1 Like

Yes, that’s another interesting idea. My personal preference is doing this at the kernel/notebook level, which I have done for Python in ‘literary’. But, this doesn’t have the same kind of granularity that you’re talking about.

1 Like

We have done something like this in curvenote.com - as you mention, it is easier when it is a web-based service. Basically we just track the cell ID of a notebook (wherever it lives or is copied to) and have an extension that adds comments and version control as an overlay. Mostly people are using it to import/reuse figures into our notebook-like articles and keep the connection alive when you update the figure in Jupyter. Means not having to copy/paste, but instead having a live link with comments/versions.

Some of our users are also using it to reuse code snippets, or have different copies of a notebook tied together in certain by certain cells (e.g. simple plotting code). Still lots of kinks, but is certainly interesting to see how people use it when it is there.