Как установить абсолютное положение окон рисунка с помощью matplotlib?
Я пишу простое приложение на Python, которое использует matplotlib для отображения нескольких цифр на экране. Количество сгенерированных цифр зависит от пользовательского ввода и изменяется в течение всей жизни приложения. Пользователь имеет возможность выполнить команду "сюжет" для создания нового окна рисунка с выбранным рядом данных. Чтобы улучшить взаимодействие с пользователем, я хотел бы предоставить еще одну команду, которая программно упорядочит все окна с открытыми фигурами в некотором удобном порядке (например, расположит их по доступному экранному пространству).
Я полагаю, что нашел API, которые позволяют мне регулировать размер окна рисунка (в пикселях), но не смог найти способ установить их абсолютную позицию на экране. Есть ли способ сделать это, не вдаваясь в детали того, какой бэкэнд используется? Я хотел бы сделать это не зависящим от бэкэнда способом, чтобы не полагаться на детали реализации, которые могут измениться в будущем.
12 ответов
Я не знаю, как сделать это независимым от бэкенда способом, но определенно возможно сделать это для некоторых распространенных бэкэндов, например, WX, tkagg и т. д.
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()
за @tim в разделе комментариев ниже, вы можете переключиться на
thismanager.window.wm_geometry("+500+0")
вместо. За TkAgg
просто измените его на
thismanager.window.wm_geometry("+500+0")
Поэтому я думаю, что вы можете исчерпать все бэкэнды, которые способны сделать это, если навязывание определенного не вариант.
НАКОНЕЦ нашел решение для бэкэнда 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)
Если кто-то не знает x- и y-width, он может сначала прочитать их, например, так:
# get the QTCore PyRect object
geom = mngr.window.geometry()
x,y,dx,dy = geom.getRect()
и затем установите новую позицию с тем же размером:
mngr.window.setGeometry(newX, newY, dx, dy)
Я довольно часто искал это и, наконец, потратил 30 минут, чтобы это выяснить. Надеюсь, что это помогает кому-то.
С помощью ответов на данный момент и некоторых моих собственных попыток, вот решение, которое проверяет текущий бэкэнд и использует правильный синтаксис.
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()
Для Qt4Agg это сработало для меня.
fig = figure()
fig.canvas.manager.window.move(0,0)
Протестировано на Win7, mpl версии 1.4.2, python 2.7.5
Вдохновленный ответом @theo, я написал скрипт для перемещения и изменения размера окна в определенную стандартную позицию на экране. Это было протестировано с бэкэндом 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 __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")
Следующее сработало для меня.
import matplotlib
matplotlib.use("TkAgg") # set the backend
if backend == 'TkAgg':
f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
Это также работает:
fig = figure()
fig.canvas.manager.window.Move(100,400)
Если вы хотите отправить график на изображение и открыть его с помощью диспетчера изображений по умолчанию (который, вероятно, запоминает положение), используйте это здесь:
fig.savefig('abc.png')
from PIL import Image
im = Image.open("abc.jpg")
im.rotate(0).show()
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()
'''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)
Для платформы Windows вы можете установить и использовать модуль pyfig от Pyfig.
Пример того, как управлять окнами рисунка, приведен ниже:
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')
Как насчет определения функции для поднятия окна на верхний уровень и перемещения его к верхнему левому углу (например) следующим образом:
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)
Затем, когда вы открываете новую фигуру, вы просто набираете "topfig()". Есть ли способ предварительно определить topfig, чтобы он всегда был доступен?
Хммм, я, должно быть, делаю что-то не так, потому что этот код ничего не должен делать, но фактически перемещает окно в верхний левый угол экрана.
f = plt.figure(boards)
mngr = plt.get_current_fig_manager()
geom = mngr.window.geometry()
x, y, dx, dy = geom.getRect()
print(x,y,dx,dy)
mngr.window.setGeometry(x, y ,dx, dy)
geom = mngr.window.geometry()
x, y, dx, dy = geom.getRect()
print(x,y,dx,dy)
Кажется, что исходный geom.getRect() возвращает (0,0) для (x,y), а затем setGeometry правильно устанавливает их в (0,0). Это происходит только тогда, когда я запускаю код в оболочке Windows, отлично работает в Spyder. Похоже, это связано с используемым сервером Qt. Какие-либо предложения?