Demo of using multiprocessing for generating data in one process and plotting in another.
Written by Robert Cimrman
from __future__ import print_function
import time
import numpy as np
from multiprocessing import Process, Pipe
# This example will likely not work with the native OSX backend.
# Uncomment the following lines to use the qt5 backend instead.
#
# import matplotlib
# matplotlib.use('qt5agg')
#
# Alternatively, with Python 3.4+ you may add the line
#
# import multiprocessing as mp; mp.set_start_method("forkserver")
#
# immediately after the ``if __name__ == "__main__"`` check.
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
This class plots data it receives from a pipe.
class ProcessPlotter(object):
def __init__(self):
self.x = []
self.y = []
def terminate(self):
plt.close('all')
def call_back(self):
while self.pipe.poll():
command = self.pipe.recv()
if command is None:
self.terminate()
return False
else:
self.x.append(command[0])
self.y.append(command[1])
self.ax.plot(self.x, self.y, 'ro')
self.fig.canvas.draw()
return True
def __call__(self, pipe):
print('starting plotter...')
self.pipe = pipe
self.fig, self.ax = plt.subplots()
timer = self.fig.canvas.new_timer(interval=1000)
timer.add_callback(self.call_back)
timer.start()
print('...done')
plt.show()
This class uses multiprocessing to spawn a process to run code from the
class above. When initialized, it creates a pipe and an instance of
ProcessPlotter
which will be run in a separate process.
When run from the command line, the parent process sends data to the spawned
process which is then plotted via the callback function specified in
ProcessPlotter:__call__
.
class NBPlot(object):
def __init__(self):
self.plot_pipe, plotter_pipe = Pipe()
self.plotter = ProcessPlotter()
self.plot_process = Process(
target=self.plotter,
args=(plotter_pipe,)
)
self.plot_process.daemon = True
self.plot_process.start()
def plot(self, finished=False):
send = self.plot_pipe.send
if finished:
send(None)
else:
data = np.random.random(2)
send(data)
def main():
pl = NBPlot()
for ii in range(10):
pl.plot()
time.sleep(0.5)
pl.plot(finished=True)
if __name__ == '__main__':
main()