I’m creating a heatmap + colormap with Bokeh + Flask. I would like to use Flask routes (instead of running a second Bokeh server involving Tornado…).
The following code works, but the slider1.on_change
is now connected to a dummy CustomJS
callback.
How to make that the slider changes trigger a re-sending of new data to the plot widget, with “AJAX”-like communication (here with a POST request /data/
)?
import numpy as np
from flask import Flask, jsonify, request
from jinja2 import Template
from bokeh.models import ColorBar, LinearColorMapper
import bokeh.plotting, bokeh.embed, bokeh.models.callbacks, bokeh.models, bokeh.layouts
from bokeh.resources import INLINE
app = Flask(__name__)
template = Template('''<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Streaming Example</title>{{ js_resources }}{{ css_resources }}</head><body>{{ plot_div }}{{ plot_script }}</body></html>''')
def new_data(mu, sigma):
return mu + np.random.randn(100, 100) * sigma
@app.route("/data", methods=['POST'])
def send_data():
params = request.json
Z = new_data(params["mu"], params["sigma"])
return jsonify(z=[Z])
@app.route("/")
def simple():
Z = new_data(mu=0, sigma=1)
color_mapper = LinearColorMapper(palette="Viridis256", low=0, high=5)
plot = bokeh.plotting.figure(x_range=(0, 1), y_range=(0, 1), height=200)
plot.image(image=[Z], color_mapper=color_mapper, dh=1.0, dw=1.0, x=0, y=0)
color_bar = ColorBar(color_mapper=color_mapper)
plot.add_layout(color_bar, "right")
callback = bokeh.models.callbacks.CustomJS(args=dict(), code="")
slider1 = bokeh.models.Slider(start=-5, end=5, value=0, step=1, title="Mu")
slider1.js_on_change('value', callback)
slider2 = bokeh.models.Slider(start=1, end=20, value=10, step=1, title="Sigma")
slider2.js_on_change('value', callback)
layout = bokeh.layouts.column(plot, slider1, slider2)
script, div = bokeh.embed.components(layout, INLINE)
html = template.render(plot_script=script, plot_div=div, js_resources=INLINE.render_js(), css_resources=INLINE.render_css())
return html
app.run(debug=True)