Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a RangeSlider widget #18829

Merged
merged 3 commits into from Dec 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/users/next_whats_new/range_slider.rst
@@ -0,0 +1,4 @@
New RangeSlider widget
----------------------
`.widgets.RangeSlider` allows for creating a slider that defines
a range rather than a single value.
68 changes: 68 additions & 0 deletions examples/widgets/range_slider.py
@@ -0,0 +1,68 @@
"""
======================================
Thresholding an Image with RangeSlider
======================================

Using the RangeSlider widget to control the thresholding of an image.

The RangeSlider widget can be used similarly to the `.widgets.Slider`
widget. The major difference is that RangeSlider's ``val`` attribute
is a tuple of floats ``(lower val, upper val)`` rather than a single float.
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import RangeSlider

# generate a fake image
np.random.seed(19680801)
N = 128
img = np.random.randn(N, N)

fig, axs = plt.subplots(1, 2, figsize=(10, 5))
plt.subplots_adjust(bottom=0.25)

im = axs[0].imshow(img)
axs[1].hist(img.flatten(), bins='auto')
axs[1].set_title('Histogram of pixel intensities')

# Create the RangeSlider
slider_ax = plt.axes([0.20, 0.1, 0.60, 0.03])
slider = RangeSlider(slider_ax, "Threshold", img.min(), img.max())

# Create the Vertical lines on the histogram
lower_limit_line = axs[1].axvline(slider.val[0], color='k')
upper_limit_line = axs[1].axvline(slider.val[1], color='k')


def update(val):
# The val passed to a callback by the RangeSlider will
# be a tuple of (min, max)

# Update the image's colormap
im.norm.vmin = val[0]
im.norm.vmax = val[1]

# Update the position of the vertical lines
lower_limit_line.set_xdata([val[0], val[0]])
upper_limit_line.set_xdata([val[1], val[1]])

# Redraw the figure to ensure it updates
fig.canvas.draw_idle()


slider.on_changed(update)
plt.show()

#############################################################################
#
# ------------
#
# References
# """"""""""
#
# The use of the following functions, methods, classes and modules is shown
# in this example:

import matplotlib
matplotlib.widgets.RangeSlider
27 changes: 27 additions & 0 deletions lib/matplotlib/tests/test_widgets.py
Expand Up @@ -298,6 +298,33 @@ def test_slider_horizontal_vertical():
assert_allclose(box.bounds, [0, 0, 1, 10/24])


@pytest.mark.parametrize("orientation", ["horizontal", "vertical"])
def test_range_slider(orientation):
if orientation == "vertical":
idx = [1, 0, 3, 2]
else:
idx = [0, 1, 2, 3]

fig, ax = plt.subplots()

slider = widgets.RangeSlider(
ax=ax, label="", valmin=0.0, valmax=1.0, orientation=orientation
)
box = slider.poly.get_extents().transformed(ax.transAxes.inverted())
assert_allclose(box.get_points().flatten()[idx], [0.25, 0, 0.75, 1])

slider.set_val((0.2, 0.6))
assert_allclose(slider.val, (0.2, 0.6))
box = slider.poly.get_extents().transformed(ax.transAxes.inverted())
assert_allclose(box.get_points().flatten()[idx], [0.2, 0, 0.6, 1])

slider.set_val((0.2, 0.1))
assert_allclose(slider.val, (0.1, 0.2))

slider.set_val((-1, 10))
assert_allclose(slider.val, (0, 1))


def check_polygon_selector(event_sequence, expected_result, selections_count):
"""
Helper function to test Polygon Selector.
Expand Down