Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive mode not working in 1.4 #3505

Closed
Nodd opened this issue Sep 12, 2014 · 53 comments
Closed

Interactive mode not working in 1.4 #3505

Nodd opened this issue Sep 12, 2014 · 53 comments

Comments

@Nodd
Copy link
Contributor

Nodd commented Sep 12, 2014

I have an application with a GUI using Pyside or PyQt (the compatibility layer is https://github.com/ros-visualization/python_qt_binding). This application displays matplotlib plots in interactive mode to avoid problems with the event loop.
It works well with matplotlib 1.3.1, but when I update to 1.4.0 the plots are not shown anymore. I tried upgrading and downgrading matplotlib only, and it confirms that the problem is linked to the update.

If I try to add show() after the plot, the window is shown with the warning QCoreApplication::exec: The event loop is already running, as if it was in non-interactive mode.

The return value of isinteractive() is 0 if I call plt.ion() and False if I cann plt.ioff().

I tried to write a minimal example of the problem but it works fine in the console. I don't recall anything special in my application that would change the behavior.

I use anaconda under Linux (Manjaro).

@tacaswell
Copy link
Member

Are you importing pyplot anywhere?

@tacaswell tacaswell added this to the v1.4.x milestone Sep 12, 2014
@Nodd
Copy link
Contributor Author

Nodd commented Sep 12, 2014

Yes, I'm using almost only pyplot.

@mdboom
Copy link
Member

mdboom commented Sep 12, 2014

Are you running your application at the Python console, or just starting is standalone? If the latter, I think this is a case where the feature to automatically turn off interactive for scripts is falling on its face (and I say that as the author of that change). As a workaround, you can do:

import sys
sys.ps1 = 'SOMETHING'

before importing matplotlib.

See the bottom of this thread for more info: #2286

I'll try to come up with a better fix that probably will make it into the next bugfix release.

@WeatherGod
Copy link
Member

Probably related to changes to only have interactive mode work in the REPL,
since that was the only mode that interactive mode was really all that
reliable in, I think.

On Fri, Sep 12, 2014 at 10:21 AM, Joseph Martinot-Lagarde <
notifications@github.com> wrote:

Yes, I'm using almost only pyplot.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@tacaswell
Copy link
Member

Making this easier by providing access to a de-pyplotified figure_manager was one of the goals of #2624 (but that has fallen over and died due to lack of time).

My advice for embedding has always been to not use pyplot.

Also be aware mpl has it's own pyside/qyqt compatibility layer, I am not sure how it will interact with python_qt_bindings. One of the other changes in 1.4.0 was to extend our wrapper to also handle qt5.

#3360 might also be related.

@Nodd
Copy link
Contributor Author

Nodd commented Sep 15, 2014

@mdboom I'm starting the app standalone and your workaround works, thanks.

@tacaswell pyplot is an easy way to have nice plots in my application, from a user point of view I don't see a reason to not use it. Having a different behavior in the interpreter and in a program is really surprising.
I tried to use the so called obect oriented api; but I found it more complicated and was always lost in the doc. It was 1 ou 2 years ago, It may have gotten better since.
Simple example: coming from pyplot, is is not natural to have so many methods starting with add_ or set_ while the equivalent function in pyplot is more straightforward.

@kogelnik
Copy link

I just upgraded to 1.4 from 1.3.1 and encountered this bug as well. Yes the 'sys.ps1' fix works.

I happen to use interactive mode from an application and not the REPL. I guess the original intent of MPL was for really for static plots, or for console exploration but there are enough hooks and performance improvements through the releases that make interactive application use possible. I use it for an interactive display of live data acquisition as well as archived data mostly by using the keypress event handler to map to many different commands.

I'm not sure from reading some of the other posts if this is a bug or if the intent was to deprecate the interactive feature from non-REPL. If the latter, it's an API change and should be posted to the release notes (it's no fun when working code breaks due to the unexpected).

If it is an API change, then there still needs to be a way for a non-console app to be interactive. I turn interactivity on and then off (for performance) in order to be able to render with the non-blocking draw() and never call show(). Currently that is broken. If there is a better way please let me know and I'd gladly put up some demo code.

Maybe the following helps debugging:
On OS X with TkAgg:

matplotlib.interactive(True)
matplotlib.is_interactive()

1.4 returns 0 rather than True
1.3.1 returns True
is_interactive() used to always return a boolean True/False not 0/False.

Thanks, and appreciate all the work!

P.S. I don't understand the comment not to use pyplot embedded. Why would that be? It's worked fine and simplifies code.

@tacaswell
Copy link
Member

Well, for one thing not using pyplot here avoids this problem.

The short answer is that pyplot has global state which if you have more than one axes and call-backs which rely on plt.gca() doing the the right thing you will get into trouble.

I strenuously disagree that using pyplot simplifies code (other than setting up figures). Almost all of the function calls in pyplot boil down to plt.gca().foo(...) which if you have a ref to your axes is just ax.foo(...). Slightly more verbose (as you are carrying around a few more references) code is simpler than code that relies on hidden global state to work properly.

I am also going to retreat to the zen of python 'explicit is better than implicit'.

Also see http://matplotlib.org/faq/usage_faq.html#coding-styles .

@WeatherGod
Copy link
Member

@kolgelnik, actually, as I continue my research for my upcoming book on writing interactive matplotlib applications (hint, hint...), I found that the original intent by John Hunter was for matplotlib to be completely interactive. Static plots was an afterthought (indeed, the ability to save to PNG files wasn't in the original codebase).

I think what happened here was a disconnect between the developers and users. For the developers, I think, interactivity comes after the call to show(). The "interactive mode" is actually something slightly different than the after-show interactivity. Comments in that PR were trying to figure out if there were any use-cases for non-REPL "interactive mode." I could have sworn that I used to be able to do such things, but every attempt I made at doing so failed to work. So I just simply assumed that it was a fluke of how the backends behaved prior to the backend-normalization work done for version 1.0.

Seeing now that there are non-REPL applications using interactive mode in the wild, I would definitely consider this change as a regression and have it fixed for 1.4.1. We, as core developers, should also make sure we better understand this use case so that we don't accidentally break this in the future.

@Nodd
Copy link
Contributor Author

Nodd commented Sep 17, 2014

To be able to better follow this thread, I finally managed to have a working example for displaying matplotlib figures in my application without using ion and using the object oriented API. Most of the work is just replacing calls like plt.plot() with ax.plot() so this part is not very complicated.

Now I have to create the figure first, and display it at the end without blocking (this is the reason why I opened this issue). For creating the figure, I have to use pyplot. In every documentation, example or tutoriel, people use pyplot to create a figure. Even in the link @tacaswell gave about coding style, the OO API uses plt.figure()`` andplt.show()```. There is no clear distinction between what relies on the global state and what is considered the OO API.

Now I have to display the figure. plt.show() is out, plt.draw() doesn't show anything, fig.canvas.draw() raises an error, fig.show() raises the same error because I used fig, ax = plt.subplots() to create the figure at this time (I was just trying to write less line). The correct way to do it is fig = plt.figure(); fig.show(). Well, this was never mentionned in any example or tutoriel I found.

If I used pyplot and ion() for my application is because that was the only way I found that worked.

Sorry if this message is a bit of a rant, matplotlib is a great tool and I'm very happy to use it. My use case (non blocking plots in an application) is not be very common (proof: no documentation nor tutorial on the subject) so it's harder to find accessible documentation.

This is the code I used, does it looks like a good use of OO API for non-REPL use ? Is there a simple way to create the figure without using pyplot ?

fig, ax = plt.subplots(1, 1)
fig.canvas.set_window_title(title)
ax.set_title(title)
ax.grid(True)
ax.plot(indices, data)
ax.set_xlim(indices[0], indices[-1])
ax.set_xlabel("Pixels")
ax.set_ylabel("Puissance (dB)")
fig.show()

@tacaswell
Copy link
Member

http://matplotlib.org/1.3.1/examples/user_interfaces/embedding_in_qt4.html is the example you want. I actually do this a fair amount so it is not as uncommon as you think.

I agree that this is a pain point (see #2624 as my first attempt to address it).

I am surprised the object that the object returned by plt.figure() has a show method. Another way to make the figure show is:

fig, ax = plt.subplots()
fig.canvas.manager.show()

@Nodd
Copy link
Contributor Author

Nodd commented Sep 17, 2014

I don't want to embed the plots, I want to show them as separate windows. This was there is more room for the main window, and the users are already familiar with the figure layout. Last point, I don't want to replace less than ten lines of simple code with a new subclass.

fig.show() is documented here: http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.show

Thanks for the alternative, the second line seems not very discoverable ! ;)

@WeatherGod
Copy link
Member

The suggestion to not use pyplot at all is a bit overkill. We are working
towards completely isolating pyplot, but we haven't achieved that yet (the
PR that thomas mentioned).The issue with pyplot is primarally the question
of "is this particular statement completely unambiguous"? The line
"plt.xlim()", for example, can only be unambiguous if preceded by a
"plt.sca()" or if one can guarantee that there will only be one axes in
play at the time of statement execution.

So, the good news is that plt.subplots(), plt.figure(), and plt.show() are
all completely unambiguous. Feel free to use them. Unfortunately,
plt.subplot() is not unambiguous (but fig.add_subplot() is).

On Wed, Sep 17, 2014 at 11:07 AM, Joseph Martinot-Lagarde <
notifications@github.com> wrote:

I don't want to embed the plots, I want to show them as separate windows.
This was there is more room for the main window, and the users are already
familiar with the figure layout. Last point, I don't want to replace less
than ten lines of simple code with a new subclass.

fig.show() is documented here:
http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.show

Thanks for the alternative, the second line seems not very discoverable !
;)


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@kogelnik
Copy link

My perception (and struggle) from having used mpl from pre-1.0 is that interactivity was something done from the console. When I was first evaluating it, it wasn't even clear from the docs and examples that the event loop could be done outside mpl. I guess it still appears that way. The current examples for animation all use show() and an update timer. But there are use cases for asynchronous external events (not mouse/keyboard) driving rendering, like live data display. For example the docs don't even mention how to do double buffering, and in a way that's fantastic as it makes mpl immediately accessible, albeit at the expense of not being able to understand the abilities of the framework.

In regards to pyplot, I use it in two ways. Code in OO style to maintain manageability, and from the console in matlab style, which allows for quick exploration without mpl getting in the way. If I had to translate from pyplot to some other function in the vastness of mpl, I'd be a complete noob. In your API cleanup I hope that the get results quickly spirit will be maintained.

@WeatherGod
Copy link
Member

"I guess it still appears that way"

You are presuming too much. In fact, as far as I know, this has never been
the case. The event loop is always owned by the GUI. We do not implement
our own event loop. Now, we will initiate it for you if it hasn't started
by the time plt.show() is called, but it still belongs to the GUI, not
matplotlib.

As for animations, you can supply your own event source object if you don't
want the default Timer object.

You are hitting on all sorts of issues and questions that I will be
addressing in my book. I think you will find it very useful when it comes
out (I don't have an official target date yet, but I presume around
December, maybe November).

On Wed, Sep 17, 2014 at 3:42 PM, kogelnik notifications@github.com wrote:

My perception (and struggle) from having used mpl from pre-1.0 is that
interactivity was something done from the console. When I was first
evaluating it, it wasn't even clear from the docs and examples that the
event loop could be done outside mpl. I guess it still appears that way.
The current examples for animation all use show() and an update timer. But
there are use cases for asynchronous external events (not mouse/keyboard)
driving rendering, like live data display. For example the docs don't even
mention how to do double buffering, and in a way that's fantastic as it
makes mpl immediately accessible, albeit at the expense of not being able
to understand the abilities of the framework.

In regards to pyplot, I use it in two ways. Code in OO style to maintain
manageability, and from the console in matlab style, which allows for quick
exploration without mpl getting in the way. If I had to translate from
pyplot to some other function in the vastness of mpl, I'd be a complete
noob. In your API cleanup I hope that the get results quickly spirit will
be maintained.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@Nodd
Copy link
Contributor Author

Nodd commented Sep 17, 2014

Coming back to the original issue, the problem isn't linked to pyplot itself but to the interactive mode. If i understand correctly I would have the same problem with ion() because it changes how the plot shows, not how it is constructed.
The OO style provide a workaround (I will try to use it because it seems cleaner but it requires some changes) but the regression is still there.

What I don't understand is why there should be a different behaviour between a script and an interactive session. This will surprise users who test something in a console then build a standalone script from their interactive experiments.

@mdboom
Copy link
Member

mdboom commented Sep 17, 2014

The reason for the change (and there are a lot of good counter reasons outlined above), is that if interactive mode is turned on, show does not block, so a script runs through and finishes with the window appearing and disappearing in the blink of an eye. Interactive mode only works if there is something else, such as a REPL, waiting on input. This is a frequently encountered problem such that this seemed like a good solution, but there are counter arguments to this. However, I would wager to guess that the use case of developing applications out of interactive mode is much smaller than users that work at the command line and then turn those commands into a script only to discover that the window doesn't appear. So I think we can provide an alternative API to force interactive mode for that smaller use case, but I'm not sure we necessarily want to backtrack on this change.

@Nodd
Copy link
Contributor Author

Nodd commented Sep 18, 2014

If this change is not reverted, there should be an error or at least a warning when calling plt.ion() in the cases where it does nothing. Currently it fails silently, that's really bad.

@BrenBarn
Copy link

I'd like to note that this change also can break interpreter-wrapping programs that run Python in a subprocess and pass commands to it. Specifically, I use DreamPie, and matplotlib in interactive mode stopped working when I installed 1.4. I was able to figure out the ps1 fix by looking in the source, but the underlying issue is still there. We should keep in mind that matplotlib's use cases are not limited to just "Do everything in IPython" and "Totally standalone script"; we should try not to needlessly close off any way of using matplotlib in combination with other tools.

The simplest approach would be to just have an explicit flag called something like force_interactive which allows the user to tell matplotlib to use interactive mode, not ask it. Piggybacking on ps1 seems like a fragile solution.

@tacaswell tacaswell modified the milestones: v1.4.1, v1.4.x Oct 2, 2014
@tacaswell
Copy link
Member

ping @mdboom On consideration, this really should be a 1.4.1 blocker.

@CnlPepper
Copy link

I'd like to add my 2p as I've just upgraded to 1.4 and have found all my interactive mode scripts have broken. My colleagues and I (www.ccfe.ac.uk) regularly use the interactive mode to display calculation progress while a long script is processing. Many of these scripts are a quick job to solve a specific problem and almost all use pyplot.

I was going to start a migration to 1.4 (I'm the python user group admin for our organisation), but I will have to put that on hold as this is a showstopper change for us. I am relatively suprised a decision was made to provide different behaviour at the command line and via script (!), it is extremely unfriendly to the users who would expect the same behaviour no matter how their code is run (where else does python code work differently interactively/scripted?). A common development process for many of our scientists (who are not great programmers and that will never change, sadly) is to test code at the command line and then copy it into a script once they see it works.

@efiring
Copy link
Member

efiring commented Oct 5, 2014

@mdboom, we've gotten enough push-back, involving real user pain, that I think we should simply revert the change entirely for 1.4.1, and then figure out what to do for 1.5. All of the interactivity functionality has always been confusing, both for users and for developers--at least for those of us, like myself, who can't keep track of all the backend, version, and environment wrinkles that can occur and interact. Maybe by taking a fresh look at the situation we can clarify and simplify it.

@mdboom
Copy link
Member

mdboom commented Oct 5, 2014

@efiring: I tend to agree at this point, but I would like confirmation from at least some of the above users that reverting the change in fact fixes their issue. I think there is confusion about what the change actually does, and we may in fact be seeing the manifestation of some other change. Particularly that this changes behavior between running interactively and scripting, when in fact the change is designed to make it more consistent.

Running a simple plt.plot([1,2,3]), with interactive mode turned on:

1.3:
   console: works
   script: window appears briefly and disappears
1.4:
   console: works
   script: works

So, I'm still not understanding the use case in which @Nodd is seeing a regression. Can you provide a standalone script that used to work that no longer does? The code sample above doesn't block for the GUI in either version.

This is the very simple diff to revert to the old behavior:

diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py
index 8a20272..2d1271c 100644
--- a/lib/matplotlib/__init__.py
+++ b/lib/matplotlib/__init__.py
@@ -1291,8 +1291,7 @@ def is_interactive():
     # ps1 exists if the python interpreter is running in an
     # interactive console; sys.flags.interactive is true if a script
     # is being run via "python -i".
-    b = rcParams['interactive'] and (
-        hasattr(sys, 'ps1') or sys.flags.interactive)
+    b = rcParams['interactive']
     return b

 def tk_window_focus():

@efiring
Copy link
Member

efiring commented Oct 5, 2014

@CnlPepper Thanks for the feedback. I like the basic idea of your suggestion. Show() needs more functionality. It already has a "block" kwarg, but it can't do exactly what you suggest yet. Some combination of the present functionality in show(), draw(), draw_if_interactive(), and pause() could be consolidated in a new version of show(). I think the real purpose of the interactive flag was supposed to be to determine whether to draw after each pyplot command, or to wait until the end of a script. We don't want a situation where, within a script, each pyplot command triggers a draw.
What you can do now in a script without interactive mode, though, is put plt.show(block=False) after a string of plotting commands. Then the plot will be displayed without blocking, as your script continues. For subsequent plotting, plt.pause(0.01) after a sequence of plotting commands will trigger display. I'm thinking that maybe pause is actually closer to what show should be than show itself is.

@CnlPepper
Copy link

Appologies to people reading the github thread, I edited out the text efiring was replying to as I wanted to think about it a bit more. I forgot about the email notifications.

@mdboom the use case you are using as an example is very simple and not representative of my scripts. I considered it correct behaviour for the graph to pop up and vanish if I run a script with ion(), the process is terminating without me configuring the script to block it. A typical analysis script I commonly see/have bashed together myself follows the following pattern:

ion()
loop of work:
plot progess (say every 10s)
ioff()
plot final result

Such a script now fails with the 1.4 change. I've had to add:

import sys
sys.ps1 = "kludge"

to all my existing scripts to get them to work.

@efiring perhaps the following would be a better approach to interactive scripting. Starting from a blank slate:

Controlling drawing/updates:
draw_on() [default] - plotting commands instantly update
draw_off() - plotting commands are stored in a draw buffer and drawing is deferred
draw_now() - forces buffer to empty, rendering changes

Both draw_on and draw_off could also implement context managers e.g.

with draw_off:
plotting commands

which will plot once the with block has ended if draw_on() was previously called.

Blocking:
If users need blocking they can just use pause in their script.

@CnlPepper
Copy link

Hmm the last bit might not be that friendly actually.... closing the figure to unblock is friendlier. Maybe a command:

block_on(figure)

would be a better approach?

Edit: draw_now(block=True)?

@efiring
Copy link
Member

efiring commented Oct 5, 2014

@CnlPepper, here is how I would do what I think you are illustrating in your "typical pattern". Save the following as a script file. It will run efficiently in 1.4.0 with interactive mode off.

import time
import numpy as np
import matplotlib
matplotlib.use('qt4agg')
import matplotlib.pyplot as plt

x = np.random.randn(10)
print('ready to plot')
plt.plot(x)
plt.pause(0.01)
print('starting to sleep (or working hard)')
time.sleep(2)
plt.plot(x + 2)
plt.pause(0.01)
print('sleeping again (or more work)')
time.sleep(2)
print('now blocking until the figure is closed')
plt.show(block=True)

@CnlPepper
Copy link

@efiring thanks for the script. I've been meaning to ask why we have to include the pauses for the qtagg backend. Why does the figure not redraw automatically following the plot command (like I assume it should)? It does for tkagg (which I always switch to due to this problem, I get fed up of adding hundreds of pauses everywhere!).

@efiring
Copy link
Member

efiring commented Oct 6, 2014

@CnlPepper, in the script above, the pauses are needed for tkagg as well--with interactive mode off. With either backend, though, the pause() is needed only when it is time to display the plot. With interactive mode, plt.draw() is being called automatically with each pyplot call, whether you want to draw then or not; but whether anything actually appears depends on the particular gui toolkit, and the way it has been configured (or hacked) for interactivity. Because of this complexity, mpl has left responsibility for interactive behavior largely to IPython, which handles setting and removing a custom gui-specific PyOS_InputHook for terminal-based sessions, or running a gui event loop for two-process sessions, along with a bit more magic to make mpl work well in IPython. It's complicated and fiddly. This division of labor generally works well--provided mpl users wanting interactive behavior either use ipython, or explicitly handle the event loop for the gui of their choice.
What about Tk? It's different, because it is already using its own PyOS_InputHook, so it doesn't require one to be supplied by IPython. (The macosx backend is also an oddball.)
Now, I thought that other backends, including qt4agg, were in fact working interactively in recent years without ipython, because their gui toolkits had adopted the practice of using their own PyOS_InputHook. I think we have had some problems with the qt4agg backend related to when to force a redraw, so I am wondering whether what you are seeing is actually that; if so, I think it is fixed in 1.4.0. If you would like to check this in your 1.4.0 installation, you can use @mdboom's trick of setting

import sys
sys.ps1 = 'SOMETHING'

at the top of your script, so that your ion() will actually set the interactive flag.

@efiring
Copy link
Member

efiring commented Oct 6, 2014

@CnlPepper, I did a little testing, and found no difference between tkagg and qt4agg backends in my test script above. Same with interactive mode on. The testing reminded me of something else: until the blocking show at the end, the plot is not truly interactive. It is displayed, but the gui event loop is not running, so the cursor position display and the buttons are non-functional.

@tacaswell
Copy link
Member

I recall there being an issue either here or on so about tk refreshing with out a pause breaking. I think that behavior is version dependent and the fact that it works is a coincident.

I would also stress that if you are showing a gui window you are embedding mpl, the library is just hiding a bunch of the details from you.

@kogelnik
Copy link

kogelnik commented Oct 6, 2014

@mdboom Here's a condensed version of a script that fails in 1.4 and works in earlier versions:

import matplotlib.pyplot as plt

plt.ion()
ax1 = plt.subplot(111)
plt.ioff()

ax1.plot([1,2,3,4])
plt.draw()

raw_input('stop:')

Consider the last line to be my event loop. The added bonus is that is works identically under REPL, script or IPython, which is why I avoided show (and since the help definition for show(block=False) is listed as 'experimental').

I'm not advocating this pattern. I just happened to stumble onto it a while back and stuck with it.

@Nodd
Copy link
Contributor Author

Nodd commented Oct 6, 2014

@mdboom : My use case it when I show matplotlib figures from a gui. If I run in non-interactive mode, plt.show() will block my whole UI. The behavior is equivalent to what @kogelnik just posted. Defining sys.ps1 is a (ugly) workaround. It looks like you can't divide the world between consoles and scripts ! ;)

This is blocking me from updating Anaconda because the last version ships with matplotlib 1.4 and it would break my program.

@WeatherGod
Copy link
Member

@efiring, to be pedantic, the GUI event loop is always started when a gui
window appears, but it is non-blocking. It is the matplotlib's event loop
that is blocking. You can start the GUI event loop without starting
matplotlib's blocking event loop.

On Sun, Oct 5, 2014 at 9:22 PM, Eric Firing notifications@github.com
wrote:

@CnlPepper https://github.com/CnlPepper, I did a little testing, and
found no difference between tkagg and qt4agg backends in my test script
above. Same with interactive mode on. The testing reminded me of something
else: until the blocking show at the end, the plot is not truly
interactive. It is displayed, but the gui event loop is not running, so the
cursor position display and the buttons are non-functional.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@tacaswell
Copy link
Member

@Nodd pyplot tries to run it's own event loop. If you are using mpl as part of a larger gui you need to do the (currently a bit cumbersome) embedding. See http://matplotlib.org/examples/user_interfaces/index.html

@smithsp
Copy link
Contributor

smithsp commented Oct 6, 2014

I just came across this problem due to calling matplotlib from a Tk GUI, where before, a figure would pop up as soon as it was created, but now a show is necessary.

@smithsp
Copy link
Contributor

smithsp commented Oct 6, 2014

I should note that the sys.ps1='Necessary for matplotlib 1.4.0 to work the way it used to' workaround works.

@mdboom
Copy link
Member

mdboom commented Oct 7, 2014

Ok -- I'm convinced enough that we should revert. That raw_input() trick really shouldn't be necessary, but I think we change it back so as to not break something that isn't broken.

At some point, we should step back and make all of this clearer or more consistent.

@WeatherGod
Copy link
Member

That stepping back and making everything clearer would be very useful for
my book. Hate to publish something that is outdated by the time it is
released.

On Tue, Oct 7, 2014 at 10:53 AM, Michael Droettboom <
notifications@github.com> wrote:

Ok -- I'm convinced enough that we should revert. That raw_input() trick
really shouldn't be necessary, but I think we change it back so as to not
break something that isn't broken.

At some point, we should step back and make all of this clearer or more
consistent.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@tacaswell
Copy link
Member

Closing this as #3620 is merged.

@Nodd @kogelnik @CnlPepper @smithsp @BrenBarn Can you all confirm that this actually reverts the behavior to what you expect?

I think one of the things to come out of this (at least in my head) is that we either need to push all of the interactive gui code off to ipython or we should pull the system specific event-loop hooks back from them (or move them a third project both project depend on).

@efiring
Copy link
Member

efiring commented Oct 7, 2014

On 2014/10/06, 3:29 AM, Benjamin Root wrote:

@efiring, to be pedantic, the GUI event loop is always started when a gui
window appears, but it is non-blocking. It is the matplotlib's event loop
that is blocking. You can start the GUI event loop without starting
matplotlib's blocking event loop.

@WeatherGod, For completeness: no, this statement is at best misleading.
When a gui window appears, it does not mean any event loop is running.

There are at least three sorts of event loop potentially in play:

One is the PyOS_InputHook hack that is in effect when at the REPL--when
python is waiting for input, it calls the hooked function, which can
process events. Tk has always set a function for that hook; other
toolkits do now, but that was not always the case. (Macosx is a
different beast; I haven't looked into it.) Ipython sets customized
functions. In any case, this event processing mechanism is
non-blocking, but the critical point relevant to this thread is that it
is effective only when python is waiting for input.

The second sort is the genuine internal gui event loop, probably
implemented with select or poll. This loop is always blocking. In
matplotlib, it gets called by show(block=True). In a proper embedding
context, it is the only event loop in effect. The gui is in full
control, and everything that happens goes through the gui via events.

The third is a short-term mpl loop implemented using sleep() via
backend_bases.start_event_loop_default(). It looks like the intention
was for this to be overridded by more efficient gui-specific methods,
but this has not been done.

@efiring
Copy link
Member

efiring commented Oct 7, 2014

On 2014/10/07, 5:48 AM, Thomas A Caswell wrote:

I think one of the things to come out of this (at least in my head) is
that we either need to push /all/ of the interactive gui code off to
ipython or we should pull the system specific event-loop hooks back from
them (or move them a third project both project depend on).

It's not that simple; but we can clarify and simplify it. Part of the
problem here is that the term "interactive" is used to mean different
things in different places.

@Nodd
Copy link
Contributor Author

Nodd commented Oct 7, 2014

@tacaswell About embedding, I don't need to do it since interactive mode works...

@BrenBarn
Copy link

BrenBarn commented Oct 7, 2014

On 2014-10-07 08:48, Thomas A Caswell wrote:

Closing this as #3620 is merged.

@Nodd @kogelnik @CnlPepper @smithsp @BrenBarn Can you all confirm
that this actually reverts the behavior to what you expect?

I think one of the things to come out of this (at least in my head)
is that we either need to push all of the interactive gui code off
to ipython or we should pull the system specific event-loop hooks
back from them (or move them a third project both project depend
on).

I've been thinking about this too as I've watched this thread develop. 

There is something fundamentally confusing about having a library like
matplotlib that purports to provide both an interactive workflow and a
GUI mechanism for multiple backends, but actually does not provide them
in combination. And, notably, this is not straightforwardly stated. It
is possible to infer it from some of the docs, but it seems the state of
affairs is really "You cannot rely on using GUI backends interactively
without IPython", and if that is the case I think it should be stated
outright at the top of the documentation, because it is very different
from "matplotlib provides an interactive mode".

But I agree that it would be better not to have to do this.  I don't 

know anything about how IPython works its magic with the GUI backends,
but is it possible to extract this code and make it a separate library
(or possibly a set of libraries for different GUI toolkits) that could
then be an optional dependency for matplotlib? Although this would help
with our current issue, what would be even better is if it could be done
in a way that allowed drop-in interactive GUI support for any task, not
just matplotlib. It would be cool if you could do from interactiveGUI import PyQt and then interactively create and manipulate a Qt GUI via a
shell, doing more or less whatever you like with it. (And by "a shell"
I mean any shell you like, not just IPython.) Is such a thing feasible?
Are these PyOS_InputHook modifications for each GUI backend modular
enough that they could be pulled out to provide generic GUI
interactivity via a module?

Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."
--author unknown

@egiovan
Copy link

egiovan commented Apr 24, 2015

I may be little bit late, but I have a similar problem.

I have written a script that first creates a figure with some axes, and then is waiting for some experimental data to be ready, it is calling a soap function connected to some webservices that returned when the experimental data were available.

When they are ready it updates the figure with the new data (well this what it was supposed to do).
Actually I couldn't make it works using the show command. The script is supposed to be running forever (it could be stopped with a ^C if needed).

I added the pause(..) and it worked but of course the figure was not anymore interactive. The sys.ps1 trick actually didn't work.

What is really the meaning of show(block=False) if the figure is not showing itself?

Would it be possible to add to the show command an option to start an event loop just for the figure itself?

I had also written some scripts that were doing some calculation, prepared some plots, and then just before the blocking show command they forked a subprocess, the main process stopped, while the child process issued a blocking show command. The idea was to return the terminal to the user while having the event loop and the figure still active. But that stopped working. Well I removed the forking part, so now the user has to close the figure to have the terminal back (not a big problem actually, but I liked how it was before). Suggestions?

Cheers

@tacaswell
Copy link
Member

@egiovan Is this still the case in 1.4.3? We backed out the change that broke this in 1.4.1 so the old behaviour should be restored.

If that is not the case, can you open a new issue with a minimal example of what you are doing?

@kogelnik
Copy link

I don't see the original problem with 1.4.3.

@egiovan
Copy link

egiovan commented Apr 24, 2015

I haven't tried the script that I'm preparing yet.
I just tried this simple script, and it is not working.
I should say that I'm using anaconda, and I have just updated to the latest version.

import sys
sys.ps1 = 'Ciao'
import time
import numpy as np
import matplotlib
matplotlib.use('qt4agg')
import matplotlib.pyplot as plt

x = np.random.randn(10)
print('ready to plot')
plt.plot(x)
plt.draw()
plt.show(block=False)

print('starting to sleep (or working hard)')
time.sleep(10)
plt.plot(x + 2)
plt.draw()
plt.show(block=False)

print('sleeping again (or more work)')
time.sleep(10)
print('now blocking until the figure is closed')
plt.show(block=True)

The plot is shown only at the end.
The version of matplot lib is 1.4.3
With numpy version 1.6

If there are other test that I could do, tell me.

I may do some other test the next week, but if you have any suggestion they are welcome.
I'll tell you that I'm using SOAPpy to connecting to a blocking webservice. If the pause works it could be ok as the plot should be shown on a screen.

@WeatherGod
Copy link
Member

If you are using anaconda and have the latest updates, then I doubt you are
using numpy version 1.6, which is rather ancient. Is that a typo and you
meant 1.9?

On Fri, Apr 24, 2015 at 10:51 AM, egiovan notifications@github.com wrote:

I haven't tried the script that I'm preparing yet.
I just tried this simple script, and it is not working.
I should say that I'm using anaconda, and I have just updated to the
latest version.

import sys
sys.ps1 = 'Ciao'
import time
import numpy as np
import matplotlib
matplotlib.use('qt4agg')
import matplotlib.pyplot as plt

x = np.random.randn(10)
print('ready to plot')
plt.plot(x)
plt.draw()
plt.show(block=False)

print('starting to sleep (or working hard)')
time.sleep(10)
plt.plot(x + 2)
plt.draw()
plt.show(block=False)

print('sleeping again (or more work)')
time.sleep(10)
print('now blocking until the figure is closed')
plt.show(block=True)

The plot is shown only at the end.
The version of matplot lib is 1.4.3
With numpy version 1.6

If there are other test that I could do, tell me.

I may do some other test the next week, but if you have any suggestion
they are welcome.
I'll tell you that I'm using SOAPpy to connecting to a blocking
webservice. If the pause works it could be ok as the plot should be shown
on a screen.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@kogelnik
Copy link

I tried the script on 1.4.3 with the Qt backend statement commented out and didn't see any problems.

So possibly it has something to do with the backend.

My numpy is 1.9.2.

@tacaswell
Copy link
Member

@kogelnik What kackend are you using?

On Fri, Apr 24, 2015 at 11:17 AM kogelnik notifications@github.com wrote:

I tried the script on 1.4.3 with the Qt backend statement commented out
and didn't see any problems.

So possibly it has something to do with the backend.

My numpy is 1.9.2.


Reply to this email directly or view it on GitHub
#3505 (comment)
.

@kogelnik
Copy link

TkAgg

I don't have Qt installed.

@egiovan
Copy link

egiovan commented Apr 27, 2015

Yes, sorry, my numpy version was 1.9.2. I fond 1.6 when I was looking for the matplotlib version:
I typed help(matplotlib) and I searched for a string 'version' in the help.
Basically I found:
matplotlib.version = '1.4.3'
matplotlib.version__numpy = '1.6'

By the way I may have misunderstood the meaning of plt.show(), I tought that it could spawn a thread with an event loop to manage the events in the figure while a main thread can still be active in the current program.

As I told you my problem is to have a figure with an event loop running and a separated thread that when receives data can update some figure properties, like some data in some plot.
Which is the easiest and the best way to achieve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants