(python) matplotlib pyplot show () .. blocking or not?

I ran into this problem with show() again and again, and I'm sure I'm doing something wrong, but not sure of the right way to do what I want.

And [I think] what I want is some way to lock in the main thread until some event occurs in the GUI thread, something like this works for the first time:

 from matplotlib import pyplot as p from scipy import rand im = (255*rand(480,640)).astype('uint8') fig = p.figure() ax = fig.add_subplot(111) ax.imshow(im) # just any mutable container for storing a click s = [-1, -1] def onclick(event): if event.xdata is not None and event.ydata is not None: s[0] = event.xdata s[1] = event.ydata p.close() cid = fig.canvas.mpl_connect('button_press_event', onclick) p.show() print s 

p.show() blocks p.show() is called in the event handler. But when the same code is run a second time, it passes by p.show() and prints the original s, [-1, -1] .

I read conflicting information about whether p.show() should or should not be called more than once from the same program. It seems that it was intended to be used once and only once at the end of the script. Other use cases seem to somehow break into pyplot (state machine?).

I tried to use combinations of p.draw() and p.ion() and p.ioff() , but could not get the desired behavior (either things did not block properly, or the graphs did not appear at the right time).

I am also confused about how an event handler can see s in general here, and whether this is a bad way to pass input / output information. If I do not use the mutable container as an array or list, the information I want to set with the event handler is simply lost as a local variable. Is there any other method that I skip when the GUI thread can pass signals back to the main thread? Is there a way to block in the main, without periodic polling or waiting for a wait, for a signal from the event handler before continuing?

So, I think, ultimately, my main question is:

Is there a neat replacement for p.show() that does what I want (the same behavior as p.show() ), or does this type of code require a complete rethinking / rewriting?

+6
source share
3 answers

I was able to solve the problem today. if anyone else is interested in changing the show() behavior, read on how you can do this:

I noticed this paragraph called several calls to show what new part of the matplotlib web page is supported:

A long-standing request is to support multiple show () calls. This was difficult because it was difficult to achieve consistent behavior across different operating systems, sets of user interfaces, and versions. Eric Fairering did a great job of streamlining the show through the backends, with the desired behavior, to show that all the raised figures raise and block the performance until they are closed. Repeated calls for display should pick up the newly created digits from the last call. Eric has done a lot of testing on user interface tools and versions and platforms that he has access to, but cannot be tested, so report problems to the mailing list and track errors.

It was that the β€œwhat's new” for version 1.0.1 , while writing the version in the synapt, still returned to 0.99.3 . I managed to download and build from source v1.0.1 . Additional packages that I also needed to satisfy the dependencies were libfreetype6-dev tk-dev tk8.5-dev tcl8.5-dev python-gtk2-dev .

Now with matplotlib.__version__ == 1.0.1 following code blocks as I expect:

 import matplotlib.pyplot as p from scipy import eye p.imshow(eye(3)) p.show() print 'a' p.imshow(eye(6)) p.show() print 'b' p.imshow(eye(9)) p.show() print 'c' 
+1
source

A couple of ideas of different quality:

If you don't like that s is a global variable, you can make onclick () a called object that attaches it to this.

Your callback may receive / release a lock to control the flow of the program (slightly dirty).

You can actively poll s to control the program flow (very dirty).

You can manually control the pattern of figures using fig.canvas.draw ()

+2
source

I noticed the difference between running the code

  • Directly inside the Python interpreter (command line)

  • Put it in a Python script and run it from the command line ("python script.py")

Both give lock behavior, which is normal.

Both images are displayed from the interpreter, only the first appears from the command line.

0
source

Source: https://habr.com/ru/post/889445/


All Articles