FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Make pyplot.pause not give focus to the figure window · Issue #11131 · matplotlib/matplotlib · GitHub

Repository navigation

Make pyplot.pause not give focus to the figure window #11131

Closed

Description

Bug report

Bug summary

I'm using matplotlib.pyplot.pause() to update a plot in a loop, mostly for debugging purposes. On my old matplotlib version (maybe 2.0.2, not sure) this worked fine, but after updating to 2.2.2 the pause function seems to have changed behaviour. Previously the figure window was left in the background, but now it is brought to the front and given focus. This makes hit hard to cancel the running script (Ctrl+C in Jupyter QtConsole), which I often use while debugging a script.

I know it is noted in the docs of pause that "This function is experimental; its behavior may be changed or extended in a future release.", but is there any way to bring back the old behaviour? Perhaps via a argument focus_window=False or something like that?

Code for reproduction

plt.figure()
# put the figure in the background, or below another window
plt.pause(2)
# now the figure will be on top, and have focus

Matplotlib version

  • Operating system: Windows 10 Pro build 1709
  • Matplotlib version: 2.2.2 (via Anaconda)
  • Matplotlib backend: Qt5Agg
  • Python version: 3.5.3

Activity

  1. FSund commented on Apr 26, 2018

    Author

    I have recreated an older version of pause

    import matplotlib
    from matplotlib import _pylab_helpers
    from matplotlib.rcsetup import interactive_bk as _interactive_bk
    def pause(interval):
        """
        Pause for *interval* seconds.
        If there is an active figure it will be updated and displayed,
        and the GUI event loop will run during the pause.
        If there is no active figure, or if a non-interactive backend
        is in use, this executes time.sleep(interval).
        This can be used for crude animation. For more complex
        animation, see :mod:`matplotlib.animation`.
        This function is experimental; its behavior may be changed
        or extended in a future release.
        """
        backend = matplotlib.rcParams['backend']
        if backend in _interactive_bk:
            figManager = _pylab_helpers.Gcf.get_active()
            if figManager is not None:
                canvas = figManager.canvas
                if canvas.figure.stale:
                    canvas.draw()
                plt.show(block=False)
                canvas.start_event_loop(interval)
                return
    
        # No on-screen figure is active, so sleep() is all we need.
        import time
        time.sleep(interval)

    When I use this version of pause, the figure is still brought to the front and given focus, so it seems like the change I noticed is due do some other changes deeper in the matplotlib system. Any ideas?

    I don't necessarily need any changes to the pause function, I just want a simple way to update/refresh/redraw a figure in a loop without bringing the figure to the front. But it would be nice if that was possible with pause, perhaps via an argument like focus_figure like mentioned.

    EDIT: I managed to not have the figure brought to the front by commenting out the line plt.show(block=False) in the snippet above. So a simple fix that works like I want is something like this:

    def pause(interval, focus_figure=True):
        backend = matplotlib.rcParams['backend']
        if backend in _interactive_bk:
            figManager = _pylab_helpers.Gcf.get_active()
            if figManager is not None:
                canvas = figManager.canvas
                if canvas.figure.stale:
                    canvas.draw()
                if focus_figure:
                    plt.show(block=False)
                canvas.start_event_loop(interval)
                return
    
        # No on-screen figure is active, so sleep() is all we need.
        import time
        time.sleep(interval)

    But I am no matplotlib expert, so I don't know what side effects removing the call to plt.show() might have.

  2. efiring commented on Apr 27, 2018

    Member

    The underlying problem is how to control both raise and focus behavior on each of the backends and for every platform and window manager. One might expect each gui backend to have a simple API for doing this, but it seems not be be the case at all. I think what you are running into is #6384. The problem that was addressing was the tendency for Qt windows to come up behind other windows, so there was no indication that a plot had been made. But I completely understand the opposite problem, of a plot popping up on top of something when that is not what you want.

    What we might be able to do is give each backend FigureManager a raise method, which would be a no-op if there is no raise functionality available, and move the functionality from the manager's show to the new raise. Then the pyplot show could call raise by default, but this could be turned off with a kwarg.

  3. CnlPepper commented on May 30, 2018

    Can you please revert the change to pause? Windows should never steal focus just to fix them popping up in the background - the reason they pop up in the background is due to the window manager choosing to keep focus on the application the user is currently working with. This change is incredibly disruptive, we also have multiple windows refreshing continuously and are unable to work with this change.

  4. mattngc commented on May 31, 2018

    Just adding support to reverting the behavior. I have found this change breaks my default development environment. I used to start a job running with interactive plots updating and then move to another Ubuntu workspace to check email or work on the script in another window, etc. Now I can't do any of this because the plot window is constantly stealing focus. For now I have reverted to 2.0.2, but please consider reverting this change.

  5. ImportanceOfBeingErnest commented on May 31, 2018

    Member

    Maybe it's worth noting that plt.pause is meant to be used in interactive mode; i.e. you usually want to use it to make some change in the plot apparent. In that sense it makes perfect sense to give it focus upon such change in the plot.

    In case people want to run some continuous loop in the background, one would rather use either the provided matplotlib.animation classes, or run a loop within the GUI's event loop, possibly using a timer that matplotlib provides as well.

  6. hofingermarkus commented on Jun 14, 2018

    I use plt.pause mostly in the interactive mode for doing quick and dirty first tests before I build something more sophisticated.
    And it definitely depends on the situation if stealing focus is something good or something bad.
    In the worst case it updates so fast, that you can't even press ctrl+c, although you just wanted to get a quick insight without much coding effort... (I know that this is inefficient etc. but often this would just be good enough for these first test...)

    So please make it choose-able by the users!

  7. evilmav commented on Aug 11, 2018

    I add to the request: I want to plot stuff in an interactive (zoomable etc) window but still be able to use my terminal the program is executed in. It is impossible if window is stealing the focus. This is not at all a minor problem.

  8. jklymak commented on Aug 11, 2018

    Member

    Within an interactive python/IPython session or from the operating system shell? If the latter you just put the python invocation in the background. If the former, I don’t think that’s possible.

  9. evilmav commented on Aug 11, 2018

    @jklymak
    From the shell, but I basically want to run a curses UI as an overview and control of a measurement system and plot some values in a Real-Time chart I can zoom around. If I put the process into background I loose the curses.

  10. carlosgmartin commented on Dec 5, 2019

    Contributor

    In that sense it makes perfect sense to give it focus upon such change in the plot.

    @ImportanceOfBeingErnest That's a false assumption. For example, I might be running a simulation in the background and want to see what it looks like every now and then. That doesn't mean I want the window popping up repeatedly in front of everything else. This behaviour is very annoying.

  11. starfleetjames commented on Dec 9, 2019

    Second @carlosgmartin statement. In my case I'm interacting with one figure and updating plots in a second figure and I don't want that second figure to steal focus every time it updates.

  12. anntzer commented on Dec 10, 2019

    Contributor

    Hopefully #15440 will make this easier to control (by providing the relevant snippets for all toolkits).

  13. starfleetjames commented on Dec 10, 2019

    I did find a workaround for at least my case: let the other figure window steal focus but set it back programmatically with

    plt.figure(fig.number)
    plt.get_current_fig_manager().show()
    

    where fig is the figure that I want to stay in focus.

  14. ImportanceOfBeingErnest commented on Dec 10, 2019

    Member

    I mean, you can always replace plt.pause(0.3) with

    plt.gcf().canvas.draw_idle()
    plt.gcf().canvas.start_event_loop(0.3)
    

    if in interactive mode (plt.ion()).

  15. petrvokac commented on Jun 10, 2020

    I mean, you can always replace plt.pause(0.3) with

    plt.gcf().canvas.draw_idle()
    plt.gcf().canvas.start_event_loop(0.3)
    

    if in interactive mode (plt.ion()).

    Bingo, thank you

  16. timhoffm commented on Jun 17, 2020

    Member

    Closed by #15440.

  17. added this to the v3.3.0 milestone on Jun 17, 2020
  18. carlosgmartin commented on Jun 17, 2020

    Contributor

    @ImportanceOfBeingErnest Is the first line necessary? It seems to work with the second line alone.

  19. tacaswell commented on Jun 17, 2020

    Member

    The draw_idlemay not be needed in some cases (it means "the next time you repaint the GUI window please re-render the figure first". If that re-rendering was scheduled anyway it is a no-op, but if you have changed the figure but not called draw_idle you may see stale output) but in will do no harm in all cases.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL