{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Rain simulation\n\nSimulates rain drops on a surface by animating the scale and opacity\nof 50 scatter points.\n\nAuthor: Nicolas P. Rougier\n\nOutput generated via `matplotlib.animation.Animation.to_jshtml`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib.animation import FuncAnimation\n\n# Fixing random state for reproducibility\nnp.random.seed(19680801)\n\n\n# Create new Figure and an Axes which fills it.\nfig = plt.figure(figsize=(7, 7))\nax = fig.add_axes((0, 0, 1, 1), frameon=False)\nax.set_xlim(0, 1), ax.set_xticks([])\nax.set_ylim(0, 1), ax.set_yticks([])\n\n# Create rain data\nn_drops = 50\nrain_drops = np.zeros(n_drops, dtype=[('position', float, (2,)),\n                                      ('size',     float),\n                                      ('growth',   float),\n                                      ('color',    float, (4,))])\n\n# Initialize the raindrops in random positions and with\n# random growth rates.\nrain_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))\nrain_drops['growth'] = np.random.uniform(50, 200, n_drops)\n\n# Construct the scatter which we will update during animation\n# as the raindrops develop.\nscat = ax.scatter(rain_drops['position'][:, 0], rain_drops['position'][:, 1],\n                  s=rain_drops['size'], lw=0.5, edgecolors=rain_drops['color'],\n                  facecolors='none')\n\n\ndef update(frame_number):\n    # Get an index which we can use to re-spawn the oldest raindrop.\n    current_index = frame_number % n_drops\n\n    # Make all colors more transparent as time progresses.\n    rain_drops['color'][:, 3] -= 1.0/len(rain_drops)\n    rain_drops['color'][:, 3] = np.clip(rain_drops['color'][:, 3], 0, 1)\n\n    # Make all circles bigger.\n    rain_drops['size'] += rain_drops['growth']\n\n    # Pick a new position for oldest rain drop, resetting its size,\n    # color and growth factor.\n    rain_drops['position'][current_index] = np.random.uniform(0, 1, 2)\n    rain_drops['size'][current_index] = 5\n    rain_drops['color'][current_index] = (0, 0, 0, 1)\n    rain_drops['growth'][current_index] = np.random.uniform(50, 200)\n\n    # Update the scatter collection, with the new colors, sizes and positions.\n    scat.set_edgecolors(rain_drops['color'])\n    scat.set_sizes(rain_drops['size'])\n    scat.set_offsets(rain_drops['position'])\n    return [scat]\n\n\n# Construct the animation, using the update function as the animation director.\nanimation = FuncAnimation(fig, update, interval=10, save_count=100, blit=True)\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        ".. tags::\n\n   component: animation\n   plot-type: scatter\n   purpose: fun\n\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}