Skip to content
Advertisement

How to update a histogram when a slider is used?

I want to build a histogram for the normal distribution and update the plot when the mean, standard deviation and sample size are changed; analogue to the post here.

However, I struggle with the update function. In the example above

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

and

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

are used but how would this have to be changed when a histogram is plotted? So, I am not sure how to use the return values from plt.hist, pass them properly to update and then update the plot accordingly. Could anyone explain this?

This is my code:

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

Advertisement

Answer

One option is to clear the axis and just replot the histogram. The other option, more in the spirit of l.set_value approach of the matplotlib slider example would be to generate the histogram data with numpy, use a bar chart and update this using bar.set_height and bar.set_x with a rescale on the axis. The complete example is then:

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

UPDATE:

Version using clear axis (ax.cla()) and redraw 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()
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement