Animate a Histogram in Python
Question: I'm trying to animate a histogram over time, and so far the code I have is the
following one:

    
    
    import matplotlib.pyplot as plt
    import numpy as np
    import time
    plt.ion()
    fig = plt.figure()
    ax = fig.add_subplot(111)
    
    alphab = ['A', 'B', 'C', 'D', 'E', 'F']
    frequencies = [1, 44, 12, 11, 2, 10]
    
    pos = np.arange(len(alphab))
    width = 1.0     # gives histogram aspect to the bar diagram
    ax.set_xticks(pos + (width / 2))
    ax.set_xticklabels(alphab)
    for bin_idx in np.linspace(0,1000000,100000000):
         t = time.time()
         #Here we just change the first bin, so it increases through the animation.
         frequencies[0] = bin_idx
         line1 =plt.bar(pos, frequencies, width, color='r')
         plt.draw()
         elapsed = time.time() - t
         print elapsed
    

The code works, but the outputs shows how after some iterations it just
becomes way slower than at the beginning. Is there a way to speed things up,
we want to update this in real time, and the process in which it runs is
pretty fast.

Also, it is important to notice, that I do not want a post processing
animation, we want real time updates, so the histogram animation example was
not working for this particular process.

Thanks


Answer: If you have a newer version of Matplotlib there is an
[`animations.FuncAnimation`
class](http://matplotlib.org/api/animation_api.html#matplotlib.animation.FuncAnimation)
which can help reduce some of the boiler-plate code. ([See this
page](http://matplotlib.org/examples/animation/histogram.html) for an
example.) It is pretty fast (~ **52 frames per second**):

    
    
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import timeit
    
    clock = timeit.default_timer
    
    fig, ax = plt.subplots()
    
    alphab = ['A', 'B', 'C', 'D', 'E', 'F']
    frequencies = [1, 44, 12, 11, 2, 10]
    
    pos = np.arange(len(alphab))
    width = 1.0     # gives histogram aspect to the bar diagram
    ax.set_xticks(pos + (width / 2))
    ax.set_xticklabels(alphab)
    
    rects = plt.bar(pos, frequencies, width, color='r')
    start = clock()
    
    def animate(arg, rects):
        frameno, frequencies = arg
        for rect, f in zip(rects, frequencies):
            rect.set_height(f)
        print("FPS: {:.2f}".format(frameno / (clock() - start))) 
    
    def step():
        for frame, bin_idx in enumerate(np.linspace(0,1000000,100000000), 1):
            #Here we just change the first bin, so it increases through the animation.
            frequencies[0] = bin_idx
            yield frame, frequencies
    
    
    ani = animation.FuncAnimation(fig, animate, step, interval=10,
                                  repeat=False, blit=False, fargs=(rects,))
    plt.show()
    

* * *

If you don't have a newer version of Matplotlib, here is the older way to do
it. It is slightly slower (~ **45 frames per second**):

Don't call `plt.bar` with each iteration of the loop. Instead, call it just
once, save the `rects` return value, and then call `set_height` to modify the
height of those `rects` on subsequent iterations of the loop. This trick (and
others) is explained in the [Matplotlib Animations
Cookbook](http://www.scipy.org/Cookbook/Matplotlib/Animations).

    
    
    import sys
    import matplotlib as mpl
    mpl.use('TkAgg')  # do this before importing pyplot
    import matplotlib.pyplot as plt
    import numpy as np
    import timeit
    
    clock = timeit.default_timer
    
    fig, ax = plt.subplots()
    
    alphab = ['A', 'B', 'C', 'D', 'E', 'F']
    frequencies = [1, 44, 12, 11, 2, 10]
    
    pos = np.arange(len(alphab))
    width = 1.0     # gives histogram aspect to the bar diagram
    ax.set_xticks(pos + (width / 2))
    ax.set_xticklabels(alphab)
    
    def animate():
        start = clock()
        rects = plt.bar(pos, frequencies, width, color='r')
        for frameno, bin_idx in enumerate(np.linspace(0,1000000,100000000), 2):
            #Here we just change the first bin, so it increases through the animation.
            frequencies[0] = bin_idx
            # rects = plt.bar(pos, frequencies, width, color='r')
            for rect, f in zip(rects, frequencies):
                rect.set_height(f)
            fig.canvas.draw()
            print("FPS: {:.2f}".format(frameno / (clock() - start)))         
    
    win = fig.canvas.manager.window
    win.after(1, animate)
    plt.show()
    

For comparison, adding `plt.clf` to your original code, on my machine reaches
about **12 frames per second**.

* * *

Some comments about timing:

You won't get accurate measurements by calculating the very small time
differences with each pass through the loop. The time resolution of
`time.time()` \-- at least on my computer -- is not great enough. You'll get
more accurate measurements by measuring one starting time and calculating the
large time difference between the start time and the current time, and then
dividing by the number of frames.

I also changed `time.time` to `timeit.default_timer`. The two are the same on
Unix computers, but `timeit.default_timer` is set to `time.clock` on Windows
machines. Thus `timeit.default_timer` chooses the more accurate timer for each
platform.

