I am using the below code flask_embed.py to embed a bokeh server app in a flask app.
from threading import Thread
from flask import Flask, render_template
from tornado.ioloop import IOLoop
from bokeh.embed import server_document
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
from bokeh.server.server import Server
from bokeh.themes import Theme
app = Flask(__name__)
def bkapp(doc):
df = sea_surface_temperature.copy()
source = ColumnDataSource(data=df)
plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43")
plot.line('time', 'temperature', source=source)
def callback(attr, old, new):
if new == 0:
data = df
else:
data = df.rolling(f"{new}D").mean()
source.data = ColumnDataSource.from_df(data)
slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
slider.on_change('value', callback)
doc.add_root(column(slider, plot))
doc.theme = Theme(filename="theme.yaml")
@app.route('/', methods=['GET'])
def bkapp_page():
script = server_document('10.XX.XXX.100:5000/bkapp')
return render_template("embed.html", script=script, template="Flask")
def bk_worker():
# Can't pass num_procs > 1 in this configuration. If you need to run multiple
# processes, see e.g. flask_gunicorn_embed.py
server = Server({'/bkapp': bkapp}, io_loop=IOLoop(), allow_websocket_origin=["10.XX.XXX.100:5000"])
server.start()
server.io_loop.start()
Thread(target=bk_worker).start()
if __name__ == '__main__':
print('Opening single process Flask app with embedded Bokeh application')
print()
print('Multiple connections may block the Bokeh app in this configuration!')
print('See "flask_gunicorn_embed.py" for one way to run multi-process')
app.run(host = 10.XX.XXX.100,port=6000)
When I run python flask_embed.py in the terminal, I see the page loaded with the text âBokeh appâ that is present in embed.html but the bokeh plot is not rendering. Below is a message that I see in the terminal after loading the page in the browser 10.XX.XXX.100:5000.
@Tauseef The bokeh server part listens on a different port than the Flask server. The error message is Flask telling you it has no idea about any of the Bokeh server endpoints. The default Bokeh server port is 5006 so assuming you donât change that, the server_embed line would need to change to
But I have to prompt, what if someone set bokeh app to port other than 5006, in case of multiple instances of bokeh development, is there solution exist to circumvent such situation ?
You have to know what the port is, one way or another. If your example code is any indication that should not be a problem since you are configuring the Bokeh Server instance right there yourself, and would have to set a different port yourself for it to be different from the default. The server instance also has a port attribute.
Hi Bryan - Thanks for your reply. I changed the port to default Bokeh server port to 5006 but still getting the same error.
from threading import Thread
from flask import Flask, render_template
from tornado.ioloop import IOLoop
from bokeh.embed import server_document
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
from bokeh.server.server import Server
from bokeh.themes import Theme
app = Flask(__name__)
def bkapp(doc):
df = sea_surface_temperature.copy()
source = ColumnDataSource(data=df)
plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43")
plot.line('time', 'temperature', source=source)
def callback(attr, old, new):
if new == 0:
data = df
else:
data = df.rolling(f"{new}D").mean()
source.data = ColumnDataSource.from_df(data)
slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
slider.on_change('value', callback)
doc.add_root(column(slider, plot))
doc.theme = Theme(filename="theme.yaml")
@app.route('/', methods=['GET'])
def bkapp_page():
script = server_document('10.XX.XXX.100:5006/bkapp')
return render_template("embed.html", script=script, template="Flask")
def bk_worker():
# Can't pass num_procs > 1 in this configuration. If you need to run multiple
# processes, see e.g. flask_gunicorn_embed.py
server = Server({'/bkapp': bkapp}, io_loop=IOLoop(), allow_websocket_origin=["10.XX.XXX.100:6000"])
server.start()
server.io_loop.start()
Thread(target=bk_worker).start()
if __name__ == '__main__':
print('Opening single process Flask app with embedded Bokeh application')
print()
print('Multiple connections may block the Bokeh app in this configuration!')
print('See "flask_gunicorn_embed.py" for one way to run multi-process')
app.run(host = 10.XX.XXX.100,port=6000)
Are you sure it is the same error? E.g the code above specifies to allow a websocket origin on port 5000 but then actually calls app.run with port 6000. If your example code is accurate, that would certainly generate a 403 permissions error (not 404).
Is there a firewall or proxy that would block access to the Bokeh server at port 5006, or redirect all traffic to Django? If you are still getting 404s from Django then that means the pages requests back to the Bokeh server never even making it to the Bokeh server. They are going to Django instead, and that is certainly a problem. That would need to be resolved. Unfortunately I canât really offer much assistance without quite a bit of knowledge about your network configuration.
TLDR; The page that django serves will contain JS code that attempts to connect to the Bokeh server. That network address will have to be reachable by the page.
I have the exact same problem. I have embedded Bokeh server app in flask. All the ports and code is correct. The same code works on my work laptop but doesnât work on my private laptop. Please have a look on the messages shown in my browser and the terminal messages are same as shown by @Tauseef .
The screen capture of your console logs look like you are using Holoviz panel to serve your application. Is that correct?
If so, what versions of panel and bokeh are you using? And worth confirming you have identical versions of everything in your two setups (working and non-working).
Would also suggest starting a separate topic for your specific issueâŚ
See this topic on the Holoviz panel discourse. I am the author of that topic; there was a regression in panel that caused panel+Flask to stop working. Things worked in panel 0.9.7, stopped working in panel 0.10.2, and were fixed in panel 0.10.3
@_jm , Yes you are right. Thanks for sending the link of your topic. It gave me a good hint. However, my problem was solved by installing latest version of panel by simply using âconda install -c anaconda panelâ. The Bokeh version on both of my setups is 2.2.3.
Yes. That link was an interim solution. Apologies if my comment in this thread was not clear; panel 0.10.3 and newer (currently 0.11.1) fixes the regression so those additional statements are no longer required.