【问题标题】:Prevent data overlap between two sliders - use a single slider for two quantities防止两个滑块之间的数据重叠 - 对两个数量使用单个滑块
【发布时间】:2017-11-17 14:31:38
【问题描述】:

我正在使用 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()

【问题讨论】:

  • 滑块在哪里?
  • 我添加了我的 GUI 的示例图像
  • 代码在哪里?创建这些滑块的代码?我出去了。其他一些同行可能会帮助你。
  • 添加了相关部分的代码
  • 这与“相关”代码无关。这是关于minimal reproducible example。你能举一个这样的例子吗?那么肯定会有人回答你的问题。如果没有,你需要幸运地找到愿意自己修补的人。

标签: python matplotlib slider


【解决方案1】:

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

以下将是这种情况的解决方案。它使用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()

【讨论】:

  • 在类中定义一个可以通过即'button.on_clicked(MinMaxSlider.reset_val())'调用的reset方法的正确方法是什么?
  • 该方法需要将 val 和 val2 重置为其初始值 valinit 和 valinit2。 def reset(self): self.val=self.valinit self.val2=self.valinit2 self.set_val(self.valinit)
  • 我有'def reset(self): self.val=self.valinit self.val2=self.valinit2 self.set_val(self.valinit)' 作为我的重置方法,我使用'resetbutton。 on_clicked(slider.reset())' 作为我的重置电话。如果不更改其余代码,则不会发生任何事情。你能指出我错过了什么吗?
  • 我不能肯定地说,但假设其他一切都正确实施,你需要resetbutton.on_clicked(slider.reset)(没有后援,因为slider.reset()只是返回None。
  • 如果可能的话,我还有另一个后续问题。假设我通过另一个小部件更改了绘图的范围,因此我想更改颜色条和滑块的最小/最大值。我可以轻松计算新的最小值/最大值,但如何确保滑块和颜色条都相应调整?
猜你喜欢
  • 2015-10-25
  • 1970-01-01
  • 2022-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多