Reputation: 369
How can I create an interactive bar plot with bokeh through a selection widget on Jupyter Notebook?
Why the Notebook raise the following error:
"RuntimeError: Models must be owned by only a single document, Title(id='1044', ...) is already in a doc ERROR:tornado.access:500 GET /autoload.js?bokeh-autoload-element=1002&bokeh-absolute-url=http://localhost:54277&resources=none (::1) 117.01ms"
I read carefully this example from github and this similar situation from a Google Bokeh Group, in the latter they run a bokeh server not a the jupyter kernel
output_notebook()
dct={'Date' : ["2018-01-07", "2018-01-12", "2018-01-13", "2018-01-14", "2018-01-20", "2018-01-24"],'Activity' : ['A','B','A','B','A','B'],'Count' : [1, 2, 5, 3, 7, 1]}
df=pd.DataFrame(dct)
activity_list=df['Activity'].unique().tolist().copy()
activity_selected='A'
def modify_doc(doc):
def make_plot(cdf):
plot = figure()
plot.vbar(x=cdf.Date, top=cdf.Count, width=0.9)
push_notebook()
show(plot, notebook_handle = True)
return plot
def update_plot(attr, old, new):
activity = select.value
sdf = df.copy()
sdf = sdf[sdf['Activity'] == activity]
layout.children[0] = make_plot(sdf)
select = Select(title='Select Activity', value=activity_selected, options=activity_list)
select.on_change('value', update_plot)
p=make_plot(df)
layout=column(select, p)
doc.add_root(layout)
show(modify_doc)
What I expect is something like this in the snapshoot:
I am using Bokeh 1.0.4
Upvotes: 0
Views: 1284
Reputation: 369
The correct code for selecting the plot through the Select
widget is:
activity_list=df['Activity'].unique().tolist().copy()
df['Date']=pd.to_datetime(df['Date'])
activity_selected='A'
def modify_doc(doc):
df_r=df.copy()
source = ColumnDataSource(data=df_r)
plot=figure(title='Daily Hours',x_axis_type="datetime")
plot.vbar(x="Date", top="Count",source=source, width=4)
def update_plot(attr, old, new):
activity = select.value
data = df_r[df_r['Activity'] == activity]
source.data = ColumnDataSource(data=data).data
select = Select(title='Select Activity', value=activity_selected, options=activity_list)
select.on_change('value', update_plot)
layout=column(select, plot)
doc.add_root(layout)
show(modify_doc)
And this will be the output that you see:
Upvotes: 0
Reputation: 34568
It's possible we need to make some documentation improvements, because there are several parts of your code that do not make sense.
push_notebook
is complementary to showing a real Bokeh server app (i.e. passing modify_doc
to show
). I can't think of any situation where it would make sense to use them together. The Bokeh server app capability is a strict superset of push_notebook
, so since you are already making a Bokeh server app, you should just update everything in the standard way.
show
should never be called inside the Bokeh server app code (in this case, inside modify_doc
) This is in fact the proximate cause of the exception you are getting. You should
You should not make a new plot every time! The entire purpose of both push_notebook
and the Bokeh server is that updates can happen efficiently without making a whole new plot every time. You should be updating the data and attributes of the existing plot.
There is a complete wokring example of a Bokeh server app in a notebook here:
https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/notebook_embed.ipynb
You should study and emulate that as it represents best practice.
Upvotes: 1