Matplotlib: нарисуйте область выделения в форме прямоугольника с помощью мыши

Я хочу иметь возможность рисовать область выбора на графике matplotlib с помощью события мыши. Я не нашел информации о том, как это сделать с помощью python.

В конце концов, я хочу иметь возможность рисовать интересующую область с помощью мыши на карте, созданной с помощью базовой карты matplotlib, и получать угловые координаты.

У кого-нибудь есть идея, например, ссылки?

Спасибо,

Грег

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]

person leroygr    schedule 21.08.2012    source источник


Ответы (2)


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()
person ImportanceOfBeingErnest    schedule 31.05.2017

Вот небольшой пример, который показывает, как использовать мышь для рисования прямоугольника на графике 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()
person ChrisB    schedule 21.08.2012
comment
Спасибо, это именно то, что я хотел! И знаете ли вы, что я могу сделать, чтобы показать, что прямоугольник рисуется во время события on_press? Можно ли также установить цвета на прозрачный светло-серый? Большое спасибо - person leroygr; 22.08.2012
comment
Если вы хотите обновлять рисунок при перемещении мыши, вам нужно добавить строку self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) и определить метод on_motion, который делает то, что вы хотите. См. matplotlib.sourceforge.net/examples/event_handling/index.html. Чтобы узнать, какие свойства прямоугольника вы можете редактировать, см. matplotlib. sourceforge.net/api/ - person ChrisB; 22.08.2012
comment
У меня почти получается! Но у меня все еще есть проблема: прямоугольник рисуется при перемещении, но я хочу, чтобы он рисовался во время событий on_press+on_motion. Смотрите мой новый код в исходном вопросе. Спасибо. - person leroygr; 31.08.2012
comment
Установите для логического атрибута is_pressed значение true в on_press, установите для него значение false в on_release и рисуйте прямоугольник только в том случае, если self.is_pressed == True (обратите внимание на то, что ваш тест if self.on_press не имеет смысла, потому что вы проверяете, метод верный) - person ChrisB; 31.08.2012
comment
@ChrisB, благодаря вашему ответу механизм mpl_connect стал для меня намного понятнее. - person Tong; 21.05.2015
comment
@ChrisB есть идеи, как сделать несколько прямоугольников, нарисованных на одной фигуре? - person Hakim; 26.07.2016