Flask server running Bokeh app: how to access plots from a script generated by server_document()

I’ve been using Bokeh to plot a large database and Flask to serve the app on localhost. The summarized code looks like this:

app = Flask(__name__)

def make_doc(doc):

    def plot_time():
        p = figure(plot_height=400, plot_width=1000, tools="xpan,box_zoom,xwheel_zoom,reset,save",
            x_axis_type="datetime", background_fill_color="#efefef",outline_line_color="#000000")
        for us,color in zip(lista_plots,colors):
            p.line(x="Instant", y=us, source=source, name=us, line_color=color, line_width=1, legend=us.title())
        return p
def plota_tempo_aux():
        p = figure(plot_height=115, plot_width=1000, x_axis_type="datetime", y_axis_type=None, tools="",  background_fill_color="#efefef")
        for us in list_plots:
            p.line(x="Instant", y=us, source=source, name=us, line_color="gray", alpha=0.55)
        return p
p1 = plot_time()
p2 = plot_time_aux()
doc.add_root(p1)
doc.add_root(p2)
doc.title = "Time Plot"

@app.route('/', methods=['GET'])

def bkapp_page():
    script = server_document('http://localhost:5006/bkapp')
    return render_template("index.html", script=script)

def bk_worker():
    server = Server({'/bkapp': make_doc}, io_loop=IOLoop(), allow_websocket_origin=["localhost:{}".format(port)])
    server.start()
    server.io_loop.start()

from threading import Thread
Thread(target=bk_worker).start()

if __name__ == '__main__':
    print('Opening single process Flask app with embedded Bokeh application on http://localhost:{}/'.format(port))
    webbrowser.open_new("http://localhost:{}/".format(port))
    app.run(port=port, debug=False)

The code runs just fine, but when it comes to access p1 and p2 to insert it in the custom divs in the Jinja2 html template, I can’t figure out how. The html template looks like this:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Time Plots</title>
</head>
<body>
    {% for root in script.roots %}
        <div>{{ embed(root) }}</div>
    {% endfor %}
    {{ script | safe }}
</body>
</html>

As it is, the script plots p1 and p2 one after the other, and just ignores the Jinja2 for loop (problably because the variables I’m referencing in the template don’t exist…). However, I’d like to pass each plot (p1 and p2) as arguments in the render_template() funtion, so that I could be free to put them at any place on the html template, but I don’t have a clue how.

Any ideas are welcome.

Create “templates” directory, move index.html there and everything works fine with the (slightly modified) code below.
Note the use of deprecated method autoload_server (I used bokeh v0.12.6).

For your newer bokeh version you can roll it back to server_document.

PS: you code was incomplete. Please always provide complete and runnable code. Then more missing code then less chance anybody will respond. Thanks

from flask import Flask, render_template
import numpy as np
import webbrowser
from tornado.ioloop import IOLoop
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.embed import autoload_server
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.server.server import Server

app = Flask(name)

def make_doc(doc):
def get_plot():
x = np.linspace(0, 10, 1000)
y = np.log(x) * np.sin(x)
source = ColumnDataSource(data = dict(x = np.linspace(0, 10, 1000), y = y))
plot = figure()
plot.line(‘x’, ‘y’, source = source)
return plot

doc.add_root(get_plot())
doc.add_root(get_plot())
doc.title = "Time Plot"

bokeh_app = Application(FunctionHandler(make_doc))

@app.route(’/’, methods = [‘GET’])
def bkapp_page():

script = server_document(‘http://localhost:5006/bkapp’)

script = autoload_server(model = None, url = 'http://localhost:5006/appname')
return render_template("index.html", script = script)

def bk_worker():
server = Server({’/appname’: bokeh_app}, io_loop = IOLoop(), allow_websocket_origin = [“localhost:{}”.format(8080)])
server.start()
server.io_loop.start()

from threading import Thread
Thread(target = bk_worker).start()

if name == ‘main’:
print(‘Opening single process Flask app with embedded Bokeh application on http://localhost:{}/’.format(8080))
webbrowser.open_new(“http://localhost:{}/”.format(8080))
app.run(port = 8080, debug = False)

``

···

On Tuesday, January 15, 2019 at 8:17:05 PM UTC+1, Samir de Oliveira Ferreira wrote:

I’ve been using Bokeh to plot a large database and Flask to serve the app on localhost. The summarized code looks like this:

app = Flask(__name__)

def make_doc(doc):

    def plot_time():
        p = figure(plot_height=400, plot_width=1000, tools="xpan,box_zoom,xwheel_zoom,reset,save",
            x_axis_type="datetime", background_fill_color="#efefef",outline_line_color="#000000")
        for us,color in zip(lista_plots,colors):
            p.line(x="Instant", y=us, source=source, name=us, line_color=color, line_width=1, legend=us.title())
        return p
def plota_tempo_aux():
        p = figure(plot_height=115, plot_width=1000, x_axis_type="datetime", y_axis_type=None, tools="",  background_fill_color="#efefef")
        for us in list_plots:
            p.line(x="Instant", y=us, source=source, name=us, line_color="gray", alpha=0.55)
        return p
p1 = plot_time()
p2 = plot_time_aux()
doc.add_root(p1)
doc.add_root(p2)
doc.title = "Time Plot"

@app.route('/', methods=['GET'])

def bkapp_page():
    script = server_document('[http://localhost:5006/bkapp](http://localhost:5006/bkapp)')
    return render_template("index.html", script=script)

def bk_worker():
    server = Server({'/bkapp': make_doc}, io_loop=IOLoop(), allow_websocket_origin=["localhost:{}".format(port)])
    server.start()
    server.io_loop.start()

from threading import Thread
Thread(target=bk_worker).start()

if __name__ == '__main__':
    print('Opening single process Flask app with embedded Bokeh application on http://localhost:{}/'.format(port))
    webbrowser.open_new("http://localhost:{}/".format(port))
    app.run(port=port, debug=False)

The code runs just fine, but when it comes to access p1 and p2 to insert it in the custom divs in the Jinja2 html template, I can’t figure out how. The html template looks like this:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Time Plots</title>
</head>
<body>
    {% for root in script.roots %}
        <div>{{ embed(root) }}</div>
    {% endfor %}
    {{ script | safe }}
</body>
</html>

As it is, the script plots p1 and p2 one after the other, and just ignores the Jinja2 for loop (problably because the variables I’m referencing in the template don’t exist…). However, I’d like to pass each plot (p1 and p2) as arguments in the render_template() funtion, so that I could be free to put them at any place on the html template, but I don’t have a clue how.

Any ideas are welcome.