Animate a Histogram in Python
animation, histogram, python
Solution
If you have a newer version of Matplotlib there is an `animations.FuncAnimation` class which can help reduce some of the boiler-plate code. (See this page 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.
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.
Problem
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