{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Animated histogram\n\nUse a path patch to draw a bunch of rectangles for an animated histogram.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nimport matplotlib.path as path\nimport matplotlib.animation as animation\n\n# Fixing random state for reproducibility\nnp.random.seed(19680801)\n\n# histogram our data with numpy\ndata = np.random.randn(1000)\nn, bins = np.histogram(data, 100)\n\n# get the corners of the rectangles for the histogram\nleft = bins[:-1]\nright = bins[1:]\nbottom = np.zeros(len(left))\ntop = bottom + n\nnrects = len(left)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here comes the tricky part -- we have to set up the vertex and path codes\narrays using `.Path.MOVETO`, `.Path.LINETO` and `.Path.CLOSEPOLY` for each\nrect.\n\n* We need 1 ``MOVETO`` per rectangle, which sets the initial point.\n* We need 3 ``LINETO``'s, which tell Matplotlib to draw lines from\n vertex 1 to vertex 2, v2 to v3, and v3 to v4.\n* We then need one ``CLOSEPOLY`` which tells Matplotlib to draw a line from\n the v4 to our initial vertex (the ``MOVETO`` vertex), in order to close the\n polygon.\n\n

#### Note

The vertex for ``CLOSEPOLY`` is ignored, but we still need a placeholder\n in the ``verts`` array to keep the codes aligned with the vertices.

\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "nverts = nrects * (1 + 3 + 1)\nverts = np.zeros((nverts, 2))\ncodes = np.full(nverts, path.Path.LINETO)\ncodes[0::5] = path.Path.MOVETO\ncodes[4::5] = path.Path.CLOSEPOLY\nverts[0::5, 0] = left\nverts[0::5, 1] = bottom\nverts[1::5, 0] = left\nverts[1::5, 1] = top\nverts[2::5, 0] = right\nverts[2::5, 1] = top\nverts[3::5, 0] = right\nverts[3::5, 1] = bottom" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To animate the histogram, we need an ``animate`` function, which generates\na random set of numbers and updates the locations of the vertices for the\nhistogram (in this case, only the heights of each rectangle). ``patch`` will\neventually be a `.Patch` object.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "patch = None\n\n\ndef animate(i):\n # simulate new data coming in\n data = np.random.randn(1000)\n n, bins = np.histogram(data, 100)\n top = bottom + n\n verts[1::5, 1] = top\n verts[2::5, 1] = top\n return [patch, ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we build the `.Path` and `.Patch` instances for the histogram using\nour vertices and codes. We add the patch to the `~.axes.Axes` instance, and\nsetup the `.FuncAnimation` with our ``animate`` function.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots()\nbarpath = path.Path(verts, codes)\npatch = patches.PathPatch(\n barpath, facecolor='green', edgecolor='yellow', alpha=0.5)\nax.add_patch(patch)\n\nax.set_xlim(left, right[-1])\nax.set_ylim(bottom.min(), top.max())\n\nani = animation.FuncAnimation(fig, animate, 50, repeat=False, blit=True)\nplt.show()" ] } ], "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.8.3" } }, "nbformat": 4, "nbformat_minor": 0 }