4

Been playing with plotting libraries for Python and came across matplotlib which seems to be battle tested and proven already. However I have came across a problem while creating a simple plot in a thread.

In the example bellow, Dummy class plotme method is run in a thread twice in a row, but it gets stuck/freezes in 2nd iteration. Most likely is something obvious and related to the threading itself, but I failed to spot it so far.

import matplotlib.pyplot as plt
from numpy import arange, sin, pi
import threading

class Dummy():

    def plotme(self, iteration = 1):

        print "%ix plotting... " % iteration,
        t = arange(0.0, 2.0, 0.01)
        s = sin(2*pi*t)
        plt.plot(t, s)
        plt.xlabel('time (s)')
        plt.ylabel('voltage (mV)')
        plt.title('About as simple as it gets, folks')
        #savefig("test.png") # irrelevant here
        plt.close()

    def threadme(self, iteration = 1):

        thread_plot = threading.Thread(target=self.plotme,
                                      args=(iteration,))
        thread_plot.start()
        thread_plot.join()

dummy = Dummy()
dummy.threadme(1)
dummy.threadme(2)
1
  • 1
    Are you aware that the commands in matplotlib.pyplot are not hread-safe? Your should use an OOÜP-approach, like creating a figure, an axes-object and then calling the methods on this axes-object, e.g. ax.plot(...) Commented Oct 1, 2013 at 8:10

1 Answer 1

5

First, be aware that pyplot-interface is not thread-safe.

Then: use the "Agg"-backend for non-interactive creation of multiple images.

A working example (with possible problems due to threading) is:

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from numpy import arange, sin, pi
import threading

class Dummy():

    def plotme(self, iteration = 1):

        print "%ix plotting... " % iteration,
        t = arange(0.0, 2.0, 0.01)
        s = sin(2*pi*t)
        plt.plot(t, s)
        plt.xlabel('time (s)')
        plt.ylabel('voltage (mV)')
        plt.title('About as simple as it gets, folks')
        plt.savefig("19110942_%i_test.png" % iteration) # irrelevant here
        plt.clf()

    def threadme(self, iteration = 1):

        thread_plot = threading.Thread(target=self.plotme,
                                      args=(iteration,))
        thread_plot.start()
        thread_plot.join()

dummy = Dummy()
dummy.threadme(1)
dummy.threadme(2)

A thread-safe version would look like this:

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from numpy import arange, sin, pi
import threading

class Dummy():

    def plotme(self, iteration = 1):

        print "%ix plotting... " % iteration,
        t = arange(0.0, 2.0, 0.01)
        s = sin(2*pi*t)

        fig, ax = plt.subplots()
        ax.plot(t, s)
        ax.set_xlabel('time (s)')
        ax.set_ylabel('voltage (mV)')
        ax.set_title('About as simple as it gets, folks (%i)' % iteration)
        fig.savefig("19110942_%i_test.png" % iteration)

    def threadme(self, iteration = 1):

        thread_plot = threading.Thread(target=self.plotme,
                                      args=(iteration,))
        thread_plot.start()
        thread_plot.join()

dummy = Dummy()
dummy.threadme(1)
dummy.threadme(2)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @Thorsten Kranz that's it. I should have investigated properly about pyplot "thread-safeness" :)
Note: I have been playing with this over the last couple of days, and can say with some confidence that the second version above is no more 'thread-safe' than the first, both will happily hang on subsequent threaded runs, if matplotlib.use('Agg') is not called. The key is using non-interactive mode, and then both will happily run many, many times in a thread without error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.