From a4694a017e3d390465058678e395f2fda34c2632 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Wed, 22 Feb 2017 21:37:52 -0500 Subject: [PATCH 01/10] DOC: numpydoc-ify widget.Slider. --- lib/matplotlib/widgets.py | 92 ++++++++++++++------------------------- 1 file changed, 33 insertions(+), 59 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 68ef8310294c..8dace616ade5 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -266,36 +266,8 @@ class Slider(AxesWidget): """ A slider representing a floating point range. - For the slider to remain responsive you must maintain a - reference to it. - - The following attributes are defined - *ax* : the slider :class:`matplotlib.axes.Axes` instance - - *val* : the current slider value - - *vline* : a :class:`matplotlib.lines.Line2D` instance - representing the initial value of the slider - - *poly* : A :class:`matplotlib.patches.Polygon` instance - which is the slider knob - - *valfmt* : the format string for formatting the slider text - - *label* : a :class:`matplotlib.text.Text` instance - for the slider label - - *closedmin* : whether the slider is closed on the minimum - - *closedmax* : whether the slider is closed on the maximum - - *slidermin* : another slider - if not *None*, this slider must be - greater than *slidermin* - - *slidermax* : another slider - if not *None*, this slider must be - less than *slidermax* - - *dragging* : allow for mouse dragging on slider + Create a slider from *valmin* to *valmax* in axes *ax*. For the slider to + remain responsive you must maintain a reference to it. Call :meth:`on_changed` to connect to the slider event """ @@ -303,54 +275,56 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', closedmin=True, closedmax=True, slidermin=None, slidermax=None, dragging=True, **kwargs): """ - Create a slider from *valmin* to *valmax* in axes *ax*. - - Additional kwargs are passed on to ``self.poly`` which is the - :class:`matplotlib.patches.Rectangle` that draws the slider - knob. See the :class:`matplotlib.patches.Rectangle` documentation for - valid property names (e.g., *facecolor*, *edgecolor*, *alpha*, ...). - Parameters ---------- ax : Axes - The Axes to put the slider in + The Axes to put the slider in. label : str - Slider label + Slider label. valmin : float - The minimum value of the slider + The minimum value of the slider. valmax : float - The maximum value of the slider - - valinit : float - The slider initial position + The maximum value of the slider. - label : str - The slider label + valinit : float, optional + The slider initial position. + Default: 0.5 - valfmt : str - Used to format the slider value, fprint format string + valfmt : str, optional + Used to format the slider value, fprint format string. + Default: '%1.2f' - closedmin : bool - Indicate whether the slider interval is closed on the bottom + closedmin : bool, optional + Indicate whether the slider interval is closed on the bottom. + Default: True - closedmax : bool - Indicate whether the slider interval is closed on the top + closedmax : bool, optional + Indicate whether the slider interval is closed on the top. + Default: True - slidermin : Slider or None + slidermin : Slider, optional Do not allow the current slider to have a value less than - `slidermin` + `slidermin.val`. + Default: None - slidermax : Slider or None + slidermax : Slider, optional Do not allow the current slider to have a value greater than - `slidermax` + `slidermax.val`. + Default: None + dragging : bool, optional + If True the slider can be dragged by the mouse. + Default: True - dragging : bool - if the slider can be dragged by the mouse - + Notes + ---------- + Additional kwargs are passed on to ``self.poly`` which is the + :class:`matplotlib.patches.Rectangle` that draws the slider + knob. See the :class:`matplotlib.patches.Rectangle` documentation for + valid property names (e.g., *facecolor*, *edgecolor*, *alpha*, ...). """ AxesWidget.__init__(self, ax) From 36ad9461f6783b201d8fd8e310505808cf3c45dd Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Wed, 22 Feb 2017 22:25:10 -0500 Subject: [PATCH 02/10] Raise ValueError if slidermin/max incompatible. --- lib/matplotlib/widgets.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 8dace616ade5..46de62a2b5ac 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -328,6 +328,13 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', """ AxesWidget.__init__(self, ax) + if slidermin is not None and not hasattr(slidermin, 'val'): + raise ValueError("Argument slidermin ({}) has no 'val'" + .format(type(slidermin))) + if slidermax is not None and not hasattr(slidermax, 'val'): + raise ValueError("Argument slidermax ({}) has no 'val'" + .format(type(slidermax))) + self.valmin = valmin self.valmax = valmax self.val = valinit From f59028e32336142aace3476bf0e53e7bde6a96d8 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Wed, 22 Feb 2017 23:19:39 -0500 Subject: [PATCH 03/10] Dry out bounds checking for reuse. --- lib/matplotlib/widgets.py | 47 +++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 46de62a2b5ac..4f5d2fb68571 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -370,6 +370,29 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', self.slidermin = slidermin self.slidermax = slidermax self.drag_active = False + self._value_in_bounds(valinit) + + def _value_in_bounds(self, val): + """ Makes sure self.val is with given bounds.""" + if val <= self.valmin: + if not self.closedmin: + return + val = self.valmin + elif val >= self.valmax: + if not self.closedmax: + return + val = self.valmax + + if self.slidermin is not None and val <= self.slidermin.val: + if not self.closedmin: + return + val = self.slidermin.val + + if self.slidermax is not None and val >= self.slidermax.val: + if not self.closedmax: + return + val = self.slidermax.val + self.set_val(val) def _update(self, event): """update the slider position""" @@ -392,29 +415,9 @@ def _update(self, event): self.drag_active = False event.canvas.release_mouse(self.ax) return - val = event.xdata - if val <= self.valmin: - if not self.closedmin: - return - val = self.valmin - elif val >= self.valmax: - if not self.closedmax: - return - val = self.valmax - - if self.slidermin is not None and val <= self.slidermin.val: - if not self.closedmin: - return - val = self.slidermin.val - - if self.slidermax is not None and val >= self.slidermax.val: - if not self.closedmax: - return - val = self.slidermax.val - - self.set_val(val) - + self._value_in_bounds(val) + def set_val(self, val): xy = self.poly.xy xy[2] = val, 1 From 9f4258b456a49f463f87ac05a44fd1cbbeb10c5c Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Thu, 23 Feb 2017 00:04:59 -0500 Subject: [PATCH 04/10] Lint: tabs to spaces. --- lib/matplotlib/widgets.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 4f5d2fb68571..d21aa95e853b 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -291,11 +291,11 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', valinit : float, optional The slider initial position. - Default: 0.5 + Default: 0.5 valfmt : str, optional Used to format the slider value, fprint format string. - Default: '%1.2f' + Default: '%1.2f' closedmin : bool, optional Indicate whether the slider interval is closed on the bottom. @@ -370,11 +370,11 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', self.slidermin = slidermin self.slidermax = slidermax self.drag_active = False - self._value_in_bounds(valinit) + self._value_in_bounds(valinit) def _value_in_bounds(self, val): """ Makes sure self.val is with given bounds.""" - if val <= self.valmin: + if val <= self.valmin: if not self.closedmin: return val = self.valmin @@ -416,8 +416,8 @@ def _update(self, event): event.canvas.release_mouse(self.ax) return val = event.xdata - self._value_in_bounds(val) - + self._value_in_bounds(val) + def set_val(self, val): xy = self.poly.xy xy[2] = val, 1 From ffba7d9925c6d81d7a3a1914e825e803bd51dc46 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Wed, 22 Feb 2017 23:10:09 -0500 Subject: [PATCH 05/10] Tests for widgets.Slider. --- lib/matplotlib/tests/test_widgets.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index e8b7d8aebc7e..99c85b600978 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -13,6 +13,8 @@ from numpy.testing import assert_allclose +import pytest + def get_ax(): fig, ax = plt.subplots(1, 1) @@ -275,3 +277,28 @@ def test_check_radio_buttons_image(): widgets.RadioButtons(rax1, ('Radio 1', 'Radio 2', 'Radio 3')) widgets.CheckButtons(rax2, ('Check 1', 'Check 2', 'Check 3'), (False, True, True)) + + +def test_slider_slidermin_slidermax_invalid(): + fig, ax = plt.subplots() + # test min/max with floats + with pytest.raises(ValueError): + widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + slidermin=10.0) + with pytest.raises(ValueError): + widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + slidermax=10.0) + + +def test_slider_slidermin_slidermax(): + fig, ax = plt.subplots() + slider_ = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=5.0) + + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=1.0, slidermin=slider_) + assert slider.val == slider_.val + + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=10.0, slidermax=slider_) + assert slider.val == slider_.val From 9d3e5e1e5066eaa5071647724f4222b663d35577 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Thu, 23 Feb 2017 13:19:37 -0500 Subject: [PATCH 06/10] Doc nit. --- lib/matplotlib/widgets.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index d21aa95e853b..3b1e07a3f028 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -266,7 +266,7 @@ class Slider(AxesWidget): """ A slider representing a floating point range. - Create a slider from *valmin* to *valmax* in axes *ax*. For the slider to + Create a slider from `valmin` to `valmax` in axes `ax`. For the slider to remain responsive you must maintain a reference to it. Call :meth:`on_changed` to connect to the slider event @@ -290,8 +290,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', The maximum value of the slider. valinit : float, optional - The slider initial position. - Default: 0.5 + The slider initial position. Default: 0.5 valfmt : str, optional Used to format the slider value, fprint format string. @@ -307,24 +306,21 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', slidermin : Slider, optional Do not allow the current slider to have a value less than - `slidermin.val`. - Default: None + the value of the Slider `slidermin`. Default: None slidermax : Slider, optional Do not allow the current slider to have a value greater than - `slidermax.val`. - Default: None + the value of the Slider `slidermax`. Default: None dragging : bool, optional - If True the slider can be dragged by the mouse. - Default: True + If True the slider can be dragged by the mouse. Default: True Notes - ---------- + ----- Additional kwargs are passed on to ``self.poly`` which is the - :class:`matplotlib.patches.Rectangle` that draws the slider - knob. See the :class:`matplotlib.patches.Rectangle` documentation for - valid property names (e.g., *facecolor*, *edgecolor*, *alpha*, ...). + :class:`~matplotlib.patches.Rectangle` that draws the slider + knob. See the :class:`~matplotlib.patches.Rectangle` documentation for + valid property names (e.g., `facecolor`, `edgecolor`, `alpha`). """ AxesWidget.__init__(self, ax) @@ -392,7 +388,7 @@ def _value_in_bounds(self, val): if not self.closedmax: return val = self.slidermax.val - self.set_val(val) + return val def _update(self, event): """update the slider position""" From ea899aaa85e51b430d762a550f7988da993e9a38 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Thu, 23 Feb 2017 13:26:24 -0500 Subject: [PATCH 07/10] Improve test coverage. --- lib/matplotlib/tests/test_widgets.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 99c85b600978..430ce3769ad7 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -302,3 +302,14 @@ def test_slider_slidermin_slidermax(): slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, valinit=10.0, slidermax=slider_) assert slider.val == slider_.val + + +def test_slider_valmin_valmax(): + fig, ax = plt.subplots() + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=-10.0) + assert slider.val == slider.valmin + + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=25.0) + assert slider.val == slider.valmax From dc55f80f31316c48811a82dbe9d1cd4de9cd8338 Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Thu, 23 Feb 2017 14:14:59 -0500 Subject: [PATCH 08/10] Bounds check returns value. --- lib/matplotlib/widgets.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 3b1e07a3f028..7556b84b4a11 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -330,13 +330,17 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', if slidermax is not None and not hasattr(slidermax, 'val'): raise ValueError("Argument slidermax ({}) has no 'val'" .format(type(slidermax))) - + self.closedmin = closedmin + self.closedmax = closedmax + self.slidermin = slidermin + self.slidermax = slidermax + self.drag_active = False self.valmin = valmin self.valmax = valmax + valinit = self._value_in_bounds(valinit) self.val = valinit self.valinit = valinit self.poly = ax.axvspan(valmin, valinit, 0, 1, **kwargs) - self.vline = ax.axvline(valinit, 0, 1, color='r', lw=1) self.valfmt = valfmt @@ -361,12 +365,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', self.cnt = 0 self.observers = {} - self.closedmin = closedmin - self.closedmax = closedmax - self.slidermin = slidermin - self.slidermax = slidermax - self.drag_active = False - self._value_in_bounds(valinit) + self.set_val(valinit) def _value_in_bounds(self, val): """ Makes sure self.val is with given bounds.""" @@ -388,7 +387,7 @@ def _value_in_bounds(self, val): if not self.closedmax: return val = self.slidermax.val - return val + return val def _update(self, event): """update the slider position""" @@ -412,7 +411,7 @@ def _update(self, event): event.canvas.release_mouse(self.ax) return val = event.xdata - self._value_in_bounds(val) + self.set_val(self._value_in_bounds(val)) def set_val(self, val): xy = self.poly.xy From 325789aa2be3eb09fd49a21e7697c2ffb89bebce Mon Sep 17 00:00:00 2001 From: Nelle Varoquaux Date: Fri, 24 Feb 2017 14:40:34 -0800 Subject: [PATCH 09/10] FIX nitpicks on docstring --- lib/matplotlib/widgets.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 7556b84b4a11..e5ff63b4f578 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -289,31 +289,28 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', valmax : float The maximum value of the slider. - valinit : float, optional - The slider initial position. Default: 0.5 + valinit : float, optional, default: 0.5 + The slider initial position. - valfmt : str, optional + valfmt : str, optional, default: "%1.2f" Used to format the slider value, fprint format string. - Default: '%1.2f' - closedmin : bool, optional + closedmin : bool, optional, default: True Indicate whether the slider interval is closed on the bottom. - Default: True - closedmax : bool, optional + closedmax : bool, optional, default: True Indicate whether the slider interval is closed on the top. - Default: True - slidermin : Slider, optional + slidermin : Slider, optional, default: None Do not allow the current slider to have a value less than - the value of the Slider `slidermin`. Default: None + the value of the Slider `slidermin`. - slidermax : Slider, optional + slidermax : Slider, optional, default: None Do not allow the current slider to have a value greater than - the value of the Slider `slidermax`. Default: None + the value of the Slider `slidermax`. - dragging : bool, optional - If True the slider can be dragged by the mouse. Default: True + dragging : bool, optional, default: True + If True the slider can be dragged by the mouse. Notes ----- From 2b4228548c9d45f77dede92db7c20f7e8f6b9a5b Mon Sep 17 00:00:00 2001 From: Heath Henley Date: Fri, 24 Feb 2017 19:56:50 -0500 Subject: [PATCH 10/10] Fix: indent error --- lib/matplotlib/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index e5ff63b4f578..20b6a4429c06 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -384,7 +384,7 @@ def _value_in_bounds(self, val): if not self.closedmax: return val = self.slidermax.val - return val + return val def _update(self, event): """update the slider position"""