防止两个滑块之间的数据重叠 - 使用单个滑块两个量

时间:2017-11-17 14:31:38

标签: python matplotlib slider

我使用2个滑块来调整2D热图的颜色条;一个用于底部(最小),一个用于顶部(最大)。我想确保两者不能重叠,即如果整个范围是0到5并且我将最大值设置为2那么最小值不能超过2.这应该以交互方式发生。我怎样才能做到这一点?另外有没有办法将两个滑块合二为一?谢谢。

GUI的一个例子。以及代码的相关部分:

def update(val, s=None):
    """Retreives the value from the sliders and updates the graph accordingly"""
    _cmin = s_cmin.val
    _cmax = s_cmax.val
    pcm.set_clim([_cmin, _cmax])
    plt.draw()

def reset(event):
    """Resets the sliders when the reset button is pressed"""
    s_cmin.reset()
    s_cmax.reset()

fig, ax = plt.subplots(figsize=(13,8))
plt.subplots_adjust(left=0.25,bottom=0.25)

# define axis minima and maxima:
x_min = Xi.min()
x_max = Xi.max()
y_min = Yi.min()
y_max = Yi.max()
c_min = Zi.min()
c_max = Zi.max()

pcm = ax.pcolormesh(Xi,Yi,Zi)
cb = plt.colorbar(pcm)
axcolor = 'lightgoldenrodyellow'
axx = plt.xlim([x_min, x_max])
ayy = plt.ylim([y_min, y_max])

# create a space in the figure to place the two sliders:
ax_cmin = plt.axes([0.15, 0.10, 0.65, 0.02], facecolor=axcolor)
ax_cmax = plt.axes([0.15, 0.15, 0.65, 0.02], facecolor=axcolor)
# the first argument is the rectangle, with values in percentage of the figure
# size: [left, bottom, width, height]

# create each slider on its corresponding place:
s_cmax = Slider(ax_cmax, 'max', c_min, c_max, valinit=c_max, valfmt='%1.4f')
s_cmin = Slider(ax_cmin, 'min', c_min, c_max, valinit=c_min, valfmt='%1.4f')

# set both sliders to call update when their value is changed:
s_cmin.on_changed(update)
s_cmax.on_changed(update)

# create a space in the figure to place the reset button
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
# create the reset button
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')
button.on_clicked(reset)

# create a space in the figure to place the textboxes:
axbox_xmin = plt.axes([0.07, 0.55, 0.04, 0.04])
axbox_xmax = plt.axes([0.12, 0.55, 0.04, 0.04])
axbox_ymin = plt.axes([0.07, 0.49, 0.04, 0.04])
axbox_ymax = plt.axes([0.12, 0.49, 0.04, 0.04])

# create the textboxes
tb_xmin = TextBox(axbox_xmin,'x', color=axcolor, hovercolor='0.975', label_pad=0.01)
tb_xmax = TextBox(axbox_xmax,'', color=axcolor, hovercolor='0.975')
tb_ymin = TextBox(axbox_ymin,'y', color=axcolor, hovercolor='0.975', label_pad=0.01)
tb_ymax = TextBox(axbox_ymax,'', color=axcolor, hovercolor='0.975')

# create the submit action
tb_xmin.on_submit(submit)
tb_xmax.on_submit(submit)
tb_ymin.on_submit(submit)
tb_ymax.on_submit(submit)

plt.show()

1 个答案:

答案 0 :(得分:0)

在某些情况下,确实可能需要一个可以同时设置最小值和最大值的滑块。因此,滑块可以有两个值,而滑块内的矩形将由两个值限制,而不是从滑块的最小值开始,而不是只有一个值。

以下是这种情况的解决方案。它使用MinMaxSlider,即Slider的子类,适用于托管两个值 它不是单个输入值,而是期望两个值,

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

使Sliderbar的范围从0.5到0.8。单击滑块将更改更接近单击的值,从而使拖动变得相当容易。

为了使用这个滑块,请注意通过on_changed回调的函数现在自然有两个参数。

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