In the screen capture of your browser, you have entered 127.0.0.1 in the address bar for the URL you’re trying to visit. Although there are low-level technical differences between using localhost and 127.0.0.1, these are, for all intents and purposes generally referencing to the same loopback address on your system.
As a starting point, you’ll want to actually put in the address where you think the server should be, 172.16.3.76:8006 in your example.
I don’t typically work with the flask development server, but prefer the Flask + Green Unicorn (gunicorn) model for something that is a little bit closer to a deployable solution. With that caveat, there might be a few other things that don’t work in your example by just navigating to a different address.
It is good that you’re using the Bokeh provided server embedded examples as a reference. That makes helping a bit easier. Here’s an example where I’ve modified three lines of their gunicorn embed file for the same sea-surface temperature smoothing example. And also added an import / configuration file to make changing the server address and port less hardcoded.
You can either use my file as a starting point for your use case or do a diff with the example in the bokeh github here https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/flask_gunicorn_embed.pyto see if that gives pointers on how to get your example to work.
To use my example with the configuration file (attached to this thread). Edit the bind variable to reflect the IP address and/or port you want for the server. To access the page, that’s also what you’ll need to put in the clients web browser.
gunicorn --config gunicorn_config.py flask_gunicorn_embed:app
FILES
gunicorn_config.py
import multiprocessing
import urllib.parse
bind = "192.168.0.136:8008"
workers = multiprocessing.cpu_count() * 2 + 1
pr = urllib.parse.urlparse('//'+bind)
APP_SERVER_ADDR = pr.hostname
APP_SERVER_PORT = pr.port
flask_gunicorn_embed.py
try:
import asyncio
except ImportError:
raise RuntimeError("This example requries Python3 / asyncio")
from threading import Thread
from flask import Flask, render_template
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
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 BaseServer
from bokeh.server.tornado import BokehTornado
from bokeh.server.util import bind_sockets
from bokeh.themes import Theme
from gunicorn_config import APP_SERVER_ADDR, APP_SERVER_PORT
if __name__ == '__main__':
print('This script is intended to be run with gunicorn. e.g.')
print()
print(' gunicorn -w 4 flask_gunicorn_embed:app')
print()
print('will start the app on four processes')
import sys
sys.exit()
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('{0}D'.format(new)).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")
# can't use shortcuts here, since we are passing to low level BokehTornado
bkapp = Application(FunctionHandler(bkapp))
# This is so that if this app is run using something like "gunicorn -w 4" then
# each process will listen on its own port
sockets, port = bind_sockets(APP_SERVER_ADDR, 0)
@app.route('/', methods=['GET'])
def bkapp_page():
script = server_document('http://%s:%d/bkapp' % (APP_SERVER_ADDR,port))
return render_template("embed.html", script=script, template="Flask")
def bk_worker():
asyncio.set_event_loop(asyncio.new_event_loop())
bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["localhost:8000", "%s:%d" % (APP_SERVER_ADDR,APP_SERVER_PORT)])
bokeh_http = HTTPServer(bokeh_tornado)
bokeh_http.add_sockets(sockets)
server = BaseServer(IOLoop.current(), bokeh_tornado, bokeh_http)
server.start()
server.io_loop.start()
t = Thread(target=bk_worker)
t.daemon = True
t.start()