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

jupyter_bokeh 3.0.6 (bokeh 3 and ipywidgets 8) #178

Merged
merged 17 commits into from
Mar 6, 2023

Conversation

mattpap
Copy link
Contributor

@mattpap mattpap commented Dec 8, 2022

This is a branch to prepare for 3.0.6 release, which is compatible with bokeh 3 and ipywidgets 8. I upgraded the build to webpack 5, as the previously used webpack 4 doesn't work with the current LTS of nodejs (18.x).

fixes #184

@theeldermillenial
Copy link

Is there an ETA on this? What remains to be done? Is there anything I can contribute?

@theeldermillenial
Copy link

theeldermillenial commented Feb 16, 2023

Well, that was a quick turn around. Thanks!

I just installed and tried running it. In Jupyter, I get what looks like a recursion error, but the chart still renders. I'm running this in VSCode.

# test.ipynb

from math import pi

import ipywidgets as widgets
import pandas as pd

from bokeh.palettes import Category20c
from bokeh.plotting import figure
from bokeh.transform import cumsum
from bokeh.io import output_notebook
import jupyter_bokeh as jbk

output_notebook()

x = {
    'United States': 157,
    'United Kingdom': 93,
    'Japan': 89,
    'China': 63,
    'Germany': 44,
    'India': 42,
    'Italy': 40,
    'Australia': 35,
    'Brazil': 32,
    'France': 31,
    'Taiwan': 31,
    'Spain': 29
}

data = pd.Series(x).reset_index(name='value').rename(columns={'index': 'country'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data['color'] = Category20c[len(x)]

p = figure(height=350, title="Pie Chart", toolbar_location=None,
           tools="hover", tooltips="@country: @value", x_range=(-0.5, 1.0))

p.wedge(x=0, y=1, radius=0.4,
        start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
        line_color="white", fill_color='color', legend_field='country', source=data)

p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

donut_label = widgets.Label("This is a donut chart")
donut_model = jbk.BokehModel(p)

out_donut = widgets.VBox([donut_label, donut_model])
out_donut.layout.height = "400px"

out_donut

Output:
image

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File /.venv/lib/python3.10/site-packages/jupyter_bokeh/widgets.py:126, in BokehModel._sync_model(self, _, content, _buffers)
    123     return
    125 # Handle ModelChangedEvent
--> 126 new, old, attr = content["new"], content["old"], content["attr"]
    127 submodel = self._model.select_one({"id": content["id"]})
    128 descriptor = submodel.lookup(content['attr'])

KeyError: 'new'
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File /.venv/lib/python3.10/site-packages/jupyter_bokeh/widgets.py:126, in BokehModel._sync_model(self, _, content, _buffers)
    123     return
    125 # Handle ModelChangedEvent
--> 126 new, old, attr = content["new"], content["old"], content["attr"]
    127 submodel = self._model.select_one({"id": content["id"]})
    128 descriptor = submodel.lookup(content['attr'])

KeyError: 'new'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File /.venv/lib/python3.10/site-packages/jupyter_bokeh/widgets.py:136, in BokehModel._sync_model(self, _, content, _buffers)
    134         cb(attr, old, new)
    135 elif kind == 'MessageSent':
--> 136     self._document.callbacks.trigger_json_event(content["msg_data"])

AttributeError: 'DocumentCallbackManager' object has no attribute 'trigger_json_event'

I think the best thing about this is that when I try to generate a static page with nbconvert, it looks like this newest version of your tool gets around a problem in the latest version of ipywidgets and nbconvert that had an error parsing these charts in JSON. I see the Bokeh toolbar pop up, but I do get a javascript error. I think I can debug this on my own though.

jupyter dejavu --execute --template=classic test.ipynb

Output:
image

@theeldermillenial
Copy link

theeldermillenial commented Feb 16, 2023

Looks like my nbconvert/dejavu error is more complicated than first expected. I thought it was a matter of adding script references, but that didn't seem to solve the problem. I was able to dump the same plot to an html file using Bokeh's file_html, but converting to html through nbconvert/dejavu does not work.

Should I open an issue or do you think this is related?

@theeldermillenial
Copy link

Okay, final comment. I tracked the javascript error down to @bokeh/jupyter_bokeh version 3.0.6 not on CDN yet (which makes sense). I replaced that and the javascript error went away.

However, what happens with nbconvert or dejavu is that the div gets URL encoded, and this causes it to get rendered weird.

When I changed the javascript module version 3.0.4 and changed nothing else, this is what I get:
image

If you take a look at the <script type="application/vnd.jupyter.widget-state+json"> in the foot of the page, you find the div in the JSON:

&lt;div id=\\\"75ce238a-11c9-4b43-b21c-690899671cf6\\\" data-root-id=\\\"p1002\\\" style=\\\"display: contents;\\\"&gt;&lt;/div&gt;

If you decode that to:

<div id=\\\"75ce238a-11c9-4b43-b21c-690899671cf6\\\" data-root-id=\\\"p1002\\\" style=\\\"display: contents;\\\"></div>

Then the chart renders properly:
image

I think this is something that's done by nbconvert/dejavu, so I don't know that there is any way of handling this. If you could confirm, I would be happy to update a couple of issues over on the nbconvert.

For now, looks like beautiful soup post processing to get Bokeh rendered on html generated by nbconvert. This is a step above what is possible for other plotting libraries though.

@hoxbro
Copy link
Contributor

hoxbro commented Feb 21, 2023

FYI getting this error running this branch in a notebook:

image

import bokeh
import jupyter_bokeh
from bokeh.models import Div
from jupyter_bokeh import BokehModel
bokeh.__version__, jupyter_bokeh.__version__
BokehModel(Div(text="example", styles={"background": "red"}))

@bryevdv
Copy link
Member

bryevdv commented Feb 21, 2023

cc @philippjfr @mattpap I believe bokeh/bokeh#11960 and bokeh/bokeh#12623 conspired to uncover this. It seems the jupyter extension should just be constructing a proper Event to call trigger_event with at this point.

@philippjfr
Copy link
Contributor

Would be get to get this ready for release pretty soon. Happy to help if needed.

@theeldermillenial
Copy link

I am also patiently waiting for this to be released. I'm currently installing from the github branch.

@mattpap mattpap force-pushed the mattpap/jupyter_bokeh_3.0.6 branch from 3eaad84 to 6bbaf44 Compare March 5, 2023 23:50
@mattpap
Copy link
Contributor Author

mattpap commented Mar 6, 2023

@philippjfr, @hoxbro, this should be fully fixed now. I tested all combinations of triggering updates between bokeh <-> ipywidgets, also streaming and patching, and everything seems to work correctly now.

@mattpap mattpap merged commit 4f7f661 into main Mar 6, 2023
@mattpap mattpap deleted the mattpap/jupyter_bokeh_3.0.6 branch March 6, 2023 16:36
@philippjfr
Copy link
Contributor

Thanks @mattpap!

@theeldermillenial
Copy link

Thanks @mattpap!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update trigger_json_event for Bokeh 3
6 participants