{ "cells": [ { "cell_type": "markdown", "metadata": { "nbpages": { "level": 0, "link": "[](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html)", "section": "" } }, "source": [ "\n", "*This notebook contains material from [cbe30338-2021](https://jckantor.github.io/cbe30338-2021);\n", "content is available [on Github](https://github.com/jckantor/cbe30338-2021.git).*\n" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 0, "link": "[](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html)", "section": "" } }, "source": [ "\n", "< [A.0 Appendices](https://jckantor.github.io/cbe30338-2021/A.00-Appendices.html) | [Contents](toc.html) | [Tag Index](tag_index.html) |

\"Open

\"Download\"" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 1, "link": "[A.1 Animation in Jupyter Notebooks](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1-Animation-in-Jupyter-Notebooks)", "section": "A.1 Animation in Jupyter Notebooks" } }, "source": [ "# A.1 Animation in Jupyter Notebooks\n", "\n", "by Jeffrey Kantor (jeff at nd.edu). The latest version of this notebook is available at [https://github.com/jckantor/CBE30338](https://github.com/jckantor/CBE30338). " ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 2, "link": "[A.1.1 Summary](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.1-Summary)", "section": "A.1.1 Summary" } }, "source": [ "## A.1.1 Summary\n", "\n", "Animation features are built into the Python matplotlib library and available through Jupyter notebooks. Unfortunately, however, the documentation is not particularly robust. This short notebook provides simple demonstrations of using animiation for the visualization of simulation results. \n", "\n", "The resulting animations are html video files embedded within the Jupyter notebook. The videos can be viewed in any modern web browser. Since they don't require an active Python kernal, the animations can be seen when the even when notebook is viewed as a static HTML web page.\n", "\n", "The techniques used below come from blog postings [Animating the Lorenz System in 3D](https://jakevdp.github.io/blog/2013/02/16/animating-the-lorentz-system-in-3d/) and [Embedding Matplotlib Animations in Jupyter Notebooks](http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/)." ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 2, "link": "[A.1.2 Prerequisites](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.2-Prerequisites)", "section": "A.1.2 Prerequisites" } }, "source": [ "## A.1.2 Prerequisites\n", "\n", "You should be able to view the animations with any modern web browser. However, to create animiations using the following cells you will need to install a video codec. By default matplotlib is configured to use ffmpeg. You find instructions on installing ffmpeg [here](https://github.com/adaptlearning/adapt_authoring/wiki/Installing-FFmpeg)." ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 2, "link": "[A.1.3 Step-by-Step Approach to Animation with Matplotlib](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3-Step-by-Step-Approach-to-Animation-with-Matplotlib)", "section": "A.1.3 Step-by-Step Approach to Animation with Matplotlib" } }, "source": [ "## A.1.3 Step-by-Step Approach to Animation with Matplotlib" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.1 Step 1. Create the background frame.](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.1-Step-1.-Create-the-background-frame.)", "section": "A.1.3.1 Step 1. Create the background frame." } }, "source": [ "### A.1.3.1 Step 1. Create the background frame.\n", "\n", "The following cell creates a background frame for the animation. These are standard matplotlib graphics commands, but where we have kept a reference to the resulting objects. The objects include `fig` for the figure object, `ax1` and `ax2` for each of the two plotting axes, and then `txt_title`, `line1`, `line2`, `pt1`, and `line3` for graphical elements that will be updated in each frame of the animation." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.1 Step 1. Create the background frame.](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.1-Step-1.-Create-the-background-frame.)", "section": "A.1.3.1 Step 1. Create the background frame." } }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtsAAAFKCAYAAADMopPTAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xt4FPWh//HPkmQhJOFqSis2WPMDuYkQPApFRKAU5dKA\nIeRSExCOVn4CGhEBj8UgaQICVcsxqK0HAQ8qRC1gPViRHKkcDgIhKFdpKKFYxEiLsBvIbef3h3V/\nBEKyk2RmJ/B+PY/Pw853J/PpZPrdzzM7mXEZhmEIAAAAQKNrFuwAAAAAwJWKsg0AAABYhLINAAAA\nWISyDQAAAFiEsg0AAABYhLINAAAAWCQ02AEAAEDTd/z4cQ0bNkxdunTxLzMMQ+np6Ro3bpzefvtt\nvf/++3rppZdszTVkyBCFhYWpRYsWcrlcqqio0IABAzR79mz97W9/0+jRo7V7925bM+HqQtkGAACN\nokWLFlq3bp3/9cmTJzVq1Cj17NkziKmkxYsX66abbpIklZeXKy0tTatXr9add94Z1Fy4OlC2AQCA\nJTp06KBOnTrp6NGjkqSSkhI98MADOnHihEJCQrRkyRLFxsaqsLBQixYtUnl5uUpKSvTjH/9Y2dnZ\nqqys1Pz581VQUKCwsDBdd911ysnJUUREhAoKCrR48WKdO3dOLpdL06ZN0+DBg+vM5Ha71bdvXx05\ncqRa2f766681d+5cnTp1SiUlJerYsaOee+45tW/fXkOGDNHYsWO1bds2nThxQnfffbcef/xxSdLm\nzZu1bNkyVVRUqEWLFpo1a5b69Oljxe5EE0XZBgAAlti9e7eOHTumm2++Wdu2bdNf//pXPfvss+rU\nqZOysrL0yiuvKDs7WytXrtT06dN12223yev1aujQodq7d6/Onz+vTz75RO+9955cLpcWLVqkQ4cO\nKTY2VnPmzNErr7yi6667TidPntT48eN144036tprr60108mTJ5Wfn69HHnmk2vI//OEP6t27tx54\n4AEZhqEHHnhA69at06RJkyRJpaWlWr16tU6ePKlhw4YpJSVFVVVVevbZZ7Vy5Uq1bdtWhw8f1n33\n3ac//vGPatmypWX7FU0LZRsAADSK8+fPKz4+XpJUVVWltm3batGiRfrBD34gSerVq5c6deokSerW\nrZs++OADSdKCBQu0ZcsWvfjiizpy5IjOnz+v0tJSde3aVSEhIUpMTNTtt9+u4cOHq1evXvroo49U\nUlKihx56yL9tl8ulQ4cO1Vi2H3vsMbVo0UI+n09hYWFKTEzU8OHDdfz4cf97JkyYoJ07d2r58uU6\nevSoDh8+rJtvvtk/PnToUEnfnq1v3769vvnmG+3Zs0dfffWVJk6cWC3HsWPH1LVr10baq2jqKNsA\nAKBRXHzN9sVCQ/9/7XC5XDIMQ5L085//XF27dtXAgQN19913a8+ePTIMQ61atdK6detUUFCg//3f\n/9Ujjzyi9PR0xcTEKDY2VmvXrvX/vJMnT6pdu3Y1bvfCa7YvZ9GiRfr000+VkJCg2267TZWVlf58\nktS8efNLsvt8PvXv31/PPfecf+zEiRP63ve+V+u2cHXh1n8AACBovvnmG+3du1ePPfaYfvrTn+rk\nyZM6duyYfD6f8vPzNXHiRPXp00fTpk3TmDFjdPDgQfXu3VvFxcXasWOHJOnAgQMaPny4vvrqq3rn\n+PjjjzVhwgSNGTNG7du31//8z/+oqqqq1nX69eunrVu3qqioSJL00Ucf6Wc/+5nKysrqnQNXHs5s\nAwCAoGndurUeeOABjR07Vm3atFHbtm0VFxen4uJiJSYmasuWLRo1apRatmyp1q1ba/78+WrXrp1+\n85vf6JlnnlFZWZkMw9Azzzyjjh071jvHQw89pGeeeUa5ubkKCQlRXFycjh07Vus6nTt31tNPP61H\nH31UhmEoNDRUy5Yt43ptVOMyLvyOBAAAAECj4TISAAAAwCKUbQAAAMAitl6zXVFRoSeeeEJffPGF\nysvLNWXKFP+tdKRvbwz/wgsvKDQ0VAkJCRo/fryd8QAAF2HeBoCGsbVsr1+/Xm3atNGiRYt0+vRp\njRkzxj9pV1RUKCcnR3l5eQoPD1dKSoqGDBmia665xs6IAIALMG8DQMPYehnJXXfdpYcffliSZBiG\nQkJC/GNFRUWKiYlR69at/Y9S/e6WPgCA4GDeBoCGsfXMdkREhCTJ4/Fo+vTp1R6V6vF4FBUVVe29\nHo+nzp9pGIZcLlfjhwUANPq8zZwN4Gpj+322T5w4oYceekipqakaPXq0f3lkZKS8Xq//tdfrrTaJ\nX47L5VJJyVlLsjZEdHQUuUwglznkMsfJuZqCxpy3mbPNIZd5Ts1GLnOcnMssWy8j+frrrzVp0iTN\nnDlT48aNqzYWGxur4uJinT59WuXl5dq5c6f69OljZzwAwEWYtwGgYWw9s/3iiy/qzJkzys3NVW5u\nriQpMTFR586dU1JSkmbPnq3JkyfLMAwlJCSoQ4cOdsYDAFyEeRsAGuaKeIKkU79mIFfgyGUOucxx\ncq6rkVN/F+QKnFNzSc7NRi5znJzLLB5qAwAAAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0AATp8\n+JCWL/9tsGMAAJoQ2x9qAwBNVefON6pz5xuDHQMA0IRQtgHgMo4dK1ZOzjyFhITK5/PpZz8bq23b\nPta8eTlKTh6rm266WceOFatdu3bKynpGISEhwY4MAHAYyjaAJiE1NVybNjVkyrr03qg/+UmlVq8+\nd9k1duzYrm7deuj//t+HtWfPbh09esQ/9re/faHnn1+mDh2+rylTJunAgf3q2fOmBuQDAFyJuGYb\nAC5j1Kh4RUZGacaMaXrrrTXVzly3bt1GHTp8X5L0ve91UHl5WbBiAgAcjDPbAJqE2s5A16W+TyL7\n+OOPdPPNfTRp0gP64IONevnlXHXv3kOS5HK56p0HAHD1oGwDwGV07dpdWVlPacWKV+Tz+ZSQMF4H\nDuwLdiwAQBNC2QaAy+jY8TotW/ZKjWPr17/v//e8eTl2RQIANDFcsw0AAABYhLINAAAAWISyDQAA\nAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISH2gDAZZSVnVd29jx9+eWXqqio\n0MMPz9C6dW/rb3/7QlVVVUpO/rmGDv2p3n57rf7rv95Vs2bN1K1bdz3yyMxgRwcAOARlG0CT0Cp1\nnJpv+mO914+uYVnZT36qM6vzLrvO73//lr7//Ws1b16O/vrXY/rwwz+qTZs2mjt3vkpLvZo06V71\n7Xur3ntvg2bMmKVu3XronXfyVFlZqdBQplcAAGUbAC7r2LFi9ev3Y0nSD38Yo1OnTumWW26VJLVs\nGaHrr/+RvvjiuJ54Yq5ef/01nTjxvHr0uCmYkQEADkPZBtAk1HYGui7R0VEqKTlrer1OnX6kAwf2\na+DAO/XFF8e1adP7crvDNGjQYJWWelVUVKRrr71WK1b8hx57bI6aN2+uRx+dqs8+26M+ffrWOy8A\n4MpB2QaAy4iPv0c5OU9r6tQHVFVVpSVLfqO3316rKVMmq6ysTJMm3a+2bdspNvb/6KGH7lfLli0V\nHR2t7t17Bjs6AMAhKNsAcBnNmzdXZuavqi2rqUiPHj1Go0ePsSsWAKAJCcqt//bs2aO0tLRLlr/6\n6qsaOXKk0tLSlJaWpiNHjgQhHQDgQszZAFB/tp/Z/u1vf6v169crPDz8krG9e/dq4cKF6tmTr2AB\nwAmYswGgYWw/sx0TE6OlS5fWOLZv3z69/PLLSklJ0UsvvWRzMgDAxZizAaBhbD+zPXz4cB0/frzG\nsZEjRyo1NVWRkZGaOnWq8vPzNXjw4Dp/ZnR0VGPHbBTkModc5pDLHKfmcjrm7OAjl3lOzUYuc5ya\nyyzH/IGkYRiaMGGCoqK+3bGDBg3S/v37A5q463NLL6vV91ZjViOXOeQyh1zmNOUPEuZse5DLPKdm\nI5c5Ts5lVlD+QLImHo9Ho0aNktfrlWEY2r59O9cBAoBDMWcDQGCCfmZ7w4YNKi0tVVJSkjIyMpSe\nni63263+/ftr0KBBwY4HALgAczYAmOMyDMMIdoiGcurXDOQKHLnMIZc5Ts51NXLq74JcgXNqLsm5\n2chljpNzmeWYy0gAAACAKw1lGwAAALAIZRsAAACwCGUbAAAAsAhlGwAAALAIZRsAAACwCGUbAAAA\nsAhlGwAAALAIZRsAAACwCGUbAAAAsAhlGwAAALAIZRsAAACwCGUbAAAAsAhlGwAAALAIZRsAAACw\nCGUbAAAAsAhlGwAAALAIZRsAAACwCGUbAAAAsAhlGwAAALAIZRsAAACwCGUbAAAAsAhlGwAAALAI\nZRsAAACwCGUbAAAAsAhlGwAAALBIUMr2nj17lJaWdsnyzZs3KyEhQUlJSVqzZk0QkgEALsacDQD1\nF2r3Bn/7299q/fr1Cg8Pr7a8oqJCOTk5ysvLU3h4uFJSUjRkyBBdc801dkcEAPwTczYANIztZ7Zj\nYmK0dOnSS5YXFRUpJiZGrVu3ltvtVt++fbVjxw674wEALsCcDQANY/uZ7eHDh+v48eOXLPd4PIqK\nivK/joiIkMfjCehnRkdH1f2mICCXOeQyh1zmODWX0zFnBx+5zHNqNnKZ49RcZtleti8nMjJSXq/X\n/9rr9VabyGtTUnLWqlj1Fh0dRS4TyGUOucxxcq6mijnbHuQyz6nZyGWOk3OZ5Zi7kcTGxqq4uFin\nT59WeXm5du7cqT59+gQ7FgCgBszZABCYoJ/Z3rBhg0pLS5WUlKTZs2dr8uTJMgxDCQkJ6tChQ7Dj\nAQAuwJwNAOa4DMMwgh2ioZz6NQO5Akcuc8hljpNzXY2c+rsgV+CcmktybjZymePkXGY55jISAAAA\n4EpD2QYAAAAsQtkGAAAALELZBgAAACxC2QYAAAAsQtkGAAAALELZBgAAACxC2QYAAAAsQtkGAAAA\nLELZBgAAACxC2QYAAAAsQtkGAAAALELZBgAAACxC2QYAAAAsQtkGAAAALELZBgAAACxC2QYAAAAs\nQtkGAAAALELZBgAAACxC2QYAAAAsQtkGAAAALELZBgAAACxC2QYAAAAsQtkGAAAALELZBgAAACxC\n2QYAAAAsEmrnxnw+nzIzM3Xo0CG53W5lZWWpU6dO/vFXX31Va9euVbt27SRJ8+bN0w033GBnRADA\nBZi3AaBhbC3bmzZtUnl5ud58800VFhZqwYIFWrZsmX987969WrhwoXr27GlnLADAZTBvA0DD2Fq2\nd+3apYEDB0qSevfurb1791Yb37dvn15++WWVlJTozjvv1C9+8Qs74wEALsK8DQANY2vZ9ng8ioyM\n9L8OCQlRZWWlQkO/jTFy5EilpqYqMjJSU6dOVX5+vgYPHlznz42OjrIsc0OQyxxymUMuc5yay+ms\nmLed+rsglzlOzSU5Nxu5zHFqLrNsLduRkZHyer3+1z6fzz9hG4ahCRMmKCrq2x07aNAg7d+/P6Cy\nXVJy1prADRAdHUUuE8hlDrnMcXIup7Ni3nbq74JcgXNqLsm52chljpNzmWXr3Uji4uK0ZcsWSVJh\nYaG6dOniH/N4PBo1apS8Xq8Mw9D27du5BhAAgox5GwAaxtYz28OGDdPWrVuVnJwswzCUnZ2tDRs2\nqLS0VElJScrIyFB6errcbrf69++vQYMG2RkPAHAR5m0AaBiXYRhGsEM0lFO/ZiBX4MhlDrnMcXKu\nq5FTfxfkCpxTc0nOzUYuc5ycyyweagMAAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWMRU\n2f7mm2+sygEAAABccQIq2wcOHNBdd92l+Ph4nTx5UsOGDdO+ffuszgYAAAA0aQGV7aysLL3wwgtq\n06aNOnTooMzMTD311FNWZwMAAACatIDK9rlz5xQbG+t/PWDAAJWXl1sWCgAAALgSBFS227Rpo4MH\nD8rlckmS1q9fr9atW1saDAAAAGjqQgN5U2ZmpmbNmqXDhw/rlltuUadOnbRo0SKrswEAAABNWkBl\nOyYmRq+//rpKS0vl8/kUGRlpdS4AAACgyau1bKelpfkvHanJypUrGz0QAAAAcKWotWxPmzZNkrRm\nzRq1aNFCY8aMUWhoqN59912VlZXZEhAAAABoqmot27feeqskaeHChXrrrbf8y3v37q177rnH2mQA\nAABAExfQ3UjKysr0l7/8xf/60KFDqqystCwUAAAAcCUI6A8kZ8+erbS0NHXo0EE+n09///vftWTJ\nEquzAQAAAE1aQGX79ttv1+bNm/X555/L5XLpxhtvVGhoQKsCAAAAV62AGvOcOXNqXJ6Tk9OoYQAA\nAIArSUBl+7s/lJSkyspKffjhh7rhhhssCwUAAABcCQIq22PHjq32ety4cUpJSbEkEAAAAHClCOhu\nJBcrKirSV1991dhZAAAAgCtKQGe2u3bt6n+SpGEYateunR599FFLgwEAAABNXUBl++DBg5csKy8v\nb/QwAAAAwJUkoMtIkpKSqr32+XxKSEiwJBAAAABwpaj1zHZ6ero++eQTSd9eSuJfKTRUQ4YMsTYZ\nAAAA0MTVWrZXrlwpScrKytKTTz7Z4I35fD5lZmbq0KFDcrvdysrKUqdOnfzjmzdv1gsvvKDQ0FAl\nJCRo/PjxDd4mAFwtSktL1bJly0b9mczbANAwtZbt/Px8DR48WD169NDvf//7S8bHjBljamObNm1S\neXm53nzzTRUWFmrBggVatmyZJKmiokI5OTnKy8tTeHi4UlJSNGTIEF1zzTWmtgEAV6v4+Hjl5OTo\nlltuabSfybwNAA1T6zXbn332mSTpk08+0fbt2y/5z6xdu3Zp4MCBkqTevXtr7969/rGioiLFxMSo\ndevWcrvd6tu3r3bs2GF6GwBwtXrqqac0Z84cLVy4sNH+iJ15GwAaptYz29OnT5fUeI9l93g8ioyM\n9L8OCQlRZWWlQkND5fF4FBUV5R+LiIiQx+MJ6OdGR0fV/aYgIJc55DKHXOY4NVdjuv3227V+/Xo9\n//zzGjdunObOnatrr73WP37hvwNlxbzt1N8Fucxxai7JudnIZY5Tc5kV0K3//vSnP+m5557TN998\nI8Mw/Ms//PBDUxuLjIyU1+v1v/b5fAoNDa1xzOv1VpvEa1NSctZUDjtER0eRywRymUMuc5ycq7GF\nh4fr4Ycf1pdffqkpU6aoVatWMgxDLpfL9JwtWTNvO/V3Qa7AOTWX5Nxs5DLHybnMCqhsZ2Vlafbs\n2ercubP/4Tb1ERcXp/z8fI0YMUKFhYXq0qWLfyw2NlbFxcU6ffq0WrZsqZ07d2ry5Mn13hYAXI3+\n+7//W08//bRuv/125efnVzsrXR/M2wDQMAGV7bZt22rw4MEN3tiwYcO0detWJScnyzAMZWdna8OG\nDSotLVVSUpJmz56tyZMnyzAMJSQkqEOHDg3eJgBcLaZPn679+/frV7/6lfr3798oP5N5GwAaJqCy\n3bdvX+Xk5GjgwIFq3ry5f/m//Mu/mNpYs2bN9PTTT1dbFhsb6//3kCFDuH83ANRTdHS01q9f36i3\n/2PeBoCGCahsf/rpp5Kk/fv3+5e5XC7/fbgBAMH3y1/+MtgRAAAXCahsr1q1yuocAAAAwBUnoLKd\nnp5e7bXL5VKLFi10ww036MEHH1Tr1q0tCQcAAAA0ZQGV7djYWP+jeCXp3Xff1ZdffqkOHTro3/7t\n3/Tv//7vloYEAAAAmqKAyvaePXv09ttv+1937dpVCQkJWrx4cY2PcQcAAABQx+Pav1NRUaHDhw/7\nXx8+fFg+n0/nz59XRUWFZeEAAACApiygM9tPPvmk7r//frVv314+n09nzpzRM888o6VLlyo+Pt7q\njAAAAECTFFDZvu2227Rp0yZ9/vnnatasmWJjYxUWFqa4uLgGPVESAAAAuJIFVLaPHDmi1atXq7S0\nVIZhyOfz6fjx4/rP//xPq/MBAAAATVZA12xnZGSoVatWOnDggLp166ZTp06pc+fOVmcDAAAAmrSA\nzmz7fD5Nnz5dlZWV6t69u5KTk5WcnGx1NgAAAKBJC+jMdnh4uMrLy3X99ddr3759crvdKisrszob\nAAAA0KQFVLbj4+P14IMP6s4779Rrr72mf/3Xf9X3v/99q7MBAAAATVqtl5F898CaiIgIDR48WFu2\nbNHYsWPVsmVLhYWF2RIQAAAAaKpqLduzZ89W+/bt1b9/f8o1AAAAYFKtZfudd97Re++9p61bt6pr\n164aMWKEfvzjH6tZs4CuPgEAAACuarWW7W7duqlbt26aMWOGPvvsM7333nv69a9/rZ49e2rkyJG6\n7bbb7MoJAAAANDkB3fpPkm666SbddNNN2rlzpxYvXqwNGzZo9+7dVmYDAAAAmrQ6y7ZhGNqxY4c2\nbtyoLVu2qFu3bkpLS9PgwYPtyAcAAAA0WbWW7aeeekp/+tOf1L17d91999167LHH1LJlS7uyAQAA\nAE1arWX7zTffVJs2bbR//37t379fv/71r6uNf/jhh5aGAwAAAJqyWss2ZRoAAACov1rLdseOHe3K\nAQAAAFxxuGE2AAAAYBHKNgAAAGARyjYAAABgkYAfatMYzp8/r5kzZ+rUqVOKiIjQwoUL1a5du2rv\nycrKUkFBgSIiIiRJubm5ioqKsjMmAEDM2QDQGGwt26+//rq6dOmiadOm6Q9/+INyc3P15JNPVnvP\nvn379Lvf/e6SCR0AYC/mbABoOFsvI9m1a5cGDhwoSbrjjju0bdu2auM+n0/FxcWaO3eukpOTlZeX\nZ2c8AMAFmLMBoOEsO7O9du1arVixotqy9u3b+79ejIiI0NmzZ6uNl5aW6t5779V9992nqqoqpaen\nq2fPnuratWut24qOduZXluQyh1zmkMscp+ZyCuZscpnl1FySc7ORyxyn5jLLsrKdmJioxMTEasum\nTp0qr9crSfJ6vWrVqlW18fDwcKWnpys8PFyS1K9fPx08eLDOibuk5Gyt48EQHR1FLhPIZQ65zHFy\nLqdgznbuMUIuc5yajVzmODmXWbZeRhIXF6ePPvpIkrRlyxb17du32vjRo0eVkpKiqqoqVVRUqKCg\nQD169LAzIgDgn5izAaDhbP0DyZSUFM2aNUspKSkKCwvTkiVLJEnLly9XTEyMhg4dqvj4eI0fP15h\nYWGKj49X586d7YwIAPgn5mwAaDiXYRhGsEM0lFO/ZiBX4MhlDrnMcXKuq5FTfxfkCpxTc0nOzUYu\nc5ycyyweagMAAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLIN\nAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0A\nAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISyDQAAAFiEsg0AAABYhLINAAAAWISyDQAA\nAFiEsg0AAABYhLINAAAAWCQoZfuDDz7QjBkzahxbs2aN7rnnHo0fP175+fk2JwMAXIw5GwDqL9Tu\nDWZlZenjjz9Wt27dLhkrKSnRqlWr9NZbb6msrEypqakaMGCA3G633TEBAGLOBoCGsv3MdlxcnDIz\nM2sc+/TTT9WnTx+53W5FRUUpJiZGBw8etDcgAMCPORsAGsayM9tr167VihUrqi3Lzs7WiBEjtH37\n9hrX8Xg8ioqK8r+OiIiQx+Opc1vR0VF1vicYyGUOucwhlzlOzeUUzNnkMsupuSTnZiOXOU7NZZZl\nZTsxMVGJiYmm1omMjJTX6/W/9nq91SbyyykpOWs6n9Wio6PIZQK5zCGXOU7O5RTM2c49RshljlOz\nkcscJ+cyy1F3I+nVq5d27dqlsrIynT17VkVFRerSpUuwYwEAasCcDQB1s/0PJGuyfPlyxcTEaOjQ\noUpLS1NqaqoMw1BGRoaaN28e7HgAgAswZwNA4FyGYRjBDtFQTv2agVyBI5c55DLHybmuRk79XZAr\ncE7NJTk3G7nMcXIusxx1GQkAAABwJaFsAwAAABahbAMAAAAWoWwDAAAAFqFsAwAAABahbAMAAAAW\noWwDAAAAFqFsAwAAABahbAMAAAAWoWwDAAAAFqFsAwAAABahbAMAAAAWoWwDAAAAFqFsAwAAABah\nbAMAAAAWoWwDAAAAFqFsAwAAABahbAMAAAAWoWwDAAAAFqFsAwAAABahbAMAAAAWoWwDAAAAFqFs\nAwAAABahbAMAAAAWoWwDAAAAFqFsAwAAABYJDcZGP/jgA23cuFFLliy5ZCwrK0sFBQWKiIiQJOXm\n5ioqKsruiACAf2LOBoD6s71sZ2Vl6eOPP1a3bt1qHN+3b59+97vfqV27djYnAwBcjDkbABrG9stI\n4uLilJmZWeOYz+dTcXGx5s6dq+TkZOXl5dkbDgBQDXM2ADSMZWe2165dqxUrVlRblp2drREjRmj7\n9u01rlNaWqp7771X9913n6qqqpSenq6ePXuqa9eutW4rOtqZX1mSyxxymUMuc5yayymYs8llllNz\nSc7NRi5znJrLLMvKdmJiohITE02tEx4ervT0dIWHh0uS+vXrp4MHD9Y5cZeUnK13TqtER0eRywRy\nmUMuc5ycyymYs517jJDLHKdmI5c5Ts5llqPuRnL06FGlpKSoqqpKFRUVKigoUI8ePYIdCwBQA+Zs\nAKhbUO5GcrHly5crJiZGQ4cOVXx8vMaPH6+wsDDFx8erc+fOwY4HALgAczYABM5lGIYR7BAN5dSv\nGcgVOHKZQy5znJzrauTU3wW5AufUXJJzs5HLHCfnMstRl5EAAAAAVxLKNgAAAGARyjYAAABgEco2\nAAAAYBHKNgAAAGARyjYAAABgEco2AAAAYBHKNgAAAGARyjYAAABgEco2AAAAYBHKNgAAAGARyjYA\nAABgEco2AAAAYBHKNgAAAGARyjYAAABgEco2AAAAYBHKNgAAAGARyjYAAABgEco2AAAAYBHKNgAA\nAGARyjYAAABgEco2AAAAYBHKNgAAAGARyjYAAABgEco2AAAAYBFby/bZs2f14IMP6t5771VSUpJ2\n7959yXsPvNHhAAALo0lEQVTWrFmje+65R+PHj1d+fr6d8QAAF2DOBoCGC7VzY8uXL1e/fv00ceJE\nHTlyRDNmzNA777zjHy8pKdGqVav01ltvqaysTKmpqRowYIDcbredMQEAYs4GgMZga9meOHGifxKu\nqqpS8+bNq41/+umn6tOnj9xut9xut2JiYnTw4EH16tXLzpgAADFnA0BjsKxsr127VitWrKi2LDs7\nW7169VJJSYlmzpypJ554otq4x+NRVFSU/3VERIQ8Ho9VEQEA/8ScDQDWsKxsJyYmKjEx8ZLlhw4d\n0qOPPqrHH39ct956a7WxyMhIeb1e/2uv11ttIr+c6Oi63xMM5DKHXOaQyxyn5nIK5mxymeXUXJJz\ns5HLHKfmMsvWP5D885//rIcfflhLlizRoEGDLhnv1auXdu3apbKyMp09e1ZFRUXq0qWLnREBAP/E\nnA0ADecyDMOwa2NTpkzRoUOH1LFjR0nfnhVZtmyZli9frpiYGA0dOlRr1qzRm2++KcMw9Itf/ELD\nhw+3Kx4A4ALM2QDQcLaWbQAAAOBqwkNtAAAAAItQtgEAAACLULYBAAAAi9j6UBuzfD6fMjMzdejQ\nIbndbmVlZalTp07+8c2bN+uFF15QaGioEhISNH78+DrXsSPXu+++qxUrVigkJERdunRRZmammjVr\nprFjxyoyMlKSdN111yknJ8fWXK+++qrWrl2rdu3aSZLmzZun66+/Pqj7q6SkRI8++qj/vQcOHNCM\nGTOUkpJi+f76zp49e7R48WKtWrWq2vJgHV915QrW8VVXrmAdX7XlCubxVVFRoSeeeEJffPGFysvL\nNWXKFA0dOtQ/Huzjyy5nz57VzJkz5fF4VFFRodmzZ6tPnz7V3rNmzRq98cYbCg0N1ZQpUzR48GDb\n8n3wwQfauHGjlixZcslYVlaWCgoKFBERIUnKzc0N6NaGVucKxv46f/68Zs6cqVOnTikiIkILFy70\n/3/9O3bur/r0AzvU53P4hhtusCWbZO7zzk5mPlfs2F/1mb9rZTjY+++/b8yaNcswDMPYvXu38eCD\nD/rHysvLjZ/85CfG6dOnjbKyMuOee+4xSkpKal3Hjlznzp0zhg4dapSWlhqGYRgZGRnGpk2bjPPn\nzxvx8fGNniXQXIZhGDNmzDA+++wzU+vYkes7BQUFRlpamlFZWWnL/jIMw3j55ZeNUaNGGYmJidWW\nB/P4qi1XMI+v2nIZRvCOr7pyfcfu4ysvL8/IysoyDMMw/vGPfxiDBg3yjwX7+LLT888/byxfvtww\nDMMoKioyxowZU238q6++MkaNGmWUlZUZZ86c8f/bDvPnzzeGDx9uPPLIIzWOJycnG6dOnbIly4Vq\nyxWs/fUf//Efxm9+8xvDMAzj3XffNebPn3/Je+zcX/XpB8HOZRg1z5N2Mft5F+xchhG8/VWf+bs2\njr6MZNeuXRo4cKAkqXfv3tq7d69/rKioSDExMWrdurXcbrf69u2rHTt21LqOHbncbrfeeOMNhYeH\nS5IqKyvVvHlzHTx4UOfOndOkSZOUnp6uwsJCW3NJ0r59+/Tyyy8rJSVFL730UkDr2JFLkgzD0Pz5\n85WZmamQkBBb9pckxcTEaOnSpZcsD+bxVVuuYB5fteWSgnd81ZVLCs7xddddd+nhhx/2bz8kJMQ/\nFuzjy04TJ05UcnKypLof+R4VFeV/5Lsd4uLilJmZWeOYz+dTcXGx5s6dq+TkZOXl5dmSqa5cwdpf\nFx6bd9xxh7Zt21Zt3O79VZ9+YIf6fA7bxeznXbBzScHbX/WZv2vj6MtIPB6P/2teSQoJCVFlZaVC\nQ0Mv+5jg2taxI1ezZs10zTXXSJJWrVql0tJSDRgwQJ9//rkmT56sxMREHT16VPfff782btxoWy5J\nGjlypFJTUxUZGampU6cqPz8/6PvrO5s3b1bnzp39Xw+1aNHC8v0lScOHD9fx48drzBys46u2XME8\nvmrLJQXv+KorlxSc4+u7r9I9Ho+mT5+uRx55xD8W7OPLKk595Pvlco0YMULbt2+vcZ3S0lLde++9\nuu+++1RVVaX09HT17NlTXbt2DWquYO2v9u3b+7cbERGhs2fPVhu3Y39dqD79wA71+Ry267Ips593\ndjH7uWLH/qrP/F0bR8/gFz8K2Ofz+Q/Yyz0muLZ17Mj13etFixbpL3/5i5YuXSqXy6Uf/ehH6tSp\nk//fbdq0UUlJiX7wgx/YksswDE2YMMF/gAwaNEj79+93xP6SpPXr1ys9Pd3/2o79ZSazncdXXYJ1\nfNUmmMdXIIJ1fJ04cUIPPfSQUlNTNXr0aP9yJx9fDWHnI98bI1dtwsPDlZ6e7v8WqV+/fjp48GCj\nlsf65ArW/po6dap/u16vV61atao2bsf+ulB9+oEd6vM5bOffKNQkmPurNsHeX2bn79o4+jKSuLg4\nbdmyRZJUWFhY7THAsbGxKi4u1unTp1VeXq6dO3eqT58+ta5jRy5Jmjt3rsrKypSbm+ufePLy8rRg\nwQJJ0smTJ+XxeBQdHW1bLo/Ho1GjRsnr9cowDG3fvl09e/Z0xP6SpL179youLs7/2o79VZtgHl91\nCdbxVZtgHl+BCMbx9fXXX2vSpEmaOXOmxo0bV23MycdXY2uqj3w/evSoUlJSVFVVpYqKChUUFKhH\njx7BjhW0/RUXF6ePPvpIkrRlyxb17du32rjd+6s+/cAO9fkcDrZg7q/aBHN/1Wf+ro2jT5kMGzZM\nW7duVXJysgzDUHZ2tjZs2KDS0lIlJSVp9uzZmjx5sgzDUEJCgjp06FDjOnbm6tmzp/Ly8nTLLbdo\nwoQJkqT09HSNGzdOc+bMUUpKilwul7Kzsxv9jFVd+ysjI0Pp6elyu93q37+/Bg0aJJ/PF9T9lZSU\npL///e+KjIyUy+Xyr2PH/qqJE46v2nIF8/iqLVcwj6+6cgXr+HrxxRd15swZ5ebmKjc3V9K3ZwzP\nnTvnuOPLSkuWLFF5ebl+9atfSar5ke9paWlKTU2VYRjKyMi45LpuO12YKz4+XuPHj1dYWJji4+PV\nuXNnR+QKxv5KSUnRrFmzlJKSorCwMP9dUoK1v+rTD+xQn8/hYHHC/qorV7D2V33m79rwuHYAAADA\nIo6+jAQAAABoyijbAAAAgEUo2wAAAIBFKNsAAACARSjbAAAAgEUcfes/oLHNmzdPBQUFqqio0LFj\nxxQbGytJSkpKksvlUkpKSpATAgDM2L59u2bMmKF169apffv2kqRXXnlFhYWFl30MOGAnbv2Hq9Lx\n48eVnp6uzZs3BzsKAKCBFi5cqKNHj2rZsmUqLCzU448/rry8vEuedAkEA2e2Acl/9mPatGkaMGCA\nBg8erJ07dyo6OlqpqalatWqVvvzySy1YsEC33nqriouLlZmZqdOnT6tFixb65S9/qe7duwf5fwUA\nXJ0yMjKUmJiolStX6rXXXtPChQsp2nAMrtkGLvL111/rzjvv1MaNGyVJmzZt0urVqzVt2jStWLFC\nkjRr1izNnDlT77zzjubPn6+MjIxgRgaAq5rb7dbixYu1YMECjRgxwhGPGwe+w5ltoAZ33HGHJKlj\nx47q27evJOnaa6/VmTNn5PV6tXfvXs2ZM8f//tLSUv3jH/9Q27Ztg5IXAK52BQUFatu2rbZt26ap\nU6cqNJSKA2fgzDZQA7fb7f93SEhItTGfzye3261169b5/1u7dq3atGljd0wAgKQ///nPWrp0qd54\n4w253W4tW7Ys2JEAP8o2YFJUVJSuv/56rVu3TpK0detW/fznPw9yKgC4OpWVlSkjI0MzZ87UD3/4\nQy1YsECvvfaaCgsLgx0NkETZBupl0aJFysvL0+jRo7VkyRI9++yzcrlcwY4FAFed7OxsdenSRfHx\n8ZK+vfxvzpw5mjlzprxeb5DTAdz6DwAAALAMZ7YBAAAAi1C2AQAAAItQtgEAAACLULYBAAAAi1C2\nAQAAAItQtgEAAACLULYBAAAAi1C2AQAAAIv8PwhBFE52BhVwAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "\n", "# create a figure and axes\n", "fig = plt.figure(figsize=(12,5))\n", "ax1 = plt.subplot(1,2,1) \n", "ax2 = plt.subplot(1,2,2)\n", "\n", "# set up the subplots as needed\n", "ax1.set_xlim(( 0, 2)) \n", "ax1.set_ylim((-2, 2))\n", "ax1.set_xlabel('Time')\n", "ax1.set_ylabel('Magnitude')\n", "\n", "ax2.set_xlim((-2,2))\n", "ax2.set_ylim((-2,2))\n", "ax2.set_xlabel('X')\n", "ax2.set_ylabel('Y')\n", "ax2.set_title('Phase Plane')\n", "\n", "# create objects that will change in the animation. These are\n", "# initially empty, and will be given new values for each frame\n", "# in the animation.\n", "txt_title = ax1.set_title('')\n", "line1, = ax1.plot([], [], 'b', lw=2) # ax.plot returns a list of 2D line objects\n", "line2, = ax1.plot([], [], 'r', lw=2)\n", "pt1, = ax2.plot([], [], 'g.', ms=20)\n", "line3, = ax2.plot([], [], 'y', lw=2)\n", "\n", "ax1.legend(['sin','cos']);" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.2 Step 2. Define a function to draw each frame](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.2-Step-2.-Define-a-function-to-draw-each-frame)", "section": "A.1.3.2 Step 2. Define a function to draw each frame" } }, "source": [ "### A.1.3.2 Step 2. Define a function to draw each frame\n", "\n", "The animiation function is a function you define to draw individual frames in the animation. The variable `n` will be the frame number. The function draws the frame by resetting the data values for the global objects `txt_title`, `line1`, `line2`, `pt1`, and `line3` that were defined above." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.2 Step 2. Define a function to draw each frame](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.2-Step-2.-Define-a-function-to-draw-each-frame)", "section": "A.1.3.2 Step 2. Define a function to draw each frame" } }, "outputs": [], "source": [ "# animation function. This is called sequentially\n", "def drawframe(n):\n", " x = np.linspace(0, 2, 1000)\n", " y1 = np.sin(2 * np.pi * (x - 0.01 * n))\n", " y2 = np.cos(2 * np.pi * (x - 0.01 * n))\n", " line1.set_data(x, y1)\n", " line2.set_data(x, y2)\n", " line3.set_data(y1[0:50],y2[0:50])\n", " pt1.set_data(y1[0],y2[0])\n", " txt_title.set_text('Frame = {0:4d}'.format(n))\n", " return (line1,line2)" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.3 Step 3. Create the Animation Object](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.3-Step-3.-Create-the-Animation-Object)", "section": "A.1.3.3 Step 3. Create the Animation Object" } }, "source": [ "### A.1.3.3 Step 3. Create the Animation Object\n", "\n", "The animation class includes a function `FuncAnimation` that incorporations a user-specified function to update the figure for each frame of the animation. The result is an animation object which is subsequently called to actually produce the desired animation." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.3 Step 3. Create the Animation Object](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.3-Step-3.-Create-the-Animation-Object)", "section": "A.1.3.3 Step 3. Create the Animation Object" } }, "outputs": [], "source": [ "from matplotlib import animation\n", "\n", "# blit=True re-draws only the parts that have changed.\n", "anim = animation.FuncAnimation(fig, drawframe, frames=100, interval=20, blit=True)" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "source": [ "### A.1.3.4 Step 4. Render the Animation\n", "\n", "The final step is to actually render and display the desired animation. This is the compute-intensive step in the procedure. The next cell imports `HTML` which is used to display a HTML elements created in a python script. The animation is rendered to html5 video with the `to_html5_video()` function and then displayed with `HTML()`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML(anim.to_html5_video())" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "source": [ "An alternative to the use of HTML is to set the default rendering of an animation object. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true, "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "outputs": [], "source": [ "from matplotlib import rc\n", "\n", "# equivalent to rcParams['animation.html'] = 'html5'\n", "rc('animation', html='html5')" ] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "source": [ "Once the default rendering of the animation object is set to html5, all you have to do is ask to display the animation object. Everything is then done behind the scenes to render and display the desired animation." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "nbpages": { "level": 3, "link": "[A.1.3.4 Step 4. Render the Animation](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.3.4-Step-4.-Render-the-Animation)", "section": "A.1.3.4 Step 4. Render the Animation" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "anim" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "nbpages": { "level": 2, "link": "[A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.4-Example:-Phase-Plane-Animation-for-an-Exothermic-Stirred-Tank-Reactor)", "section": "A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor" } }, "source": [ "## A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor\n", "\n", "This is more complex example that demonstrates the complex dynamics of an exothermic continuous stirred-tank reactor when operated with an unstable steady state. The computational strategy is to compute solutions to the dynamical model for a set of initial conditions, then step through the solutions simulataneously to draw frames in the animation." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "nbpages": { "level": 2, "link": "[A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.4-Example:-Phase-Plane-Animation-for-an-Exothermic-Stirred-Tank-Reactor)", "section": "A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor" }, "scrolled": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import seaborn as sns\n", "from scipy.integrate import odeint\n", "\n", "from matplotlib import animation\n", "from IPython.display import HTML\n", "\n", "# mode parameteres\n", "Ea = 72750 # activation energy J/gmol\n", "R = 8.314 # gas constant J/gmol/K\n", "k0 = 7.2e10 # Arrhenius rate constant 1/min\n", "V = 100.0 # Volume [L]\n", "rho = 1000.0 # Density [g/L]\n", "Cp = 0.239 # Heat capacity [J/g/K]\n", "dHr = -5.0e4 # Enthalpy of reaction [J/mol]\n", "UA = 5.0e4 # Heat transfer [J/min/K]\n", "q = 100.0 # Flowrate [L/min]\n", "cAi = 1.0 # Inlet feed concentration [mol/L]\n", "Ti = 350.0 # Inlet feed temperature [K]\n", "cA0 = 0.5; # Initial concentration [mol/L]\n", "T0 = 350.0; # Initial temperature [K]\n", "Tc = 305.0 # Coolant temperature [K]\n", "\n", "# Arrhenius rate expression\n", "def k(T):\n", " return k0*np.exp(-Ea/R/T)\n", "\n", "def deriv(y,t):\n", " cA,T = y\n", " dcA = (q/V)*(cAi - cA) - k(T)*cA\n", " dT = (q/V)*(Ti - T) + (-dHr/rho/Cp)*k(T)*cA + (UA/V/rho/Cp)*(Tc-T)\n", " return [dcA,dT]\n", "\n", "# create a set of initial conditions\n", "ICs = [[cA0,T0] for cA0 in [0] for T0 in np.linspace(295,480,19)]\n", "ICs += [[cA0,T0] for cA0 in np.linspace(0,1,21) for T0 in [290]]\n", "ICs += [[cA0,T0] for cA0 in [1] for T0 in np.linspace(295,475,18)]\n", "\n", "# perform simulations for each of the initial conditions\n", "t = np.linspace(0,10.0,800)\n", "sols = [odeint(deriv,IC,t) for IC in ICs]\n", "\n", "# create background figure and axes\n", "sns.set(font_scale=1.5)\n", "fig, ax = plt.subplots(figsize=(8,8))\n", "ax.set_xlim((0,1))\n", "ax.set_ylim((290,480))\n", "ax.set_xlabel('Concentration [gmol/liter]')\n", "ax.set_ylabel('Temperature [K]')\n", "ax.set_title('Exothermic Reactor with Tc = {0:.1f} K'.format(Tc))\n", "\n", "# create lists of colors, points, and lines\n", "colors = sns.color_palette(\"husl\",len(sols))\n", "pts = sum([ax.plot([],[],'o',color=colors[k],ms=15) for k in range(0,len(sols))],[])\n", "lines = sum([ax.plot([],[],color=colors[k],lw=2) for k in range(0,len(sols))],[])\n", "\n", "# don't show the plain background\n", "plt.close()\n", "\n", "# define function to draw each frame\n", "def drawframe(n):\n", " for k in range(0,len(sols)):\n", " C,T = sols[k].T\n", " pts[k].set_data(C[n],T[n])\n", " lines[k].set_data(C[:n],T[:n])\n", " return pts + lines\n", "\n", "# create animiation object and render in HTML video\n", "anim = animation.FuncAnimation(fig, drawframe, frames=len(t), interval=20, blit=True)\n", "HTML(anim.to_html5_video())" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "nbpages": { "level": 2, "link": "[A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.4-Example:-Phase-Plane-Animation-for-an-Exothermic-Stirred-Tank-Reactor)", "section": "A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor" } }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "nbpages": { "level": 2, "link": "[A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor](https://jckantor.github.io/cbe30338-2021/A.01-Animation-in-Jupyter-Notebooks.html#A.1.4-Example:-Phase-Plane-Animation-for-an-Exothermic-Stirred-Tank-Reactor)", "section": "A.1.4 Example: Phase Plane Animation for an Exothermic Stirred-Tank Reactor" } }, "source": [ "\n", "< [A.0 Appendices](https://jckantor.github.io/cbe30338-2021/A.00-Appendices.html) | [Contents](toc.html) | [Tag Index](tag_index.html) |

\"Open

\"Download\"" ] } ], "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.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }