How do you set the absolute position of figure windows with matplotlib?

PythonMatplotlib

Python Problem Overview


I'm writing a simple Python application that uses matplotlib to display a few figures on screen. The number of figures generated is based on user input and changes throughout the application's life. The user has the ability to issue a "plot" command to generate a new figure window with the selected data series. In order to improve the user experience, I would like to provide another command that would programmatically arrange all open figure windows in some convenient arrangement (e.g. tile them across the available screen space).

I believe to have found APIs that allow me to adjust the size of the figure window (in pixels), but haven't had any success in finding a way to set their absolute position on screen. Is there a way to do this without delving into the details of whatever backend is in use? I would like to do this in a backend-agnostic way so I can avoid relying upon implementation details that might change in the future.

Python Solutions


Solution 1 - Python

FINALLY found the solution for QT backend:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
mngr = plt.get_current_fig_manager()
# to put it into the upper left corner for example:
mngr.window.setGeometry(50,100,640, 545)

If one doesn't know the x- and y-width one can read them out first, like so:

# get the QTCore PyRect object
geom = mngr.window.geometry()
x,y,dx,dy = geom.getRect()

and then set the new position with the same size:

mngr.window.setGeometry(newX, newY, dx, dy)

I was searching quite often for this and finally invested the 30 minutes to find this out. Hope that helps someone.

Solution 2 - Python

With help from the answers thus far and some tinkering on my own, here's a solution that checks for the current backend and uses the correct syntax.

import matplotlib
import matplotlib.pyplot as plt

def move_figure(f, x, y):
    """Move figure's upper left corner to pixel (x, y)"""
    backend = matplotlib.get_backend()
    if backend == 'TkAgg':
        f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
    elif backend == 'WXAgg':
        f.canvas.manager.window.SetPosition((x, y))
    else:
        # This works for QT and GTK
        # You can also use window.setGeometry
        f.canvas.manager.window.move(x, y)

f, ax = plt.subplots()
move_figure(f, 500, 500)
plt.show()

Solution 3 - Python

there is not that I know a backend-agnostic way to do this, but definitely it is possible to do it for some common backends, e.g., WX, tkagg etc.

import matplotlib
matplotlib.use("wx")
from pylab import *
figure(1)
plot([1,2,3,4,5])
thismanager = get_current_fig_manager()
thismanager.window.SetPosition((500, 0))
show()

per @tim at the comment section below, you might wanna switch to

thismanager.window.wm_geometry("+500+0")

instead. For TkAgg, just change it to

thismanager.window.wm_geometry("+500+0")

So I think you can exhaust through all the backends that are capable of doing this, if imposing a certain one is not an option.

Solution 4 - Python

For Qt4Agg, this worked for me.

fig = figure()
fig.canvas.manager.window.move(0,0)

Tested on Win7, mpl version 1.4.2, python 2.7.5

Solution 5 - Python

Inspired by @theo answer, I wrote a script to move and resize a window to a specific standard position on the screen. This was tested with the Qt4Agg backend:

import matplotlib.pyplot as plt

def move_figure(position="top-right"):
    '''
    Move and resize a window to a set of standard positions on the screen.
    Possible positions are:
    top, bottom, left, right, top-left, top-right, bottom-left, bottom-right
    '''

    mgr = plt.get_current_fig_manager()
    mgr.full_screen_toggle()  # primitive but works to get screen size
    py = mgr.canvas.height()
    px = mgr.canvas.width()

    d = 10  # width of the window border in pixels
    if position == "top":
        # x-top-left-corner, y-top-left-corner, x-width, y-width (in pixels)
        mgr.window.setGeometry(d, 4*d, px - 2*d, py/2 - 4*d)
    elif position == "bottom":
        mgr.window.setGeometry(d, py/2 + 5*d, px - 2*d, py/2 - 4*d)
    elif position == "left":
        mgr.window.setGeometry(d, 4*d, px/2 - 2*d, py - 4*d)
    elif position == "right":
        mgr.window.setGeometry(px/2 + d, 4*d, px/2 - 2*d, py - 4*d)
    elif position == "top-left":
        mgr.window.setGeometry(d, 4*d, px/2 - 2*d, py/2 - 4*d)
    elif position == "top-right":
        mgr.window.setGeometry(px/2 + d, 4*d, px/2 - 2*d, py/2 - 4*d)
    elif position == "bottom-left":
        mgr.window.setGeometry(d, py/2 + 5*d, px/2 - 2*d, py/2 - 4*d)
    elif position == "bottom-right":
        mgr.window.setGeometry(px/2 + d, py/2 + 5*d, px/2 - 2*d, py/2 - 4*d)


