Search code examples
pythonbokeh

Embedding plot into template and serving from bokeh


I am trying to combine the two bokeh examples embed_multiple.py and simple_stream.py to have dynamic graphs served within a template from bokeh-server.

The aim is to have dynamic graphs embedded in a layout with additional information such as text and links.

The below code will produce the HTML file as expected from embed_multiple.py, but the bokeh_server window only displays the plots (no header / body info is preserved).

    import time
    import numpy as np

    from bokeh.plotting import cursession, figure, show, output_server
    from bokeh.models import GlyphRenderer, Range1d
    from bokeh.embed import components
    from jinja2 import Template

    # static pages requirements
    import webbrowser
    import os
    import six

    output_server("simple_stream")

    # live graph example data
    x = np.linspace(0, 4*np.pi, 200)
    y = np.sin(x)
    # create some data
    x1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    y1 = [0, 8, 2, 4, 6, 9, 5, 6, 25, 28, 4, 7]
    x2 = [2, 5, 7, 15, 18, 19, 25, 28, 9, 10, 4]
    y2 = [2, 4, 6, 9, 15, 18, 0, 8, 2, 25, 28]
    x3 = [0, 1, 0, 8, 2, 4, 6, 9, 7, 8, 9]
    y3 = [0, 8, 4, 6, 9, 15, 18, 19, 19, 25, 28]

    # select the tools we want
    TOOLS="pan,wheel_zoom,box_zoom,reset,save"

    # live graph example figure
    p = figure(title="Simple streaming example")
    p.line(x,y, color="Orange", line_width=2)

    # the red and blue graphs will share this data range
    xr1 = Range1d(start=0, end=30)
    yr1 = Range1d(start=0, end=30)

    # only the green will use this data range
    xr2 = Range1d(start=0, end=30)
    yr2 = Range1d(start=0, end=30)

    # build our figures
    p1 = figure(x_range=xr1, y_range=yr1, tools=TOOLS, plot_width=300, plot_height=300)
    p1.scatter(x1, y1, size=12, color="red", alpha=0.5)

    p2 = figure(x_range=xr1, y_range=yr1, tools=TOOLS, plot_width=300, plot_height=300)
    p2.scatter(x2, y2, size=12, color="blue", alpha=0.5)

    p3 = figure(x_range=xr2, y_range=yr2, tools=TOOLS, plot_width=300, plot_height=300)
    p3.scatter(x3, y3, size=12, color="green", alpha=0.5)

    # plots can be a single PlotObject, a list/tuple, or even a dictionary
    plots = {'Orange': p, 'Red': p1, 'Blue': p2, 'Green': p3}

    script, div = components(plots)

    template = Template('''<!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Bokeh Scatter Plots</title>
            <h1> embedding multiple graphs - can we do it live?</h1>
            <b> So, this text will show up on the static page, but not from Bokeh server! <br \> I must be missing something... </b>
            <style> div{float: left;} </style>
            <link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.9.0.min.css" type="text/css" />
            <script type="text/javascript" src="http://cdn.bokeh.org/bokeh/release/bokeh-0.9.0.min.js"></script>
            {{ script }}
        </head>
        <body>
        {% for key in div.keys() %}
            {{ div[key] }}
        {% endfor %}
        </body>
    </html>
    ''')

    show(template.render(script=script, div=div))

    html_file = 'embed_multiple.html'
    with open(html_file, 'w') as textfile:
        textfile.write(template.render(script=script, div=div))
    url = 'file:{}'.format(six.moves.urllib.request.pathname2url(os.path.abspath(html_file)))
    webbrowser.open(url)

    ds = p.select({"type": GlyphRenderer})[0].data_source
    while True:
        oldx = ds.data["x"]
        newx = np.hstack([oldx, [oldx[-1] + 4*np.pi/200]])
        ds.data["x"] = newx
        ds.data["y"] = np.sin(newx)
        cursession().store_objects(ds)
        time.sleep(0.5)

My suspicion is that I am using 'show' incorrectly:

    show(template.render(script=script, div=div))

Thanks for your time!

Edit:

Using the separate http.server alongside bokeh_server approach outlined in the embed examples (modified animated.py) still seems to strip HTML! (h1 in this example)


Solution

  • I'm still a little shaky with what you're trying to do exactly, but I think one concept you're not doing right is showing multiple plots (p - p3) in the right way.

    This seems to be a nice tutorial on how to format your multi-plot layouts with bokeh. I haven't looked at their API until tonight but it seems pretty intuitive.

    If you're having issues with something else in the code, maybe edit your question to better reflect that issue and I'll take another stab at it.