I am trying to create a Bokeh dashboard and ran into an issue trying to deploy it. Essentially, when the dashboard is launched, the plots will show, but the widgets for interactively updating the plot doesn't. Here is my code:-
import numpy as np
import pandas as pd
import pandas_bokeh
from bokeh.io import show
from bokeh.layouts import column, layout, row
from bokeh.models import DateRangeSlider, Dropdown
#color palette
colors=['#FDE724','#D01C8B','#4DAC26']
#define the categorical variable
category_a = ['A','B','C']
category_b = ['X','Y','Z']
#set random seed to make the dataset reproducible
np.random.seed(42)
#create a dataset
#df_random = pd.DataFrame({
# 'id': np.arange(0, 15),
# 'month':np.random.randint(1, 12, 15),
# 'sensor_1': np.random.uniform(0, 1,15),
# 'sensor_2': np.random.uniform(10, 15, 15),
# 'sensor_3': np.random.randint(0, 20, 15),
# 'category': np.random.choice(category, 15, p=[0.2, 0.4, 0.4]),
#})
df_random2 = pd.DataFrame({
'id': np.arange(0, 30),
'date': pd.date_range(start='1/1/2021', periods=30, freq='D'),
'month':np.random.randint(1, 12, 30),
'sensor_1': np.random.uniform(0, 1,30),
'sensor_2': np.random.uniform(10, 15, 30),
'sensor_3': np.random.randint(0, 20, 30),
'categorya': np.random.choice(category_a, 30, p=[0.2, 0.4, 0.4]),
'categoryb': np.random.choice(category_b, 30, p=[0.6, 0.2, 0.2]),
})
#set index to id column
df_random2=df_random2.set_index('id')
df_random2.shape
df_random2.head()
mindate=df_random2['date'].min()
maxdate=df_random2['date'].max()
menucols = [("Category A", "categorya"),("Category B","categoryb")]
date_range_slider = DateRangeSlider(value=(mindate, maxdate),
start=mindate, end=maxdate)
category_picker = Dropdown(label = "Column select", button_type="default", menu=menucols)
# Plot1 - Line plot
p_line= df_random2.groupby(['date']).mean().plot_bokeh(kind="line",y="sensor_2",color='#d01c8b',plot_data_points=True,show_figure=False)
# Plot2- Barplot
p_bar = df_random2.groupby(['date']).mean().plot_bokeh(kind="bar",y='sensor_2', colormap=colors,show_figure=False)
# Plot3- stacked bar chart
df_sensor=df_random2.drop(['date','month','categorya'],axis=1)
p_stack=df_sensor.groupby(['categoryb']).mean().plot_bokeh(kind='barh', stacked=True,colormap=colors,show_figure=False)
#Plot4- Scatterplot
p_scatter = df_random2.plot_bokeh(kind="scatter", x="month", y="sensor_2",category="categoryb",colormap=colors,show_figure=False)
#Plot5- Pie chart
p_pie= df_random2.groupby(['categoryb']).mean().plot_bokeh.pie(y='sensor_1',colormap=colors,show_figure=False)
#Plot6- Histogram
p_hist=df_sensor.plot_bokeh(kind='hist', histogram_type="stacked",bins=6,colormap=colors, show_figure=False)
widgets = [date_range_slider,category_picker]
#Make Dashboard with Grid Layout:
plots=pandas_bokeh.plot_grid([[p_line, p_bar,p_stack],[p_scatter, p_pie,p_hist]], plot_width=400)
bokehlayout = layout(widgets,plots)
show(bokehlayout)
And here is the error message I get:-
RuntimeError: Models must be owned by only a single document, HoverTool(id='2836', ...) is already in a doc
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
m:\bokehdash\exploratorydatanalysis.py in <module>
83 bokehlayout = layout(widgets,plots)
84
---> 85 show(bokehlayout)
~\anaconda3\lib\site-packages\bokeh\io\showing.py in show(obj, browser, new, notebook_handle, notebook_url, **kw)
137 return run_notebook_hook(state.notebook_type, 'app', obj, state, notebook_url, **kw)
138
--> 139 return _show_with_state(obj, state, browser, new, notebook_handle=notebook_handle)
140
141 #-----------------------------------------------------------------------------
~\anaconda3\lib\site-packages\bokeh\io\showing.py in _show_with_state(obj, state, browser, new, notebook_handle)
175
176 if state.file or not shown:
--> 177 _show_file_with_state(obj, state, new, controller)
178
179 return comms_handle
~\anaconda3\lib\site-packages\bokeh\io\showing.py in _show_file_with_state(obj, state, new, controller)
158
159 '''
--> 160 filename = save(obj, state=state)
161 controller.open("file://" + filename, new=NEW_PARAM[new])
162
~\anaconda3\lib\site-packages\bokeh\io\saving.py in save(obj, filename, resources, title, template, state, **kwargs)
84
85 filename, resources, title = _get_save_args(state, filename, resources, title)
---> 86 _save_helper(obj, filename, resources, title, template, theme)
87 return abspath(filename)
88
~\anaconda3\lib\site-packages\bokeh\io\saving.py in _save_helper(obj, filename, resources, title, template, theme)
146 '''
147 from ..embed import file_html
--> 148 html = file_html(obj, resources, title=title, template=template, theme=theme)
149
150 with open(filename, mode="w", encoding="utf-8") as f:
~\anaconda3\lib\site-packages\bokeh\embed\standalone.py in file_html(models, resources, title, template, template_variables, theme, suppress_callback_warning, _always_new)
301 models_seq = models
302
--> 303 with OutputDocumentFor(models_seq, apply_theme=theme, always_new=_always_new) as doc:
304 (docs_json, render_items) = standalone_docs_json_and_render_items(models_seq, suppress_callback_warning=suppress_callback_warning)
305 title = _title_from_models(models_seq, title)
~\anaconda3\lib\contextlib.py in __enter__(self)
111 del self.args, self.kwds, self.func
112 try:
--> 113 return next(self.gen)
114 except StopIteration:
115 raise RuntimeError("generator didn't yield") from None
~\anaconda3\lib\site-packages\bokeh\embed\util.py in OutputDocumentFor(objs, apply_theme, always_new)
132 doc = Document()
133 for model in objs:
--> 134 doc.add_root(model)
135
136 # handle a single shared document
~\anaconda3\lib\site-packages\bokeh\document\document.py in add_root(self, model, setter)
319 self._roots.append(model)
320 finally:
--> 321 self._pop_all_models_freeze()
322 self._trigger_on_change(RootAddedEvent(self, model, setter))
323
~\anaconda3\lib\site-packages\bokeh\document\document.py in _pop_all_models_freeze(self)
1102 self._all_models_freeze_count -= 1
1103 if self._all_models_freeze_count == 0:
-> 1104 self._recompute_all_models()
1105
1106 def _recompute_all_models(self):
~\anaconda3\lib\site-packages\bokeh\document\document.py in _recompute_all_models(self)
1125 d._detach_document()
1126 for a in to_attach:
-> 1127 a._attach_document(self)
1128 self._all_models = recomputed
1129 self._all_models_by_name = recomputed_by_name
~\anaconda3\lib\site-packages\bokeh\model.py in _attach_document(self, doc)
690 '''
691 if self._document is not None and self._document is not doc:
--> 692 raise RuntimeError("Models must be owned by only a single document, %r is already in a doc" % (self))
693 doc.theme.apply_to_model(self)
694 self._document = doc
RuntimeError: Models must be owned by only a single document, HoverTool(id='2836', ...) is already in a doc
Is there anything additional I need to add into my existing code to fix this and to get both the widgets and plots to deploy?
this is known issue with pandas_bokeh. this error came if you have same plots name but it works when you use curdoc/server type showing.
import curdoc
and instead of show(bokehlayout)
, use curdoc().add_root(bokeh_layout)
and start bokeh server with bokeh serve --show filename.py
about error, mentioned here