web-dev-qa-db-fra.com

Comment définir la position absolue des fenêtres de figures avec matplotlib?

J'écris une simple application Python qui utilise matplotlib pour afficher quelques chiffres à l'écran. Le nombre de chiffres générés est basé sur les entrées de l'utilisateur et change tout au long de la vie de l'application. L'utilisateur a la possibilité d'émettre une commande "plot" pour générer une nouvelle fenêtre de figure avec la série de données sélectionnée. Afin d'améliorer l'expérience utilisateur, je voudrais fournir une autre commande qui organiserait par programme toutes les fenêtres à chiffres ouverts selon un agencement commode (par exemple, en les plaçant sur l'espace d'écran disponible).

Je pense avoir trouvé des API qui me permettent d'ajuster la taille de la fenêtre de figure (en pixels), mais je n'ai pas réussi à trouver le moyen de définir leur position absolue à l'écran. Existe-t-il un moyen de le faire sans entrer dans les détails du backend utilisé? J'aimerais procéder de manière agnostique sur le backend afin d'éviter de me fier aux détails de la mise en œuvre susceptibles de changer à l'avenir.

29
Jason R

je ne connais pas de méthode agnostique pour les backends, mais il est tout à fait possible de le faire pour des backends classiques, comme 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()

par @tim à la section commentaire ci-dessous, vous voudrez peut-être passer à 

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

au lieu. Pour TkAgg, remplacez-le simplement par

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

Donc, je pense que vous pouvez épuiser tous les backends qui sont capables de le faire, si imposer un tel n'est pas une option.

11
nye17

FINALEMENT trouvé la solution pour le backend QT:

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)

Si on ne connaît pas les largeurs x et y, on peut les lire en premier, comme ceci:

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

puis définissez la nouvelle position avec la même taille:

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

Je cherchais souvent cela et j'ai finalement investi 30 minutes pour le découvrir. J'espère que ça aide quelqu'un.

28
K.-Michael Aye

Avec l'aide des réponses apportées jusqu'à présent et quelques modifications personnelles, voici une solution qui vérifie le backend actuel et utilise la syntaxe correcte.

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()
10
cxrodgers

Inspiré par @theo answer, j'ai écrit un script pour déplacer et redimensionner une fenêtre vers une position standard spécifique sur l'écran. Ceci a été testé avec le backend Qt4Agg:

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 __== '__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")
5
divenex

Pour Qt4Agg, cela a fonctionné pour moi.

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

Testé sur Win7, mpl version 1.4.2, python 2.7.5

3
otterb

Cela fonctionne aussi:

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

Si vous souhaitez envoyer un tracé à une image et le laisser ouvert avec le gestionnaire d'images par défaut (qui se souvient probablement de la position), utilisez cette option depuis ici :

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

Ce qui suit a fonctionné pour moi.

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

if backend == 'TkAgg':  
    f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
1
Cryptoman
'''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)
1
theo olsthoorn

Pour la plate-forme Windows, vous pouvez installer et utiliser le module pyfig à partir de Pyfig .

Voici un exemple de manipulation des fenêtres de figures:

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')
1
Per A.

Pourquoi ne pas définir une fonction pour élever la fenêtre au niveau supérieur et la déplacer vers le coin supérieur gauche (par exemple) comme ceci:

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)

Ensuite, chaque fois que vous ouvrez une nouvelle figure, vous tapez simplement "topfig ()". Existe-t-il un moyen de prédéfinir topfig pour qu'il soit toujours disponible?

0
slehar