Skip to content

Interactive mode not working in 1.4 #3505

Closed

Description

@Nodd

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).

Activity

  1. tacaswell commented on Sep 12, 2014

    @tacaswell
    Member

    Are you importing pyplot anywhere?

  2. added this to the v1.4.x milestone on Sep 12, 2014
  3. Nodd commented on Sep 12, 2014

    @Nodd
    ContributorAuthor

    Yes, I'm using almost only pyplot.

  4. mdboom commented on Sep 12, 2014

    @mdboom
    Member

    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.

  5. WeatherGod commented on Sep 12, 2014

    @WeatherGod
    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)
    .

  6. tacaswell commented on Sep 12, 2014

    @tacaswell
    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.

  7. Nodd commented on Sep 15, 2014

    @Nodd
    ContributorAuthor

    @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.

  8. kogelnik commented on Sep 17, 2014

    @kogelnik

    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.

  9. tacaswell commented on Sep 17, 2014

    @tacaswell
    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 .

  10. WeatherGod commented on Sep 17, 2014

    @WeatherGod
    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.

  11. Nodd commented on Sep 17, 2014

    @Nodd
    ContributorAuthor

    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()
    
  12. tacaswell commented on Sep 17, 2014

    @tacaswell
    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()
    
  13. Nodd commented on Sep 17, 2014

    @Nodd
    ContributorAuthor

    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 ! ;)

  14. WeatherGod commented on Sep 17, 2014

    @WeatherGod
    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)
    .

  15. 28 remaining items

  16. tacaswell commented on Oct 7, 2014

    @tacaswell
    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).

  17. efiring commented on Oct 7, 2014

    @efiring
    Member

    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.

  18. efiring commented on Oct 7, 2014

    @efiring
    Member

    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.

  19. Nodd commented on Oct 7, 2014

    @Nodd
    ContributorAuthor

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

  20. BrenBarn commented on Oct 7, 2014

    @BrenBarn

    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

  21. egiovan commented on Apr 24, 2015

    @egiovan

    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

  22. tacaswell commented on Apr 24, 2015

    @tacaswell
    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?

  23. kogelnik commented on Apr 24, 2015

    @kogelnik

    I don't see the original problem with 1.4.3.

  24. egiovan commented on Apr 24, 2015

    @egiovan

    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.

  25. WeatherGod commented on Apr 24, 2015

    @WeatherGod
    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)
    .

  26. kogelnik commented on Apr 24, 2015

    @kogelnik

    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.

  27. tacaswell commented on Apr 25, 2015

    @tacaswell
    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)
    .

  28. kogelnik commented on Apr 25, 2015

    @kogelnik

    TkAgg

    I don't have Qt installed.

  29. egiovan commented on Apr 27, 2015

    @egiovan

    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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions