plotly / jupyterlab-dash

An Extension for the Interactive development of Dash apps in JupyterLab
MIT License
360 stars 56 forks source link

Idea: Dash apps as JupyterLab mime renderers #15

Open jonmmease opened 5 years ago

jonmmease commented 5 years ago

This idea is not very fleshed out yet, and I'm not sure if it should even belong in this repo, but I wanted to write it out while I'm thinking about it.

JupyterLab supports the very flexible concept of Mime Renderer Extensions, which allow 3rd party extensions to create custom viewers/editors for various file types.

These are really powerful, but they involve writing the extension in JavaScript, and if the extension needs access to Python functionality there needs to be a corresponding server side extension. See see the jupyterlab-latex for an example of an extension that does mime rendering with a Python server component.

Because of this, the creation of custom mime renderer extensions is not very accessible to Python analysts without experience with web technologies.

Dash is now a mature technology for building sophisticated react-based web apps in pure Python. What would it take to allow special Dash apps to be registered as mime renderers? I'm picturing that the Dash apps would be registered as server extensions, and then a single JupyterLab extension would look for these server extensions, route mime renderer requests to the appropriate Dash app, and display the app in an iframe.

This would give extension authors access to a Python kernel and a rich set of react components, all from Python.

Two examples come immediately to mind.

  1. A Dash DataTable based viewer/editor for tabular datafiles. If the file could be loaded on the Python side then it wouldn't need to be all sent to the front-end at once, making it possible to support really large files. Could also support other tabular file types with Python readers like parquet.

    1. An image editor based on Dash-canvas and scikit-image

cc @chriddyp @jackparmer @nicolaskruchten @gnestor @ian-r-rose

ian-r-rose commented 5 years ago

Hi @jonmmease I agree this would be really cool.

Coincidentally, @mrocklin and I spent some hours trying to do something very similar yesterday, but with bokeh dashboards. This can be found here The basic idea is as follows:

  1. Developers of dashboard-type plots may be much more comfortable writing in Python than Javascript (in this case bokeh, but could just as easily be dash).
  2. These dashboard plots are available via some webserver exposed via some port. The webserver is proxied under the notebook server via a server extension (in this case jupyter-server-proxy).
  3. There is an "index" endpoint, informing the frontend what dashboards are available.
  4. The frontend JupyterLab extension learns about the available dashboards via the index and constructs a launcher for them.
  5. When the dashboards are launched, they are opened in an iframe in JupyterLab as one of the main area panels.

This doesn't take a mime-renderer approach, since there is a bit more logic on the frontend than those allow. With a bit of work, however, it should be possible to make the frontend mostly agnostic to who is providing the dashboards.

A similar approach would be to use the jupyterlab extension functionality that @yuvipanda has built into jupyter-server-proxy. With this you add some relatively limited metadata to an entrypoint and it automatically creates a JupyterLab launcher item which, when clicked, starts a separate server and opens it in a separate browser tab (rather than in a main area widget). This is used, for instance, to launch rstudio processes from the notebook server.

yuvipanda commented 5 years ago

@ian-r-rose this sounds great to me! I'd welcome a PR to jupyter-server-proxy's jupyterlab extension that lets you open it in an iframe inside a JupyterLab tab. I think that, plus some more dynamism in how proxies are registered (which you need for the dask labextension anyway) would probably be a nice generic form of doing this.

jonmmease commented 5 years ago

Thanks for your perspective @ian-r-rose and @yuvipanda! This isn't something I have immediate plans to work on, but I'll definitely take a look at building on/extending jupyter-server-proxy when I do.

gnestor commented 5 years ago

@jonmmease If I understand you correctly, you're proposing that we create mimerender-like extensions for individual dash components (like dash-table and dash-canvas) vs. entire dashboards? So that you could open a CSV with "Dash DataTable" and PNGs with "Dash Canvas"? I really like this idea because plotly has developed so many components and JupyterLab provides a simple way to provide data to them. If these components require access to a kernel (e.g. fetching rows from a CSV on disk), then a mimerender extension would not suffice. However, I recently converted a mimerender extension to a regular extension specifically to access a document's session, so that can serve as a simple example of how to create kernel-connected renderer extensions.

jonmmease commented 5 years ago

@gnestor thanks for sharing the mimerenderer -> extension example, that looks like a really helpful reference.

If I understand you correctly, you're proposing that we create mimerender-like extensions for individual dash components (like dash-table and dash-canvas) vs. entire dashboards?

I wasn't thinking of necessarily restricting this to individual components. It some cases I expect it would be helpful for these mime-style renderers to contain multiple Dash components and various Python callbacks.

And my hope was that we wouldn't need to create a separate JupyterLab extension for each dashboard/filetype pairing. I'm imagining that the dash-mimetype-renderer author would specify the mimetype registration info (e.g. file extensnion) on the Python side in some standard way. Then we would have a single dash-mimetype-renderer JupyterLab extension that would query the Python side for this info, and then register itself as a mimetype renderer for each one. Then the extension would be responsible for dispatching "Open with" requests to the appropriate Python dash-mimetype-renderer implementation.

If possible, this would allow folks to create new file renderer extensions in pure Python. And users could install new extensions using pip/conda without needing to rebuild JupyterLab.