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

Add "bring window to front" functionality · Issue #596 · matplotlib/matplotlib · GitHub

Repository navigation

Add "bring window to front" functionality #596

Closed

Description

It would be nice to have a method on the figure object that would bring its GUI window to the top of stack -- if this is possible -- in a backend-neutral way.

(Suggested by Marshall Perrin on the PyInt mailing list)

Activity

  1. embray commented on Nov 17, 2011

    Contributor

    Hmm.. I've been wanting to get into development on matplotlib's GUI features, and this seems like a simple enough issue to start with (depending, of course, on the backend).

    Would it be a logical approach to add a couple methods to FigureManagerBase? I'm thinking maybe:

    • FigureManagerBase.bring_to_front()
    • FigureManagerBase.send_to_back()

    and go from there?

  2. mdboom commented on Nov 17, 2011

    MemberAuthor

    Yes -- that makes sense.

    Then there would need to be identical methods on the Figure object to delegate to these (since that's how most users will probably interact with it). A pair of pyplot methods to act on the current figure would also be useful. But that's just gravy once the various gui API hooks have been added.

  3. embray commented on Nov 21, 2011

    Contributor

    I was playing around with this a bit and it turns out it's a bit trickier than I expected on Linux. This is because I can call the appropriate methods on each backend (GTK+, Tk, etc) to bring a window to the front. But what happens next depends entirely on what the window manager feels like doing, and in my case it doesn't usually want to actually bring them up.

    I could fairly easily write some functions to talk directly to the window manager (at least as long as it follows the EWMH standard. But I'm not sure it's worth the effort.

  4. sparks commented on Mar 30, 2012

    This bug is a big peeve for me. I'm gonna try my hand at implementing this the mac os x backend, however I don't know much about matplotlib structure for the moment so I'm open to suggestions about how to best approach this.

    Also assuming this was implemented shouldn't the show() command always bring the window to the front right away?

  5. embray commented on Mar 30, 2012

    Contributor

    @sparks See if you can stick to my suggestion of FigureManagerBase.bring_to_front(). send_to_back() I would consider optional. This should actually be quite doable on OSX--the only reason I didn't do that is that I don't normally work on an OSX machine.

    I threw my hands up over the annoyance of different window managers in Linux doing different things, but that shouldn't be as much an issue on OSX. I do still plan on coming back to this for Linux sometime though, as it's an annoyance for me too.

    And I agree that show() should bring the window to the front. Not sure how others feel about that.

  6. pelson commented on Sep 2, 2012

    Member

    I would love to see somebody tackle this issue - it would be fantastic to have a cross platform, cross toolkit interface which "just works".

  7. efiring commented on Sep 2, 2012

    Member

    @iguananaut, one does not always want show to bring windows to the front; it should be configurable.

  8. dmcdougall commented on Sep 3, 2012

    Member

    I'm an OS X user and I'm fairly familiar with objective-c, and with the OS X window manager it's fairly easy to give a window focus (if the window manager is able to give it focus). Window managers in general, though, may choose to ignore any message passed to them, depending on what they're currently doing. They also certainly do not behave uniformly. X11 may behave differently from GNOME and KDE. I'd be happy to look into this a little but. A lot of toolkits (GTK, TK, QT) have a function that pings the window manager and says, "Hey, I'm important, give me focus!" But as I've said, this functionality will almost certainly not work uniformly across window managers. And I have absolutely no clue and how Windows deals with anything.

    The question is, do we want to implement something that is potentially going to be temperamental in its behaviour? Honestly, I'd rather just rely on the user the click the window to give it focus.

  9. efiring commented on Sep 3, 2012

    Member

    I think that if each of the gui toolkits has a reasonably similar set of functions for (1) raising a window within the application--that is, relative to other windows in that application, and (2) requesting that the window manager raise the window, and (3) requesting that the window manager give it focus, then providing a gui-neutral api in mpl would be helpful. But I would not want to see this get complicated, or impose possibly unwanted new behavior.

  10. dmcdougall commented on Sep 3, 2012

    Member

    Personally, I find it inconvenient when a window unexpectedly steals focus. Having said that, it seems that given the discussion in this issue, it would be the user's choice to initiate such behaviour. I'm happier with this than always stealing focus. Moreover, I did some Googling. It is the case that Windows never lets an application steal keyboard focus, but instead makes the taskbar flash. Not that there's really anything anybody can do about it, implementing the ideas discussed here would result in inconsistent behaviour across operating systems.

  11. embray commented on Sep 5, 2012

    Contributor

    @efiring The point of this issue was not that windows should automatically be brought to the front--just that matplotlib should expose an API for doing so. That way if the GUI window pops up under my terminal I can just type a quick command to bring it forward. Or, more importantly, for applications that use matplotlib it would be nice to be able to do this.

    I would say then that it's the responsibility of an application using matplotlib to provide users with an option to not allow windows to steal focus. All matplotlib needs to do is provide the appropriate API. I think this should still be done, but it turns out to be surprisingly tricky to get consistent across platforms. OSX should be fairly straightfoward, but X11 is tough. As @dmcdougall wrote all the relevant GUI toolkits have a way of doing this, but the actual resulting behavior is up to the whims of the window manager.

    What we can do for X11 is bypass the window manager altogether and communicate with the X server via EWMH protocol--a standard protocol for window managers supported by most window managers still in common use. If we use EWMH it should be possible to do this without confusing the active window manager, so long as it's EWMH-compliant. Otherwise fall back on doing the best the GUI toolkit can provide and not guarantee the results. I could give that a try, but it would be up to others to provide the OSX and Windows implementations.

  12. embray commented on Sep 5, 2012

    Contributor

    After a quick experiment, the EWMH approach works very well with metacity--the default WM for GNOME. Would have to experiment with more, but this is promising considering how widely used metacity is. Is matplotlib allowed to use ctypes?

  13. efiring commented on Sep 5, 2012

    Member

    We have never used ctypes, as far as I know. In what way would you propose to use it?

    I would have expected that the way to implement this API in mpl would be via each toolkit, not by bypassing the toolkits and going straight to X or OSX or Windows.

  14. embray commented on Sep 5, 2012

    Contributor

    I would prefer to do it through the GUI toolkits, as a matter of preference if not policy. If it is a matter of policy then so be it--it makes things pretty easy. When I experimented with this on GTK and Tk I found frustratingly inconsistent results, hence the desire to bypass the GUI toolkits in this case. For example, I simply could not get it to work with Tkinter, where the relevant method is "lift". The problem is that Tk will go ahead and configure the window stacking order, but then the window manager (in this case metacity, but ymmv) happily ignores it. GTK on the other hand uses the appropriate EWMH messages which the WM does obey, and so it gives better results. I guess the fault lies with the toolkit in this case.

    Another open question would be: Do we want "bring_to_front()" to just raise the window in the stacking order, or should it also change the focus? I would tend to prefer, "No, don't change the focus."

  15. efiring commented on Sep 5, 2012

    Member

    We need to keep focus separate and independent from position.

  16. 39 remaining items

  17. mbrennwa commented on May 31, 2017

    I have Ubuntu Linux with Gnome-3 desktop environment, and I use the TkAgg backaend. matplotlib 1.5 behaves as it should, matplotlib 2.0 does not.

    Below is a copy of what I posted on stackexchange:


    I have a python / matplotlib application that frequently updates a plot with new data coming in from a measurement instrument. The plot window should not change from background to foreground (or vice versa) with respect to other windows on my desktop when the plot is updated with new data.

    This worked as desired with Python 3 on a machine running Ubuntu 16.10 with matplotlib 1.5.2rc. However, on a different machine with Ubuntu 17.04 and matplotlib 2.0.0, the figure window pops to the front every time the plot is updated with new data.

    How can I control the window foreground/background behavior and keep the window focus when updating the plot with new data?

    Here's a code example illustrating my plotting routine:

    import matplotlib
    import matplotlib.pyplot as plt
    from time import time
    from random import random
    
    print ( matplotlib.__version__ )
    
    # set up the figure
    fig = plt.figure()
    plt.xlabel('Time')
    plt.ylabel('Value')
    plt.ion()
    
    # plot things while new data is generated:
    t0 = time()
    t = []
    y = []
    while True:
        t.append( time()-t0 )
        y.append( random() )
        fig.clear()
        plt.plot( t , y )
        plt.pause(1)
    

  18. efiring commented on May 31, 2017

    Member

    Apart from the change suggested in #8692, which won't help you any time soon, I think you can improve your situation by changing your plotting strategy to avoid using pause, which is calling show, which is raising the window.
    Have you tried using the animation module? See http://matplotlib.org/devdocs/gallery/animation/random_data.html#sphx-glr-gallery-animation-random-data-py for example. Modifying it to match your example above would involve adding a call to line.set_xdata, and setting 'interval' to 1000 (milliseconds).
    I think that if you use the animation module you will need to manually put the window behind others once at the start, but then it will stay there.

  19. mbrennwa commented on Jun 1, 2017

    That animation example does the trick of keeping the window in the background (or in the foreground, wherever I put it) even when the data is updated. I could adapt my code example above to use the animation module.

    However, I believe the approach in the example will not work in my real-life application, because I cannot leave it to the animation module to ask for new data to update the plot. My application needs direct control to talk to the measurement instrument, and then update the plot as needed. Is there a way to do this?

  20. efiring commented on Jun 1, 2017

    Member

    Yes, I think it could be done with the animation module, but figuring out how--via subclassing Animation--might take a bit of time. There is probably a simpler way, but it is hard to specify it without seeing exactly what you are trying to do.
    Suggestions:

    1. Put the ion() call at the top, before creating the figure, or run inside of ipython so that you can take advantage of its interactive magic (with no need for the ion call).
    2. General good practice: use the object-oriented API, reserving pyplot for a minimum of calls like plt.ion() and plt.subplots().
    3. Don't clear the figure unless you need to; if you are making an updating line plot, for example, just use the data updating strategy illustrated in the animation examples.

    I think that is about all you will need; no clear, no pause; the redrawing should occur each time you update the data.

  21. WeatherGod commented on Jun 1, 2017

    Member
  22. mbrennwa commented on Jun 1, 2017

    Ok, I had a look at this.

    At first, I thought I'd try your suggestions on how to get this working without the animation module. I sort of have this working. However, it is not possible to resize or move the plot window on the screen. I guess there's some event loop that would need to be called, but I don't know how to fix this. Any suggestions?

    Then I thought again about the animation module. I believe I could use this for my purposes if it would just update the plot with the current data from my measurement instrument stored in a buffer. However, I'd need to make the plot window to be "non blocking". In my existing code I use the pyplot.ion() function to get an interactive figure that does not block the code following the pyplot.show(). This is required to execute the code for instrument control and data acquisition. All examples I found for the animation module use a blocking window without the pyplot.ion() function, and I was not able to make the animation work in a non-blocking (interactive) way. Any suggestions?

  23. mbrennwa commented on Jun 1, 2017

    @WeatherGod: thanks for this suggestion. It would be cool if I could read up on this without buying a book. Any suggestions?

  24. mbrennwa commented on Jun 1, 2017

    Ok, I got it working without the animation module. Window resizing and similar actions are taken care of by calling fig.canvas.flush_events() .

    Still, it would be nice if the animation module could be used with non-blocking plots. Is this possible? How?

  25. danielfaust commented on Aug 17, 2017

    I'm facing the same issue as @mbrennwa

    Stack Overflow: Make interactive matplotlib window not pop to front on each update (Windows 7)

    Honestly, there is nothing in the semantics of the word pause which implies that something should be brought to the front. This may be different with the word show, but pause definitely should not be doing this. This is a buggy behavior.

  26. mbrennwa commented on Aug 18, 2017

    I fully agree with danielfaust.

    Here's how I made things work in my application by avoiding the call to the buggy pause(...) command:
    https://stackoverflow.com/questions/44278369/how-to-keep-matplotlib-python-window-in-background

  27. tacaswell commented on Aug 20, 2017

    Member

    @mbrennwa FuncAnimation and friends work just fine with plt.ion() (I use it all the time). What examples are you referring to?

    FuncAnimation can take a generator as input as well so you can write things like

    def get_data():
        while True:
            yield get_some_hardware_data()
        
    anim = FuncAnimation(fig, update_func, get_data(), interval=interval)

    Could @mbrennwa and @danielfaust take a look at #4779 which is a start of thoroughly documenting how GUI event loop integration works in the context of Matplotlib?

  28. danielfaust commented on Aug 20, 2017

    @tacaswell I migrated my code over to to FuncAnimation when I faced the plt.pause issue. But my problem with FuncAnimation is that I don't want to use a fixed interval. I want a fetch-data-time + process-data-time + a fixed pause of let's say 5 seconds. I have some variants where the fetching and processing takes more than 5 seconds, others where both together take about 0.1 seconds, so in the case of the 0.1 seconds I'd choose an interval of 1 second, or a pause of 1 second, with the other one also a pause of one second, but I'd have to choose an interval of about 6-10 seconds with FuncAnimation. It's far better for me to just add a pause.

  29. tacaswell commented on Aug 21, 2017

    Member

    If you have vary computation time on the data retrieval I would create a thread for that work and have it drop data into a queue, something like

    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    import threading
    from queue import Queue, Empty
    import time
    import numpy as np
    
    q = Queue()
    
    
    def data_getting_worker():
        while True:
            time.sleep(np.random.rand() * 5)
            q.put(np.random.randn(15))
            print('put some data')
    
    
    th_gettr = threading.Thread(target=data_getting_worker)
    
    data = np.random.randn(15)
    
    
    def data_reciver_gen():
        global data
        while True:
            try:
                # pull data off the queue until we get to the most recent one
                data = q.get(block=False)
                print('got some data')
            except Empty:
                yield data
    
    
    fig, ax = plt.subplots()
    
    ln, = ax.plot(data)
    
    
    def updater(d_in):
        print('updating line')
        ln.set_ydata(d_in)
        return [ln]
    
    
    th_gettr.start()
    anim = FuncAnimation(fig, updater, frames=data_reciver_gen(), interval=1000)

    Which so long as the processing in data_getting_worker is not a tight loop in c you will get a reasonably responsive figure. You can also use the same pattern with multiprocess to push that work off to a sub-process.

  30. mbrennwa commented on Aug 21, 2017

    @tacaswell: running the data acquisition (and a lot more) in FuncAnimation (or any other GUI for that matter) would be very awkward in my application. Plotting is just a small side job, and it may not even be possible on some machines that are running without a display system. Wrapping the whole code in a FuncAnimation is therefore certainly not the way to go in my case. I will therefore stick to my current solution, and I might improve the handling of the GUI/plotting event loop a bit following this example: https://stackoverflow.com/questions/45729092/make-interactive-matplotlib-window-not-pop-to-front-on-each-update-windows-7/45734500#45734500

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


      Back | FazBrowse Home | New Git URL