2011-09-16 394 views
20

我在写一个简单的Python应用程序,它使用matplotlib在屏幕上显示一些数字。生成的图形数量基于用户输入和整个应用程序生命周期的变化。用户可以发出“绘图”命令,以生成具有选定数据系列的新数字窗口。为了改善用户体验,我想提供另一个命令,以编程方式将所有打开的数字窗口排列成一些方便的布局(例如,将它们平铺在可用的屏幕空间中)。如何用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") 

所以我认为你可以通过所有能够这样做的,如果施加一定是一个无法选择的后端排出。

+0

谢谢。我在我的系统上使用TKAgg,但我认为我不认为最终用户会这样做。不过,我可能会强制用户必须使用它们的一些子集。 –

+0

@Jason R它真的取决于这个指定定位在您的应用程序中的重要性。如果仅仅是为了改善用户体验,那么您可以简单地选择任何可以照顾的子集,否则只能生成一个窗口,并在删除旧的子图时动态地将每个图作为子图进行布局? – nye17

+3

不知道为什么,但是对于我来说('Windows Idle,Python 2.7,从Notepad ++开始)'thismanager.window.wm_geometry(“+ 500 + 0”)'工作,'thismanager.window.SetPosition((500,0 ))'没有;-) – tim

1

针对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') 
2

这也适用于:

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

如果你想在一个图发送到图像,并打开它与默认图片管理器(可能会记住位置)使用此从here

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

在'move'中有小'm' – Olexandr

+2

不适用于QT。 –

+0

结合前面两个注释:至少在使用Qt后端(Qt4Agg,也可能是Qt5Agg)时,调整大小的正确命令是'fig.canvas.manager.window.move(100,400)'。 GTK3Agg似乎也是如此,所以我会编辑这个答案。 –

19

终于找到了QT后端的溶液:

import matplotlib.pyplot as plt 

fig, ax = 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宽度可以首先读出来,如下所示:

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

然后设置相同尺寸的新位置:

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

我经常为此寻找,最后投入了30分钟才发现这一点。希望能帮助别人。

+0

伟大的解决方案,感谢分享! – Gabriel

+0

比接受的答案好得多。 – Muppet

+2

请注意,除了mngr = get_current_fig_manager()之外,我们还可以使用fig.canvas.manager – poppie

1
'''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) 
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") 
+0

如何添加中间选项? – Rich

0

如何定义一个函数到窗口提升到最高级,并且将其移向的左上角(例如)是这样的:

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,以便它始终可用?

3

对于Qt4Agg,这为我工作。

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

测试Win7上,MPL版本1.4.2,2.7.5蟒

7

与答案迄今的帮助和对我自己的一些修修补补,下面是检查当前后端和应用解决方案正确的语法。

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) 
    plt.show() 


f, ax = plt.subplots() 
move_figure(f, 500, 500) 
+0

嘿,我只是试过这个,并得到一个错误:'AttributeError:'AxesSubplot'对象没有'canvas''属性 – Rich

+0

这是唯一的答案,这对我来说,特别是使用'f.canvas.manager.window。移动()'。语法也是最简单的。 – Anonymous