I wish to run a simulation while at the same time output its progress in a plot. I've been looking through a lot of examples of threading and multiprocessing, but they are all pretty complex. So I thought with Python's new asyncio
library this should be easier.
I found an example (How to use 'yield' inside async function?) and modified it for my cause:
import matplotlib.pyplot as plt
import asyncio
import numpy as npclass DataAnalysis():def __init__(self):# asyncio so we can plot data and run simulation in parallelloop = asyncio.get_event_loop()try:loop.run_until_complete(self.plot_reward())finally:loop.run_until_complete(loop.shutdown_asyncgens()) # see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.shutdown_asyncgensloop.close()async def async_generator(self):for i in range(3):await asyncio.sleep(.4)yield i * iasync def plot_reward(self):# Prepare the datax = np.linspace(0, 10, 100)# Plot the dataplt.plot(x, x, label='linear')#plt.show()# add lines to plotasync for i in self.async_generator():print(i)# Show the plotplt.show()if __name__ == '__main__':DataAnalysis()
Question
I added a simple plt.show()
and the program still freezes. I thought with asyncio
I could run it in parallel? Obviously my knowledge is still lacking.
An example that does the following would be really helpful:
- Add a line to a plot (of
matplotlib
) everytime async_generator
returns a value.
First of all, I misunderstood asyncio, it doesn't make run things in parallel (use asyncio for parallel tasks).
It seems the only thing that worked for me was plt.pause(0.001)
(Plotting in a non-blocking way with Matplotlib). plt.draw()
opened a window, but it didn't show anything and plt.show
freezes the program. It seems that plt.show(block=False)
is deprecated and using plt.ion
gives the problem that the final result closes when the program is finished. Also await asyncio.sleep(0.1)
didn't make the plot draw a line.
Working code
import matplotlib.pyplot as plt
import asyncio
import matplotlib.cbook
import warnings
warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)class DataAnalysis():def __init__(self):# asyncio so we can plot data and run simulation in parallelloop = asyncio.get_event_loop()try:loop.run_until_complete(self.plot_reward())finally:loop.run_until_complete(loop.shutdown_asyncgens()) # see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.shutdown_asyncgensloop.close()# keep plot window openplt.show()async def async_generator(self):for i in range(3):await asyncio.sleep(.4)yield i * iasync def plot_reward(self):#plt.ion() # enable interactive mode# receive dicts with training resultsasync for i in self.async_generator():print(i)# update plotif i == 0:plt.plot([2, 3, 4])elif i == 1:plt.plot([3, 4, 5])#plt.draw()plt.pause(0.1)#await asyncio.sleep(0.4)if __name__ == '__main__':da = DataAnalysis()
Notes
You get however a deprecated message: python3.6/site-packages/matplotlib/backend_bases.py:2445: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)
, which you can suppress with: warnings.filterwarnings()
.
I'm not sure if asyncio
was actually necessary for my use case...
Difference between threading
and multiprocessing
for who's interested: Multiprocessing vs Threading Python