You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
from __future__ import division
import threading
import time
import sys
import numpy as np
import matplotlib
matplotlib.use('MacOSX')
import matplotlib.pyplot as plt
class async_worker(threading.Thread):
def __init__(self, fig, axis):
threading.Thread.__init__(self)
self.fig = fig
self.axis = axis
def run(self):
i = 0
while True:
print "Run thread %d" % i
sys.stdout.flush()
i += 1
time.sleep(0.1)
def main():
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(np.random.rand(251, 1))
async_worker(fig, ax).start()
plt.show()
if __name__ == "__main__":
main()
I expect to see "Run thread" repeated every 0.1 seconds, no matter if I interact with the plot or not. Instead I only see it repeat when I click and drag around in the MPL figure.
When switching to matplotlib.use('TkAgg'), the second thread runs as expected.
I can confirm the bug if I have interactive : False in matplotlibrc ;
the bug does not appear if I set interactive : True. @nils-werner Can you confirm this?
@nils-werner Can you try with the latest master (or release candidate 1.5rc2)?
If I add plt.interactive(True) to the top of the script, the second thread runs and the window behaves normally.
@nils-werner We're not quite there yet; I have not yet been able to reproduce the spinning ball of death in the interactive case. Also there may be a more appropriate place to put the Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS block.
@nils-werner On second thought, since we are in the process of release candidates for the 1.5 release, perhaps it's better to wait with more extensive changes to _macosx.m. So if you could prepare a PR with the simply fix of putting Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS around [NSApp run], then I can accept it.
You are trying to draw from the secondary thread, while typically you should draw from the main thread only. If you replace self.fig.canvas.draw by self.fig.canvas.invalidate, your script should work. Then the secondary thread merely informs the main thread that it should redraw itself, while the main thread does the actual drawing. I haven't done much testing with threads, so you may still run into some bugs; please let us know if you do.
You could use self.fig.canvas.draw_idle (which calls self.fig.canvas.invalidate on MacOSX backend). The draw_idle function is defined for all backends. In practice, this seems to work for the MacOSX backend only; tkagg gives "RuntimeError: main thread is not in main loop" and gtkagg gives a segmentation fault.
@nils-werner Actually can you provide an example script that shows how you want to use threads in practice? From your current example, it's not clear to me what you are trying to achieve.
Activity
mdboom commentedon Oct 15, 2015
Cc: @mdehoon
mdehoon commentedon Oct 16, 2015
I cannot replicate this with the current matplotlib in master; I get the same behavior with the MacOSX backend and the tkagg backend.
Which version of matplotlib are you using?
Can you try with the matplotlib release candidate:
https://github.com/matplotlib/matplotlib/releases/tag/v1.5.0rc2
nils-werner commentedon Oct 16, 2015
I have the same problem with 1.4.3 and after cloning and
pip install -eing e7e8bcb: The second thread only runs when I am moving my mouse.mdehoon commentedon Oct 16, 2015
I can confirm the bug if I have interactive : False in matplotlibrc ;
the bug does not appear if I set interactive : True.
@nils-werner Can you confirm this?
nils-werner commentedon Oct 16, 2015
When I add
plt.interactive(True)to the top of the scriptmdehoon commentedon Oct 16, 2015
@nils-werner Can you try with the latest master (or release candidate 1.5rc2)?
If I add plt.interactive(True) to the top of the script, the second thread runs and the window behaves normally.
nils-werner commentedon Oct 16, 2015
I tried it with both stable and master, the behaviour is always the same: The figure window stays blank.
WeatherGod commentedon Oct 16, 2015
how was python installed/built for you? Maybe it is a subtle difference
like the whole frameworks/nonframeworks issue?
On Fri, Oct 16, 2015 at 11:29 AM, Nils Werner [email protected]
wrote:
nils-werner commentedon Oct 16, 2015
and fixed the virtualenv framework issue using https://github.com/gldnspud/virtualenv-pythonw-osx
mdehoon commentedon Oct 16, 2015
@nils-werner
Can you try the following:
In the function
static PyObject* show(PyObject* self)in src/_macosx.m, replaceby
That should get you the correct behavior in the non-interactive case.
nils-werner commentedon Oct 19, 2015
Yes, that indeed fixes the issue! Shall I prepare a PR with that fix?
mdehoon commentedon Oct 19, 2015
@nils-werner We're not quite there yet; I have not yet been able to reproduce the spinning ball of death in the interactive case. Also there may be a more appropriate place to put the Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS block.
mdehoon commentedon Oct 23, 2015
@nils-werner On second thought, since we are in the process of release candidates for the 1.5 release, perhaps it's better to wait with more extensive changes to _macosx.m. So if you could prepare a PR with the simply fix of putting Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS around [NSApp run], then I can accept it.
Fix Mac OSX backend threading issues, issue matplotlib#5251
tacaswell commentedon Oct 24, 2015
@mdehoon Should this be closed or left open for a more through fix?
mdehoon commentedon Oct 25, 2015
@tacaswell Let's leave it open. I will have another look after 1.5 final is out.
nils-werner commentedon Nov 2, 2015
I have discovered another issue while trying to
draw()from another thread:Whenever I click any of the navigation bar buttons, the entire process deadlocks. Again, when using
TkAgg, this works just fine.mdehoon commentedon Nov 7, 2015
You are trying to draw from the secondary thread, while typically you should draw from the main thread only. If you replace self.fig.canvas.draw by self.fig.canvas.invalidate, your script should work. Then the secondary thread merely informs the main thread that it should redraw itself, while the main thread does the actual drawing. I haven't done much testing with threads, so you may still run into some bugs; please let us know if you do.
nils-werner commentedon Nov 7, 2015
When I try to use
invalidateI getI tried in both mpl 1.4.3 and 1.5.0
tacaswell commentedon Nov 7, 2015
What does
matplotlib.get_backend()return?invalidateis an OSX backend specific thing, I would not expect it to work withTkAgg.mdehoon commentedon Nov 8, 2015
You could use self.fig.canvas.draw_idle (which calls self.fig.canvas.invalidate on MacOSX backend). The draw_idle function is defined for all backends. In practice, this seems to work for the MacOSX backend only; tkagg gives "RuntimeError: main thread is not in main loop" and gtkagg gives a segmentation fault.
nils-werner commentedon Nov 12, 2015
Ah ok. Well obviously I want to write platform and backend independent code.
Wasn't
draw_idlesupposed to be deprecated?mdehoon commentedon Nov 13, 2015
@nils-werner Actually can you provide an example script that shows how you want to use threads in practice? From your current example, it's not clear to me what you are trying to achieve.
mdehoon commentedon Nov 25, 2015
Pull request #5562 provides a comprehensive fix for the first issue (October 15).
For the second issue (November 2), the following script should work:
jklymak commentedon Aug 16, 2018
So far as I can tell the original issue now works in master on my mac, so I'm going to close this one.