Matplotlib: draw a selection area in the shape of a rectangle with the mouse
21,151
Solution 1
Matplotlib provides its own RectangleSelector
. There is an example on the matplotlib page, which you may adapt to your needs.
A simplified version would look something like this:
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()
Solution 2
Here's a small example that shows how to use the mouse to draw a rectangle on a matplotlib plot.
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()
Author by
leroygr
Updated on May 31, 2020Comments
-
leroygr about 4 years
I want to be able to draw a selection area on a matplotlib plot with a mouse event. I didn't find information on how to do it with python.
In the end, I want to be able to draw a region of interest with my mouse on a map created with matplotlib basemap and retrieve the corner coordinates.
Anyone has an idea, example, references?
Thanks,
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]
-
leroygr almost 12 yearsThanks, that's exactly what I wanted! And do you know what I can do to show the rectangle being drawed during the on_press event? Is it also possible to set the colors to transparent light grey? Thanks a lot
-
ChrisB almost 12 yearsIf you want to update the drawing as you move the mouse, you want to add the line
self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
and define a method on_motion that does what you want. See matplotlib.sourceforge.net/examples/event_handling/index.html. To see what rectangle properties you can edit, see matplotlib.sourceforge.net/api/… -
leroygr almost 12 yearsI almost succeed! But I still have an issue: the rectangle is drawn on move but I want it to be drawn during on_press+on_motion events. See my new code in the original question. Thanks.
-
ChrisB almost 12 yearsSet a boolean is_pressed attribute to true within on_press, set it to false in on_release, and only draw the rectangle if self.is_pressed == True (note your test to if self.on_press doesn't make sense, because you're testing whether a method is True)
-
Tong about 9 years@ChrisB, thanks to your answer, the mpl_connect mechanism is much more clearer for me.
-
Hakim almost 8 years@ChrisB any idea how to make multiple rectangles drawn on the same figure ?