matplotlib fixed size when dragging RectangleSelector
Question:
When I click the center of RectangleSelector
and drag it to the edges of axes
, the width or height will be changed (become smaller). This behavior is different from EllipseSelector
whose width and height don’t be changed and can be dragged outside current axes
view. So how can keep RectangleSelector
size when dragging?
Answers:
I don’t know if there is an easier way to fix this behavior, but you could create a custom RectangleSelector
overriding the _onmove
method to make sure the rectangle X position (respectively Y position) is updated only when the width (respectively the height) do not change.
class CustomRectangleSelector(RectangleSelector):
def _onmove(self, event):
# Start bbox
s_x0, s_x1, s_y0, s_y1 = self.extents
start_width = np.float16(s_x1 - s_x0)
start_height = np.float16(s_y1 - s_y0)
super()._onmove(event)
# Custom behavior only if selector is moving
if not self._active_handle == 'C':
return
# End bbox
e_x0, e_x1, e_y0, e_y1 = self.extents
end_width = np.float16(e_x1 - e_x0)
end_height = np.float16(e_y1 - e_y0)
if start_width != end_width:
e_x0, e_x1 = s_x0, s_x1
if start_height != end_height:
e_y0, e_y1 = s_y0, s_y1
self.extents = e_x0, e_x1, e_y0, e_y1
Thanks to @thmslmr. I finally achieved the goal by override _draw_shape
.
class CustomRectangleSelector(RectangleSelector):
def _draw_shape(self, extents):
x0, x1, y0, y1 = extents
xmin, xmax = sorted([x0, x1])
ymin, ymax = sorted([y0, y1])
# DO NOT apply the xy limits
#xlim = sorted(self.ax.get_xlim())
#ylim = sorted(self.ax.get_ylim())
#xmin = max(xlim[0], xmin)
#ymin = max(ylim[0], ymin)
#xmax = min(xmax, xlim[1])
#ymax = min(ymax, ylim[1])
self._selection_artist.set_x(xmin)
self._selection_artist.set_y(ymin)
self._selection_artist.set_width(xmax - xmin)
self._selection_artist.set_height(ymax - ymin)
self._selection_artist.set_angle(self.rotation)
When I click the center of RectangleSelector
and drag it to the edges of axes
, the width or height will be changed (become smaller). This behavior is different from EllipseSelector
whose width and height don’t be changed and can be dragged outside current axes
view. So how can keep RectangleSelector
size when dragging?
I don’t know if there is an easier way to fix this behavior, but you could create a custom RectangleSelector
overriding the _onmove
method to make sure the rectangle X position (respectively Y position) is updated only when the width (respectively the height) do not change.
class CustomRectangleSelector(RectangleSelector):
def _onmove(self, event):
# Start bbox
s_x0, s_x1, s_y0, s_y1 = self.extents
start_width = np.float16(s_x1 - s_x0)
start_height = np.float16(s_y1 - s_y0)
super()._onmove(event)
# Custom behavior only if selector is moving
if not self._active_handle == 'C':
return
# End bbox
e_x0, e_x1, e_y0, e_y1 = self.extents
end_width = np.float16(e_x1 - e_x0)
end_height = np.float16(e_y1 - e_y0)
if start_width != end_width:
e_x0, e_x1 = s_x0, s_x1
if start_height != end_height:
e_y0, e_y1 = s_y0, s_y1
self.extents = e_x0, e_x1, e_y0, e_y1
Thanks to @thmslmr. I finally achieved the goal by override _draw_shape
.
class CustomRectangleSelector(RectangleSelector):
def _draw_shape(self, extents):
x0, x1, y0, y1 = extents
xmin, xmax = sorted([x0, x1])
ymin, ymax = sorted([y0, y1])
# DO NOT apply the xy limits
#xlim = sorted(self.ax.get_xlim())
#ylim = sorted(self.ax.get_ylim())
#xmin = max(xlim[0], xmin)
#ymin = max(ylim[0], ymin)
#xmax = min(xmax, xlim[1])
#ymax = min(ymax, ylim[1])
self._selection_artist.set_x(xmin)
self._selection_artist.set_y(ymin)
self._selection_artist.set_width(xmax - xmin)
self._selection_artist.set_height(ymax - ymin)
self._selection_artist.set_angle(self.rotation)