Matplotlib:用鼠标绘制矩形形状的选择区域

11

我想在matplotlib图中使用鼠标事件绘制选择区域。但是我没有找到关于如何使用Python实现的信息。

最终,我希望能够在使用matplotlib basemap创建的地图上使用鼠标绘制感兴趣的区域,并检索角落坐标。

有人有想法、示例或参考资料吗?

谢谢,

Greg

class Annotate(object):
  def __init__(self):
      self.ax = plt.gca()
      self.rect = Rectangle((0,0), 1, 1, facecolor='None', edgecolor='green')
      self.x0 = None
      self.y0 = None
      self.x1 = None
      self.y1 = None
      self.ax.add_patch(self.rect)
      self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
      self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release)
      self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
  def on_press(self, event):
      print 'press'
      self.x0 = event.xdata
      self.y0 = event.ydata    
      self.x1 = event.xdata
      self.y1 = event.ydata
      self.rect.set_width(self.x1 - self.x0)
      self.rect.set_height(self.y1 - self.y0)
      self.rect.set_xy((self.x0, self.y0))
      self.rect.set_linestyle('dashed')
      self.ax.figure.canvas.draw()
  def on_motion(self,event):
      if self.on_press is True:
          return
      self.x1 = event.xdata
      self.y1 = event.ydata
      self.rect.set_width(self.x1 - self.x0)
      self.rect.set_height(self.y1 - self.y0)
      self.rect.set_xy((self.x0, self.y0))
      self.rect.set_linestyle('dashed')
      self.ax.figure.canvas.draw()
  def on_release(self, event):
      print 'release'
      self.x1 = event.xdata
      self.y1 = event.ydata
      self.rect.set_width(self.x1 - self.x0)
      self.rect.set_height(self.y1 - self.y0)
      self.rect.set_xy((self.x0, self.y0))
      self.rect.set_linestyle('solid')
      self.ax.figure.canvas.draw()
      print self.x0,self.x1,self.y0,self.y1
      return [self.x0,self.x1,self.y0,self.y1]
2个回答

19

这是一个小例子,展示了如何使用鼠标在matplotlib图形上绘制矩形。

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

class Annotate(object):
    def __init__(self):
        self.ax = plt.gca()
        self.rect = Rectangle((0,0), 1, 1)
        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.ax.add_patch(self.rect)
        self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release)

    def on_press(self, event):
        print 'press'
        self.x0 = event.xdata
        self.y0 = event.ydata

    def on_release(self, event):
        print 'release'
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.ax.figure.canvas.draw()

a = Annotate()
plt.show()

谢谢,这正是我想要的!你知道我可以怎么做来在 on_press 事件期间显示正在绘制的矩形吗?还有可能将颜色设置为透明浅灰色吗?非常感谢。 - leroygr
2
如果您想在移动鼠标时更新绘图,则需要添加以下代码:self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion),并定义一个名为on_motion的方法来实现您想要的功能。请参见http://matplotlib.sourceforge.net/examples/event_handling/index.html。要查看可以编辑的矩形属性,请参见http://matplotlib.sourceforge.net/api/artist_api.html?highlight=rectangle#matplotlib.patches.Rectangle。 - ChrisB
我差不多成功了!但是我仍然有一个问题:矩形是在移动时绘制的,但我希望它在on_press+on_motion事件期间绘制。请查看原始问题中的新代码。谢谢。 - leroygr
1
在 on_press 中将一个布尔型变量 is_pressed 设置为 true,在 on_release 中将其设置为 false,并且只有当 self.is_pressed == True 时才绘制矩形(请注意,测试 self.on_press 是否为真是没有意义的,因为您正在测试方法是否为 true)。 - ChrisB
@ChrisB,感谢您的回答,mpl_connect机制对我来说更加清晰了。 - Tong
@ChrisB 有没有想法如何在同一张图上绘制多个矩形? - Hakim

6

Matplotlib提供了自己的RectangleSelector。在matplotlib页面上有一个示例,您可以根据需要进行调整。

一个简化版本可能如下所示:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets  import RectangleSelector

xdata = np.linspace(0,9*np.pi, num=301)
ydata = np.sin(xdata)

fig, ax = plt.subplots()
line, = ax.plot(xdata, ydata)


def line_select_callback(eclick, erelease):
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata

    rect = plt.Rectangle( (min(x1,x2),min(y1,y2)), np.abs(x1-x2), np.abs(y1-y2) )
    ax.add_patch(rect)


rs = RectangleSelector(ax, line_select_callback,
                       drawtype='box', useblit=False, button=[1], 
                       minspanx=5, minspany=5, spancoords='pixels', 
                       interactive=True)

plt.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接