{ "cells": [ { "cell_type": "markdown", "id": "68eaace0-94bf-4d58-8d98-ff5f453a3f78", "metadata": {}, "source": [ "# Heat Transfer Problem\n", "\n", "A wall 0.12 m thick has a thermal diffusivity of 1.5*10^(-6) m^2/s and is initially at a uniform temperature of 85 deg C. Suddenly, one face is lowered to a temperature of 20 deg C, while the other face is perfectly insulated. Using an explicit finite deference technique with time increments of 300s, find the temperature distribution at t = 45 minutes througout the wall.\n", "\n", "\n", "Assume:\n", "- Unsteady\n", "- 1D\n", "- Constant properties\n", "- Neg. Radiation\n" ] }, { "cell_type": "markdown", "id": "b3fde277", "metadata": {}, "source": [ "### Input:\n", "- alpha: thermal diffusivity (m^2/s)\n", "- T_i: initial temperature (°C)\n", "- dt: time step (s)\n", "- T_0: boundary temperature (°C)\n", "- F_0: Fourier number (dimensionless)\n", "- thickness: length of the rod (m)\n", "- t_final: final time (s)" ] }, { "cell_type": "code", "execution_count": 2, "id": "c9f2059c-2807-4483-8ec4-0eb69a4b604d", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import math\n", "from matplotlib.animation import FuncAnimation\n", "import matplotlib.pyplot as plt\n", "\n", "# Input parameters\n", "alpha = 1.5e-6 # m^2/s\n", "T_i = 85 # degC\n", "dt = 300 # s\n", "T_0 = 20 # degC\n", "F_0 = 0.5\n", "thickness = 0.12 # m\n", "t_final = 45 * 60 # s\n" ] }, { "cell_type": "markdown", "id": "43d4c367", "metadata": {}, "source": [ "### Create our equations" ] }, { "cell_type": "code", "execution_count": 3, "id": "fc9fff42", "metadata": {}, "outputs": [], "source": [ "dx = np.sqrt(alpha*dt/F_0)\n", "t = np.arange(0,t_final+1,dt)\n", "\n", "no_internal_nodes = int(thickness/dx)\n", "no_phantom_nodes = math.ceil((len(t) - no_internal_nodes)/2)\n", "total_nodes = 1+no_internal_nodes+no_phantom_nodes" ] }, { "cell_type": "markdown", "id": "b2977e5f-a777-45d0-be70-de80bf652fac", "metadata": {}, "source": [ "- Initialize imposed temperature T_0 and initial uniform temp distribution\n", "- For each column starting at T_1 to end: average the previous temperature of the adjacent nodes." ] }, { "cell_type": "code", "execution_count": 4, "id": "03044026", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[20. 85. 85. 85. 85. ]\n", " [20. 52.5 85. 85. 85. ]\n", " [20. 52.5 68.75 85. 85. ]\n", " [20. 44.375 68.75 76.875 85. ]\n", " [20. 44.375 60.625 76.875 80.938]\n", " [20. 40.312 60.625 70.782 80.938]\n", " [20. 40.312 55.547 70.782 76.875]\n", " [20. 37.774 55.547 66.211 76.875]\n", " [20. 37.774 51.992 66.211 73.32 ]\n", " [20. 35.996 51.992 62.656 73.32 ]]\n" ] } ], "source": [ "Temp = np.zeros((len(t),total_nodes))\n", "\n", "# Imposed temperature T_0\n", "Temp[:,0] = T_0\n", "\n", "# Initialize temperatures of upper triangle\n", "for i in range(len(t)):\n", " for j in range(i,total_nodes-1):\n", " Temp[i,j+1]=T_i\n", "\n", "# Calculates averages temperatures of lower triangle\n", "for i in range(1,len(t)):\n", " for j in range(1,total_nodes-1):\n", " Temp[i,j]=round((Temp[i-1,j-1]+Temp[i-1,j+1])/2, 3)\n", "\n", "# Remove phantom nodes\n", "Temp = np.delete(Temp, np.s_[-no_phantom_nodes:], axis=1)\n", "print(Temp)" ] }, { "cell_type": "markdown", "id": "445305be", "metadata": {}, "source": [ "### Visualization" ] }, { "cell_type": "code", "execution_count": 5, "id": "fbd3afb0-cd92-4d3c-89bc-5aa802ccc411", "metadata": {}, "outputs": [ { "data": { "image/png": "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p5UrVyojI0OlpaVKTk5WQUGBax++e3A+1ekfie+fajN91DXXXGOOGTOmwrZLL73UfOqpp7xUERqC5557zuzWrVuVz5WXl5vR0dHmSy+95Np26tQpMywszPzLX/5imqZpHj9+3AwICDDnzJnj2mffvn2mn5+fOX/+/DqtHd4lyZw3b57rsaf6ZevWraYkc+XKla59VqxYYUoyv/vuuzo+KtQHe++YpmmOHDnSHDx48HlfQ+/gjNzcXFOSmZmZaZom3z1wj71/TJPvH3f45IxSSUmJ1q5dq+Tk5Arbk5OTtXz5ci9VhYZix44dio2NVUJCgu699179+OOPkqSsrCzl5ORU6BuHw6G+ffu6+mbt2rVyOp0V9omNjVVSUhK91ch4ql9WrFihsLAw9ezZ07XPtddeq7CwMHrKxy1evFiRkZHq1KmTRo0apdzcXNdz9A7OOHHihCSpZcuWkvjugXvs/XMG3z/V45NB6fDhwyorK1NUVFSF7VFRUcrJyfFSVWgIevbsqffff19fffWV3nrrLeXk5Kh37946cuSIqzcu1Dc5OTkKDAxUeHj4efdB4+CpfsnJyVFkZGSl94+MjKSnfNigQYP0wQcfaOHChfrjH/+o1atXq3///iouLpZE78BimqYmTJig66+/XklJSZL47kH1VdU/Et8/7mji7QLqkmEYFR6bpllpGxqXQYMGuX7u0qWLevXqpQ4dOmjWrFmuCxlr0jf0VuPliX6pan96yrcNHTrU9XNSUpJ69Oih+Ph4ff7550pJSTnv6+idxmX8+PHauHGjli1bVuk5vnvwU87XP3z/VJ9Pzii1atVK/v7+lRJtbm5upd/AoHFr1qyZunTpoh07drhWv7tQ30RHR6ukpETHjh077z5oHDzVL9HR0Tp48GCl9z906BA91YjExMQoPj5eO3bskETvQHr00Uf16aefatGiRWrbtq1rO989qI7z9U9V+P45P58MSoGBgerevbsyMjIqbM/IyFDv3r29VBUaouLiYm3btk0xMTFKSEhQdHR0hb4pKSlRZmamq2+6d++ugICACvscOHBAmzdvprcaGU/1S69evXTixAl98803rn1WrVqlEydO0FONyJEjR7Rnzx7FxMRIoncaM9M0NX78eH388cdauHChEhISKjzPdw8u5Kf6pyp8/1xAvS8fUU/mzJljBgQEmO+88465detWMzU11WzWrJm5a9cub5cGL3r88cfNxYsXmz/++KO5cuVK8/bbbzdDQkJcffHSSy+ZYWFh5scff2xu2rTJvO+++8yYmBgzLy/P9R5jxowx27Zta/7v//6vuW7dOrN///5mt27dzNLSUm8dFupIfn6+uX79enP9+vWmJHP69Onm+vXrzd27d5um6bl+ueWWW8yuXbuaK1asMFesWGF26dLFvP322+v9eOE5F+qd/Px88/HHHzeXL19uZmVlmYsWLTJ79epltmnTht6B+ctf/tIMCwszFy9ebB44cMA1CgsLXfvw3YPz+an+4fvHPT4blEzTNF977TUzPj7eDAwMNK+66qoKSyOicRo6dKgZExNjBgQEmLGxsWZKSoq5ZcsW1/Pl5eXmc889Z0ZHR5sOh8O84YYbzE2bNlV4j6KiInP8+PFmy5YtzeDgYPP22283s7Oz6/tQUA8WLVpkSqo0Ro4caZqm5/rlyJEj5vDhw82QkBAzJCTEHD58uHns2LF6OkrUhQv1TmFhoZmcnGy2bt3aDAgIMNu1a2eOHDmyUl/QO41TVX0jyXz33Xdd+/Ddg/P5qf7h+8c9hmmaZv3NXwEAAABAw+eT1ygBAAAAQG0QlAAAAADAhqAEAAAAADYEJQAAAACwISgBAAAAgA1BCQAAAABsCEoAAAAAYENQAgAAAAAbghIAoMFKS0vTz372M699/jPPPKNHHnmkWvs+8cQT+tWvflXHFQEA6othmqbp7SIAAI2PYRgXfH7kyJGaOXOmiouLFRERUU9VnXXw4EElJiZq48aNat++/U/un5ubqw4dOmjjxo1KSEio+wIBAHWKoAQA8IqcnBzXz3PnztWzzz6r7du3u7YFBwcrLCzMG6VJktLT05WZmamvvvqq2q+566671LFjR7388st1WBkAoD5w6h0AwCuio6NdIywsTIZhVNpmP/XugQce0JAhQ5Senq6oqCi1aNFCU6ZMUWlpqZ588km1bNlSbdu21V//+tcKn7Vv3z4NHTpU4eHhioiI0ODBg7Vr164L1jdnzhzdeeedFbZ99NFH6tKli4KDgxUREaGbb75ZBQUFrufvvPNOffjhh7X+uwEAeB9BCQBwUVm4cKH279+vJUuWaPr06UpLS9Ptt9+u8PBwrVq1SmPGjNGYMWO0Z88eSVJhYaFuvPFGNW/eXEuWLNGyZcvUvHlz3XLLLSopKanyM44dO6bNmzerR48erm0HDhzQfffdp4ceekjbtm3T4sWLlZKSonNPzLjmmmu0Z88e7d69u27/EgAAdY6gBAC4qLRs2VJ//vOf1blzZz300EPq3LmzCgsL9dvf/laJiYmaNGmSAgMD9fXXX0uyZob8/Pz09ttvq0uXLrrsssv07rvvKjs7W4sXL67yM3bv3i3TNBUbG+vaduDAAZWWliolJUXt27dXly5dNHbsWDVv3ty1T5s2bSTpJ2erAAANXxNvFwAAgDuuuOIK+fmd/T1fVFSUkpKSXI/9/f0VERGh3NxcSdLatWu1c+dOhYSEVHifU6dO6YcffqjyM4qKiiRJQUFBrm3dunXTTTfdpC5dumjgwIFKTk7W3XffrfDwcNc+wcHBkqxZLADAxY2gBAC4qAQEBFR4bBhGldvKy8slSeXl5erevbs++OCDSu/VunXrKj+jVatWkqxT8M7s4+/vr4yMDC1fvlwLFizQq6++qsmTJ2vVqlWuVe6OHj16wfcFAFw8OPUOAODTrrrqKu3YsUORkZHq2LFjhXG+VfU6dOig0NBQbd26tcJ2wzB03XXXacqUKVq/fr0CAwM1b9481/ObN29WQECArrjiijo9JgBA3SMoAQB82vDhw9WqVSsNHjxYS5cuVVZWljIzM/XYY49p7969Vb7Gz89PN998s5YtW+batmrVKqWnp2vNmjXKzs7Wxx9/rEOHDumyyy5z7bN06VL16dPHdQoeAODiRVACAPi0pk2basmSJWrXrp1SUlJ02WWX6aGHHlJRUZFCQ0PP+7pHHnlEc+bMcZ3CFxoaqiVLlujWW29Vp06d9PTTT+uPf/yjBg0a5HrNhx9+qFGjRtX5MQEA6h43nAUAoAqmaeraa69Vamqq7rvvvp/c//PPP9eTTz6pjRs3qkkTLgEGgIsdM0oAAFTBMAy9+eabKi0trdb+BQUFevfddwlJAOAjmFECAAAAABtmlAAAAADAhqAEAAAAADYEJQAAAACwISgBAAAAgA1BCQAAAABsCEoAAAAAYENQAgAAAAAbghIAAAAA2BCUAAAAAMDm/wEoaIR+k/2F7gAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plotting time vs temperature at all nodes\n", "plt.figure(figsize=(10, 6))\n", "plt.title('Temperature at all nodes over time')\n", "plt.xlabel('Time (s)')\n", "plt.ylabel('Temperature (°C)')\n", "plt.xlim(0, t_final)\n", "plt.ylim(0, T_i)\n", "plt.grid()\n", "for j in range(Temp.shape[1]):\n", " plt.plot(t, Temp[:, j], label=f'Node {j}')\n", "plt.legend(loc='upper right')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 6, "id": "ff837a7c", "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\n", "window.mpl = {};\n", "\n", "mpl.get_websocket_type = function () {\n", " if (typeof WebSocket !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof MozWebSocket !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert(\n", " 'Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.'\n", " );\n", " }\n", "};\n", "\n", "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = this.ws.binaryType !== undefined;\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById('mpl-warnings');\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent =\n", " 'This browser does not support binary websocket messages. ' +\n", " 'Performance may be slow.';\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message('supports_binary', { value: fig.supports_binary });\n", " fig.send_message('send_image_mode', {});\n", " if (fig.ratio !== 1) {\n", " fig.send_message('set_device_pixel_ratio', {\n", " device_pixel_ratio: fig.ratio,\n", " });\n", " }\n", " fig.send_message('refresh', {});\n", " };\n", "\n", " this.imageObj.onload = function () {\n", " if (fig.image_mode === 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function () {\n", " fig.ws.close();\n", " };\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "};\n", "\n", "mpl.figure.prototype._init_header = function () {\n", " var titlebar = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute('tabindex', '0');\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;' +\n", " 'z-index: 2;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box;' +\n", " 'pointer-events: none;' +\n", " 'position: relative;' +\n", " 'z-index: 0;'\n", " );\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box;' +\n", " 'left: 0;' +\n", " 'pointer-events: none;' +\n", " 'position: absolute;' +\n", " 'top: 0;' +\n", " 'z-index: 1;'\n", " );\n", "\n", " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", " if (this.ResizeObserver === undefined) {\n", " if (window.ResizeObserver !== undefined) {\n", " this.ResizeObserver = window.ResizeObserver;\n", " } else {\n", " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", " this.ResizeObserver = obs.ResizeObserver;\n", " }\n", " }\n", "\n", " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", " // There's no need to resize if the WebSocket is not connected:\n", " // - If it is still connecting, then we will get an initial resize from\n", " // Python once it connects.\n", " // - If it has disconnected, then resizing will clear the canvas and\n", " // never get anything back to refill it, so better to not resize and\n", " // keep something visible.\n", " if (fig.ws.readyState != 1) {\n", " return;\n", " }\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " /* This rescales the canvas back to display pixels, so that it\n", " * appears correct on HiDPI screens. */\n", " canvas.style.width = width + 'px';\n", " canvas.style.height = height + 'px';\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " this.resizeObserverInstance.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " /* User Agent sniffing is bad, but WebKit is busted:\n", " * https://bugs.webkit.org/show_bug.cgi?id=144526\n", " * https://bugs.webkit.org/show_bug.cgi?id=181818\n", " * The worst that happens here is that they get an extra browser\n", " * selection when dragging, if this check fails to catch them.\n", " */\n", " var UA = navigator.userAgent;\n", " var isWebKit = /AppleWebKit/.test(UA) && !/Chrome/.test(UA);\n", " if(isWebKit) {\n", " return function (event) {\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We\n", " * want to control all of the cursor setting manually through\n", " * the 'cursor' event from matplotlib */\n", " event.preventDefault()\n", " return fig.mouse_event(event, name);\n", " };\n", " } else {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " canvas_div.addEventListener(\n", " 'dblclick',\n", " on_mouse_event_closure('dblclick')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " canvas_div.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " canvas_div.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " canvas_div.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " canvas_div.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\n", " return false;\n", " });\n", "\n", " function set_focus() {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "};\n", "\n", "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", "};\n", "\n", "mpl.figure.prototype.send_message = function (type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "};\n", "\n", "mpl.figure.prototype.send_draw_message = function () {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "};\n", "\n", "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", " y1 = Math.floor(y1) + 0.5;\n", " var min_x = Math.min(x0, x1);\n", " var min_y = Math.min(y0, y1);\n", " var width = Math.abs(x1 - x0);\n", " var height = Math.abs(y1 - y0);\n", "\n", " fig.rubberband_context.clearRect(\n", " 0,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "};\n", "\n", "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "};\n", "\n", "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", " fig.canvas_div.style.cursor = msg['cursor'];\n", "};\n", "\n", "mpl.figure.prototype.handle_message = function (fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "};\n", "\n", "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "};\n", "\n", "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "};\n", "\n", "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Called whenever the canvas gets updated.\n", " this.send_message('ack', {});\n", "};\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function (fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " var img = evt.data;\n", " if (img.type !== 'image/png') {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " img.type = 'image/png';\n", " }\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src\n", " );\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " img\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig['handle_' + msg_type];\n", " } catch (e) {\n", " console.log(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\n", " }\n", " }\n", " };\n", "};\n", "\n", "function getModifiers(event) {\n", " var mods = [];\n", " if (event.ctrlKey) {\n", " mods.push('ctrl');\n", " }\n", " if (event.altKey) {\n", " mods.push('alt');\n", " }\n", " if (event.shiftKey) {\n", " mods.push('shift');\n", " }\n", " if (event.metaKey) {\n", " mods.push('meta');\n", " }\n", " return mods;\n", "}\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * https://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys(original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object') {\n", " obj[key] = original[key];\n", " }\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function (event, name) {\n", " if (name === 'button_press') {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " // from https://stackoverflow.com/q/1114465\n", " var boundingRect = this.canvas.getBoundingClientRect();\n", " var x = (event.clientX - boundingRect.left) * this.ratio;\n", " var y = (event.clientY - boundingRect.top) * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " buttons: event.buttons,\n", " modifiers: getModifiers(event),\n", " guiEvent: simpleKeys(event),\n", " });\n", "\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", " // Handle any extra behaviour associated with a key event\n", "};\n", "\n", "mpl.figure.prototype.key_event = function (event, name) {\n", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.key === this._key) {\n", " return;\n", " } else {\n", " this._key = event.key;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.key !== 'Control') {\n", " value += 'ctrl+';\n", " }\n", " else if (event.altKey && event.key !== 'Alt') {\n", " value += 'alt+';\n", " }\n", " else if (event.shiftKey && event.key !== 'Shift') {\n", " value += 'shift+';\n", " }\n", "\n", " value += 'k' + event.key;\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", " return false;\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", " if (name === 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message('toolbar_button', { name: name });\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "\n", "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", "// prettier-ignore\n", "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\", \"webp\"];\n", "\n", "mpl.default_extension = \"png\";/* global mpl */\n", "\n", "var comm_websocket_adapter = function (comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.binaryType = comm.kernel.ws.binaryType;\n", " ws.readyState = comm.kernel.ws.readyState;\n", " function updateReadyState(_event) {\n", " if (comm.kernel.ws) {\n", " ws.readyState = comm.kernel.ws.readyState;\n", " } else {\n", " ws.readyState = 3; // Closed state.\n", " }\n", " }\n", " comm.kernel.ws.addEventListener('open', updateReadyState);\n", " comm.kernel.ws.addEventListener('close', updateReadyState);\n", " comm.kernel.ws.addEventListener('error', updateReadyState);\n", "\n", " ws.close = function () {\n", " comm.close();\n", " };\n", " ws.send = function (m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function (msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " var data = msg['content']['data'];\n", " if (data['blob'] !== undefined) {\n", " data = {\n", " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", " };\n", " }\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(data);\n", " });\n", " return ws;\n", "};\n", "\n", "mpl.mpl_figure_comm = function (comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.on(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\n", " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable();\n", " fig.parent_element.innerHTML =\n", " '';\n", " fig.close_ws(fig, msg);\n", "};\n", "\n", "mpl.figure.prototype.close_ws = function (fig, msg) {\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "};\n", "\n", "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\n", "};\n", "\n", "mpl.figure.prototype.updated_canvas_event = function () {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message('ack', {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\n", " for (var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " if (event.target !== this) {\n", " // Ignore bubbled events from children.\n", " return;\n", " }\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('tabindex', 0);\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "};\n", "\n", "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\n", "};\n", "\n", "mpl.find_output_cell = function (html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i = 0; i < ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code') {\n", " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] === html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "};\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel !== null) {\n", " IPython.notebook.kernel.comm_manager.register_target(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Animations in Jupyter Notebook\n", "%matplotlib notebook\n", "\n", "# Animation\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "ax.set_title('Temperature distribution over time')\n", "ax.set_xlabel('Distance (m)')\n", "ax.set_ylabel('Temperature (°C)')\n", "ax.set_xlim(0, thickness)\n", "ax.set_ylim(0, T_i)\n", "ax.grid()\n", "\n", "line, = ax.plot([], [], label='Time = 0 s')\n", "legend = ax.legend(loc='upper right')\n", "\n", "def init():\n", " line.set_data([], [])\n", " return line,\n", "\n", "def update(frame):\n", " time = frame * dt\n", " line.set_data(np.linspace(0, thickness, Temp.shape[1]), Temp[frame])\n", " line.set_label(f'Time = {time} s')\n", " legend = ax.legend(loc='upper right')\n", " return line, legend\n", "\n", "ani = FuncAnimation(fig, update, frames=len(t), init_func=init, blit=True, interval=100)\n", "\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12.9" } }, "nbformat": 4, "nbformat_minor": 5 }