googlecolab/colabtools

Support installation of custom widgets.

blois opened this issue ยท 50 comments

blois commented

Currently Colab only supports the widgets included in the ipywidgets package and does not allow installing additional widgets.

Additional background is available at https://github.com/nteract/nes/tree/master/portable-widgets.

Qgrid would make it easier to work with pandas dataframe.

Hope it will be supported in the future.

We're building a custom widget called Clustergrammer2 that is a webgl DataFrame viewer and is currently supported on Kaggle https://www.kaggle.com/cornhundred/heatmap-view-of-modern-era-player-stats

Also see nbviewer https://nbviewer.jupyter.org/github/ismms-himc/clustergrammer2-notebooks/blob/master/notebooks/3.0_10X_Genomics_2700_Dataset_NBViewer.ipynb

blois commented

Glancing at the widget code in https://github.com/ismms-himc/clustergrammer2/blob/5acea9bff7eda546cf0647b9e3647f631eb6f5f5/clustergrammer2/clustergrammer_fun/__init__.py#L222, it doesn't seem like it's making much use of the Widgets API, specifically comms messages.

A quick example of your (very slick) notebook running in Colab, with the visualizations:
https://colab.sandbox.google.com/gist/blois/dd01cd63d199acca951aadefb22067a8/heatmap-view-of-modern-era-player-stats.ipynb

