it-swarm.com.de

Wie stellen Sie die absolute Position von Figurenfenstern mit matplotlib ein?

Ich schreibe eine einfache Python-Anwendung, die Matplotlib verwendet, um einige Zahlen auf dem Bildschirm anzuzeigen. Die Anzahl der generierten Zahlen basiert auf Benutzereingaben und Änderungen während der gesamten Lebensdauer der Anwendung. Der Benutzer kann einen "Plot" -Befehl ausgeben, um ein neues Figurenfenster mit der ausgewählten Datenreihe zu erstellen. Um die Benutzererfahrung zu verbessern, möchte ich einen anderen Befehl bereitstellen, der alle geöffneten Figurenfenster in einer bequemen Anordnung programmgesteuert anordnet (z. B. über den verfügbaren Bildschirmbereich anordnen).

Ich glaube, APIs gefunden zu haben, die es mir ermöglichen, die Größe des Figurenfensters (in Pixel) anzupassen, aber es war nicht erfolgreich, einen Weg zu finden, um ihre absolute Position auf dem Bildschirm festzulegen. Gibt es eine Möglichkeit, dies zu tun, ohne auf die Details des verwendeten Backends einzugehen? Ich möchte dies auf eine Backend-agnostische Weise tun, um zu vermeiden, dass Implementierungsdetails verwendet werden, die sich in der Zukunft möglicherweise ändern.

29
Jason R

ich kenne keinen Backend-agnostischen Weg, dies zu tun, aber definitiv ist es möglich, dies für einige gängige Backends zu tun, z. B. WX, Tkagg usw.

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 im Kommentarbereich weiter unten, möchten Sie vielleicht zu wechseln 

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

stattdessen. Für TkAgg ändern Sie es einfach in

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

Ich denke, Sie können alle Backends, die dazu in der Lage sind, erschöpfen, wenn es nicht möglich ist, ein bestimmtes zu erzwingen.

11
nye17

ENDLICH die Lösung für das QT-Backend gefunden:

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)

Wenn man die x- und y-Breite nicht kennt, kann man sie wie folgt auslesen:

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

und dann die neue Position mit der gleichen Größe einstellen:

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

Ich habe ziemlich oft danach gesucht und schließlich die 30 Minuten investiert, um das herauszufinden. Hoffe das hilft jemandem.

28
K.-Michael Aye

Mit Hilfe der bisherigen Antworten und einigem Basteln habe ich hier eine Lösung, die das aktuelle Backend überprüft und die richtige Syntax verwendet.

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

Inspiriert von der Antwort von @theo, schrieb ich ein Skript, um ein Fenster an eine bestimmte Standardposition auf dem Bildschirm zu verschieben und dessen Größe zu ändern. Dies wurde mit dem Qt4Agg-Backend getestet:

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

Für Qt4Agg hat das für mich funktioniert.

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

Getestet unter Win7, MPL-Version 1.4.2, Python 2.7.5

3
otterb

Das funktioniert auch:

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

Wenn Sie ein Plot an ein Bild senden und es mit dem Standard-Image-Manager öffnen möchten (der sich wahrscheinlich die Position merkt), verwenden Sie diesen Befehl von hier :

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

Folgendes hat für mich gearbeitet.

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

Für die Windows-Plattform können Sie das pyfig-Modul von Pyfig installieren und verwenden.

Ein Beispiel zur Bearbeitung der Figurenfenster finden Sie im Folgenden:

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.

Wie wäre es, wenn Sie eine Funktion definieren, um das Fenster auf die oberste Ebene anzuheben und es in die linke obere Ecke zu verschieben (beispielsweise):

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)

Wenn Sie dann eine neue Figur öffnen, geben Sie einfach "topfig ()" ein. Gibt es eine Möglichkeit, topfig vorab zu definieren, damit es immer verfügbar ist?

0
slehar