1"""
2===============
3Rain simulation
4===============
5
6Simulates rain drops on a surface by animating the scale and opacity
7of 50 scatter points.
8
9Author: Nicolas P. Rougier
10"""
11
12import numpy as np
13import matplotlib.pyplot as plt
14from matplotlib.animation import FuncAnimation
15
16# Fixing random state for reproducibility
17np.random.seed(19680801)
18
19
20# Create new Figure and an Axes which fills it.
21fig = plt.figure(figsize=(7, 7))
22ax = fig.add_axes([0, 0, 1, 1], frameon=False)
23ax.set_xlim(0, 1), ax.set_xticks([])
24ax.set_ylim(0, 1), ax.set_yticks([])
25
26# Create rain data
27n_drops = 50
28rain_drops = np.zeros(n_drops, dtype=[('position', float, 2),
29                                      ('size',     float, 1),
30                                      ('growth',   float, 1),
31                                      ('color',    float, 4)])
32
33# Initialize the raindrops in random positions and with
34# random growth rates.
35rain_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))
36rain_drops['growth'] = np.random.uniform(50, 200, n_drops)
37
38# Construct the scatter which we will update during animation
39# as the raindrops develop.
40scat = ax.scatter(rain_drops['position'][:, 0], rain_drops['position'][:, 1],
41                  s=rain_drops['size'], lw=0.5, edgecolors=rain_drops['color'],
42                  facecolors='none')
43
44
45def update(frame_number):
46    # Get an index which we can use to re-spawn the oldest raindrop.
47    current_index = frame_number % n_drops
48
49    # Make all colors more transparent as time progresses.
50    rain_drops['color'][:, 3] -= 1.0/len(rain_drops)
51    rain_drops['color'][:, 3] = np.clip(rain_drops['color'][:, 3], 0, 1)
52
53    # Make all circles bigger.
54    rain_drops['size'] += rain_drops['growth']
55
56    # Pick a new position for oldest rain drop, resetting its size,
57    # color and growth factor.
58    rain_drops['position'][current_index] = np.random.uniform(0, 1, 2)
59    rain_drops['size'][current_index] = 5
60    rain_drops['color'][current_index] = (0, 0, 0, 1)
61    rain_drops['growth'][current_index] = np.random.uniform(50, 200)
62
63    # Update the scatter collection, with the new colors, sizes and positions.
64    scat.set_edgecolors(rain_drops['color'])
65    scat.set_sizes(rain_drops['size'])
66    scat.set_offsets(rain_drops['position'])
67
68
69# Construct the animation, using the update function as the animation director.
70animation = FuncAnimation(fig, update, interval=10)
71plt.show()
72