Thanks @blois for your help. In order to run the notebook you sent I had to add the Seasons_Stats.csv (from here https://www.kaggle.com/drgilermo/nba-players-stats) to the filesystem.

However, I did not see the interactive visualization. Update: the heatmap did show up after a minute. I'll think about how to clean up the implementation. Thanks again!!

Looking forward to custom widget support, but this definitely helps out in the interim.

BTW @blois, how can I upload a dataset permanently into a shareable colab notebook (e.g. the sandbox link you sent)?

Here is a link to a notebook that does not require an external dataset https://colab.research.google.com/gist/cornhundred/b7154ee964c71cec6a2378f9cbba8eeb/clustergrammer2_example.ipynb?authuser=1

cc @manugarciaquismondo.

blois commented

@korakot we recently added an interactive dataframe viewer that we've been using internally for ages.

You can enable it by default with:

%load_ext google.colab.data_table
from vega_datasets import data
data.cars()

Or use it on a per-dataframe basis:

from google.colab.data_table import DataTable
from vega_datasets import data
DataTable(data.cars())

@blois Thanks a lot. It will surely help.

BTW, is there a widget to edit the dataframe as well?

And what other %load_ext are available? Is there a list somewhere?

can you install custom widgets now? I'd like to have a variable previewer just like allefeld/ipyinspector#1

This problem still persists with Google Colab on August 13th, 2020.
ArcGIS Python API maps will not display.
All the other portions of the API seem to work great in Colab, and I am able to conduct ArcGIS Online Admin from Colab.
Currently switching over to the AGOL Jupyter Notebook interface to view the map widget display.
Perhaps there could be a clever workaround by exporting to html or viewing as JavaScript.

@blois Please add support for ipyleaflet, which would make visualizing and interacting Google Earth Engine tile layers much easier with the earthengine-api. @tylere @SylvainCorlay @martinRenou @davidbrochart

Hi, let me know if this isn't the right place - it would be great to have support for pymotif, which is a Jupyter widget for Motif, a no-code graph visualization platform. Thank you! @timlrx

@blois any updates on this?

Qgrid would make it easier to work with pandas dataframe.

Hope it will be supported in the future.

+1 for QGRID

blois commented

We are working on this, some details of the proposal are in https://github.com/googlecolab/colab-cdn-widget-manager.

Right now the support can be experimented with by adding to the cell displaying the widget:

from IPython.display import Javascript

display(Javascript('''
  google.colab.widgets.installCustomManager('https://ssl.gstatic.com/colaboratory-static/widgets/colab-cdn-widget-manager/6a14374f468a145a/manager.min.js');
'''))

This will remain opt-in but we plan to work on improving the mechanism.

Some examples:

This specific widget manager version is tied to @jupyter-widgets/base v5.0.0a so there may be some incompatibilities with with specific widget versions (https://github.com/bloomberg/ipydatagrid is known to be incompatible for example).

Please feel free to open specific bugs in https://github.com/googlecolab/colab-cdn-widget-manager/issues.

@blois This is exciting!! Thank you so much for implementing this. It is a game-changer!!

blois commented

An update that the mechanism to opt-into this will be changing shortly to:

from google.colab import output
output.enable_custom_widget_manager()

Which only needs to be executed once in the notebook to affect all later executions.

@blois This is fantastic, making life much easier! When will it be released? Can't wait to try it out.

blois commented

@giswqs Hopefully later today.

@blois It is working now. I have integrated the following two lines into the geemap and leafmap packages so that users don't have to execute them explicitly. Now the same code can run seamlessly on both Colab and Jupyter without making any changes. I also created a pull request to update ipyleaflet jupyter-widgets/ipyleaflet#869

from google.colab import output
output.enable_custom_widget_manager()

One issue I noticed is that the toolbar icon size (created using ipywidgets) is much bigger on Colab than on Jupyter notebook. I could not figure out why.

Leafmap Colab example: https://colab.research.google.com/drive/1NSdDIkXxeD2tCVw38gQ7nLIvgdwOx20c

Colab:
Screenshot_20210911_000403

Jupyter notebok
Screenshot_20210911_000520

I just tried it with qgrid, but it still doesn't display the widget.
Here's my colab notebook:
https://colab.research.google.com/drive/11VLvg_R-oADW1lBYCsjxtIq2xi986pyT?usp=sharing

Am I using this correctly?

Related to: quantopian/qgrid#263

@blois Thanks for the working example on qgrid. I also tried plotly's FigureWidget and it didn't work for me. Here's my notebook:

https://colab.research.google.com/drive/1HS_YQ_E4IwrBUuktJkUHM97XgqZlUpeW?usp=sharing

Related to:

I'm excited that custom widgets is getting attention and a beta API exists. Unfortunately it appears that the current Colab widgets implementation is incomplete. Specifically Comm messages sent from following cells never arrive at widget views in previous outputs.

I took some time to create a minimal reproducible example of this, showing how the API works in JupyterLab and where it fails in Colab.

I created a new, very basic widget based on ipywidgets just for debugging: https://github.com/kylebarron/jupyter-widget-echo-testing. This uses the default TypeScript Widget Cookiecutter with a couple modifications:

Then I created two notebooks, one for use in Jupyter Notebook/Lab showing how I expect the widget implementation to work, and one for use in Colab showing where the implementation is incomplete. Here are direct links:

Binder

Open In Colab

Specifically, any messages after the initial cell fail to reach the JS code running in the original widget view. This means that it's hard (impossible?) for widget developers to support interactivity from Python to running JS code and severely limits what's possible to do with widgets in Colab.

blois commented

@kylebarron Thanks for the great report, will take a bit to dig into it.

Some tricks for future explorers in this area- you can define a 'custom widget manager' with a base64 URL which resolves to an ES6 module which implements this API-

export declare interface WidgetManagerModule {
.

A really simple example of this is https://colab.research.google.com/gist/blois/4d3125395020ed671599d90a0dcedefe/custom_widget_hack.ipynb.

Can also use Comms without using widgets, I think this example may expose the issue you mentioned-
https://colab.research.google.com/gist/blois/3fe2426b2aef36f55d5370e496fec736/comms.ipynb

blois commented

@shadiakiki1986 Added details in the jupyter-widgets bug, I believe that Colab is matching JupyterLab behavior when custom widget support is enabled.

@blois What about Tab and Accordion?

Update: I also noticed that display(stacked) works but stacked without wrapping it in display() doesn't. Not sure if this is significant.

blois commented

@kylebarron The fix for your issue should be live now.

@blois it seems that custom widgets still aren't working with Plotly. I've implemented this example from the Plotly website in Colab here. While the widgets appear, the plot itself does not. Do you have any idea why this might be the case?

The plot appears for me when you call g.show() in a cell. Though the message passing doesn't appear to work immediately for me.

@kylebarron I had also tried g.show() but haven't gotten the message passing to work.

Possibly relevant; Plotly has a weird way of sending messages between Python and JS. https://github.com/plotly/plotly.py/blob/df19fc702b309586cc24e25373b87e8bdbb3ff60/packages/python/plotly/plotly/basewidget.py#L52-L101

These properties are used to send messages from Python to the frontend. Messages are sent by assigning the message contents to the appropriate _py2js_* property and then immediatly assigning None to the property.

Instead of using something like widget.send() for a custom message (maybe a newer API than when Plotly's FigureWidget was first developed). You could probably debug within Colab to see when you set a Python attribute if that changes on the JS side or not, and vice versa.

@kylebarron I tried debugging this and the messages are passed without issue. It seems the proper commands are sent to plotly but nothing is being displayed (i.e., the entire DOM element for plotly is empty). It would be really nice to have this working in Colab.

The plot appears for me when you call g.show() in a cell. Though the message passing doesn't appear to work immediately for me.

Just noting that I was wrong here. The Plotly FigureWidget subclasses from both BaseFigure and widgets.DOMWidget. The .show() comes from BaseFigure, so when you call .show it's rendering a static HTML output without touching the widget machinery at all. When you render the widget directly in a cell, i.e.

from google.colab import output
output.enable_custom_widget_manager()

import plotly.graph_objects as go
f = go.FigureWidget(layout={'height': 400, 'width': 400})
f

if you look in the network tab the right plotly widget bundle gets downloaded (plotlywidget for plotly v4 and jupyterlab-plotly for plotly v5). I'm guessing there's some sort of bad interaction with Colab's widget manager but it's hard to tell.

blois commented

Thanks for taking a look at this @kylebarron @JesseFarebro, and thanks for the quick fix @bloisโ€”I'm looking forward to seeing it go live!

blois commented

@cardinalgeo your example should now be working, see googlecolab/colab-cdn-widget-manager#19 (comment).

Thanks @blois! However, the example is unfortunately still not working. Running the block in the jupyter lab screenshot below should produce both the widgets and the plot, as is pictured. But running the same cell in colab only produces the widgets. I can run g.show() in a separate cell to display the plot, but, while the message passing seems to work, a change in the dropdown widgets only results in a change in the plot after re-running g.show(), which is not ideal. Do you have any idea why the widgets and figure aren't both being displayed in the output such that a change in the widgets automatically produces a change in the figure?
Screen Shot 2021-11-24 at 9 07 12 PM

From my comment here #498 (comment)

The Plotly FigureWidget subclasses from both BaseFigure and widgets.DOMWidget. The .show() comes from BaseFigure, so when you call .show it's rendering a static HTML output without touching the widget machinery at all.

In order to render the widget and not the static HTML output mode, you need to render without .show. The below Colab notebook is a direct copy of this page in the Plotly docs, adding only the command to enable custom widgets.

Open In Colab

Here, the widget doesn't render, and I see this console error:
image

Here's an example for qgrid: https://colab.research.google.com/gist/blois/3b36d0aa4c32d2ecc71e9208c32cf333/qgrid.ipynb

For those who want to use qgrid in their Colab notebook but don't want to confuse people on colab force restart, I found a workaround for using qgrid without restarting the session. The question is about qgrid 1.1.1 not supporting pandas>1.0.0. You can fork qgrid to your own repo, roll back the version to 1.1.1, and change the code according to quantopian/qgrid#287. Then, you could pip install via git from your repo.

For example, you can do pip install git+https://github.com/lukewys/qgrid.git (a fork of qgrid where I fixed this issue).

Please add support for the ipytree widget too: #2522

Here, the widget doesn't render, and I see this console error:

@kylebarron thanks for the Plotly widget example! I can't find a way to view the console error (is it from terminal, which is only available with colab pro)? Do you have any sense of whether this issue can be resolved on the Colab side or if it will require work on the Plotly side?

blois commented

@cardinalgeo Support for the plotly widgets was tracked in googlecolab/colab-cdn-widget-manager#19. There's a link to your example working in there.

blois commented

At this point installation of custom widgets is supported. This requires opting in by using the code:

from google.colab import output
output.enable_custom_widget_manager()

Specific widgets may need additional investigation or tweaks. It's easiest to open individual issues for these investigations. Most of the bugs have been tracked in https://github.com/googlecolab/colab-cdn-widget-manager/issues?q=is%3Aissue.

Hi @blois, thanks for the follow up! However, the example still seems to not work. I'll continue this thread in googlecolab/colab-cdn-widget-manager#19

Thanks a lot for your work on this @blois !

Thanks @blois!!! This is amazing!

Today ipywidgets Text will no longer work. There is a message about adding two lines to allow external widgets loading but that does not fix the problem.

@nulflux downgrading the ipywidgets version should work for you until we can get a fix out:

!pip install ipywidgets==7.7.1 and then restart your runtime

blois commented

Added some details on the issue in #3020 (comment).