if __name__ == '__main__':

    # Usage example for move_figure()

    plt.figure(1)
    plt.plot([0, 1])
    move_figure("top-right")

    plt.figure(2)
    plt.plot([0, 3])
    move_figure("bottom-right")

Solution 6 - Python

This also works:

fig = figure()
fig.canvas.manager.window.Move(100,400)

If you want to send a plot to an image and have it open with the default image manager (which likely remembers position) use this from here:

fig.savefig('abc.png')
from PIL import Image
im = Image.open("abc.jpg")
im.rotate(0).show()

Solution 7 - Python

'''This is a way to resize the window to a given fraction of the screen.
It uses the screenSize in pixels. User specifies the fx and fy fraction
of the sreen or just a fraction. Couldn't fine how to really position the
window though. No hints in the current figmanager could be found.
But of course, this could be combined with mgr.canvas.move()

'''

import matplotlib.pyplot as plt
#pylab

def screenPos(f):
   '''reset window on screen to size given by fraction f
   where f may by a scalar or a tuple, and where all values
   are 0<=f<=1
   '''
   if type(f)==float: f=(f,) # assert we have a tuple
   mgr = plt.get_current_fig_manager()
   mgr.full_screen_toggle() # primitive but works
   py = mgr.canvas.height()
   px = mgr.canvas.width()
   mgr.resize(f[0]*px,f[-1]*py)
   return f[0]*px,f[-1]*py

px,py = screenPos(0.8)

Solution 8 - Python

The following worked for me.

import matplotlib  
matplotlib.use("TkAgg") # set the backend  

if backend == 'TkAgg':  
    f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))

Solution 9 - Python

For the windows platform you could install and use pyfig module from Pyfig.

Example on how to manipulate the figure windows is given below:

import pylab as p
import pyfig as fig
for ix in range(6): f = p.figure(ix)
fig.stack('all')
fig.stack(1,2)
fig.hide(1)
fig.restore(1)
fig.tile()
fig.pile()
fig.maximize(4)
fig.close('all')

Solution 10 - Python

def show_img(img, title=""):
    plt.imshow(img)
    plt.title(title)
    thismanager = plt.get_current_fig_manager()
    thismanager.window.wm_geometry("+100+100")
    plt.show()

Solution 11 - Python

How about defining a function to raise the window to the top level and move it toward the top-left corner (for example) like this:

def topfig():
    figmgr = get_current_fig_manager()
    figmgr.canvas.manager.window.raise_()
    geom = figmgr.window.geometry()
    x,y,dx,dy = geom.getRect()
    figmgr.window.setGeometry(10, 10, dx, dy)

Then whenever you open a new figure you just type "topfig()". Is there a way to pre-define topfig so it will always be available?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJason RView Question on Stackoverflow
Solution 1 - PythonK.-Michael AyeView Answer on Stackoverflow
Solution 2 - PythoncxrodgersView Answer on Stackoverflow
Solution 3 - Pythonnye17View Answer on Stackoverflow
Solution 4 - PythonotterbView Answer on Stackoverflow
Solution 5 - PythondivenexView Answer on Stackoverflow
Solution 6 - Pythonuser2484697View Answer on Stackoverflow
Solution 7 - Pythontheo olsthoornView Answer on Stackoverflow
Solution 8 - PythonCryptomanView Answer on Stackoverflow
Solution 9 - PythonPer A.View Answer on Stackoverflow
Solution 10 - PythonleenremmView Answer on Stackoverflow
Solution 11 - PythonsleharView Answer on Stackoverflow