diff --git a/doc/api/next_api_changes/deprecations/20601-ES.rst b/doc/api/next_api_changes/deprecations/20601-ES.rst new file mode 100644 index 000000000000..4d30bdd10a1c --- /dev/null +++ b/doc/api/next_api_changes/deprecations/20601-ES.rst @@ -0,0 +1,9 @@ +Selector widget state internals +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Several `~matplotlib.widgets.EllipseSelector`, +`~matplotlib.widgets.RectangleSelector` and `~matplotlib.widgets.SpanSelector` +class internals have been privatized and deprecated: + +- ``eventpress`` +- ``eventrelease`` +- ``state`` diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index e7deb9ad5973..a199e45d4018 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1789,11 +1789,15 @@ def __init__(self, ax, onselect, useblit=False, button=None, self.validButtons = button # will save the data (position at mouseclick) - self.eventpress = None + self._eventpress = None # will save the data (pos. at mouserelease) - self.eventrelease = None + self._eventrelease = None self._prev_event = None - self.state = set() + self._state = set() + + eventpress = _api.deprecate_privatize_attribute("3.5") + eventrelease = _api.deprecate_privatize_attribute("3.5") + state = _api.deprecate_privatize_attribute("3.5") def set_active(self, active): super().set_active(active) @@ -1846,14 +1850,14 @@ def ignore(self, event): return True # If no button was pressed yet ignore the event if it was out # of the axes - if self.eventpress is None: + if self._eventpress is None: return event.inaxes != self.ax # If a button was pressed, check if the release-button is the same. - if event.button == self.eventpress.button: + if event.button == self._eventpress.button: return False # If a button was pressed, check if the release-button is the same. return (event.inaxes != self.ax or - event.button != self.eventpress.button) + event.button != self._eventpress.button) def update(self): """Draw using blit() or draw_idle(), depending on ``self.useblit``.""" @@ -1899,13 +1903,13 @@ def press(self, event): """Button press handler and validator.""" if not self.ignore(event): event = self._clean_event(event) - self.eventpress = event + self._eventpress = event self._prev_event = event key = event.key or '' key = key.replace('ctrl', 'control') # move state is locked in on a button press if key == self.state_modifier_keys['move']: - self.state.add('move') + self._state.add('move') self._press(event) return True return False @@ -1915,13 +1919,13 @@ def _press(self, event): def release(self, event): """Button release event handler and validator.""" - if not self.ignore(event) and self.eventpress: + if not self.ignore(event) and self._eventpress: event = self._clean_event(event) - self.eventrelease = event + self._eventrelease = event self._release(event) - self.eventpress = None - self.eventrelease = None - self.state.discard('move') + self._eventpress = None + self._eventrelease = None + self._state.discard('move') return True return False @@ -1930,7 +1934,7 @@ def _release(self, event): def onmove(self, event): """Cursor move event handler and validator.""" - if not self.ignore(event) and self.eventpress: + if not self.ignore(event) and self._eventpress: event = self._clean_event(event) self._onmove(event) return True @@ -1959,7 +1963,7 @@ def on_key_press(self, event): return for (state, modifier) in self.state_modifier_keys.items(): if modifier in key: - self.state.add(state) + self._state.add(state) self._on_key_press(event) def _on_key_press(self, event): @@ -1971,7 +1975,7 @@ def on_key_release(self, event): key = event.key or '' for (state, modifier) in self.state_modifier_keys.items(): if modifier in key: - self.state.discard(state) + self._state.discard(state) self._on_key_release(event) def _on_key_release(self, event): @@ -2240,9 +2244,9 @@ def _onmove(self, event): v = event.xdata if self.direction == 'horizontal' else event.ydata if self.direction == 'horizontal': - vpress = self.eventpress.xdata + vpress = self._eventpress.xdata else: - vpress = self.eventpress.ydata + vpress = self._eventpress.ydata # move existing span # When "dragging from anywhere", `self._active_handle` is set to 'C' @@ -2290,7 +2294,7 @@ def _set_active_handle(self, event): # Prioritise center handle over other handles # Use 'C' to match the notation used in the RectangleSelector - if 'move' in self.state: + if 'move' in self._state: self._active_handle = 'C' elif e_dist > self.handle_grab_distance: # Not close to any handles @@ -2712,23 +2716,23 @@ def _release(self, event): # update the eventpress and eventrelease with the resulting extents x0, x1, y0, y1 = self.extents - self.eventpress.xdata = x0 - self.eventpress.ydata = y0 + self._eventpress.xdata = x0 + self._eventpress.ydata = y0 xy0 = self.ax.transData.transform([x0, y0]) - self.eventpress.x, self.eventpress.y = xy0 + self._eventpress.x, self._eventpress.y = xy0 - self.eventrelease.xdata = x1 - self.eventrelease.ydata = y1 + self._eventrelease.xdata = x1 + self._eventrelease.ydata = y1 xy1 = self.ax.transData.transform([x1, y1]) - self.eventrelease.x, self.eventrelease.y = xy1 + self._eventrelease.x, self._eventrelease.y = xy1 # calculate dimensions of box or line if self.spancoords == 'data': - spanx = abs(self.eventpress.xdata - self.eventrelease.xdata) - spany = abs(self.eventpress.ydata - self.eventrelease.ydata) + spanx = abs(self._eventpress.xdata - self._eventrelease.xdata) + spany = abs(self._eventpress.ydata - self._eventrelease.ydata) elif self.spancoords == 'pixels': - spanx = abs(self.eventpress.x - self.eventrelease.x) - spany = abs(self.eventpress.y - self.eventrelease.y) + spanx = abs(self._eventpress.x - self._eventrelease.x) + spany = abs(self._eventpress.y - self._eventrelease.y) else: _api.check_in_list(['data', 'pixels'], spancoords=self.spancoords) @@ -2743,7 +2747,7 @@ def _release(self, event): return # call desired function - self.onselect(self.eventpress, self.eventrelease) + self.onselect(self._eventpress, self._eventrelease) self.update() return False @@ -2759,12 +2763,12 @@ def _onmove(self, event): y1 = event.ydata # move existing shape - elif (('move' in self.state or self._active_handle == 'C' or + elif (('move' in self._state or self._active_handle == 'C' or (self.drag_from_anywhere and self._contains(event))) and self._extents_on_press is not None): x0, x1, y0, y1 = self._extents_on_press - dx = event.xdata - self.eventpress.xdata - dy = event.ydata - self.eventpress.ydata + dx = event.xdata - self._eventpress.xdata + dy = event.ydata - self._eventpress.ydata x0 += dx x1 += dx y0 += dy @@ -2772,13 +2776,13 @@ def _onmove(self, event): # new shape else: - center = [self.eventpress.xdata, self.eventpress.ydata] - center_pix = [self.eventpress.x, self.eventpress.y] + center = [self._eventpress.xdata, self._eventpress.ydata] + center_pix = [self._eventpress.x, self._eventpress.y] dx = (event.xdata - center[0]) / 2. dy = (event.ydata - center[1]) / 2. # square shape - if 'square' in self.state: + if 'square' in self._state: dx_pix = abs(event.x - center_pix[0]) dy_pix = abs(event.y - center_pix[1]) if not dx_pix: @@ -2790,7 +2794,7 @@ def _onmove(self, event): dy *= maxd / (abs(dy_pix) + 1e-6) # from center - if 'center' in self.state: + if 'center' in self._state: dx *= 2 dy *= 2 @@ -2891,7 +2895,7 @@ def _set_active_handle(self, event): e_idx, e_dist = self._edge_handles.closest(event.x, event.y) m_idx, m_dist = self._center_handle.closest(event.x, event.y) - if 'move' in self.state: + if 'move' in self._state: self._active_handle = 'C' self._extents_on_press = self.extents # Set active handle as closest handle, if mouse click is close enough. @@ -3204,7 +3208,7 @@ def _remove_vertex(self, i): def _press(self, event): """Button press event handler.""" # Check for selection of a tool handle. - if ((self._polygon_completed or 'move_vertex' in self.state) + if ((self._polygon_completed or 'move_vertex' in self._state) and len(self._xs) > 0): h_idx, h_dist = self._polygon_handles.closest(event.x, event.y) if h_dist < self.vertex_select_radius: @@ -3230,8 +3234,8 @@ def _release(self, event): # Place new vertex. elif (not self._polygon_completed - and 'move_all' not in self.state - and 'move_vertex' not in self.state): + and 'move_all' not in self._state + and 'move_vertex' not in self._state): self._xs.insert(-1, event.xdata) self._ys.insert(-1, event.ydata) @@ -3243,7 +3247,7 @@ def onmove(self, event): # Method overrides _SelectorWidget.onmove because the polygon selector # needs to process the move callback even if there is no button press. # _SelectorWidget.onmove include logic to ignore move event if - # eventpress is None. + # _eventpress is None. if not self.ignore(event): event = self._clean_event(event) self._onmove(event) @@ -3262,16 +3266,16 @@ def _onmove(self, event): self._xs[-1], self._ys[-1] = event.xdata, event.ydata # Move all vertices. - elif 'move_all' in self.state and self.eventpress: - dx = event.xdata - self.eventpress.xdata - dy = event.ydata - self.eventpress.ydata + elif 'move_all' in self._state and self._eventpress: + dx = event.xdata - self._eventpress.xdata + dy = event.ydata - self._eventpress.ydata for k in range(len(self._xs)): self._xs[k] = self._xs_at_press[k] + dx self._ys[k] = self._ys_at_press[k] + dy # Do nothing if completed or waiting for a move. elif (self._polygon_completed - or 'move_vertex' in self.state or 'move_all' in self.state): + or 'move_vertex' in self._state or 'move_all' in self._state): return # Position pending vertex. @@ -3293,7 +3297,8 @@ def _on_key_press(self, event): # Remove the pending vertex if entering the 'move_vertex' or # 'move_all' mode if (not self._polygon_completed - and ('move_vertex' in self.state or 'move_all' in self.state)): + and ('move_vertex' in self._state or + 'move_all' in self._state)): self._xs, self._ys = self._xs[:-1], self._ys[:-1] self._draw_polygon()