|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "metadata": {}, |
| 6 | + "source": [ |
| 7 | + "# Surface animations\n", |
| 8 | + "\n", |
| 9 | + "Here we show how to make animations of surface plots.\n", |
| 10 | + "\n", |
| 11 | + "First we need some imports:" |
| 12 | + ] |
| 13 | + }, |
| 14 | + { |
| 15 | + "cell_type": "code", |
| 16 | + "execution_count": null, |
| 17 | + "metadata": {}, |
| 18 | + "outputs": [], |
| 19 | + "source": [ |
| 20 | + "%matplotlib notebook\n", |
| 21 | + "import numpy as np\n", |
| 22 | + "import matplotlib.pyplot as plt\n", |
| 23 | + "import animatplot as amp" |
| 24 | + ] |
| 25 | + }, |
| 26 | + { |
| 27 | + "cell_type": "markdown", |
| 28 | + "metadata": {}, |
| 29 | + "source": [ |
| 30 | + "Let's use: $z = \\sin(x^2+y^2-t)$.\n", |
| 31 | + "\n", |
| 32 | + "First, we generate the data." |
| 33 | + ] |
| 34 | + }, |
| 35 | + { |
| 36 | + "cell_type": "code", |
| 37 | + "execution_count": null, |
| 38 | + "metadata": {}, |
| 39 | + "outputs": [], |
| 40 | + "source": [ |
| 41 | + "x = np.linspace(-2, 2, 41)\n", |
| 42 | + "y = np.linspace(-2, 2, 41)\n", |
| 43 | + "t = np.linspace(0, 2*np.pi, 30)\n", |
| 44 | + "\n", |
| 45 | + "X, Y, T = np.meshgrid(x, y, t)\n", |
| 46 | + "\n", |
| 47 | + "data = np.sin(X*X+Y*Y-T)" |
| 48 | + ] |
| 49 | + }, |
| 50 | + { |
| 51 | + "cell_type": "markdown", |
| 52 | + "metadata": {}, |
| 53 | + "source": [ |
| 54 | + "We need to be careful here. Our time axis is the last axis of our data, but animatplot assumes it is the first axis by default. Fortunately, we can use the ```t_axis``` argument.\n", |
| 55 | + "\n", |
| 56 | + "We need to create a special `Axes` object with a 3d projection to make surface animations. Here we do this by using `plt.subplots(subplot_kw={\"projection\": \"3d\"})`. In more complicated situations, you might need to pass an axes argument for various subplots, but here we only have one subplot, so we do not need to pass in the axes as animatplot can pick them up using `plt.gca()`." |
| 57 | + ] |
| 58 | + }, |
| 59 | + { |
| 60 | + "cell_type": "code", |
| 61 | + "execution_count": null, |
| 62 | + "metadata": { |
| 63 | + "scrolled": false |
| 64 | + }, |
| 65 | + "outputs": [], |
| 66 | + "source": [ |
| 67 | + "# standard matplotlib stuff\n", |
| 68 | + "# create the different plotting axes\n", |
| 69 | + "fig, ax = plt.subplots(subplot_kw={\"projection\": \"3d\"})\n", |
| 70 | + "\n", |
| 71 | + "ax.set_xlabel(\"x\")\n", |
| 72 | + "ax.set_ylabel(\"y\")\n", |
| 73 | + "ax.set_zlabel(\"z\")\n", |
| 74 | + "\n", |
| 75 | + "# animatplot stuff\n", |
| 76 | + "# now we make our block\n", |
| 77 | + "\n", |
| 78 | + "block = amp.blocks.Surface(X[:,:,0], Y[:,:,0], data, t_axis=2)\n", |
| 79 | + "timeline = amp.Timeline(t, fps=10)\n", |
| 80 | + "\n", |
| 81 | + "# now to contruct the animation\n", |
| 82 | + "anim = amp.Animation([block], timeline)\n", |
| 83 | + "anim.controls()\n", |
| 84 | + "\n", |
| 85 | + "anim.save_gif('images/surface')\n", |
| 86 | + "plt.show()" |
| 87 | + ] |
| 88 | + }, |
| 89 | + { |
| 90 | + "cell_type": "markdown", |
| 91 | + "metadata": {}, |
| 92 | + "source": [ |
| 93 | + "There is a lot going on here so lets break it down.\n", |
| 94 | + "\n", |
| 95 | + "Firstly, the ```standard matplotlib stuff``` is creating, and labeling all of our axes for our subplot. This is exactly how one might do a static, non-animated plot.\n", |
| 96 | + "\n", |
| 97 | + "When we make the Surface block, we pass in the x, y data as 2D arrays (```X[:,:,0]``` and ```Y[:,:,0]```), and the z data as a 3D array. We also specifify that the time axis is the last axis of the data ```t_axis=2```.\n", |
| 98 | + "\n", |
| 99 | + "To set the axis limits, you need to use `ax.set_xlim()`, `ax.set_ylim()` and `ax.set_zlim()`. The keywords ```vmin```, and ```vmax``` control the color scale if you pass a cmap argument.\n", |
| 100 | + "\n", |
| 101 | + "The rest simply brings the block and the timeline together into an animation." |
| 102 | + ] |
| 103 | + }, |
| 104 | + { |
| 105 | + "cell_type": "raw", |
| 106 | + "metadata": { |
| 107 | + "raw_mimetype": "text/restructuredtext" |
| 108 | + }, |
| 109 | + "source": [ |
| 110 | + ".. image:: images/surface.gif" |
| 111 | + ] |
| 112 | + }, |
| 113 | + { |
| 114 | + "cell_type": "code", |
| 115 | + "execution_count": null, |
| 116 | + "metadata": {}, |
| 117 | + "outputs": [], |
| 118 | + "source": [] |
| 119 | + } |
| 120 | + ], |
| 121 | + "metadata": { |
| 122 | + "celltoolbar": "Raw Cell Format", |
| 123 | + "kernelspec": { |
| 124 | + "display_name": "Python 3", |
| 125 | + "language": "python", |
| 126 | + "name": "python3" |
| 127 | + }, |
| 128 | + "language_info": { |
| 129 | + "codemirror_mode": { |
| 130 | + "name": "ipython", |
| 131 | + "version": 3 |
| 132 | + }, |
| 133 | + "file_extension": ".py", |
| 134 | + "mimetype": "text/x-python", |
| 135 | + "name": "python", |
| 136 | + "nbconvert_exporter": "python", |
| 137 | + "pygments_lexer": "ipython3", |
| 138 | + "version": "3.8.6" |
| 139 | + } |
| 140 | + }, |
| 141 | + "nbformat": 4, |
| 142 | + "nbformat_minor": 2 |
| 143 | +} |
0 commit comments