Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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()
like image 209
Cleb Avatar asked Mar 13 '17 12:03

Cleb


People also ask

How do you superimpose two histograms in Python?

For creating the Histogram in Matplotlib we use hist() function which belongs to pyplot module. For plotting two histograms together, we have to use hist() function separately with two datasets by giving some settings.

How do you make a histogram look better?

We can achieve this by increasing the number of bins, which is essentially the number of classes the histogram divides the data into. More bins will make the histogram smoother.


1 Answers

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()
like image 196
Ed Smith Avatar answered Sep 21 '22 20:09

Ed Smith