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