Using RangeSliders

In [ ]:
%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np

from mpl_interactions import ipyplot as iplt

How to automatically generate a RangeSlider

In order to createa a RangeSlider rather than a Slider you prefix the tuples with either "r" or "range", then the rest of the tuple is created according to the rules from converting tuples to sliders. So arrays will remain arrays, or the values will be passed through to np.linspace as approriate.

# passed through to np.linspace
("range", min, max, [step]) 
("r", min, max, [step])

# array used directly
("range", np.array)
("r", np.array)

then function can use them the same as any other kwargs, except now they are tuples rather than just numbers.

In [ ]:
def f_x(xrange, **kwargs):
    return np.linspace(xrange[0], xrange[1], 1000)


def f_y(x, tau, **kwargs):
    return np.sin(x * tau)


fig, ax = plt.subplots()
controls = iplt.plot(f_x, f_y, xrange=("r", -1, 3), tau=(5, 10))

Using a RangeSlider for Scalar arguments - Thresholding an Image

There are some arguments, such as vmin and vmax that are both scalar and often make sense to have as two ends of a RangeSlider. For these mpl_interactions treats them as a special case and offers a third argument vmin_vmax that can be used to control both vmin and vmax with a range slider.

Additionally it will also add the vmin and vmax parameters individually to the controls object. This means that they can be used for other things, such as determinging the positions of the vertical lines on the histogram below. These are accessed by indexing the controls object. For more examples of controlling a scalar argument see Scalar Arguments

In [ ]:
N = 128
im = np.random.randn(N * N).reshape(N, N)

fig, axs = plt.subplots(1, 2, figsize=(12, 5))

# plot histogram of pixel intensities
axs[1].hist(im.flatten(), bins="auto")
axs[1].set_title("Histogram of Pixel Intensities")

# create interactive controls
ctrls = iplt.imshow(im, vmin_vmax=("r", im.min(), im.max()), ax=axs[0])
iplt.axvline(ctrls["vmin"], ax=axs[1], c="k")
_ = iplt.axvline(ctrls["vmax"], ax=axs[1], c="k")

Using a Matplotlib RangeSlider

But maptlotlib doesn't have range sliders???!?!?

One of the implicit promises of this library is that it will work equally well both in and out of a jupyter notebook. So it leverages ipywidgets when available but otherwise will use matplotlib widgets. However, ipywidgets has RangeSliders while Matplotlib does not, so have we broken this contract? Happily the answer is no. RangeSliders are being added to matplolibt in https://github.com/matplotlib/matplotlib/pull/18829, and in the meantime they are availiable via mpl_interactions.widgets.RangeSlider

In [ ]:
from mpl_interactions.widgets import RangeSlider

fig, axs = plt.subplots(1, 2, figsize=(12, 5))

# plot histogram of pixel intensities
axs[1].hist(im.flatten(), bins="auto")

# make thresholding slider
plt.subplots_adjust(bottom=0.25)
s_ax = plt.axes([0.575, 0.1, 0.25, 0.05])
slider = RangeSlider(s_ax, "threshold", im.min(), im.max(), valinit=(im.min(), im.max()))

# create interactive controls
ctrls = iplt.imshow(im, vmin_vmax=slider, ax=axs[0])
iplt.axvline(ctrls["vmin"], ax=axs[1], c="k")
iplt.axvline(ctrls["vmax"], ax=axs[1], c="k")
In [ ]: