Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling rendering on nbviewer by persisting state of anywidget in Jupyter Notebook #343

Open
andersy005 opened this issue Oct 12, 2023 · 9 comments
Labels
bug-jupyter-widgets Something isn't working with Jupyter Widgets

Comments

@andersy005
Copy link

@manzt and i have been experimenting with anywidget + @carbonplan/maps in https://github.com/manzt/carbonplan. The notebook works perfectly fine when connected to a live kernel. however, i am facing an issue with persisting the widget's state within the notebook and having external services like nbviewer render the initial state of the widget.

to illustrate the problem, i have shared a sample notebook at https://nbviewer.org/gist/andersy005/f8bca6c542135a75ab3e11203eada3a1. as you can observe, the last cell of the notebook is not being rendered.

any guidance on how to resolve this issue?

Screenshare.-.2023-10-12.4_24_14.PM.mp4

Cc @katamartin

@rgbkrk
Copy link
Collaborator

rgbkrk commented Oct 13, 2023

I'm a bit new to how widgets persist state in the notebook so for my own sake (and maybe others) I'm going to document what I see in the notebook. I can see the widget model in the output:

image

There is no other reference to the widget model in the source of the notebook and nothing for nbviewer to render (other than that text/plain entry).

When I try the simplest widget in JupyterLab, the IntSlider I'm also not seeing the persistence.

Cell:

from ipywidgets import IntSlider
islide = IntSlider()
islide

Notebook:

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "088fffff-0cb1-4055-a722-2635371d3be1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9480df1fa4f04356873a4969ef4038c4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from ipywidgets import IntSlider\n",
    "islide = IntSlider()\n",
    "islide"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

If I recall correctly, the classic notebook had a "Save Widget State" button. I don't have that in JupyterLab.

@rgbkrk
Copy link
Collaborator

rgbkrk commented Oct 13, 2023

It looks like there's a setting that has to be enabled in JupyterLab to automatically save widget state

image

After doing that and also making sure to update my jupyterlab and ipywidgets installation, I restarted JupyterLab and see a big pile of state:

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "088fffff-0cb1-4055-a722-2635371d3be1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "03a522b9129949d8ae7a802b0f344980",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from ipywidgets import IntSlider\n",
    "islide = IntSlider()\n",
    "islide"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "03a522b9129949d8ae7a802b0f344980": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "IntSliderModel",
      "state": {
       "behavior": "drag-tap",
       "layout": "IPY_MODEL_1db186f70ff646aea16422745dea7a8b",
       "style": "IPY_MODEL_30cb35a482a54c17a2173a45376f43ea",
       "value": 85
      }
     },
     "1db186f70ff646aea16422745dea7a8b": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {}
     },
     "30cb35a482a54c17a2173a45376f43ea": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "SliderStyleModel",
      "state": {
       "description_width": ""
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

However, that doesn't render in notebook viewer. https://nbviewer.org/gist/rgbkrk/d11992979381414b32d18b16be2d64cf

I've been away from working on nbviewer and nbconvert so I don't know how it takes the widget state into account.

@manzt
Copy link
Owner

manzt commented Oct 13, 2023

However, that doesn't render in notebook viewer. nbviewer.org/gist/rgbkrk/d11992979381414b32d18b16be2d64cf

I'm not sure how nbviewer is implemented, but nbconvert works for rendering widgets to HTML. flekschas/jupyter-scatter#81 (comment)

If you nbconvert --execute the notebook, it will embed the widget model state, otherwise you'll need to make sure the model state is embedded (i.e., "Save Widget State Automatically" in JupyterLab).

For clarity, @andersy005 this is not an issue with anywidget, but Jupyter Widgets (standard ipywidgets do not render in nbviewer either, thanks to @rgbkrk example). But thank you @rgbkrk for the exploration, and maybe we can at least figure out if this is unexpected or expected behavior!

@andersy005
Copy link
Author

andersy005 commented Oct 13, 2023

@rgbkrk / @manzt, thank you for looking into this and suggesting workarounds. i was able to convert the executed notebook to HTML and then served it from an s3 bucket: https://carbonplan-share.s3.us-west-2.amazonaws.com/leap-demo.html

and it appears to be working: initial states of the widgets are captured as expected

@manzt
Copy link
Owner

manzt commented Oct 13, 2023

Awesome! @andersy005 if you use ipywidgets.jslink instead of ipywidgets.link you can also link the inputs on the client side (i.e., sliders and dropdowns will still work in the HTML-only version).

import ipywidgets

colormap = ipywidgets.Dropdown(options=["warm", "fire", "water"])
clim = ipywidgets.FloatRangeSlider(min=-20, max=30)
opacity = ipywidgets.FloatSlider(min=0, max=1, step=0.001)
region = ipywidgets.Checkbox(description="Region")

-- ipywidgets.link((map_widget, "colormap"), (colormap, "value"))
-- ipywidgets.link((map_widget, "clim"), (clim, "value"))
-- ipywidgets.link((map_widget, "opacity"), (opacity, "value"))
-- ipywidgets.link((map_widget, "region"), (region, "value"))
++ ipywidgets.jslink((map_widget, "colormap"), (colormap, "value"))
++ ipywidgets.jslink((map_widget, "clim"), (clim, "value"))
++ ipywidgets.jslink((map_widget, "opacity"), (opacity, "value"))
++ ipywidgets.jslink((map_widget, "region"), (region, "value"))

ipywidgets.VBox([
    ipywidgets.HBox([colormap, opacity, clim]),
    region,
    map_widget,
])

@andersy005
Copy link
Author

thank you very much, @manzt! the jslink changes work :) with the exception of any selection widgets (dropdown, radiobuttons, select, etc), and this appears to be a well known issue upstream:

however, i'm satisfied with dropping the dropdown widget for the time being: https://carbonplan-share.s3.us-west-2.amazonaws.com/leap-demo.html

@manzt
Copy link
Owner

manzt commented Oct 20, 2023

Great! I'm going to mark this issue as resolved!

@manzt manzt closed this as completed Oct 20, 2023
@manzt manzt reopened this Oct 20, 2023
@manzt
Copy link
Owner

manzt commented Oct 20, 2023

Ah, actually realizing this doesn't address that things don't seem to be working in nbviewer. Still need to look into that, but it doesn't seem like any widgets render with nbviewer.

@manzt
Copy link
Owner

manzt commented Nov 2, 2023

@manzt manzt added the bug-jupyter-widgets Something isn't working with Jupyter Widgets label Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-jupyter-widgets Something isn't working with Jupyter Widgets
Projects
None yet
Development

No branches or pull requests

3 participants