From a0d25af903c8dcb6b329042212cf900f553fa714 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 27 Feb 2023 19:54:32 -0500 Subject: [PATCH] Fix RangeSlider.set_val when outside existing value The clipping in the setter ensures that min <= max, but if you are setting both values outside the existing range, this will incorrectly set new minimum to old maximum and vice versa. The tests also passed accidentally because all the new ranges overlapped with the old, and did not trigger this issue. Fixes #25338 --- lib/matplotlib/tests/test_widgets.py | 8 ++++---- lib/matplotlib/widgets.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 92b87a96b3d2..5706df46e328 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -1297,12 +1297,12 @@ def handle_positions(slider): else: return [h.get_xdata()[0] for h in slider._handles] - slider.set_val((0.2, 0.6)) - assert_allclose(slider.val, (0.2, 0.6)) - assert_allclose(handle_positions(slider), (0.2, 0.6)) + slider.set_val((0.4, 0.6)) + assert_allclose(slider.val, (0.4, 0.6)) + assert_allclose(handle_positions(slider), (0.4, 0.6)) box = slider.poly.get_extents().transformed(ax.transAxes.inverted()) - assert_allclose(box.get_points().flatten()[idx], [0.2, .25, 0.6, .75]) + assert_allclose(box.get_points().flatten()[idx], [0.4, .25, 0.6, .75]) slider.set_val((0.2, 0.1)) assert_allclose(slider.val, (0.1, 0.2)) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index eb4b97da279f..c25644dbe6b8 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -702,7 +702,7 @@ def __init__( valmin, valmax, valfmt, dragging, valstep) # Set a value to allow _value_in_bounds() to work. - self.val = [valmin, valmax] + self.val = (valmin, valmax) if valinit is None: # Place at the 25th and 75th percentiles extent = valmax - valmin @@ -947,9 +947,9 @@ def set_val(self, val): """ val = np.sort(val) _api.check_shape((2,), val=val) - vmin, vmax = val - vmin = self._min_in_bounds(vmin) - vmax = self._max_in_bounds(vmax) + # Reset value to allow _value_in_bounds() to work. + self.val = (self.valmin, self.valmax) + vmin, vmax = self._value_in_bounds(val) self._update_selection_poly(vmin, vmax) if self.orientation == "vertical": self._handles[0].set_ydata([vmin])