diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 424466227faa..9ea4cc416173 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -192,6 +192,15 @@ and the title will not be moved via this algorithm. +Adjusted ``matplotlib.widgets.Slider`` to have vertical orientation +------------------------------------------------------------------- + +The :class:`matplotlib.widgets.Slider` widget now takes an optional argument +``orientation`` which indicates the direction (``'horizontal'`` or +``'vertical'``) that the slider should take. + + + New convenience methods for GridSpec ------------------------------------ diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 6eecb4b0c540..1f5b4aaeb0a2 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -319,6 +319,20 @@ def test_slider_valmin_valmax(): assert slider.val == slider.valmax +def test_slider_horizontal_vertical(): + fig, ax = plt.subplots() + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=12.0, orientation='horizontal') + slider.set_val(10.0) + assert slider.val == 10.0 + + fig, ax = plt.subplots() + slider = widgets.Slider(ax=ax, label='', valmin=0.0, valmax=24.0, + valinit=12.0, orientation='vertical') + slider.set_val(10.0) + assert slider.val == 10.0 + + def check_polygon_selector(event_sequence, expected_result, selections_count): """Helper function to test Polygon Selector diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 901287c3bf29..8fe0837c2493 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -268,7 +268,8 @@ class Slider(AxesWidget): """ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', closedmin=True, closedmax=True, slidermin=None, - slidermax=None, dragging=True, valstep=None, **kwargs): + slidermax=None, dragging=True, valstep=None, + orientation='horizontal', **kwargs): """ Parameters ---------- @@ -310,6 +311,9 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', valstep : float, optional, default: None If given, the slider will snap to multiples of `valstep`. + orientation : str, 'horizontal' or 'vertical', default: 'horizontal' + The orientation of the slider. + Notes ----- Additional kwargs are passed on to ``self.poly`` which is the @@ -325,6 +329,11 @@ 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))) + if orientation not in ['horizontal', 'vertical']: + raise ValueError("Argument orientation ({}) must be either" + "'horizontal' or 'vertical'".format(orientation)) + + self.orientation = orientation self.closedmin = closedmin self.closedmax = closedmax self.slidermin = slidermin @@ -338,12 +347,19 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', valinit = valmin 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) + if orientation == 'vertical': + self.poly = ax.axhspan(valmin, valinit, 0, 1, **kwargs) + self.hline = ax.axhline(valinit, 0, 1, color='r', lw=1) + else: + self.poly = ax.axvspan(valmin, valinit, 0, 1, **kwargs) + self.vline = ax.axvline(valinit, 0, 1, color='r', lw=1) self.valfmt = valfmt ax.set_yticks([]) - ax.set_xlim((valmin, valmax)) + if orientation == 'vertical': + ax.set_ylim((valmin, valmax)) + else: + ax.set_xlim((valmin, valmax)) ax.set_xticks([]) ax.set_navigate(False) @@ -351,14 +367,24 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', self.connect_event('button_release_event', self._update) if dragging: self.connect_event('motion_notify_event', self._update) - self.label = ax.text(-0.02, 0.5, label, transform=ax.transAxes, - verticalalignment='center', - horizontalalignment='right') + if orientation == 'vertical': + self.label = ax.text(0.5, 1.02, label, transform=ax.transAxes, + verticalalignment='bottom', + horizontalalignment='center') + + self.valtext = ax.text(0.5, -0.02, valfmt % valinit, + transform=ax.transAxes, + verticalalignment='top', + horizontalalignment='center') + else: + self.label = ax.text(-0.02, 0.5, label, transform=ax.transAxes, + verticalalignment='center', + horizontalalignment='right') - self.valtext = ax.text(1.02, 0.5, valfmt % valinit, - transform=ax.transAxes, - verticalalignment='center', - horizontalalignment='left') + self.valtext = ax.text(1.02, 0.5, valfmt % valinit, + transform=ax.transAxes, + verticalalignment='center', + horizontalalignment='left') self.cnt = 0 self.observers = {} @@ -412,7 +438,10 @@ def _update(self, event): self.drag_active = False event.canvas.release_mouse(self.ax) return - val = self._value_in_bounds(event.xdata) + if self.orientation == 'vertical': + val = self._value_in_bounds(event.ydata) + else: + val = self._value_in_bounds(event.xdata) if val not in [None, self.val]: self.set_val(val) @@ -425,8 +454,12 @@ def set_val(self, val): val : float """ xy = self.poly.xy - xy[2] = val, 1 - xy[3] = val, 0 + if self.orientation == 'vertical': + xy[1] = 0, val + xy[2] = 1, val + else: + xy[2] = val, 1 + xy[3] = val, 0 self.poly.xy = xy self.valtext.set_text(self.valfmt % val) if self.drawon: