Reputation: 2840
Trying to build a dashboard with multiple pages using Flask/Bokeh combination.
The code that I use for main file (test.py
) collects(imports) all the files corresponding to pages of the dashboard.
# test.py
from page1 import Page1
app = Flask(__name__)
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
class Dashboard(object):
def __init__(self, *pages):
self._pages = [page(self) for page in pages]
def __call__(self, doc):
tabs = []
for page in self._pages:
tabs.append(Panel(child=page.layout, title=page.title))
doc.add_root(Tabs(tabs=tabs))
bkapp = Application(FunctionHandler(Dashboard(Page1)))
The intent is to define each page of the dashboard in its own file which, eventually, is imported in the main file(test.py
) and served by an webserver (gunicorn, for example).
# page1.py from bokeh.models.widgets import Select
from bokeh.layouts import column, gridplot, widgetbox, layout, row
class Page(object):
title = "Override in subclass"
def __init__(self, dashboard):
self._dash = dashboard
self._layout = None
@property
def layout(self):
if self._layout is None:
self._layout = self._make_layout()
return self._layout
def _make_layout(self):
raise NotImplementedError("subclasses must define")
class Page1(Page):
title = "Page1"
def _make_layout(self):
self.sim_prod = Select(title="Selection:",
value="Yes",
options=["Yes", "No"]
)
self.x = row(self.sim_prod)
self.layout1 = layout([ [self.x] ], sizing_mode='scale_width')
return self.layout1
def some_callback(self, attr, old, new):
# to be defined later
pass
The widget(Select
, in this case) is built and served properly (see picture) but an error is generated when trying to reload the page:
Error:
raise RuntimeError("Models must be owned by only a single document, %r is already in a doc" % (self))
RuntimeError: Models must be owned by only a single document, WidgetBox(id='04f8b890-e3ca-48d9-954d-c33b96e80c78', ...) is already in a doc
ERROR:tornado.access:500 GET /bkapp/autoload.js?bokeh-autoload-element=8ca7bf9a-0c4f-462c-97f9-1f6b1a246628&bokeh-app-path=/bkapp&bokeh-absolute-url=http://127.0.0.1:60624/bkapp (127.0.0.1) 233.03ms
[2018-05-01 10:17:20 -0700] [94201] [DEBUG] GET /
Any suggestion how to fix it, greatly appreciated! I'm using Python 3.6 and Bokeh 0.12.15.
Cheers,
Upvotes: 2
Views: 2272
Reputation: 2840
In case someone else bumps into the same issue, changing the layout
method of Page
class, as shown below, re-creates the layout every time the page is reloaded.
class Page(object):
title = "Override in subclass"
def __init__(self, dashboard):
self._dash = dashboard
self._layout = None
@property
def layout(self):
return self._make_layout()
def _make_layout(self):
raise NotImplementedError("subclasses must define")
Upvotes: 2