I can't run bokeh server within flask beind apache so now I'm trying to serve bokeh within flask locally. The figure does not render. Here is the flask code:
from flask import Flask, render_template
app = Flask(__name__)
from bokeh.embed import server_document
@app.route("/")
def techblog():
try:
tag = server_document(url=r'/bokeh', relative_urls=True)
return render_template('techblog.html', tag=tag)
except Exception as e:
return str(e)
if __name__ == '__main__':
app.run(debug=True)
Here is the bokeh code:
from numpy.random import random
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import Button, ColumnDataSource
from bokeh.server.server import Server
def run(doc):
fig = figure(title='random data', width=400, height=200, tools='pan,box_zoom,reset,save')
source = ColumnDataSource(data={'x': [], 'y': []})
fig.line('x', 'y', source=source)
def click(n=100):
source.data = {'x': range(n), 'y': random(n)}
button = Button(label='update', button_type='success')
button.on_click(click)
layout = column(widgetbox(button), fig)
doc.add_root(layout)
click()
# configure and run bokeh server
kws = {'port': 5000, 'prefix':'/bokeh','allow_websocket_origin': ['127.0.0.1']}
server = Server(run, **kws)
server.start()
# if __name__ == '__main__':
server.io_loop.add_callback(server.show, '/')
server.io_loop.start()
Here is my html template:
<h1 style='color:blue'>Hello There!</h1>
</br>
{{ tag|safe }}
</br>
{{ tag }}
I'm running flask app via python. And on a separate command processor I run bokeh app via,
bokeh serve --allow-websocket-origin=localhost:5000 filename.py
I only get the tag without "safe" as
<script src="/bokeh/autoload.js?bokeh-autoload-element=1001&bokeh-app-path=/bokeh" id="1001"></script>
And I have this message on flask console. It is a standart 404:
"GET /bokeh/autoload.js?bokeh-autoload-element=1000&bokeh-app-path=/bokeh HTTP/1.1" 404 -
That'a all. No figure or button is rendered. What should I change to see the figure?
Edit: I've specified the port and the prefix in the bokeh code. The outcome has not changed.
Edit 2: I've add the console msj for 404 error on flask console.
I add some details to @bigreddot's answer.
Code didn't work for me too. I even found exactly this code in some tutorial and main problem was that it was using nginx
which was converting /bokeh
to http://127.0.0.1/bokeh
. But on local computer without nginx
I have to change all urls.
EDIT: I found tutorial with this code https://rbtechblog.com/blog/deploy_bokeh_app
I start changing code and reduce it to create minimal code which works. I made changes similar to changes mentioned by bigreddot.
I put code directly in file without def
and without Server
filename.py
from numpy.random import random
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import Button, ColumnDataSource
def click(n=100):
source.data = {'x': range(n), 'y': random(n)}
fig = figure(title='random data', width=800, height=400, tools='pan,box_zoom,reset,save')
source = ColumnDataSource(data={'x': [], 'y': []}) # place for data
fig.line('x', 'y', source=source) # draw plot
button = Button(label='update', button_type='success') # create button
button.on_click(click) # assign function to button
layout = column(fig, widgetbox(button)) # create layout
curdoc().add_root(layout) # add all to document
click() # generate random data at start
Now I can run it in console
bokeh serve filename.py
and I can see it in web browser using url
http://localhost:5006/filename
(bokeh
should display this url in console after start - if you will use different file or options then you may see different url)
At this moment I don't need any other options but later I will need --allow-websocket-origin
but I will describe it later.
BTW: I not use name bokeh.py because it can make problem to import original bokeh
.
Because I don't use nginx
which could convert /bokeh
to http://localhost:5006/filename
so I have to use full url in serve_document
For test I used render_template_string
instead of render_template
so I don't have to create templates/index.html
so it will easier to copy and test code.
I removed try/except
to get more details if there will be error.
app.py
from flask import Flask, render_template, render_template_string
from bokeh.embed import server_document
app = Flask(__name__)
@app.route("/")
def index():
tag = server_document(url='http://localhost:5006/filename')
#return render_template('index.html', tag=tag)
return render_template_string('''<div>{{ tag|safe }}</div>''', tag=tag)
if __name__ == '__main__':
app.run(debug=True)
Now I can run it
python app.py
and I can open page in web browser using standard url
http://localhost:5000/
but I will not see plot and bokeh
will display
Refusing websocket connection from Origin 'http://127.0.0.1:5000';
use --allow-websocket-origin=127.0.0.1:5000
or set BOKEH_ALLOW_WS_ORIGIN=127.0.0.1:5000 to permit this;
currently we allow origins {'localhost:5006'}
so I have to restart bokeh
with this option
bokeh serve filename.py --allow-websocket-origin=127.0.0.1:5000
(as bigreddot mentioned it has to be 127.0.0.1
, not localhost
)
And now flask
should display plot.
BTW: if I use template without any HTML tag
render_template_string('''{{ tag|safe }}''', tag=tag)
then browser may treat all code (<script ...></scrip>
) as part of <head></head>
and it will not display it because browser never display elements which are in <head></head>
even if there are correct images or plots.