【问题标题】:How do you set the absolute position of figure windows with matplotlib?matplotlib如何设置图形窗口的绝对位置?
【发布时间】:2011-11-18 23:01:31
【问题描述】:

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

我相信已经找到了允许我调整图形窗口大小(以像素为单位)的 API,但在找到一种方法来设置它们在屏幕上的绝对位置方面没有任何成功。有没有办法做到这一点,而无需深入研究正在使用的任何后端的细节?我想以与后端无关的方式执行此操作,这样我就可以避免依赖将来可能会更改的实现细节。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    终于找到了 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 宽度,可以先读出它们,如下所示:

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

    然后将新位置设置为相同大小:

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

    我经常搜索这个,最后花了 30 分钟才找到这个。希望对某人有所帮助。

    【讨论】:

    • 注意,我们也可以使用 fig.canvas.manager 代替 mngr = get_current_fig_manager()
    • 首先,fig, ax = subplots() 不起作用。它必须是fig, ax = plt.subplots()。然后,在mngr.window.setGeometry() 上,我得到“# AttributeError: SetPosition”。
    • 首先,感谢代码中错误的友好指针。其次,我不明白属性“setGeometry()”的使用如何导致提到 SetPosition 的属性错误。可能,您的 PyQT 没有作为后端激活。尝试ipython --pylab=pyqt5 以确保 pyqt 处于活动状态。
    • 在 Pycharm 我得到AttributeError: '_tkinter.tkapp' object has no attribute 'setGeometry'
    • 另一个注意事项:这将定位图形区域本身,标题栏和边框(由操作系统提供)是额外的。在默认设置的 Windows 10 上,这是一个 30 像素的标题栏和 1 像素的边框,因此您的窗口将是 newX + 2 宽和 newY + 32 高,并且可能部分位于屏幕之外。
    【解决方案2】:

    在迄今为止的答案的帮助和我自己的一些修补下,这里有一个检查当前后端并使用正确语法的解决方案。

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

    【讨论】:

    • 嘿,我刚试了一下,报错:AttributeError: 'AxesSubplot' object has no attribute 'canvas'
    • 这是唯一适合我的答案,特别是使用f.canvas.manager.window.move()。语法也是最简单的。
    • 很好,但是将 plt.show 移到函数之外,因为它会阻塞。你可能想要这个的主要原因是当你有很多数字时!
    • @supergra 感谢您的提示,我编辑了...我总是在交互模式下运行 pyplot,所以它不会阻止我,但没有理由不进行更改
    • 好提示。我将此添加到我的 ipython 启动脚本中。还在move_figure 函数中添加了if isinstance(f,int) : f = plt.figure(f),因此它适用于数字或对象。 (即move_figure(1,500,500)
    【解决方案3】:

    我不知道有一种与后端无关的方法来做到这一点,但对于一些常见的后端来说绝对可以做到这一点,例如 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")
    

    所以我认为你可以通过所有能够做到这一点的后端,如果不能强加某个后端的话。

    【讨论】:

    • 谢谢。我在我的系统上使用 TKAgg,但我认为我不能假设最终用户会这样做。不过,我也许可以强制用户必须使用其中的某个子集。
    • 不知道为什么,但对我来说(Windows、Python Idle、Python 2.7,从 Notepad++ 开始)thismanager.window.wm_geometry("+500+0") 有效,thismanager.window.SetPosition((500, 0)) 没有 ;-)
    • 尝试两种解决方案,我得到'MainWindow' object has no attribute 'SetPosition''MainWindow' has no attribute 'wm_geometry'
    • 我复制粘贴了您的代码,但出现以下错误:1) 在plt.use("wx") 上,我得到“AttributeError: 'module' object has no attribute 'use'”2) 在mngr.window.SetPosition() ,我得到“#AttributeError:SetPosition”。 (我运行 PY 版本 2.7)
    • 上述评论的更正:我在matplotlib.use("wx") 上收到以下错误:“AttributeError: 'module' object has no attribute 'use'”。那么mngr.window.SetPosition()当然就不行了。
    【解决方案4】:

    对于 Qt4Agg,这对我有用。

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

    在Win7上测试,mpl版本1.4.2,python 2.7.5

    【讨论】:

      【解决方案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")
      

      【讨论】:

      • 如何添加中间选项?
      【解决方案6】:

      这也有效:

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

      【讨论】:

      • m 中的小move
      • 结合前面的两个 cmets:至少在使用 Qt 后端(Qt4Agg,可能还有 Qt5Agg)时,调整大小的正确命令是 fig.canvas.manager.window.move(100,400)。 GTK3Agg 似乎也是如此,所以我会编辑这个答案。
      【解决方案7】:
      '''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)
      

      【讨论】:

        【解决方案8】:

        以下内容对我有用。

        import matplotlib  
        matplotlib.use("TkAgg") # set the backend  
        
        if backend == 'TkAgg':  
            f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
        

        【讨论】:

        • 以这个答案为基础: mngr = plt.get_current_fig_manager() mngr.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
        【解决方案9】:

        对于 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')
        

        【讨论】:

          【解决方案10】:
          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()
          

          【讨论】:

            【解决方案11】:

            如何定义一个函数将窗口提升到顶层并将其移向左上角(例如),如下所示:

            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 使其始终可用?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-11-26
              • 1970-01-01
              • 2015-04-05
              • 2012-12-27
              • 1970-01-01
              • 2011-03-18
              相关资源
              最近更新 更多