Need to modify plots many times in the same browser window from Python process

Hi folks!

I have some time-consuming Python script that has a cycle with about 1000 iterations (each step takes about one minute). I want to plot the results of each iteration to make sure that my code works correctly.

I can use matplotlib, but in non-blocking mode it does respond to GUI events (for example, window minimize/maximize), so I need to run an extra GUI message loop, for example, Qt one. And the simplest way to do it is the following:

  1. refactor my calculations and wrap them into a QObject;
  2. move it to a separate QThread
  3. make a QApplication
  4. wrap my plots into a QWidget
  5. connect the widget with the mathematics via signals and slots
  6. finally see the desired plot updates after each step and not need to wait to next iteration if windows is minimized.

But now is not 2009 but already 2019. And, I hope, there is some simpler way to get such an effect. Can you advice me something?

There are lots of possible things that come to mind. There’s not really enough specificity in the description to make a suggestion, so I will just list them.

  • If you can run inside a Jupyter notebook, you could use push_notebook to update a bokeh plot in the notebook in between iterations

  • Similarly you could embed a Bokeh app in a notebook and do the same thing by updating the data source in between iterations.

  • If you have to run a script, you could use a ServerSentDataSource to push data updates to a single open page

  • Or, if you expose the updated state behind some REST endpoint, you could have a page pull the new data in with an AjaxDataSource

  • You could run everything in a Bokeh server app, with the expensive operations running in a separate thread, as described in the docs. (And see the spectrogram example).

  • You could embed a bokeh server as a library and add a POST endpoint to it that could receive updates, similar to the way Dask updates its realtime cluster dashboard operates.

Alas, I’ve already moved from IPython notebooks to normal scripts, but I still often need a simple tool for updatable plots that will help me to debug and monitor their execution without their deep refactoring.

I don’t want to wrap my calculations to Flask apps, so I did a much simpler thing:

import sys
from bokeh.plotting import figure
from bokeh.client import pull_session
from bokeh.models import ColumnDataSource

# Please run "bokeh serve" in console before start!


if __name__ == "__main__":

    # Preparing plotting engine...
    session = pull_session()

    fig = figure(title=("Total TBS (in bits)"), plot_height=300, plot_width=800)
    datasource = ColumnDataSource(data={"x": [], "y": []})
    line = fig.line(x="x", y="y", source=datasource, line_width=2, legend=("Super dooper line from hell"))
    session.show(fig)

    # Here should be my mathematically-loaded code with a couple of thousands iterations, but this is just a dummy example
    for i in range(10000):

        datasource.stream({"x": [i], "y": [i ** 2]})

        # Without this call the plot in browser tab will stop refreshing after about 30-40 frames, so don't forget to call it = )
        session.force_roundtrip()

No blocking show(...) calls or other similar stuff: my code just executes and sometimes sends the updates to plotting server, that’s really cool = )

P.S. Maybe this looks like a quick and dirty trick, but it’s just what I want.