ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

ipywidgets not working with JupyterLab examples/notebook sample code

Open languy opened this issue 6 years ago • 4 comments

Hi, I read all other issues in Jupyterlab and also googled the problem, but none of the solutions mentioned worked (most of them upgrading to the latest version of the various utilities/packages). This is similar to this issue, but I'm not sure whether it is the same, so rather than adding noise to that one, I decided to open a new one. Apologies if it's a duplicate.

Setup:

  1. I have a jupyter server running: image
  2. I made one modification of the examples/notebook sample code to point to my server: line 40: let manager = new ServiceManager({ serverSettings: ServerConnection.makeSettings({ baseUrl: "<my jupyter server url here" }) });
  3. In examples/notebook: npm install, npm run build
  4. Copy the build result and serve in a separate webapp using webpack-dev-server

Everything renders fine in the notebook except I get this error if I want to execute some ipywidget code like this one: import ipywidgets out = ipywidgets.Dropdown(options=['1', '2', '3'], value='2', description='Number') display(out)

image

And the result renders as: Dropdown(description='Number', index=1, options=('1', '2', '3'), value='2')

If I open the notebook from the native's jupyterlab app: http://myserver:port/lab? Then it renders fine, which tells me that there must be a bug in the sample code of the packages it depends on, but the general jupyter server config/installation should work fine.

I tried the few things below, but no luck:

  • jupyter lab clean; jupyter lab build
  • checked this page for compatibility
  • in examples/notebook/package.json: updated the @jupyterlab/* packages from "^1.0.0-alpha.3" to 0.19.1 (or whatever is the latest. E.g services to 3.2.1).

At this point, I'm running out of ideas other than deep diving in the code to understand how the http://server/lab? frontend code differs from the examples/notebook.

Any ideas?

languy avatar Apr 08 '19 09:04 languy

This is what I found out. This broadly applies to all jupyterlab extensions: I was mainly focused on getting ipywidgets and gmap to work.

  • There are two parts to it: the python code that runs in the backend (jupyter server) and the js code that runs in the frontend (jupyterlab app).
  • Doing pip install some-package installs the backend python code.
  • Doing jupyter labextension install xyz installs the frontend jupyterlab code. Jupyterlab must include the js code for the jupyter extensions. Jupyter ships with jupyterlab's source code and built and that is why after installing some jupyterlab extension, you must rebuild the actual jupyterlab webapp and reload the page (either via the jupyterlab ui or via terminal with jupyter labextension build). So, no, the jupyterlab doesn't load some extensions' js rendering code at runtime, it's built with it.
  • Codewise: all these dependencies are specified as "plugins" which are essentially a bunch of npm packages that support some common api (e.g. activate(): which is called by the app to register the code). These plugins can access any part of the app via dependency injection.
  • The jupyterlab build infra generates a index.out.js file which explicitly lists all the "plugins" that the app requires: some of them are builtin and listed in package.json like the jupyterlab components (DocumentRegistry, JupyterLabApp, whatnot), some of them are "local" (ie were installed via jupyter labextension install). webpack.config.js detects all these packages and uses a template to generate index.out.js.
  • From there, this list of plugins is fed to the @phosphor application which loads, registers and activates the plugins. One part of this process is for the plugin to register to kernel changes which will intercept kernel updates and trigger its rendering code (at least for ipywidgets and gmaps).

Conclusions:

  • ipywidgets therefore isn't supported in examples/notebook which doesn't include the whole aforementioned plugin infra.
  • A quick hack to get it to work is to explicitly load the package in the code and mimick the activation code that jupyterlab does. It just comes down to this: In package.json, add this to the "dependencies":
"@jupyter-widgets/jupyterlab-manager": "0.38.1",
"@jupyter-widgets/controls": "1.4.3",

In examples/notebook/index.ts code:

import * as widgetModule from "@jupyter-widgets/jupyterlab-manager";
import "@jupyter-widgets/controls";
...
let mockJupyterLabApp = {
    docRegistry: docRegistry
  };
(widgetModule as any).default.activate(mockJupyterLabApp);

The result of this activation hangs off the docRegistry that is used by the notebook example.

  • This quick hack didn't work to activate gmaps, because it required some dependencies as a 2nd argument to the activate() method. The only way I could make it work was to duplicate the entire plugin pipeline by copy-pasting parts of the jupyterlab source code and part of the @phospor application source code. I hardcoded the plugins that I wanted in my app.

If you're looking into doing the same, start from index.out.js and include all the methods that get called in your code. Most of the code is contained in these files: @phospor/application/src/index.ts jupyterlab/staging/build/index.out.js packages/application/src/lab.ts

Lessons learned: Obviously, duplicating jupyterlab and @phospor code and hardcoding package isn't gonna work long-term.

  • Investing some time to make this plugin discovery/loading/activation pipeline reusable outside of the jupyterlab would be ideal.
  • Interestingly, this made my app not require jupyter labextension install xyz (and build) anymore, since it's already built-in. However, it won't support any extension that gets installed after the fact.
  • It means that building and serving examples/notebook app outside of jupyterlab isn't gonna work, because the cell output rendering part will always be tied to jupyter server.

languy avatar Apr 15 '19 08:04 languy

The next version of the jupyterlab widget manager will use a different mechanism for activating rendering widgets in a notebook, which may make it easier to use in the standalone notebook example.

Thanks very much for deep-diving into this and posting your comprehensive results. Do you mind if I reopen this so we can continue exploring this in the future?

jasongrout avatar Apr 15 '19 15:04 jasongrout

Happy to hear that this part is getting improvements. By all means, let's reopen the issue :). I'd be happy to provide more details about my use case, if that helps.

languy avatar Apr 15 '19 16:04 languy

Hi @languy, @jasongrout,

I've got very similar problem. I would like to run ipywidgets in examples/cell. Here is my output: image

I was trying to enable extension: image

Is there any way to enable ipywidgets in examples? What should be added?

pplonski avatar Nov 09 '23 08:11 pplonski