Search code examples
python-3.xflaskbokeh

Bokeh Widget in Flask


I want to use bokeh widgets in my flask application but I cannot seem to trigger even a simple on_click behaviour.

I'm new to flask/bokeh/javascript/html. The code looks sound to me, perhaps it is the encoding step? (I pulled this together from the few examples online).

My working example is below. I can click the boop button all I like but nothing changes (no printouts, change in label, console log etc.)

app.py

from flask import Flask, render_template
from bokeh.embed import components
from bokeh.resources import INLINE
from bokeh.util.string import encode_utf8
from bokeh.models.widgets import Button
app = Flask(__name__)

@app.route('/')
def index():
    # grab the static resources
    js_resources = INLINE.render_js()
    css_resources = INLINE.render_css()
    widget_status = "no clicked"

    # Submit button
    button = Button(label="boop", button_type="success")
    def my_button_handler():
        widget_status = "clicked"
        button.label = "mlem"

    button.on_click(my_button_handler)
    scriptb, divb = components(button)

    # render template
    html = render_template(
        'bokeh_bokeh.html',
        js_resources=js_resources,
        css_resources=css_resources,
        scriptb=scriptb,
        divb=divb,
        widget_status=widget_status
    )
    return encode_utf8(html)


if __name__ == '__main__':
    app.run(port=5000)

bokeh_bokeh.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>Bokeh Bokeh</title>
    {{ js_resources|indent(4)|safe }}
    {{ css_resources|indent(4)|safe }}
    {{ scriptb|indent(4)|safe }}
  </head>
  <body>
    {{ divb|indent(4)|safe }}
    {{ widget_status|indent(4)|safe }}
  </body>
</html>

Solution

  • on_click only works for applications that are running in a Bokeh server (the Bokeh server is the actual Python process that would execute the callback code). The components API is for generating standalone (pure HTML+JS) output, so this combination cannot work. Your options are: