防止两个滑块之间的数据重叠-将单个滑块用于两个数量 [英] Prevent data overlap between two sliders - use a single slider for two quantities

查看:58
本文介绍了防止两个滑块之间的数据重叠-将单个滑块用于两个数量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我的

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 the full range is 0 till 5 and I set the maximum on 2 then the minimum cannot surpass 2. This should happen interactively. How can I achieve this? Additionally is there a maybe a way to integrate the two sliders into one? Thank you.

An example of my GUI. And the relevant part of the code:

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()

解决方案

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()

这篇关于防止两个滑块之间的数据重叠-将单个滑块用于两个数量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