Dynamic plot (datashade) in Flask

I create a base map plot with geoviews (bokeh backend). Then I create a holoviews hv.Curve chart, which I datashade. I Jupyter Notebook it works just fine, but not in a Flask app (using components). The plot is not rendered correctly (only a rectange with subdata ist plotted) and it is not dynamic (no adaption when I zoom in).

In the notebook, Holoviews is certainly using a Bokeh server behind the scenes to actually provide all the events and callbacks necessary to do the updates and keep everything in sync when UI changes happen. You can certainly embed a Bokeh server in your Flask app manually yourself. Holowiews may have some higher-level tools or APIs that can help make this simpler. I will try to point some of the HV devs at the question.

In the mean time though, I would advise you to provide more information. Ideally, a minimal (i.e toy) example that reproduces what you are seeing. Without code to focus a discussion, it is hard to speculate, and sometimes hard even to do that.

1 Like

Thanks for your quick reply! I will build a minimal example. I hope for a solution without starting a detached bokeh server (I have to deploy a Flask app to a Pivotal CloudFoundry system, where I can’t start a Bokeh server as I only can serve one port).

def create_map_figure():
    from colorcet import bgy

    import holoviews as hv
    from holoviews.operation.datashader import datashade
    import geoviews.tile_sources as gts
    hv.extension('bokeh')

    from datashader.geo import lnglat_to_meters

    shade_pd = [["localtime", "from_lon", "from_lat", "to_lon", "to_lat"]] # TODO: create test data

    # datashader and bokeh work with mercator proj
    shade_pd.loc[:, 'from_lon'], shade_pd.loc[:, 'from_lat'] = lnglat_to_meters(shade_pd["from_lon"], shade_pd["from_lat"])
    shade_pd.loc[:, 'to_lon'], shade_pd.loc[:, 'to_lat'] = lnglat_to_meters(shade_pd["to_lon"], shade_pd["to_lat"])

    muc_coords = {"lat": 48.137154, "lon": 11.576124}
    x1, y1 = lnglat_to_meters(muc_coords["lon"]-0.1, muc_coords["lat"]-0.1)
    x2, y2 = lnglat_to_meters(muc_coords["lon"]+0.1, muc_coords["lat"]+0.1)

    plot_width = 800
    plot_height = 400

    tile_opts = dict(width=plot_width, height=plot_height, xaxis=None, yaxis=None, show_grid=False)
    map_tiles = gts.CartoLight.opts(style=dict(alpha=1), plot=tile_opts)

    lines = hv.Curve(shade_pd[["from_lon", "from_lat", "to_lon", "to_lat"]], ["from_lon", "from_lat"],
                 ["to_lon", "to_lat"])
    routes = datashade(lines, x_sampling=2, y_sampling=2, cmap=bgy, x_range=(x1, x2), y_range=(y1, y2), alpha=50)

    renderer = hv.renderer('bokeh')

    return renderer.get_plot(map_tiles * routes).state

@app.route("/")
def dash():

    from bokeh.embed import components

    # Create the plot
    plot_map = create_map_figure()

    # Embed plot into HTML via Flask Render
    script_map, div_map = components(plot_map)

    return render_template("index.html", script_map=script_map, div_map=div_map)

Right off the bat I can state that this definitely would not work. As the documentation states, components is only useful for standalone Bokeh content, i.e. that is purely HTML/CSS/JS. But dynamic datashading requires executing real Python code e.g. when the viewport changes. That means a Bokeh server (the Bokeh server is exactly the Python process that would run the datashader code to update the plot) Hopefully one of the Holoviews devs will come point you in the right direction to do this at a high level with their tools

Otherwise, you will either need to run a separate bokeh serve process, and embed that content with server_document, or embed a server directly in your Flask process, e.g. like the flask_embed.py example.

1 Like

Are holoviews devs following the threads here or do I have to create a separate issue at their github? I created one here https://github.com/pyviz/datashader/issues/756

I can’t really comment. I pinged them on their gitter channel but your best bet may be to open a discussion there yourself https://gitter.im/pyviz/pyviz

I’ll give it a try, thank you very much for your support so far!

1 Like

@anderl80 Please let me know if you have found a solution as I am having the same problem.

2 Likes

As I am working on cloud foundry, and I am not sure how to handle with websockets, routes and ports while embedding the bokeh app in flask (which is surely possible somehow), I switched to deploy a bokeh app on the cloud foundry server. You can find the gist here https://gist.github.com/anderl80/f2e7f5d4075704ee84a88ffb2578e30a

@anderl80
Hi,
so we have to use torando server then only we can have dynamic property ?
or is there any other way
I too want dynamic map zoom property for my plot with flask,
I made flask embedded code with component but we can’t have dynamic property as we know,
Any more links you can provide by which i can make my plot dynamic in nature with flask IBM server.
Thank you.