Skip to content Skip to sidebar Skip to footer

Prevent Data Overlap Between Two Sliders - Use A Single Slider For Two Quantities

I am using 2 sliders to adjust the colorbar of a 2D heat map; one for the bottom (minimum) and one for the top (maximum). I want to make sure that the two cannot overlap i.e. if th

Solution 1:

In some cases it may indeed be desired to have one single Slider which can set some minimum and maximum simultaneously. So instead of having one single value, the slider could have two values and the rectangle inside the slider would be bounded by the two values, instead of starting at the minimum value of the slider.

The following would be solution to such a case. It uses a MinMaxSlider, i.e. a subclass of the Slider which is adapted to host two values.
Instead of a single input value, it would expect two values,

MinMaxSlider(... , valinit=0.5,valinit2=0.8)

such that the Sliderbar ranges from 0.5 to 0.8. Clicking on the slider would change the value which is closer to the click, making dragging rather easy.

In order to use this slider be aware that the function that the callback via on_changed now naturally has two arguments.

import six
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

class MinMaxSlider(Slider):
    def __init__(self,ax, label, valmin, valmax, **kwargs):
        self.valinit2 = kwargs.pop("valinit2", valmax)
        self.val2 = self.valinit2
        Slider.__init__(self,ax, label, valmin, valmax, **kwargs)
        self.poly.xy = np.array([[self.valinit,0],[self.valinit,1],
                        [self.valinit2,1],[self.valinit2,0]])
        self.vline.set_visible(False)

    def set_val(self, val):
        if np.abs(val-self.val) < np.abs(val-self.val2):
            self.val = val
        else:
            self.val2 = val
        self.poly.xy = np.array([[self.val,0],[self.val,1],
                                 [self.val2,1],[self.val2,0]])
        self.valtext.set_text(self.valfmt % self.val +"\n"+self.valfmt % self.val2)
        if self.drawon:
            self.ax.figure.canvas.draw_idle()
        if not self.eventson:
            return
        for cid, func in six.iteritems(self.observers):
            func(self.val,self.val2)


import numpy as np

x = np.linspace(0,16,1001)
f = lambda x: np.sin(x)*np.sin(1.7*x+2)*np.sin(0.7*x+0.05)*x

fig,(ax, sliderax) = plt.subplots(nrows=2,gridspec_kw={"height_ratios":[1,0.05]})
fig.subplots_adjust(hspace=0.3)

ax.plot(x,f(x))

slider = MinMaxSlider(sliderax,"slider",x.min(),x.max(),
                      valinit=x.min(),valinit2=x.max())

def update(mini,maxi):
    ax.set_xlim(mini,maxi)

slider.on_changed(update)
update(x.min(),x.max())

plt.show()

enter image description here


Post a Comment for "Prevent Data Overlap Between Two Sliders - Use A Single Slider For Two Quantities"