Bokeh Server + Flask : Passing data to plot from Flask to the Bokeh server app

Hi all,

First of all, and like many others, I would like to thank everyone involved in Bokeh as I have been using it successfully for more than a year now so thank you all. I have pretty much always found my way through the documentation / examples / mailing-list but this time I think I need your help!

I have a Flask application which aim is to fetch data from a database, gives the user different processing options and finally plot the results. For now I was embedding the plots using components which gives something like that:

@app.route(‘/plot’)
def plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)

# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()

# Plot the result
plot = figure()
p.line(model.data.x, model.data.y)
...

script, div = components(plot)
return render_template('my_template.html', script=script, div=div)

``

Then I thought that moving to apps served by Bokeh server would be a good idea, giving it more flexibility, scalability, … I have started with the sliders example and got it working fairly quickly. However, I am now totally stuck on how to pass the data to be plotted to Bokeh server. Here is what I have got so far:

@app.route(‘/serverplot’)
def server_plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)

# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()
···
##############
### How can I pass my model.data to the bokeh app from here ?
##############

script = autoload_server(model=None, app_path="/testapp", url=...)

return render_template('my_template.html', script=script)

``

I initially thought I could embed the data in the session, something of that kind:

s = pull_session()
s.document[‘data’] = model.data
script = autoload_server(model=None, app_path=“/testapp”, url=…, session=s.id)

``

But editing the document this way is not allowed. I have also tried s.document.session_context[‘data’] with the same problem, am I missing something here ?

Poking around the different sources of information, I also found this from Bryan Van de Ven :

There are plenty of ways to do that, and also do the “heavy lifting” elsewhere. You just need to communicate the results/data/whatever the app needs in order to do its plotting, the the app. But that could be done any number of ways:

  • apps can access HTML request args (new feature)
  • apps can access cookies
  • apps can access data in external databases (redis, mongo, etc.)
  • apps can make AJAX calls to REST APIs

Based on it, I think a possible solution could be :

  1. Generate the data to be plotted (on Flask side)
  2. Obtain a session with pull_session()
  3. Temporarily store the data in redis using the session.id as a key
  4. Fetch the data from redis using the session_id in the bokeh app
    That adds the question of properly deleting the redis entry when the session is finished, is there something that could be used for that ?

And more generally, is there not a simpler approach to pass data from Flask to the Bokeh app ?

Thanks,

Bertrand

Hello, Bertrand!

You can use Bokeh’s AjaxDataSource and Flask’s crossdomain like this example from Bryan if you want to periodically poll data or just make an normal http request from Bokeh app to some Flask route:

from bokeh.models import ColumnDataSource, AjaxDataSource
from bokeh.plotting import figure, curdoc
import requests

Bokeh’s Ajax

source = AjaxDataSource(data_url=‘http://localhost:5000/data’, polling_interval=1000)

source.data = dict(Date=, Price=)

Regular http request

url = “http://127.0.0.1:5000/alldata
res = requests.get(url, timeout=20)
data = res.json()
source = ColumnDataSource(data)

plot = figure(plot_width=700, plot_height=400)
plot.line(‘Date’, ‘Price’, source=source)

curdoc().add_root(plot)


Also, Bokeh needs to be runnig as server and this can be done as an cli server or like this example that shows how to integrate Bokeh server with Flask in a [library fashion](https://github.com/bokeh/bokeh/blob/0.12.4/examples/howto/server_embed/flask_embed.py). I made [some modifications](https://github.com/Corleo/flask_bokeh_app) into it to separate Flask and Bokeh apps into 2 scripts.

Corleo

Umm. I still don’t see how this answers Bertrand’s question. How does he pass on context to the bokeh app?

···

On Wednesday, February 15, 2017 at 7:33:02 AM UTC-8, Faucon Glorieux wrote:

Hi all,

First of all, and like many others, I would like to thank everyone involved in Bokeh as I have been using it successfully for more than a year now so thank you all. I have pretty much always found my way through the documentation / examples / mailing-list but this time I think I need your help!

I have a Flask application which aim is to fetch data from a database, gives the user different processing options and finally plot the results. For now I was embedding the plots using components which gives something like that:

@app.route(‘/plot’)
def plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)

# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()

# Plot the result
plot = figure()
p.line(model.data.x, model.data.y)
...

script, div = components(plot)
return render_template('my_template.html', script=script, div=div)

``

Then I thought that moving to apps served by Bokeh server would be a good idea, giving it more flexibility, scalability, … I have started with the sliders example and got it working fairly quickly. However, I am now totally stuck on how to pass the data to be plotted to Bokeh server. Here is what I have got so far:

@app.route(‘/serverplot’)
def server_plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)
# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()

##############
### How can I pass my model.data to the bokeh app from here ?
##############

script = autoload_server(model=None, app_path="/testapp", url=...)

return render_template('my_template.html', script=script)

``

I initially thought I could embed the data in the session, something of that kind:

s = pull_session()
s.document[‘data’] = model.data
script = autoload_server(model=None, app_path=“/testapp”, url=…, session=s.id)

``

But editing the document this way is not allowed. I have also tried s.document.session_context[‘data’] with the same problem, am I missing something here ?

Poking around the different sources of information, I also found this from Bryan Van de Ven :

There are plenty of ways to do that, and also do the “heavy lifting” elsewhere. You just need to communicate the results/data/whatever the app needs in order to do its plotting, the the app. But that could be done any number of ways:

  • apps can access HTML request args (new feature)
  • apps can access cookies
  • apps can access data in external databases (redis, mongo, etc.)
  • apps can make AJAX calls to REST APIs

Based on it, I think a possible solution could be :

  1. Generate the data to be plotted (on Flask side)
  2. Obtain a session with pull_session()
  3. Temporarily store the data in redis using the session.id as a key
  4. Fetch the data from redis using the session_id in the bokeh app
    That adds the question of properly deleting the redis entry when the session is finished, is there something that could be used for that ?

And more generally, is there not a simpler approach to pass data from Flask to the Bokeh app ?

Thanks,

Bertrand

Hello Bertrand,

I decided not to use bokeh server for my flask applications since it is not very convenient to manipulate the plots from flask. Instead, I found a more convenient way to integrate bokeh plots via Ajax calls. I put together a very simple app showing how to integrate bokeh plots (you can create a plot dynamically by pressing a button) that have similar functionality to the bokeh server ( including streaming data) . Source code can be found here. I haven’t tested it on a big dataset so I can say nothing about the performance. The only disadvantage you may find is that you need to know a little of jQuery in order to write Ajax calls.

Best,

Vitali

···

On Wednesday, February 15, 2017 at 10:33:02 AM UTC-5, Faucon Glorieux wrote:

Hi all,

First of all, and like many others, I would like to thank everyone involved in Bokeh as I have been using it successfully for more than a year now so thank you all. I have pretty much always found my way through the documentation / examples / mailing-list but this time I think I need your help!

I have a Flask application which aim is to fetch data from a database, gives the user different processing options and finally plot the results. For now I was embedding the plots using components which gives something like that:

@app.route(‘/plot’)
def plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)

# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()

# Plot the result
plot = figure()
p.line(model.data.x, model.data.y)
...

script, div = components(plot)
return render_template('my_template.html', script=script, div=div)

``

Then I thought that moving to apps served by Bokeh server would be a good idea, giving it more flexibility, scalability, … I have started with the sliders example and got it working fairly quickly. However, I am now totally stuck on how to pass the data to be plotted to Bokeh server. Here is what I have got so far:

@app.route(‘/serverplot’)
def server_plot():
data_id = request.args.get(‘data_id’)

# Fetch the data from the database
data = db.fetch(data_id)
# Load it into data models
model = MyModel(data)

# The user applies a combination of processings available for the model
model.process()

##############
### How can I pass my model.data to the bokeh app from here ?
##############

script = autoload_server(model=None, app_path="/testapp", url=...)

return render_template('my_template.html', script=script)

``

I initially thought I could embed the data in the session, something of that kind:

s = pull_session()
s.document[‘data’] = model.data
script = autoload_server(model=None, app_path=“/testapp”, url=…, session=s.id)

``

But editing the document this way is not allowed. I have also tried s.document.session_context[‘data’] with the same problem, am I missing something here ?

Poking around the different sources of information, I also found this from Bryan Van de Ven :

There are plenty of ways to do that, and also do the “heavy lifting” elsewhere. You just need to communicate the results/data/whatever the app needs in order to do its plotting, the the app. But that could be done any number of ways:

  • apps can access HTML request args (new feature)
  • apps can access cookies
  • apps can access data in external databases (redis, mongo, etc.)
  • apps can make AJAX calls to REST APIs

Based on it, I think a possible solution could be :

  1. Generate the data to be plotted (on Flask side)
  2. Obtain a session with pull_session()
  3. Temporarily store the data in redis using the session.id as a key
  4. Fetch the data from redis using the session_id in the bokeh app
    That adds the question of properly deleting the redis entry when the session is finished, is there something that could be used for that ?

And more generally, is there not a simpler approach to pass data from Flask to the Bokeh app ?

Thanks,

Bertrand