Make interactive matplotlib window not pop to front on every update (Windows 7)
Today I updated matplotlib to version 2.0.2 after not updating for maybe 3 years.
Now the problem I have is that on interactive plots, the window always pops out to the front, as if it makes the matplotlib plot window pop up, since the active behavior has become the default behavior.
How can I disable this? I don't want the window to go forward every 5 seconds and rise above my text editor, browser, ...
I want it to remain in the z-order where I placed it, whether in front of or behind the active window.
I believe the following commit, dated January 31, 2016, is responsible for this problematic behavior: tkagg: bring up every new window; partially of address No. 596
Found a relevant comment on Github https://github.com/matplotlib/matplotlib/issues/596#issuecomment-305298577
it looks like this is causing my challenge plt.pause
, not the challenge plt.plot
.
source to share
Backend change
The problem seems to be present only when using the backend Tk
. Using the backend Qt
, the window will stay where it was when updated with plt.pause
.
To change the backend use these lines at the beginning of your script.
import matplotlib
matplotlib.use("Qt4agg") # or "Qt5agg" depending on you version of Qt
Modification plt.pause
If changing the backend is not possible, the following may help. The reason the window pops up constantly forwards is the plt.pause
caller plt.show()
inside. Therefore, you implement your own function pause
without calling show
. To do this, you must first switch to interactive mode plt.ion()
and then call at least once plt.show()
. After that, you can update the graph using the custom function mypause
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)
Use animation
.
Finally, using a class matplotlib.animation
will make all of the above obsolete. An example for is matplotlib.animation.FuncAnimation
shown on the matplotlib page .
source to share
I rewrote the code to use matplotlib.animation
using this documentation page https://matplotlib.org/devdocs/api/animation_api.html#module-matplotlib.animation
I got to this page via this https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.pause.html
which talks about matplotlib.pyplot.pause
This can be used for rough animation. For more complex animations see matplotlib.animation.
This feature is experimental; its behavior may be changed or expanded in a future release.
source to share
It is April 2019 and the mypause () function (copied from modern pyplot implementation) for Matplotlib 3.0.3 should look 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)
After some testing (Qt5 backend / Spyder / Windows 7 64bit) the calls that suit 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)
If fig is your object shape. In both cases, nothing worked. According to the animation documentation , this is exactly what FuncAnimation does.
source to share