-
-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Interactive mode not working in 1.4 #3505
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
Comments
Are you importing |
Yes, I'm using almost only pyplot. |
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:
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. |
Probably related to changes to only have interactive mode work in the REPL, On Fri, Sep 12, 2014 at 10:21 AM, Joseph Martinot-Lagarde <
|
Making this easier by providing access to a de-pyplotified 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 #3360 might also be related. |
@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 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: matplotlib.interactive(True)
matplotlib.is_interactive() 1.4 returns 0 rather than True 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. |
Well, for one thing not using pyplot here avoids this problem. The short answer is that I strenuously disagree that using pyplot simplifies code (other than setting up figures). Almost all of the function calls in 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 . |
@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. |
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 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 Now I have to display the figure. 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 ?
|
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
|
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.
Thanks for the alternative, the second line seems not very discoverable ! ;) |
The suggestion to not use pyplot at all is a bit overkill. We are working So, the good news is that plt.subplots(), plt.figure(), and plt.show() are On Wed, Sep 17, 2014 at 11:07 AM, Joseph Martinot-Lagarde <
|
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. |
"I guess it still appears that way" You are presuming too much. In fact, as far as I know, this has never been As for animations, you can supply your own event source object if you don't You are hitting on all sorts of issues and questions that I will be On Wed, Sep 17, 2014 at 3:42 PM, kogelnik notifications@github.com wrote:
|
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 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. |
The reason for the change (and there are a lot of good counter reasons outlined above), is that if interactive mode is turned on, |
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. |
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 |
ping @mdboom On consideration, this really should be a 1.4.1 blocker. |
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. |
@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. |
@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
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(): |
@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. |
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() Such a script now fails with the 1.4 change. I've had to add: import sys 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: Both draw_on and draw_off could also implement context managers e.g. with draw_off: which will plot once the with block has ended if draw_on() was previously called. Blocking: |
Hmm the last bit might not be that friendly actually.... closing the figure to unblock is friendlier. Maybe a command:
would be a better approach? Edit: draw_now(block=True)? |
@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) |
@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!). |
@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. import sys
sys.ps1 = 'SOMETHING' at the top of your script, so that your ion() will actually set the interactive flag. |
@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. |
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. |
@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 I'm not advocating this pattern. I just happened to stumble onto it a while back and stuck with it. |
@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 This is blocking me from updating Anaconda because the last version ships with matplotlib 1.4 and it would break my program. |
@efiring, to be pedantic, the GUI event loop is always started when a gui On Sun, Oct 5, 2014 at 9:22 PM, Eric Firing notifications@github.com
|
@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 |
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. |
I should note that the |
Ok -- I'm convinced enough that we should revert. That At some point, we should step back and make all of this clearer or more consistent. |
That stepping back and making everything clearer would be very useful for On Tue, Oct 7, 2014 at 10:53 AM, Michael Droettboom <
|
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). |
On 2014/10/06, 3:29 AM, Benjamin Root wrote:
@WeatherGod, For completeness: no, this statement is at best misleading. 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 The second sort is the genuine internal gui event loop, probably The third is a short-term mpl loop implemented using sleep() via |
On 2014/10/07, 5:48 AM, Thomas A Caswell wrote:
It's not that simple; but we can clarify and simplify it. Part of the |
@tacaswell About embedding, I don't need to do it since interactive mode works... |
On 2014-10-07 08:48, Thomas A Caswell wrote:
There is something fundamentally confusing about having a library like
know anything about how IPython works its magic with the GUI backends, Brendan Barnwell |
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). 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 |
@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? |
I don't see the original problem with 1.4.3. |
I haven't tried the script that I'm preparing yet. 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. 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. |
If you are using anaconda and have the latest updates, then I doubt you are On Fri, Apr 24, 2015 at 10:51 AM, egiovan 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. |
@kogelnik What kackend are you using? On Fri, Apr 24, 2015 at 11:17 AM kogelnik notifications@github.com wrote:
|
TkAgg I don't have Qt installed. |
Yes, sorry, my numpy version was 1.9.2. I fond 1.6 when I was looking for the matplotlib version: 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. |
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 warningQCoreApplication::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).
The text was updated successfully, but these errors were encountered: