Non-blocking drawing and updating charts with bokeh

image



I have one Python script with calculations. There was a cycle of about 2000 iterations, each of which was considered a few minutes.



And I decided to cleverly debug that script, display a graph of some metrics from the iteration number. And as the next iteration is calculated, so this schedule and update.



The easiest way to do this is with bokeh. More precisely, using a bokeh server to draw graphs. How - now I’ll tell you.



First, start the server: the servochka comes out of the box with bokeh itself, so after pip install bokeh just type bokeh serve in the console and the server is started.



Why is it needed? And then to show the charts





This is done like this:



import time import sys from bokeh.plotting import figure from bokeh.client import pull_session from bokeh.models import ColumnDataSource #     --    -,    bokeh serve # Please run "bokeh serve" in console before start! if __name__ == "__main__": #    (  ,     ) 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) #     for i in range(10000): #          .   datasource     #       = ) datasource.stream({"x": [i], "y": [i ** 2]}) #       30-40      ,   session.force_roundtrip() #  !
      
      





Previously, I also had to do this, but previous decisions were, to put it mildly, not so good. What I have not tried in my life ...



Caution, brain ballast!
You can use matplotlib in non-blocking mode by manually pulling plt.draw () at each iteration. True, matplotlib does not have its own processing of messages from the GUI in non-blocking mode, and if the window minimizes or closes with another window, we must wait for the next iteration to redraw it. So-so crutch, but for debugging it will do.



It is possible in Negro to generate a picture with a chart of the same matplotlib and dump it to disk. Also a fierce crutch, but a ride on a lack of fish. Or on a remote machine without graphics.



You can do it in a cool way: use PyQt, wrap the calculation code in a QObject, push it into a separate thread, wrap the matplotlib graphics in a QWidget (or use the graphs from Qt Data Visualizaion, or from PyQtGraph), connect the math to the graphics through a signal with a slot , and there will be happiness. True, this is a little like a quick debugging solution, and Qt needs to be taught, but I did it a couple of times.



You can raise a small server application for drawing graphs in a separate process (for example, using aiohttp + PyQt + PyQtGraph), which can be knocked through the REST API from the main process. Once I did this, but it didn’t attract quick-fix-for-debugging either.



You can write to some kind of database (what is it in fashion right now?), And then let Grafan go into fashion. True, you need to put both the database and Grafan, configure them, and generally bother writing to the database. It’s probably also possible through a file, but for two graphs for a thousand points each is like a cannon sparrow ...



Or you can understand plotly.dash, put the math in a separate stream, wrap it in a dash application, and do a hell of a lot of garbage. This I have not mastered, although it would be necessary.



In short, successful debugging!



All Articles