I'm trying to plot live the output of a generator.
The following code works as expected (Ctrl-C terminates execution):
import numpy as np
import pylab as p
from Queue import Queue
from threading import Thread
import time
def dataGenerator():
while True:
yield np.random.random()
def populate():
f = dataGenerator()
while True:
x = f.next(); y = f.next()
q.put([x,y])
q = Queue()
p.figure(); p.hold(True); p.show(block=False)
populatorThread = Thread(target=populate)
populatorThread.daemon = True
populatorThread.start()
while True:
data = q.get()
x = data[0]
y = data[1]
p.plot(x,y,'o')
p.draw()
q.task_done()
populatorThread.join()
However, if instead I put the plotting in a thread, I get RuntimeError: main thread is not in main loop:
import numpy as np
import pylab as p
from Queue import Queue
from threading import Thread
import time
def dataGenerator():
while True:
yield np.random.random()
def plotter():
while True:
data = q.get()
x = data[0]
y = data[1]
p.plot(x,y,'o')
p.draw()
print x,y
q.task_done()
q = Queue()
p.figure(); p.hold(True); p.show(block=False)
plotThread = Thread(target=plotter)
plotThread.daemon = True
plotThread.start()
f = dataGenerator()
while True:
x = f.next()
y = f.next()
q.put([x,y])
plotThread.join()
Why does matplotlib care which thread does the plotting?
EDIT: I'm not asking how to solve this but rather why is this happening in the first place.
It's probably the GUI that you're using for backend. The GUI likely expects to find itself in the main thread, but it isn't when matplotlib calls get_current_fig_manager().canvas.draw().
For example, when I do this, I get the following traceback:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "tmp.py", line 18, in plotter
p.draw()
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 555, in draw
get_current_fig_manager().canvas.draw()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 349, in draw
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)
File "/usr/lib/pymodules/python2.7/matplotlib/backends/tkagg.py", line 13, in blit
tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array))
RuntimeError: main thread is not in main loop
Note the tk.call(...) line. The exception you get is not raised from matplotlib, it's raised from TkInter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With