Used to work on 1.4.3, not on 2.0.0: replace an existing figure entirely by connecting to a server

Aloha all,

I use bokeh as a plotting system for a long data reduction pipeline which keeps producing new plots and sends them to the same server, started separately using bokeh serve. The pipeline is in Python.
The way I use is to push the session at the beginning with an empty or dummy figure, in a column layout.
When I want a new figure to be displayed, I retrieve the layout, and replace the children with the new figure.

This used to work perfectly on 1.4.3. On 2.0.0, the first dummy figure is displayed, but the following figures are ignored. I have run bokeh serve in trace log level and in 1.4.3 I see the new figure being processed, in 2.0.0, there are no messages whatsoever when the children.insert command is used.

Here is an example code. When run in 1.4.3, after 5 seconds the second figure appears. In 2.0.0, only the first figure appears, then after 5 seconds the code exits with no errors.

from bokeh.client import push_session,pull_session
from bokeh.io import curdoc
from bokeh.plotting.figure import figure
from bokeh.layouts import column
import time

p = figure(plot_width=400, plot_height=400, name = 'main_plot')
r = p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

mainLayout = column(children=[p], name='mainLayout')
curdoc().add_root(mainLayout)
bokeh_session = push_session(curdoc())
bokeh_session.show(mainLayout)

print("waiting 5 seconds")
time.sleep(5)

p1 = figure(plot_width=400, plot_height=400, name='main_plot')
r1 = p1.circle([2, 3, 4, 5, 6], [10, 1, 3, 1, 1], size=20, color="red", alpha=0.5)

layout = curdoc().get_model_by_name('mainLayout')
figure = curdoc().get_model_by_name('main_plot')
children = layout.children
children.remove(figure)
children.insert(0, p1)

So the question is: how do I reuse an existing server to display a completely new figure in 2.0.0 ?
Thank you!
Luca

I think I found a solution.

I added:

bokeh_session.push() 

at the end of my code and it now works.
Still, this is a different behavior than in 1.4.3, where the push was not needed.

@lucarizzi please edit your post to use code-formatting so that the code is legible.

@Bryan done, thank you and sorry for that

@lucarizzi To be honest, this kind of usage, pushing updates to a “blank” Bokeh server from an external process, is highly discouraged by us [1]. Absent real python on_change callbacks, all of the above could be accomplished with a Flask or Django app that uses Bokeh to generate and embed standalone content pages it served. AjaxDataSource or ServerSentDataSource might even suffice to make a single static HTML page that can accept updates.

All that said, Bokeh 2.0 was a major number bump, specifically indicating breaking changes. So, regarding:

Still, this is a different behavior than in 1.4.3, where the push was not needed.

That’s not to be unexpected.


  1. “Reasonable” uses of bokeh.client are basically:

    • One time, up front customization of sessions before embedding them with server_session

    • Testing

    ↩︎

Thank you for this (and for all you do with Bokeh).
My understanding of AjaxDataSource is that it can be used to alter the data in a figure, replacing the points being displayed, similar to ServerSentDataSource.

Maybe I should more explicit about the use case.

My need is generate a long series of plots, each of them completely independent from each other. One might be a histogram, one might a curve, one might a scatter plot and so on. Different axis, different content. They are all generated by the same python program. It can be done in Matplotlib, but I am rather passionate about Bokeh and I wanted to find a solution.

So the question is:

Can I use an existing server and a web browser pointed to it to display a sequence of completely unrelated figures, which appear and disappear in front of the user under the control of python?

If the answer is that Bokeh is not the right tool I am fine with it, of course, but it seems that those functionalities are actually provided even if discouraged.

Thank you again

@lucarizzi I think you can certainly do all that you have described with Bokeh.

  • Use Bokeh to generate PNGs and then do what you would otherwise do with MPL (e.g. if interactivity is not a requirement)

  • Have a Flask or other web app use Bokeh as API to generate content that it embeds in pages in any of the various ways Bokeh standalone content can be embedded in response to outside triggers (if at most browser/js interactivity is needed)

  • Embed the Bokeh server as a library in an app that responds to outside triggers (if full Python callbacks are needed for the displayed content)

  • Push Bokeh JSON to some document database that a static HTML page can monitor and respond to.

There are lots of possibilities, that all have their pros and cons, and that would depend on your specific situation and requirements. I am only trying to impress that this specific kind of usage of bokeh.client is not really recommended (which is why we don’t demonstrate it, anywhere).

Of course another solution is to become involved in core development so that you can become an advocate for this kind of usage and functionality and help ensure that it is maintained to your requirements.

@Bryan Thank you so much for your detailed response.
I will look into these options.

I would love to contribute to the development, I am not a professional programmer at all, I am scientist using Bokeh because of its power, but I am happy to try to have a look at the codebase and see if my skill level can be useful in any way.

1 Like