#!/usr/bin/env python3
# source
# https://matplotlib.org/stable/gallery/animation/rain.html

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

# fixing random state for reproducibility
np.random.seed(19680801)

# create new Figure and an Axes which fills it
fig = plt.figure(figsize=(7, 7))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1), ax.set_xticks([])
ax.set_ylim(0, 1), ax.set_yticks([])

# rain drops as an array of specified data type ´dtype'
n_drops = 50
rain_drops = np.zeros(n_drops, dtype=[('position', float, (2,)),
                                      ('size',     float),
                                      ('growth',   float),
                                      ('color',    float, (4,))])

# random initial raindrops 
rain_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))
rain_drops['growth'] = np.random.uniform(50, 200, n_drops)

# scatter plot, will be updated during animation
scat = ax.scatter(rain_drops['position'][:, 0], rain_drops['position'][:, 1],
                  s=rain_drops['size'], lw=0.5, edgecolors=rain_drops['color'],
                  facecolors='none')

#
# -- the update function
#
def update(frame_number):
# get an index which we can use to re-spawn the oldest raindrop
    current_index = frame_number % n_drops

# make all colors more transparent as time progresses
    rain_drops['color'][:, 3] -= 1.0/len(rain_drops)
    rain_drops['color'][:, 3] = np.clip(rain_drops['color'][:, 3], 0, 1)

# make circles bigger
    rain_drops['size'] += rain_drops['growth']

# pick a new position for oldest rain drop, 
# resetting its size
    rain_drops['position'][current_index] = np.random.uniform(0, 1, 2)
    rain_drops['size'][current_index] = 5
    rain_drops['color'][current_index] = (0, 0, 0, 1)
    rain_drops['growth'][current_index] = np.random.uniform(50, 200)

# update the scatter collection, with the new colors, sizes and positions
    scat.set_edgecolors(rain_drops['color'])
    scat.set_sizes(rain_drops['size'])
    scat.set_offsets(rain_drops['position'])

#
# --- animation, with the update function as the animation director
#
animation = FuncAnimation(fig, update, interval=10, save_count=100)
plt.show()

