matplotlib‘s FAQ has a section dealing with the exact topic of this post: using matplotlib in a web application server. The problem is that I couldn’t find it easily from my Web searches. What I’m doing here is adding my own twist to the answer, and hopefully making it slightly more search-friendly.
While testing a Web app that I was working on, I noticed that it would often hang. At first I dismissed it as a server problem, but it kept occuring on one particular page. A few hours and many head scratches later, I narrowed the problem down to matplotlib.
# Negative example; do not use. import matplotlib.pyplot as plt def callback(): # ... (process data) fig = plt.figure() # ... (draw stuff) fig.savefile(path)
I used matplotlib to draw a plot and save it to a file. The code was quite long, but it involved steps similar to the above listing. The first time it ran, everything went OK. The second time, it always hung at the
pyplot.figure call. This smelled like a threading / deadlock problem, so I tried to put a lock on the pyplot calls (which I should have done anyway, considering pyplot operates on a single plot at a time). Still, it didn’t work.
After some Web searches and more head scratching, I accidentally arrived at the FAQ entry mentioned earlier.
Here’s the gist of the available solutions.
First option: configure matplotlib to use the Anti-Grain Geometry backend. Continue using pyplot, carefully grouping its commands together and surrounding them with a lock.
from threading import Lock lock = Lock() import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt def callback(): # ... (process data) with lock: fig = pyplot.figure() # ... (draw stuff) fig.savefile(path)
Second, better option: dump pyplot and use matplotlib’s object-oriented API instead. For this one, you don’t need to care about threads or locking or whatever.
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas from matplotlib.figure import Figure def callback(): # ... (process data) fig = Figure() canvas = FigureCanvas(fig) # ... (draw stuff) canvas.print_figure(path)