Skip to content

Instantly share code, notes, and snippets.

@astrofrog
Created December 10, 2011 00:11
Show Gist options
  • Save astrofrog/1453933 to your computer and use it in GitHub Desktop.
Save astrofrog/1453933 to your computer and use it in GitHub Desktop.
Asynchronous Plotting in Matplotlib: rather than call savefig directly, add plots to an asynchronous queue to avoid holding up the main program. Makes use of multiple processes to speed up the writing out. Suggestions welcome!
import time
import multiprocessing as mp
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
class AsyncPlotter():
def __init__(self, processes=mp.cpu_count()):
self.manager = mp.Manager()
self.nc = self.manager.Value('i', 0)
self.pids = []
self.processes = processes
def async_plotter(self, nc, fig, filename, processes):
while nc.value >= processes:
time.sleep(0.1)
nc.value += 1
print "Plotting " + filename
fig.savefig(filename)
plt.close(fig)
nc.value -= 1
def save(self, fig, filename):
p = mp.Process(target=self.async_plotter,
args=(self.nc, fig, filename, self.processes))
p.start()
self.pids.append(p)
def join(self):
for p in self.pids:
p.join()
# Create instance of Asynchronous plotter
a = AsyncPlotter()
for i in range(10):
print 'Preparing %04i.png' % i
# Generate random points
x = np.random.random(10000)
y = np.random.random(10000)
# Generate figure
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_xscale('log')
ax.set_yscale('log')
ax.scatter(x, y)
# Add figure to queue
a.save(fig, '%04i.png' % i)
# Wait for all plots to finish
a.join()
@theRealSuperMario
Copy link

theRealSuperMario commented Jan 31, 2021

when I run this, I get the following

RuntimeError: 
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

I was able to resolve this by changing the default start method to fork
mp.set_start_method("fork")

Note that this might be due to my python version: Running 3.7

import time
import multiprocessing as mp

mp.set_start_method("fork")

import numpy as np

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt


class AsyncPlotter:
    def __init__(self, processes=mp.cpu_count()):

        self.manager = mp.Manager()
        self.nc = self.manager.Value("i", 0)
        self.pids = []
        self.processes = processes

    def async_plotter(self, nc, fig, filename, processes):

        while nc.value >= processes:
            time.sleep(0.1)
        nc.value += 1
        print("Plotting " + filename)
        fig.savefig(filename)
        plt.close(fig)
        nc.value -= 1

    def save(self, fig, filename):
        p = mp.Process(
            target=self.async_plotter, args=(self.nc, fig, filename, self.processes)
        )
        p.start()
        self.pids.append(p)

    def join(self):
        for p in self.pids:
            p.join()


# Create instance of Asynchronous plotter
a = AsyncPlotter()

for i in range(10):

    print("Preparing %04i.png" % i)

    # Generate random points
    x = np.random.random(10000)
    y = np.random.random(10000)

    # Generate figure
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.set_xscale("log")
    ax.set_yscale("log")
    ax.scatter(x, y)

    # Add figure to queue
    a.save(fig, "%04i.png" % i)

# Wait for all plots to finish
a.join()

@gaburipeach
Copy link

thanks guys v helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment