【问题标题】:How to update a histogram when a slider is used?使用滑块时如何更新直方图?
【发布时间】:2017-03-13 12:59:05
【问题描述】:

我想为正态分布构建直方图,并在均值、标准差和样本量发生变化时更新绘图;类似于帖子here

但是,我在 update 函数上遇到了困难。在上面的例子中

l, = plot(f(S, 1.0, 1.0))

def update(val):
    l.set_ydata(f(S, sGmax.val, sKm.val))

已使用,但在绘制直方图时必须如何更改?所以,我不确定如何使用来自plt.hist 的返回值,将它们正确传递给update,然后相应地更新绘图。谁能解释一下?

这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider


def update(val):
    mv = smean.val
    stdv = sstd.val
    n_sample = round(sn.val)
    # what needs to go here? how to replace xxx
    xxx(np.random.normal(mv, stdv, n_sample))
    plt.draw()


ax = plt.subplot(111)
plt.subplots_adjust(left=0.25, bottom=0.25)

m0 = -2.5
std0 = 1
n0 = 1000
n_bins0 = 20

nd = np.random.normal(m0, std0, n0)

# what needs to be returned here?
plt.hist(nd, normed=True, bins=n_bins0, alpha=0.5)

axcolor = 'lightgray'
axmean = plt.axes([0.25, 0.01, 0.65, 0.03], axisbg=axcolor)
axstd = plt.axes([0.25, 0.06, 0.65, 0.03], axisbg=axcolor)
axssize = plt.axes([0.25, 0.11, 0.65, 0.03], axisbg=axcolor)

smean = Slider(axmean, 'Mean', -5, 5, valinit=m0)
sstd = Slider(axstd, 'Std', 0.1, 10.0, valinit=std0)
sn = Slider(axssize, 'n_sample', 10, 10000, valinit=n0)

smean.on_changed(update)
sstd.on_changed(update)
sn.on_changed(update)

plt.show()

【问题讨论】:

    标签: python matplotlib slider


    【解决方案1】:

    一种选择是清除轴并重新绘制直方图。另一个选项,更符合 matplotlib 滑块 examplel.set_value 方法的精神,将使用 numpy 生成直方图数据,使用条形图并使用 bar.set_heightbar.set_x 使用 rescale 更新它轴上。完整的例子是:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import Slider
    
    
    def update(val):
        mv = smean.val
        stdv = sstd.val
        n_sample = round(sn.val)
        nd = np.random.normal(loc=mv, scale=stdv, size=n_sample)
        #Update barchart height and x values
        hist, bins = np.histogram(nd, normed=True, bins=n_bins0)
        [bar.set_height(hist[i]) for i, bar in enumerate(b)]
        [bar.set_x(bins[i]) for i, bar in enumerate(b)]
        ax.relim()
        ax.autoscale_view()
        plt.draw()
    
    
    def reset(event):
        mv.reset()
        stdv.reset()
        n_sample.reset()
    
    
    ax = plt.subplot(111)
    plt.subplots_adjust(left=0.25, bottom=0.25)
    
    m0 = -2.5
    std0 = 1
    n0 = 1000
    n_bins0 = 20
    
    nd = np.random.normal(m0, std0, n0)
    hist, bins = np.histogram(nd, normed=True, bins=n_bins0)
    b = plt.bar(bins[:-1], hist, width=.3)
    
    axcolor = 'lightgray'
    axmean = plt.axes([0.25, 0.01, 0.65, 0.03], axisbg=axcolor)
    axstd = plt.axes([0.25, 0.06, 0.65, 0.03], axisbg=axcolor)
    axssize = plt.axes([0.25, 0.11, 0.65, 0.03], axisbg=axcolor)
    
    smean = Slider(axmean, 'Mean', -5, 5, valinit=m0)
    sstd = Slider(axstd, 'Std', 0.1, 10.0, valinit=std0)
    sn = Slider(axssize, 'n_sample', 10, 10000, valinit=n0)
    
    smean.on_changed(update)
    sstd.on_changed(update)
    sn.on_changed(update)
    
    plt.show()
    

    更新:

    版本使用清轴(ax.cla())并重绘ax.hist(...)

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import Slider
    
    
    def update(val):
        mv = smean.val
        stdv = sstd.val
        n_sample = round(sn.val)
        nd = np.random.normal(loc=mv, scale=stdv, size=n_sample)
        #Redraw histogram
        ax.cla()
        ax.hist(nd, normed=True, bins=n_bins0, alpha=0.5)
        plt.draw()
    
    
    def reset(event):
        mv.reset()
        stdv.reset()
        n_sample.reset()
    
    
    ax = plt.subplot(111)
    plt.subplots_adjust(left=0.25, bottom=0.25)
    
    m0 = -2.5
    std0 = 1
    n0 = 1000
    n_bins0 = 20
    
    nd = np.random.normal(m0, std0, n0)
    plt.hist(nd, normed=True, bins=n_bins0, alpha=0.5)
    
    axcolor = 'lightgray'
    axmean = plt.axes([0.25, 0.01, 0.65, 0.03], axisbg=axcolor)
    axstd = plt.axes([0.25, 0.06, 0.65, 0.03], axisbg=axcolor)
    axssize = plt.axes([0.25, 0.11, 0.65, 0.03], axisbg=axcolor)
    
    smean = Slider(axmean, 'Mean', -5, 5, valinit=m0)
    sstd = Slider(axstd, 'Std', 0.1, 10.0, valinit=std0)
    sn = Slider(axssize, 'n_sample', 10, 10000, valinit=n0)
    
    smean.on_changed(update)
    sstd.on_changed(update)
    sn.on_changed(update)
    
    plt.show()
    

    【讨论】:

    • 由于您基本上(需要)重绘此解决方案中的所有内容(条形图、刻度线、刻度标签),因此与 ax.clear() ax.hist() 解决方案相比,选择此解决方案没有任何好处。因此,您可能还想提供(更简单的)解决方案的代码。
    • 这似乎完成了工作,谢谢(赞成)!如果您可以根据@ImportanceOfBeingErnest 的建议更新代码,我将不胜感激。
    • 我已经添加了示例,如果您要重绘很多条形图,重绘最终可能会变慢,尽管我不确定 blitting 是否适用于滑块...
    • 太棒了,谢谢。不幸的是,我不能投两次票 :) 如果出现更好的结果,如果不接受,我会再等几个小时。
    【解决方案2】:

    您可以在 matplotlib.container.BarContainer 对象上使用 remove() 函数

    fig, ax = plt.subplots(constrained_layout=True, figsize=(9, 3.5))
    
    _,_,q = ax.hist([1,2,3,4,4,4,3])
    fig.canvas.draw()
    
    q.remove()
    _,_,q = ax.hist([1,2,3,4,1,1,3])
    fig.canvas.draw()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-16
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 2010-12-20
      • 2017-05-18
      • 1970-01-01
      • 2015-06-23
      相关资源
      最近更新 更多