Reputation: 14239
Today I upgraded matplotlib to version 2.0.2, after not upgrading for possibly 3 years.
Now I have the problem that in interactive plots the window always comes to the front, as if this here make matplotlib plotting window pop up as the active one had come to be the default behaviour.
How can I deactivate it? I don't want the window to come to front every 5 seconds and raise over my text editor, browser, ...
I want it to stay in the z-ordering where I've placed it, be it to front or behind an active window.
I believe that the following commit from 31 Jan 2016 is responsible for this problematic behaviour: tkagg: raise each new window; partially addresses #596
Found a related comment on Github https://github.com/matplotlib/matplotlib/issues/596#issuecomment-305298577
it appears that it is my call to plt.pause
which is causing this issue, and not the plt.plot
call.
Upvotes: 20
Views: 13380
Reputation: 3985
Starting from matplotlib version 3.3.0 you can do the following at the beginning
import matplotlib.pyplot as plt
plt.rcParams["figure.raise_window"]=False
Credit to https://github.com/matplotlib/matplotlib/issues/22939#issuecomment-1113696066
Upvotes: 1
Reputation: 576
It is October 2024 and the mypause() function (copied from the upto date pyplot implementation) for Matplotlib 3.0.3 should look more like
import time
import matplotlib.pyplot as plt
def mypause(interval):
manager = plt._pylab_helpers.Gcf.get_active()
if manager is not None:
canvas = manager.canvas
if canvas.figure.stale:
canvas.draw_idle()
#plt.show(block=False)
canvas.start_event_loop(interval)
else:
time.sleep(interval)
Note: It won't work without this line when using tooltip windows (at least on Qt5Agg), you should uncomment it in these cases, as it will not steal focus on its own:
plt.show(block=False)
After some testing (Qt5 backend/Spyder/Windows 7 64bit) the calls that do the trick for me are:
#plt.pause(0.001) #Brings plot to foreground
#fig.canvas.draw() #Does not work
#plt.draw_all() #Does not work
#plt.draw() #Does not work
#fig.canvas.flush_events() #Updates only if I click the figure
#import time; time.sleep(0.001) #Does not help flush_events()
#fig.canvas.draw_idle() #Does not work by itself
#fig.canvas.start_event_loop(0.001) #Does not work by itself
#mypause(0.001) #Works!
#Works!
fig.canvas.draw_idle()
fig.canvas.start_event_loop(0.001)
Were fig is your figure object. Either of both alone didn't work in my case. According to the animation documentation this is essentially what FuncAnimation does.
Upvotes: 11
Reputation: 6948
I had the same problem on the Mac. I'm not sure if this is the best approach, but instead of using plt.pause(0.001)
, I switched to fig.canvas.start_event_loop(0.001)
to update each frame on my animation. This allows the windows to stay in the background.
Upvotes: 10
Reputation: 14239
I rewrote the code to use matplotlib.animation
with the help from this documentation page https://matplotlib.org/devdocs/api/animation_api.html#module-matplotlib.animation
I got to that page through this one https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.pause.html
which states the following about matplotlib.pyplot.pause
This can be used for crude animation. For more complex animation, see matplotlib.animation.
This function is experimental; its behavior may be changed or extended in a future release.
Upvotes: 0
Reputation: 339580
The issue seems only present using the Tk
backend. Using the Qt
backend, the window would stay where it was while updating with plt.pause
.
To change the backend use those lines at the beginning of your script.
import matplotlib
matplotlib.use("Qt4agg") # or "Qt5agg" depending on you version of Qt
plt.pause
If changing the backend is not an option, the following might help. The cause of the window constantly popping up to the front comes from plt.pause
calling plt.show()
internally. You therefore implement you own pause
function, without calling show
. This requires to be in interactive mode plt.ion()
first and then at least once call plt.show()
. Afterwards you may update the plot with the custom mypause
function as shown below.
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from time import time
from random import random
plt.ion()
# set up the figure
fig = plt.figure()
plt.xlabel('Time')
plt.ylabel('Value')
plt.show(block=False)
def mypause(interval):
backend = plt.rcParams['backend']
if backend in matplotlib.rcsetup.interactive_bk:
figManager = matplotlib._pylab_helpers.Gcf.get_active()
if figManager is not None:
canvas = figManager.canvas
if canvas.figure.stale:
canvas.draw()
canvas.start_event_loop(interval)
return
t0 = time()
t = []
y = []
while True:
t.append( time()-t0 )
y.append( random() )
plt.gca().clear()
plt.plot( t , y )
mypause(1)
animation
.Finally, using a matplotlib.animation
class would render all of the above obsolete. An example for matplotlib.animation.FuncAnimation
is shown on the matplotlib page.
Upvotes: 29