{ "metadata": { "name": "", "signature": "sha256:5b76069e0e751e9e0117b297530db92683d26f33bad3f8fc2b9ba3e41f085293" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Adding HTML elements to figures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook contains examples how to add HTML elements to figures and create interaction between Javascript and Python code.\n", "\n", "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline\n", "import matplotlib.pylab as plt\n", "import mpld3\n", "mpld3.enable_notebook()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Simple example: slider plugin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We add a simple slider HTML element ```` to our figure. When slider position is changed, we call ``kernel.execute()`` and pass updated value to Python function ``runCalculation()``. In this simple example we just update the frequency $\\omega$ of $\\sin(\\omega x)$." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class SliderView(mpld3.plugins.PluginBase):\n", " \"\"\" Add slider and JavaScript / Python interaction. \"\"\"\n", "\n", " JAVASCRIPT = \"\"\"\n", " mpld3.register_plugin(\"sliderview\", SliderViewPlugin);\n", " SliderViewPlugin.prototype = Object.create(mpld3.Plugin.prototype);\n", " SliderViewPlugin.prototype.constructor = SliderViewPlugin;\n", " SliderViewPlugin.prototype.requiredProps = [\"idline\", \"callback_func\"];\n", " SliderViewPlugin.prototype.defaultProps = {}\n", "\n", " function SliderViewPlugin(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", " };\n", "\n", " SliderViewPlugin.prototype.draw = function(){\n", " var line = mpld3.get_element(this.props.idline);\n", " var callback_func = this.props.callback_func;\n", "\n", " var div = d3.select(\"#\" + this.fig.figid);\n", "\n", " // Create slider\n", " div.append(\"input\").attr(\"type\", \"range\").attr(\"min\", 0).attr(\"max\", 10).attr(\"step\", 0.1).attr(\"value\", 1)\n", " .on(\"change\", function() {\n", " var command = callback_func + \"(\" + this.value + \")\";\n", " console.log(\"running \"+command);\n", " var callbacks = { 'iopub' : {'output' : handle_output}};\n", " var kernel = IPython.notebook.kernel;\n", " kernel.execute(command, callbacks, {silent:false});\n", " });\n", "\n", " function handle_output(out){\n", " //console.log(out);\n", " var res = null;\n", " // if output is a print statement\n", " if (out.msg_type == \"stream\"){\n", " res = out.content.data;\n", " }\n", " // if output is a python object\n", " else if(out.msg_type === \"pyout\"){\n", " res = out.content.data[\"text/plain\"];\n", " }\n", " // if output is a python error\n", " else if(out.msg_type == \"pyerr\"){\n", " res = out.content.ename + \": \" + out.content.evalue;\n", " alert(res);\n", " }\n", " // if output is something we haven't thought of\n", " else{\n", " res = \"[out type not implemented]\"; \n", " }\n", "\n", " // Update line data\n", " line.data = JSON.parse(res);\n", " line.elements()\n", " .attr(\"d\", line.datafunc(line.data))\n", " .style(\"stroke\", \"black\");\n", "\n", " }\n", "\n", " };\n", " \"\"\"\n", "\n", " def __init__(self, line, callback_func):\n", " self.dict_ = {\"type\": \"sliderview\",\n", " \"idline\": mpld3.utils.get_id(line),\n", " \"callback_func\": callback_func}" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "\n", "def updateSlider(val1):\n", " t = np.linspace(0, 10, 500)\n", " y = np.sin(val1*t)\n", " return map(list, list(zip(list(t), list(y))))\n", "\n", "fig, ax = plt.subplots(figsize=(8, 4))\n", "\n", "t = np.linspace(0, 10, 500)\n", "y = np.sin(t)\n", "ax.set_xlabel('Time')\n", "ax.set_ylabel('Amplitude')\n", "\n", "# create the line object\n", "line, = ax.plot(t, y, '-k', lw=3, alpha=0.5)\n", "ax.set_ylim(-1.2, 1.2)\n", "ax.set_title(\"Slider demo\")\n", "\n", "mpld3.plugins.connect(fig, SliderView(line, callback_func=\"updateSlider\"))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAfsAAAEZCAYAAACQB4xbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl0lPed5/t3aQeEkMS+CAQII1aJXRISCAQYYwOG4Njg\nxEnmnE5P387puXf63kl6zr037nOnT3fmdE8ynUx3Mj3HiZM4MXaMbXYDBgnQgpCExL4ZxGp2gZAQ\nWuv+8ZQe6hFClISqnlo+r3Oeo/rV+rXMo299f89vARERERERERERERERERERERERERERERERERER\nERGRoPVd4IBb+yGQ7OFze9u7wO+8+P4i4qEwuwMQkW7LBoqA+8Bd4CAw+xnP7Q9U+yaspzht+lwR\n6SDC7gBEpFvigK3AnwMfAdFADtDo4zjCgDYff6aI9JAqe5HA8hJGxbzR9fMxsBs49ozntwHjXLcH\nApuBB8AhYHyH56a63usucBp4w+2x3wD/CmwH6oDcTj5rLFAA1AK7gEEdHs/A6JGoASqBhW6P5QP/\nH1CIcelhs+v1H7jiLQXGuD0/CziM0btRCmR2Eo+IiEhA6g/cwUi+y4GEDo9/F+t1ePdk/6Hr6ANM\nAa4C+12P9QOuAN/BKALSgdvAJNfjv8FIrO1JNbqT2IqBfwQiMXobaoHfuh4b6Yp7uau9xNUe6Grn\nA2cxvjDEASeAc8BiIBx4H3jP9dxEjC8Mb7tifQu457pfREQkKKQCv8ZIzs3A58AQ12PfpfNkHw40\nYfQMtPs7t+e+yZPE3+5XwP/ruv0b1/Eso12x9HG77wOeJPsfut1utxN4x3V7H/A3bo/9I7DNrf0a\ncMR1+9tASYf3KsL4oiIinVA3vkjgOQ18D0gCpgIjgJ895zWDMcboXHG777Lb7THAPIyKuf3YAAx1\nPe7s8NqORrhe0+B23yXA4fb+b3R4//nAMLfn33S7/Ri41aEd6/ZZ7rG3f9bILuITCWlK9iKB7QxG\nF/fU5zzvNtCCUYG3c799GeN6e4Lb0R/4Sw/j+Nr1mr5u943hyYj8yxjT8Dq+/399xvt1NZL/Gtbr\n9+2fddXDWEVCjpK9SGCZCPxHnlSxScB6jOvlXWkFNmHMfe8DTMbo9m5Pqtswuvi/hXHNPRKYg3HJ\nAJ5U6M9yCSgD/tb12myMrvd2vwdWAsswLinEYAzyc6/GHc+43dEOV6zrMXor3nTFufU5MYqELCV7\nkcDyEKO7/RDGqPhi4Cjw167HnVirYvfbP8DoCr+BMdjtPbfHHmIk4rcwKuevgb8Hop7xvp3Z4Irt\nHsa1/vfdHrsKrAb+M0b3/GVXzO5JvWPcHT+vvX0X44vEX2MM8vs/Xe17z4lPRERERERERERERERE\nRERERERERESk9zxvOk1ASEtLc1ZVVdkdhoiIiK9UYSxr7ZGgmHpXVVWF0+nU4cXjxz/+se0xBPuh\n37F+z8Fy6Hfs/QNI606eDIpkLyIiIs+mZC8iIhLklOzFI7m5uXaHEPT0O/YN/Z69T79j/xMUA/QA\np+sahoiISNBzOBzQjRyuyl5ERCTIKdmLiIgEOSV7ERGRIKdkLyIiEuSU7EVERIKckr2IiEiQU7IX\nEREJckr2IiIiQc7uZP8ecBM41sVz/hk4h7HDzwxfBCUiIhJM7E72vwaWd/H4CiAFmAB8H/hXXwQl\nIiISTCJs/vwDQHIXj68C3nfdPgTEA0MxegOkg+bmZmpqanj06BHNzc2EhYURGRlJ//79iYuLIzw8\n3O4QRSRAOZ1O6uvruX//Po2NjbS2thIZGUlMTAzx8fH06dPH7hClC3Yn++cZCVxxa18FRqFkD0Bt\nbS3nz5/n/Pnz3Lhxg5qaGp61R0B4eDjDhg1j5MiRjB07lpSUFCIjI30csYgEipaWFq5cucKFCxe4\nePEit27doqmp6ZnPj42NJSkpidGjRzNhwgQGDRrkw2jlefw92cPTC/13ms3effdd83Zubm7Q7rrU\n0tLCiRMnKCsr48qVK89/gUtrayvXrl3j2rVrlJaWEhUVxcSJE5k9ezajR49u31RBRELczZs3qaio\n4OjRozQ0NHj8urq6Ok6dOsWpU6f44osvGD58ONOnTyc9PV1Vfy/Iz88nPz+/x6/3h7/wycAWYFon\nj/0SyAc+dLVPAwt5urIP+l3vmpqaKCkpoaSkhEePHnX6HIfDQUJCArGxsURFReF0OmlsbKS2tpba\n2tpnvvfIkSOZP38+kyZNUtIXCVFXr15l7969XLhw4ZnPiY6OJjExkT59+hAWFkZLS4vZtd/c3Nzp\na6KiopgzZw6ZmZnExsZ6K/yQ091d7/zhL3syz072K4AfuH5mAD9z/ewoaJN9W1sb5eXlFBQUUFdX\nZ3ksLCyM5ORkUlJSGDt2LIMGDXpm1/yjR4+4fv06ly5d4uTJk9y9e/ep54waNYpXXnmFkSNHeuW/\nRUT8z507d9i1axdnz5596rH4+Hheeuklxo0bR1JSEn379u20IHA6ndy+fZvLly/z1VdfcfbsWVpb\nWy3PiYyMJCcnh6ysLCIiAqFT2b8FWrL/I0alPgijWv8x0J6tfuX6+QuMEfv1wPeAik7eJyiT/a1b\nt/j888+5du2a5f74+HhmzZrFjBkzevRN2el0cuPGDcrKyqiqqqKlpcXy+MyZM1m2bBkxMTEvFL+I\n+K/W1lYOHjzI/v37LYk5LCyMSZMmMWvWLMaOHduj3r7Hjx9z8uRJiouLuX37tuWxxMREVqxYQUpK\nygv/N4SyQEv2vSWokn1bWxsHDx6koKDAchLGxcWRm5tLeno6YWG9M2uyrq6OoqIiDh06ZPms+Ph4\n1qxZw5gxY3rlc0TEf9y+fZuPP/6YW7dumfc5HA6mTZvGwoULGThwYK98jtPp5MyZM+Tn53Pjxg3L\nY/PmzWPp0qWq8ntIyT7A1dfXs2nTJr766ivzvvDwcBYuXEhmZqbXRtDfu3ePL774gjNnzpj3ORwO\nFixYQG5urq7liwSJyspKtm3bZrnGPnLkSFauXMmwYcO88pntlyO//PJLHj9+bN4/dOhQ1q1bx+DB\ng73yucFMyT6AXbt2jY0bN1oG040aNYrVq1f77GQ4ceIEW7dutYzCnThxImvXriU6OtonMYhI72tt\nbWX79u2Ul5eb90VGRpKXl8fcuXN7rbewK/X19WzevNlSVERHR7Nu3TomTJjg9c8PJkr2Aer06dP8\n6U9/slw/b6+qfXESuqutreWzzz6zjModPHgwGzZsICEhwaexiMiLe/z4MR9//LGlx3DQoEF885vf\nZMiQIT6Nxel0Ul5ezs6dO82/dw6Hg2XLlpGRkaFeRA8p2Qegw4cPs337dnNBnD59+rB27Vpbv+m2\ntbWxZ88eioqKzPv69+/Pt7/9bZ//cRCRnqutreX3v/+95fr8tGnTWLlyJVFRUbbFdfPmTf7whz/w\n4MED876MjAxefvllJXwPKNkHmP3797N3716znZiYyNtvv91rA2ReVFVVFVu2bDG/gffp04e3336b\nUaNG2RyZiDzP/fv3ef/996mpqTHvW7RoEQsWLPCLhFpXV8fGjRstC4TNnDmT1157zec9moFGyT6A\nFBQUsG/fPrM9cuRINmzYQL9+/WyM6mnV1dX88Y9/pLGxETAWyfjWt77F6NGjbY5MRJ6lpqaG3/zm\nN2blHB4ezqpVq0hLS7M5MquWlhY2bdrEyZMnzfumTZvGmjVrlPC7oGQfIDom+nHjxvHWW2/Z2q3W\nlevXr/P73//eXL0vOjqa73znO4wYMcLmyESko/v37/Pee++Zg30jIiJ48803/XYQXFtbG5s3b6ay\nstK8Lz09ndWrV/tFD4Q/6m6y19cmG5SUlFgS/fjx41m/fr3fJnqAESNG8L3vfc/sdWhsbOR3v/sd\nN29qTyIRf1JXV8dvf/tbS6Jfv3693yZ6MBbyWb16NXPmzDHvq6ysZOfOnc/c3Eu6R8nex44fP87O\nnTvN9vjx43nrrbcCYge6wYMH884775ibWjQ0NPC73/2O+/fv2xyZiIAx6v6DDz7g3r17gJHoN2zY\nwPjx422O7PkcDgcrVqxg5syZ5n2HDh2yFEbSc0r2PnThwgU+/fRTs52UlBQwib7d0KFD+fa3v23O\nua+rq+ODDz6wLJQhIr7X2trKxo0b+frrrwEjea5bt45x48bZHJnnHA4Hr732GlOnTjXv279/P0eO\nHLExquCgZO8jt2/fZuPGjeaStO3z1gMp0bcbMWIE69evJzw8HHj6v01EfMvpdLJt2zYuXrxo3rdq\n1SpSU1NtjKpnwsLCWLNmjeWyw5YtW7rcjU+eT8neBx49emQZzR4XF8e3vvWtgN7jOTk5mddff91s\nX7x4ka1bt+r6mogNiouLqah4skdYXl4eM2bMsDGiFxMeHs66devM5Xvb2tr46KOPntpURzynZO9l\nra2tfPzxx+Y1tMjISDZs2MCAAQNsjuzFTZs2jby8PLN95MgRDh8+bGNEIqHn7Nmz7N6922ynpaWR\nnZ1tY0S9Izo6mg0bNtC/f3/AGI/w4Ycf6pJhDynZe9mePXssXWtr16712mYTdsjOzrbM2925cyeX\nLl2yMSKR0FFTU8OmTZvMHrXRo0ezcuXKoJmuFhcXZ7nceffuXT799FP1IPaAkr0XnTp1iuLiYrO9\nePFiJk2aZGNEva99QE37fPv27jb3zXxEpPe1tLTw0UcfmZXugAEDePPNN4Nuy9jhw4ezevVqs33m\nzBkOHDhgY0SBScneS2pqavj888/NdmpqKjk5OTZG5D2RkZG8+eab5hz89m1629rabI5MJHjt3LnT\nHHkfHh7OG2+84Xerb/aWqVOnkpmZabb37dunAXvdpGTvBR2/ccfHxwf9SlADBgzgjTfeMP8bq6ur\n9e1bxEuOHj1KWVmZ2V62bFnQ71exdOlSkpOTAWP2waeffkp9fb29QQUQJXsv+OKLL576xh3II+89\nlZyczMKFC812fn6+rt+L9LI7d+6wZcsWsz1lyhTmzp1rY0S+ERYWxrp168zei4cPH/L555/r+r2H\nlOx72ZkzZywj0pctW8bIkSNtjMi3FixYwJgxYwDj2/cnn3xCQ0ODzVGJBIfW1lY2bdpEc3MzAAMH\nDmTVqlVB3WvoLjY21jLl9+zZs5SWltoYUeBQsu9F9fX1bN682WxPnjw5JL5xuwsLC+Mb3/iG2ZNR\nW1urb98ivWT//v1cv34deNJr2L6aZaiYMGGC5fr9rl27uHHjho0RBQYl+17idDrZunWreQ2pf//+\nQTUFpjvi4uIs375Pnz7N0aNHbYxIJPBdvXrVMg5m8eLFQTWNtzvy8vIYPnw4YPR2fPLJJ7S0tNgc\nlX9Tsu8lVVVVnDp1ymyvXr06JK7TP8vEiRMtO1jt2LFD0/FEeqipqckyw2XMmDGW6jbUREREsG7d\nOnP+/e3bt8nPz7c3KD+nZN8L7t+/z44dO8z2nDlzSElJsTEi/7B06VISEhIAY/WrLVu2qDtfpAd2\n7dplrsIZHR3NmjVrCAsL7T/fAwcOZOnSpWa7sLCQa9eu2RiRfwvtfy29wOl0snnzZnPd+8TERMs/\nwFAWFRVl6c4/d+4clZWVNkYkEniqq6st0+xWrFhBfHy8jRH5jzlz5lim43322Wfqzn8GJfsXVFVV\nZS7u4HA4WLNmDVFRUTZH5T/GjBlDRkaG2d65cycPHjywMSKRwNHc3GwZ9Juamsr06dNtjMi/OBwO\nVq9ebf7NVXf+synZv4C6ujq++OILs52RkUFSUpKNEfmnvLw8Bg4cCEBjYyPbtm1Td76IBwoKCszu\n+5iYGF599dWQHPTblYSEBHXne0DJ/gXs3LnTnEMeHx/PokWLbI7IP0VGRvL666+bf6TOnj1rGcwo\nIk/7+uuvKSoqMttLly41d4ATq9mzZzN27FjA6M7fsmWLluvuQMm+h86ePcvx48fN9sqVK9V934Wk\npCRmz55ttnfs2KGtKkWeoa2tjc2bN5sJKzk5mZkzZ9oclf9yOBysWrXK3AToxo0bHDp0yOao/IuS\nfQ80NjaydetWs52Wlsb48eNtjCgw5OXlERsbCxhLXe7du9fmiET8U0lJibnkdkREREitktdTCQkJ\nluW69+3bp/FBbpTse6CgoMCcM96vXz9efvllmyMKDDExMbzyyitm+/Dhw1y9etXGiET8T21trWWQ\nWW5uLomJifYFFECysrIYPHgwYKxN4D4lOtQp2XfT7du3KSkpMdsvv/wyffv2tTGiwDJ58mQmTJgA\n6NqaSGd27dpFU1MTAEOGDAnpxXO6Kzw8nNdee81snz59mjNnztgYkf9Qsu8Gp9PJ9u3bLatYTZs2\nzeaoAovD4eDVV181V766efOmZeMgkVB24cIFy1igFStWEB4ebmNEgWfMmDHMmDHDbG/fvt3cOCiU\nKdl3w4kTJ7h48SJgbPiiaTA9Ex8f/9S1Ne1LLaGutbWV7du3m+3p06ebC8ZI9yxdutTscX3w4AGF\nhYU2R2Q/JXsPNTY2WubUz507lyFDhtgYUWDLyMgw594/fvxYg/Uk5BUXF3Pnzh3AWBJXK3H2XN++\nfcnLyzPbhYWFIT9YT8neQ/v37+fhw4eAsadybm6uvQEFuIiICJYvX262KyoqzK07RULNw4cPKSgo\nMNuLFi3SnPoXNGPGDHNnvObmZnbt2mVzRPZSsvfAvXv3LIPyli1bRkxMjI0RBYcJEybw0ksvAcZ4\niB07dmhlPQlJX375pXldeejQocydO9fmiAJfWFiYZfbPiRMnuHTpko0R2UvJ3gO7d++mtbUVMBaH\n0aC83rN8+XJzANKVK1e0772EnOvXr1s2iHr55ZdDfke73jJ69GimTp1qtnfs2BGys3/s/he1HDgN\nnAN+2MnjucAD4Ijr+L99FplLdXW1ZWnX5cuXa1BeL0pMTCQrK8ts79mzRyNnJWQ4nU7LWKCJEycy\nbtw4GyMKPkuXLjVn/9y4cYOKigqbI7KHnck+HPgFRsKfDKwHJnXyvAJghuv4Lz6LjqdPxOnTpzNy\n5EhfhhAScnJyzOuTDx8+pLi42OaIRHzj1KlTZtdyWFgYy5Ytszmi4DNgwACys7PN9t69e809TUKJ\nncl+LnAeqAaagQ+B1Z08z7YyuqqqylyyMjIy0jK6U3pPVFSUZROhgwcPUldXZ2NEIt7X0tLC7t27\nzfbcuXPNGSrSu7KysoiPjwfg0aNH7N+/3+aIfM/OZD8SuOLWvuq6z50TyAKqgO0YPQA+0dTUxJdf\nfmm2s7KyGDBggK8+PuSkp6ebUxmbmprYt2+fzRGJeNehQ4eoqakBoE+fPpa1J6R3RUZGWqYylpaW\ncv/+fRsj8j07k70nw64rgCQgDfg58JlXI3JTVFRkmWo3f/58X310SOrYhVlRUcGtW7dsjEjEe+rr\n6y3VZW5uLn369LExouA3efJkRo0aBRgLGIXa2h4RNn72NYxE3i4Jo7p399Dt9g7gX4BE4F7HN3v3\n3XfN27m5uS80D762ttay4lJeXp62r/WBlJQUxo8fz1dffYXT6WT37t28/fbbdocl0usKCgpobGwE\nYNCgQZbtn8U7HA4Hy5Yt47333gPg6NGjZGZmmnPx/V1+fr5lg6TusnNYeQRwBsgDrgOlGIP0Trk9\nZyhwC6MXYC7wEZDcyXs5e3N+9pYtWygvLwdg2LBhfP/739dUGB+5efMmv/zlL8359u+8845GJ0tQ\nuXfvHr/4xS/MKWAbNmww15sQ7/vwww85ffo0AGPHjuWdd94JyBlWrpg9DtzODNYC/AD4AjgJbMRI\n9H/uOgDWAceASuBnwFveDurOnTscOXLEbC9btkyJ3oeGDh1Kenq62d61a1fIzouV4LRv3z7LZlrt\nu0CKbyxZssT8m37x4kW++uormyPyDbuz2A5gIpAC/L3rvl+5DoD/AUwF0jEG6pV0fIPe5n4ijhs3\nTlWlDRYtWmSZF+u+C5hIILtx4wbHjh0z20uWLAnIqjKQDRo0iJkzZ5rt3bt3h0RBYXey9yvXr1/n\nxIkTZltT7ewRFxdn2cN737595gqGIoFsz5495u3U1FSSkpK6eLZ4S25urjkO6+bNmyGxcqeSvRv3\nqXaTJ0/WAjo2ysrKMkcn19TUWC6tiASi6upqzp8/DxjXWxcvXmxzRKErNjbWsnLn3r17aWlpsTEi\n71Oyd7lw4YJ57SYsLEwnos1iYmIsq14VFBRoGV0JWE6n01LVp6WlaYtsm2VlZdGvXz/AmIFVVlZm\nc0TepWSPcSK6V/Xp6ekMGjTIxogEjBXF3JfRLS0ttTkikZ45ffo0V68aM4vDw8O1RbYfiIqKYsGC\nBWb7wIEDNDU12RiRdynZY5yI165dA4x91nUi+ofIyEjLyXjw4EEeP35sY0Qi3dfW1mZZwGXu3Lnm\n0q1ir1mzZpkro9bX1wd1QRHyyb6trc1S1c+dO5e4uDgbIxJ3M2fOJCEhAYCGhgZtkiMBp6qqitu3\nbwMQHR1NTk6OzRFJu4iICEtBUVhYGLQFRcgn+6qqKu7cuQMYJ6L7dWKxX3h4uGWTnOLiYurr622M\nSMRzLS0tllXPsrKy6Nu3r30ByVPS09NJTEwEgrugCOlk39raajkR58+frxPRD02dOtWySc7Bgwdt\njkjEM0eOHOHBgwcA9OvXzzKlVPxDxzEUxcXFPHr0yL6AvCSkk737idi3b18yMjJsjkg603F2xOHD\nh83/byL+qqWlhQMHDpjt+fPna48NPxUKBUXIJvuWlhbLrlM6Ef3bxIkTzR2rOv6/E/FHFRUV1NbW\nAsa87jlz5tgckTxLWFiY5XJhaWmpuetpsAjZZH/kyBHzROzXr59ORD/ncDgsKxoeOXIk5PajlsDR\n3Nxsqeqzs7PNJaDFP6WmpjJixAjg6V6ZYBCSyb5jZZidna2qPgAkJyczZswYwJhFEWwnowSP8vJy\nszLs378/s2bNsjkieZ6OqxqWl5cHVUERksne/USMjY3VXtIBwuFwWAbSqLoXf9Tc3Gy55puTk6Oq\nPkCMHz+e0aNHA8YA7mAqKEIu2Xc8EdW9FlhU3Yu/O3z4MHV1dYCxqZP7Dmvi3xwOh+XafWVlZdAU\nFCGX7NW9FthU3Ys/a2pqorCw0Gzn5OQQERFhY0TSXe4FRWtra9CMzA+pZK+qPjiouhd/dfjwYXPR\npwEDBjBjxgybI5LucjgcLFy40Gy7T9EOZCGV7MvKyszuNVX1gUvVvfijxsZGS1W/YMECVfUBauzY\nsZZr98FQ3YdMsm9ublb3WhAZO3YsycnJgKp78Q+lpaXmymvx8fGkp6fbHJH0VMfq3n3NhEAVMsle\ng2aCj6p78ReNjY0UFRWZ7QULFhAeHm5jRPKixo0bR1JSEhAc1b0nyb4f8P8A/+ZqTwBe81pEXqCq\nPjglJydbqnutqid2OXz4MA0NDQAkJCSQlpZmc0TyojpeLiwvLw/o6t6TZP9roAnIcrWvA3/ntYi8\noLy8XINmgpT7yVhZWUlNTY19wUhIam5utuyUlpOTo6o+SIwbN85cpjvQq3tPkv144CcYCR8goPYX\nbWlpsVT12dnZquqDSMfqXtfuxdc6FhOq6oNHx+q+oqIiYNfM9yTZNwJ93NrjXfcFhMrKSstqearq\ng4/7yVhVVRUU02QkMHRWTKiqDy7jx49n5MiRgPH/O1Cre0+S/bvATmAU8AdgL/BDL8bUazp2u8yf\nP19VfRDquAiG+x9fEW9SMRH8Ort2H4jVvSfJfhfwDeB7GMl+FrDPm0H1lmPHjpkjtPv27at59UFs\nwYIF5u2Kigpz5oWIt6iYCB0pKSmWHfECsaDoKtnPAma6jtEYA/O+dt32+3lrHa/fZmZmame7IDZu\n3DhLV5v7NCgRbzh69KiKiRDRWXXfPk4jUHSV7P/JdfwLcAhj6t3/dN3+H94P7cWcPHmSu3fvAhAT\nE6P96oOcw+GwVPdlZWXmAicivU3FROiZMGECw4YNA4wZGCUlJTZH1D1dJftcYBFGRT8To9KfBcxw\n3ee3nE6nZc71vHnziImJsTEi8YWXXnqJoUOHAsaGJIF2MkrgOHHiBPfu3QOMYmLu3Lk2RyTe1rGg\nKC0t5fHjxzZG1D2eXLNPBY65tY8Dk7wTTu84c+YMt27dAiAqKop58+bZHJH4QseT8dChQwF1Mkpg\ncDqdlqo+IyOD6OhoGyMSX5k0aRKDBg0CjFUTS0tLbY7Ic54k+6PA/+JJpf9vQJUXY3ohHav6OXPm\n0LdvXxsjEl8K5JNRAsPp06dVTIQoh8NBTk6O2S4uLqapqamLV/gPT5L994CTwH8A/sp1+3veDOpF\nfPXVV1y/blxliIiIIDMz0+aIxJfCwsIsJ2NJSUnAnIzi/zoWE3PnzqVPnz5dvEKCzbRp00hISACg\noaGBsrIymyPyjCfJvgH4b8Aa1/FTwC/7Rp1OJwUFBWZ71qxZxMbG2hiR2GHq1Knmyfjo0SPKy8tt\njkiCxblz5/j6668BiIyMVDERgsLCwsjOzjbbRUVFtLS02BiRZzxJ9hc7OS54M6ieunTpEleuXAEg\nPDyc+fPn2xyR2KHj//vCwsKAOBnFv3Ws6mfNmkW/fv1sjEjskpaWRlxcHAB1dXUcOXLE5oiez5Nk\nP8ftyAH+O/CBN4PqKfcTMT093fyfIaEnPT2d/v37A4FzMop/u3jxIlevXgVUTIS6iIgIsrKyzPbB\ngwdpbW21MaLn8yTZ33E7rgI/A171ZlA9ceXKFS5cMDocOnazSOiJiIiw/DEOhJNR/Jt7MTFz5kzz\ny6SEJveenQcPHnD06FGbI+qaJ8nefSW92cC/B/xupwf3E9F9AIWErkA7GcV/Xbp0ierqasAoJlTV\nS2RkJBkZGWb74MGDtLW12RhR1zxJ9v/kdvw9RvL/pjeD6olz584BT0+NkNDVcQDVgQMH/PpkFP/l\nXkykpaURHx9vYzTiL+bOnWsu2Hb37l1Onjxpc0TP5kmy/3cY8+sXAUuBP+PJ3vZ+Z8qUKeY8a5E5\nc+aYU6Pu3bvHiRMnbI5IAs21a9f46quvAKOY0CVCaRcdHW1ZZ2H//v04nU4bI3o2T5L9nzy8ryeW\nA6eBczxRtikGAAAabUlEQVR729x/dj1ehbFUb5dU1Yu7QDoZxT+5V/VTp05l4MCBNkYj/mbevHnm\nvgi3bt3izJkzNkfUua6S/SSMrW3jgbWu22uB7wK9sdB8OPALjIQ/GVjP08vwrgBSgAnA94F/7eoN\nU1NTzbXRRdrNmzfPXM709u3bnD592uaIJFDcuHHD8sfbfTlmETB2PJw9e7bZPnDggF8WFF0l+4nA\nSmCA6+drrp8zMbryX9Rc4DxQDTQDHwKrOzxnFfC+6/YhjC8ez8zmquqlM3369LHseqjqXjzlvgb+\npEmTGDx4sI3RiL/KysoiIiICMC77tM8M8yddJfvPMKr41zCWx20//grojc3CRwJX3NpXXfc97zmj\nOnuzlJQUcz9zkY4yMzOJjIwE4Ouvv+b8+fM2RyT+7s6dO5YBV6rq5VliY2OZOXOm2Xa/9OMvIrp4\n7IfAT4ANrsOdEyPpvwhPSyuHJ68rLy83/4Dn5uaSm5vb88gk6PTr149Zs2aZ294WFBSQkpKCw9Hx\nn5eI4eDBg2YP0IQJExg+fLjNEYk/mz9/PmVlZbS1tXHp0iUuXbrEmDFjeu398/Pzyc/P7/Hru0r2\n7V9pO1tYvDf6QK8BSW7tJIzKvavnjHLd95Sf/vSnvRCSBLOsrCwOHz5Ma2srV69epbq6mrFjx9od\nlvih+/fvW9ZlUFUvzzNgwADS0tLM1ToPHDjQq8m+YxH7t3/7t916fVfd+FtcP3/TyfF+J8/vrjKM\ngXfJQBTwJrC5w3M2A++4bmcA94GbvfDZEoLi4uKYMePJhA5/7GoT/+C+QEpycjJJSUnPeYUIZGdn\nm72F58+f59q1TmtTWzwv2T/r6JiUe6IF+AHwBUYvwkbgFPDnrgNgO8amO+eBXwH/Wy98roSw7Oxs\nwsKMf/YXL17k8uXLNkck/ubhw4eWvRRU1YunBg4cyNSpU822+wBPu3XVjf9PXTzWW0OZd7gOd7/q\n0P5BL32WCPHx8UyfPp3KykrAOBnffvttm6MSf1JUVGTuozBq1Chd6pFuycnJ4dixYwCcPn2amzdv\n+sWU8K4q+3y3oxioAe5ijMQveNaLRPxdTk6O2dV27tw5rl+/bnNE4i/q6+spKysz2wsWLNAgTumW\nIUOGkJqaarb9pbr3ZAW9VzG60f8ZYxGcrzAWuxEJSAMHDmTKlClm219ORrFfSUkJzc3NAAwbNowJ\nEybYHJEEIvdLPydOnODOnTs2RmPwJNn/N4x18Re6jlxAQ98loLkvwHTq1Clu3bplYzTiDx4/fkxp\naanZdu8BEumOESNGmF8UnU4nBw8etDkiz5J9LUZl3+6C6z6RgDV06FC/7GoT+5SWltLY2AjAoEGD\nmDSp4+rdIp5zr+6PHj1KTU2NjdF4luzLMUbFf9d1bMWYNrfWdYgEJPeT8fjx49y9e9fGaMROTU1N\n5oJLYFT17bM2RHoiKSnJHNzZ1tZme3Xvyb/mGOAWT7rxb7vuW+k6RALSiBEjSElJAfynq03sUVZW\nxqNHjwBjxob79CmRnnIvKCorK3nw4IFtsXQ19a7dd70dhIhdFixYYC6zXFVVxcKFC4mPj7c5KvGl\nlpYWioqebPeRnZ1NeHi4jRFJsEhOTmb06NFcvnyZ1tZWioqKeOWVV2yJxZPKfhzGgLxP6d1FdURs\nN3r0aEtXW2Fhoc0Ria8dOXKEuro6APr37096errNEUmwcDgcluq+vLzc/Lfma54k+8+Ai8DPMRba\naT9EgoL7yVhRUcHDhw9tjEZ8qbW11XL5Zv78+eZWpSK9Yfz48YwYMQJ4uhfJlzxJ9o8x5tjv5cki\nO1pUR4KG+9rnra2tqu5DyNGjR83rqH379rVsUyrSGzpW9+7jQ3zJk2T/c+BdIBOY6XaIBIXOutrq\n6+ttjEh8oeMI6czMTKKiomyMSILVxIkTzSVzm5qaKC4u9nkMniT7KcCfAf+AuvElSKWkpJj7lTc3\nN9tyMopvnTx50pxuGRMTw5w5c2yOSIJVx4KitLSUhoYGn8bgSbJ/AxiLMe1ukdshEjT84WQU33E6\nnZYtjufNm0dMTIyNEUmwmzRpEoMGDQKgsbHRslqjL3iS7I8BCd4ORMRuqampDB48GDC62g4dOmRz\nROIt7kskR0VFMW/ePJsjkmAXFhZmWaa7pKTEXLHRJ5/vwXMSgNPALjT1ToJYx+r+0KFDPj0ZxTec\nTicFBU/GGM+dO5e+ffvaGJGEimnTppGQYNTODQ0NHD582Gef7Umy/zGwBvg7jGv1h4EUbwYlYpcp\nU6aQmJgI+P5kFN84deoUN2/eBIyqPjMz0+aIJFR0rO6Li4vNXRa9/tkePCcfY+Ob14D3gcXAv3ox\nJhHb2Hkyivd1rOrnzJlDv379bIxIQk1aWhoDBgwAoL6+nvLycp98blfJfiLGlLtTwM+Ay4ADY4vb\nn3s7MBG7TJ8+3XIylpWV2RyR9JbTp0+bVX1kZCRZWVk2RyShJjw8nPnz55vtwsJCWlpavP65XSX7\nUxjz6V8GFmAk+FavRyRis/DwcLKzs832wYMHaWpqsjEi6Q2dXatXVS92mDlzJv379wfg4cOHVFRU\neP0zu0r2a4EGYD/wSyAPo7IXCXozZsxQdR9kzpw5w40bNwBV9WKviIgIS3V/4MABr18u7CrZfwa8\nCUwFDgD/BzAY43r9Mq9GJWKziIgIy7X7wsJCVfcBzOl0kp+fb7Z1rV7sNmvWLEt17+1r954M0KsD\nPsAYoJcEHAF+5M2gRPzBjBkzzO1u6+vrfb4IhvQeVfXibyIjI5+6XOjN6t6TZO/uHvA/MUbkiwS1\n8PBwS3VfVFSkefcBqOO1+tmzZxMbG2tjRCKGWbNmERcXB0BdXZ1Xp/p2N9mLhJT09HRzEYxHjx6p\nug9AZ8+e5euvvwaevlYqYidfXi5UshfpQnh4uGVVPVX3gaWzefWq6sWfdBwM7K3qXsle5DmmT59u\nWeJSa+YHjjNnznD9+nVAVb34p4iICEtBUVhY6JWCQsle5DnCw8NZuHCh2S4qKuLx48c2RiSeaGtr\nY+/evWZbVb34K19cLlSyF/HA9OnTGThwIACPHz+mpKTE5ojkeU6cOGHZ2c595LOIP+nscmFvFxRK\n9iIeCAsLs5yMJSUl2u/ej7W2trJv3z6znZGRoXn14temT59u2YSrty8XKtmLeGjatGmW6r64uNjm\niORZqqqquHfvHgAxMTGaVy9+r+PlwuLi4l6t7pXsRTwUFhZGbm6u2S4pKaGurs6+gKRTLS0tlhH4\n8+fPJyYmxsaIRDzTsaAoKirqtfdWshfphilTpjB06FAAmpqaOHDggM0RSUfl5eU8ePAAgH79+jFv\n3jybIxLxTMeCori4uNcKCiV7kW4ICwsjLy/PbJeVlVFTU2NjROKuqamJ/fv3m+2cnByioqJsjEik\ne6ZOnWoWFM3NzZZeqhehZC/STRMmTGD06NHA0wPBxF6lpaXU19cDEBcXx+zZs22OSKR7HA4HS5Ys\nMdvl5eXm+JMXoWQv0k0dT8Zjx45x8+ZNGyMSMK5xFhYWmu2FCxcSERFhY0QiPZOSksKYMWMAY72I\n3igolOxFemD06NG89NJLgLEk65dffmlzRFJUVGROh0xMTCQ9Pd3miER6xuFwsHTpUrN97Ngxc3+H\nnlKyF+mhvLw8HA4HYGy2cvnyZZsjCl21tbWWqZCLFi0iPDzcxohEXsyoUaNITU012y9aUNiV7BOB\n3cBZYBcQ/4znVQNHgSOAthsTvzJ06FCmTZtmtvfs2YPT6bQxotC1b98+cy/w4cOHM3XqVJsjEnlx\n7gXF+fPnuXjxYo/fy65k/yOMZP8S8KWr3RknkAvMAOb6JDKRbnCvIC9fvsy5c+dsjij03Lx5k8rK\nSrO9bNky8w+kSCAbPHiw5XLUixQUdiX7VcD7rtvvA6938VydteK3EhISLCO+9+zZQ1tbm40RhR73\nP4ATJkxg7NixNkck0ntyc3PNgabXrl3j9OnTPXofu5L9UKB9+PJNV7szTmAPUAb8mQ/iEuk297nc\nt27d4siRIzZHFDouXLhg9qZ0nCUhEgwGDBjA3LlPOrb37NlDa2trt9/Hm8l+N3Csk2NVh+c5XUdn\n5mN04b8C/CWQ45VIRV5AbGysZZ/0vXv3emU/arFyOp3s3r3bbKenp5uLkYgEk+zsbHPJ57t371Je\nXt7t9/DmJNSlXTx2ExgG3ACGA7ee8bz2uQa3gU8xrtt3uj7pu+++a97Ozc21LDko4m1ZWVmUl5dT\nW1tLfX09Bw4cUJXpZcePHzenI0VGRrJo0SKbIxLxjr59+9KvXz927twJwMGDB7v9HnatOLEZ+A7w\nE9fPzzp5Tl8gHHgI9AOWAX/7rDd0T/YivhYZGcmSJUvYtGkTYGySM3v2bOLjnzXRRF5Ec3Mze/bs\nMdsZGRnExcXZGJGId/3FX/wFbW1t5vLc3Z2KZ9c1+3/AqPzPAotdbYARwDbX7WEYVXwlcAjYijFN\nT8QvTZs2jZEjRwLGzmvuyUh6V2FhobnZTd++fS2XUUSCUURExAv1FtqV7O8BSzCm3i0D7rvuvw68\n6rp9AUh3HVOBv/dxjCLd4nA4ePnll8328ePHuXLlio0RBacHDx5YlsXNy8vTFrYSEiZPnkxSUlKP\nXqsV9ER60ejRo5kyZYrZ3rlzpxba6WW7du2yLKAzY8YMmyMS8Y2OBUV3KNmL9LIlS5aYC+1cu3aN\no0eP2hxR8KiurubEiRNme/ny5YSF6c+YhI5Ro0aRk9P9iWk6S0R6WUJCApmZmWZ79+7dPH782MaI\ngkNbW5s5GhmMfb/bdwYTCSV5eXndfo2SvYgX5OTk0L9/fwDq6urIz8+3N6AgUFFRwY0bNwBj9oP7\nrmAi0jUlexEviI6OtlxbKy0t1Z73L6ChoYG9e/ea7ZycHAYMGGBjRCKBRclexEumTJlirtPe1tbG\n9u3bNVivh/bs2cOjR48AiI+Pt1wmEZHnU7IX8RKHw8GKFSvMAWSXLl3i2LFjNkcVeC5fvmxZHnT5\n8uVERkbaGJFI4FGyF/GiwYMHW6rQXbt20dDQYGNEgaW1tZWtW7ea7YkTJ5KammpjRCKBSclexMsW\nLFhgLuVaV1dn2bxFulZcXMytW8bWGVFRUaxYscLmiEQCk5K9iJdFR0dbklRFRQUXL160MaLAUFNT\nY5nFsGjRIg3KE+khJXsRH0hNTWXy5Mlme8uWLeYqcPI0p9PJtm3baGlpAWDYsGHMmzfP5qhEApeS\nvYiPrFixwlzD/d69e5p734XKykrOnz8PGAMdV65cqZXyRF6Azh4RH4mNjWXZsmVmu6ioiOvXr9sY\nkX968OCBZaW8efPmmbsJikjPKNmL+NCMGTPMufdOp5PPPvvM7KoW43eyZcsWGhsbARg4cGCPlgYV\nESslexEfau+Sbp8nfuvWLb788kubo/IfR44csXTfr169WnPqRXqBkr2IjyUmJlq680tKSjQ6H6P7\n/osvvjDbGRkZjB492saIRIKHkr2IDWbPnk1KSgrwpDs/lHfGa2trY9OmTZbu+8WLF9sclUjwULIX\nsUF7F3WfPn0Ao6rdsWOHzVHZZ//+/Vy6dAmAsLAwXn/9dXXfi/QiJXsRm/Tv35+VK1ea7aqqKo4e\nPWpjRPaorq6moKDAbOfm5pKUlGRjRCLBR8lexEaTJ08mLS3NbG/ZsoXbt2/bGJFvPXr0iE2bNpm7\nASYnJ5OdnW1zVCLBR8lexGYrVqxg0KBBADQ3N/PRRx/R1NRkc1Te53Q6+fzzz6mtrQWgb9++rF27\nVovniHiBzioRm0VHR/PNb37TvEZ9+/Zttm7dala7wergwYOcOXPGbK9evdrcMEhEepeSvYgfGDJk\nCK+++qrZPnr0qGUP92Bz/vx59u7da7YzMjKYOHGijRGJBDclexE/kZ6ezowZM8z29u3bqa6uti8g\nL6mpqeGTTz4xey7GjBnD0qVLbY5KJLgp2Yv4kRUrVjBs2DDAmHv+0UcfUVNTY3NUvefx48f88Y9/\npKGhAYC4uDjeeOMNwsPDbY5MJLgp2Yv4kcjISNavX09sbCxgjFb/wx/+EBQL7rS2trJx40Zu3boF\nQHh4OG+++ab53yoi3qNkL+JnBgwYwFtvvUVERARgDNj78MMPA3rDnPYNbtyXBX799de1m52IjyjZ\ni/ihUaNGsWrVKrNdXV3NJ598Qltbm41R9dzevXuprKw024sXL2batGk2RiQSWpTsRfzU9OnTWbJk\nidk+depUQE7JO3DgAAcOHDDbM2bMICcnx8aIREKPkr2IH5s/fz6ZmZlmu6Kigm3btgVMwi8pKbFs\n4Ttx4kRee+01HA6HjVGJhB4lexE/5nA4WLZsmWVJ3bKyMrZs2eL3Cb+wsJCdO3ea7XHjxmnkvYhN\nIuwOQES61r5DntPpNDfKqaiooKWlhdWrV/td8nQ6nezdu9fSdZ+UlGQZdCgivhUsfWlOf69yRF5U\nW1sbn3/+OVVVVeZ948aN45vf/CYxMTE2RvZEa2sr27dvt6z+l5yczPr164mOjrYxMpHg4roU5nEO\nV7IXCSBtbW1s27bNkkyHDBnC+vXrSUhIsDEyY02Ajz76yLLq30svvcQbb7yhvelFepmSvUiQczqd\nHDx40DLwLSYmhjVr1ti2vvz169f5+OOPLav9TZ8+3S8vM4gEAyV7kRBx9OhRPv/8c1pbW837MjMz\nWbx4sc8q6ba2NoqKiti7d6+5BoDD4SAvL4/58+dr1L2IlyjZi4SQq1ev8vHHH/PgwQPzvsTERFau\nXMnYsWO9+tk3b95k+/btXLp0ybwvKiqKtWvXkpqa6tXPFgl1SvYiIaahoYFPP/2Us2fPWu6fNm0a\nixYtIjExsVc/79GjRxQUFHD48GHLin6jRo1i7dq1vf55IvK0QEn2bwDvAqnAHKDiGc9bDvwMCAf+\nF/CTZzxPyV5CmtPppKKigt27d1s2zQkLCyM9PZ2MjAyGDBnyQp9RW1tLcXEx5eXlNDU1WT4jJyeH\nhQsXEhampTtEfCFQkn0q0Ab8CvhrOk/24cAZYAlwDTgMrAdOdfJcJXsR4OHDh+zYsYOTJ08+9VhS\nUhJpaWmkpKQQHx/v0fs1NDRw9uxZjh07xoULF55am3/cuHG88sorDB48uFfiFxHPBEqyb7ePZyf7\nTODHGNU9wI9cP/+hk+cq2Yu4uXLlCl9++aVlGpy7gQMHMmzYMAYNGkR8fLw5B765uZmHDx9y9+5d\nrl69yu3btzt9/dChQ1m4cCGTJk3SIDwRG3Q32fvzclYjgStu7avAPJtiEQkoSUlJfOc73+HSpUsc\nPnyYU6dOWaryu3fvcvfu3W6/b3JyMllZWUyYMEFJXiSAeDPZ7waGdXL/fwa2ePD6bpXq7777rnk7\nNzeX3Nzc7rxcJOg4HA6Sk5NJTk6mrq6O48ePc/78eaqrq2lpafHoPcLCwhg+fDiTJk1i6tSpHnf/\ni0jvys/PJz8/v8evt/ureVfd+BkYg/jau/H/BuM6f2eD9NSNL+Kh5uZmbty4wZ07d7h79y4PHz40\nB9xFREQQGxvLgAEDGD58OCNGjNDqdyJ+KBC78Z8VbBkwAUgGrgNvYgzQE5EXEBkZSVJSEklJSXaH\nIiI+Ytc8mTUY1+MzgG3ADtf9I1xtgBbgB8AXwElgI52PxBcREZEu2N2N31vUjS8iIiGju934WgFD\nREQkyCnZi4iIBDklexERkSCnZC8iIhLklOxFRESCnJK9iIhIkFOyFxERCXJK9iIiIkFOyV5ERCTI\nKdmLiIgEOSV78ciLbK0ontHv2Df0e/Y+/Y79j5K9eEQnr/fpd+wb+j17n37H/kfJXkREJMgp2YuI\niAS5YNnithJIszsIERERH6kC0u0OQkREREREREREREREQt5y4DRwDvihzbEEqyRgH3ACOA78lb3h\nBLVw4Aiwxe5AglQ88CfgFHASyLA3nKD0Nxh/K44BfwCi7Q0naLwH3MT4vbZLBHYDZ4FdGP++g1I4\ncB5IBiIxBulNsjOgIDWMJ4NAYoEz6PfsLf8R+ADYbHcgQep94N+5bkcAA2yMJRglAxd4kuA3At+x\nLZrgkgPMwJrs/yvwn1y3fwj8g6+D8pVMYKdb+0euQ7zrMyDP7iCC0ChgD7AIVfbeMAAjEYn3JGIU\nAwkYX6a2AEtsjSi4JGNN9qeBoa7bw1ztZwrkefYjgStu7auu+8R7kjG+XR6yOY5g9FPg/wLa7A4k\nSI0FbgO/BiqAfwP62hpR8LkH/BNwGbgO3Mf4AiveMRSjax/Xz6FdPDegk73T7gBCTCzG9c7/ANTZ\nHEuweQ24hXG9PljWvvA3EcBM4F9cP+tRT2BvGw/87xhFwQiMvxlv2xlQCHHynJwYyMn+GsbgsXZJ\nGNW99L5I4BPg9xjd+NK7soBVwEXgj8Bi4Le2RhR8rrqOw672nzCSvvSe2UARcBdoATZh/NsW77iJ\n0X0PMByjYAhKEcBXGN8io9AAPW9xYCSen9odSIhYiK7Ze8t+4CXX7XeBn9gXSlBKw5ix0wfj78b7\nwF/aGlFwSebpAXrts9B+RBAP0AN4BWNAyHmMKR/S+7IxriNXYnQzH8GY8ijesRCNxveWNIzKvgqj\n6tRo/N73n3gy9e59jF5BeXF/xBgH0YQxVu17GAMi9xACU+9ERERERERERERERERERERERERERERE\nRERERERERLxsIE/WU/gaY9W5I8BD4Bc2xiUiIiJe8GOMbXdFJMAF8tr4IuJ97Rvz5PJkGd93MVZH\n2w9UA2uBfwSOAjswlrIGmAXkA2UY21G3r+MtIj6mZC8iPTEWWISxgc/vgd3AdKABeBVjmdSfA9/A\n2CDl18Df2RKpiJjfwEVEPOXEqOBbMTY+CQO+cD12DGPDjpeAKTzZzzwcY21vEbGBkr2I9EST62cb\n0Ox2fxvG3xUHxoYo2uJUxA+oG19Eusvx/KdwBhgMZLjakcBkr0UkIl1SsheRrjjdfnZ2mw6329vN\nwDqMPePbt0fO9F6YIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiEhL+fwLS1RxC\ngAAbAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Complex example: beam deflection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When creating more interaction between Javascript and Python, things get easily quite complicated. Therefore one should consider using e.g. Backbone or similar to get more structured code in Javascript side. IPython notebook seems to be using Backbone internally already.\n", "\n", "In the next example we add more inputs and use Backbone to handle syncronizing Python and Javascript. In this example we calculate the deflection line $v(x)$ for simple supported Euler Bernoulli beam and update visualization when user changes force location $x \\in [0, 1]$. The formula for deflection $v(x)$ is \n", "\n", "\\begin{equation}\n", "v(x) = \\frac{FL^2}{6EI}\\left[ \\frac{ab}{L^2}(L+b)\\frac{x}{L} - b\\left(\\frac{x}{L}\\right)^3 + \\frac{1}{L^2}^3 \\right],\n", "\\end{equation}\n", "where\n", "\\begin{equation}\n", "=\\begin{cases}\n", "0 & ,x\n", "

Tools

\n", "

Force location

\n", " \n", " \n", "

Boundary conditions

\n", " \n", "

Young's modulus (GPa)

\n", " \n", "

Other options

\n", "
\n", " \n", "
\n", "\n", "\"\"\")" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n" ], "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our plugin code comes next. Note that we have now Backbone model LineModel to handle Python-Javascript-interaction and Backbone views ToolsView and CanvasView to take care of visualization when data is changed.\n", "\n", "Note that not all input elements are \"connected\" to the visualization, they are more like placeholders ready for your own coding experiments. They are not implemented on purpose to keep lines of code as low as possible. To get them work, modify ``this.notImplemented`` $\\rightarrow$ ``this.modelChanged`` in ``initialize`` function and change ``var command = ... `` in ``modelChanged`` to pass more parameters to notebook server. Don't forget to change Python side function accordingly." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class MyUserInterface(mpld3.plugins.PluginBase):\n", " \"\"\" Here we use Backbone to create more structured Javascript. \"\"\"\n", "\n", " JAVASCRIPT = \"\"\"\n", "\n", "var LineModel = Backbone.Model.extend({\n", "\n", " initialize: function(options) {\n", " this.options = options || {};\n", " this.on(\"change:sliderPosition\", this.modelChanged);\n", " this.on(\"change:boundaryCondition\", this.notImplemented);\n", " this.on(\"change:youngsModulus\", this.notImplemented);\n", " this.on(\"change:useFEM\", this.notImplemented);\n", " },\n", "\n", " /**\n", " This example should be quite easy to extend to use more inputs. You\n", " just have to pass more model.get('...') things to kernel execute command below.\n", " */\n", " notImplemented: function(model) {\n", " alert(\"This function is not implemented in the example on purpose.\");\n", " },\n", "\n", " /**\n", " Model changed, execute notebook kernel and update model data.\n", " */\n", " modelChanged: function(model) {\n", " var command = this.options.callback_func + \"(\" + model.get('sliderPosition') + \")\";\n", " console.log(\"IPython kernel execute \"+command);\n", " var callbacks = {\n", " 'iopub' : {\n", " 'output' : function(out) {\n", " //console.log(out);\n", " var res = null;\n", " // if output is a print statement\n", " if (out.msg_type == \"stream\"){\n", " res = out.content.data;\n", " }\n", " // if output is a python object\n", " else if(out.msg_type === \"pyout\"){\n", " res = out.content.data[\"text/plain\"];\n", " }\n", " // if output is a python error\n", " else if(out.msg_type == \"pyerr\"){\n", " res = out.content.ename + \": \" + out.content.evalue;\n", " alert(res);\n", " }\n", " // if output is something we haven't thought of\n", " else{\n", " res = \"[out type not implemented]\";\n", " alert(res);\n", " }\n", " model.set(\"line\", JSON.parse(res));\n", " }\n", " }\n", " };\n", " IPython.notebook.kernel.execute(command, callbacks, {silent:false});\n", " }\n", "\n", "});\n", "\n", "\n", "var ToolsView = Backbone.View.extend({\n", "\n", " /**\n", " This view renders toolbar with slider and other html elements.\n", " */\n", " initialize: function(options) {\n", " this.options = options || {};\n", " _.bindAll(this, 'render');\n", " },\n", "\n", " render: function() {\n", " var template = _.template($(\"#tools-template\").html(), {});\n", " $(this.el).append(template);\n", " return this;\n", " },\n", "\n", " /**\n", " Listen event changes.\n", " */\n", " events: {\n", " \"change #slider1\": \"changeSlider1\",\n", " \"change #boundary_conditions\": \"changeBoundaryConditions\",\n", " \"change #young\": \"changeModulus\",\n", " \"change #useFEM\": \"changeUseFEM\"\n", " },\n", "\n", " changeSlider1: function(ev) {\n", " var sliderPosition = $(ev.currentTarget).val();\n", " this.model.set('sliderPosition', sliderPosition);\n", " $(this.el).find(\"#slider1label\").text(parseFloat(sliderPosition).toFixed(2));\n", " },\n", "\n", " changeBoundaryConditions: function(ev) {\n", " this.model.set('boundaryCondition', $(ev.currentTarget).val());\n", " },\n", "\n", " changeModulus: function(ev) {\n", " this.model.set('youngsModulus', $(ev.currentTarget).val());\n", " },\n", "\n", " changeUseFEM: function(ev) {\n", " var isChecked = $(ev.currentTarget).is(\":checked\");\n", " this.model.set('useFEM', isChecked);\n", " }\n", "\n", "});\n", "\n", "var CanvasView = Backbone.View.extend({\n", "\n", " initialize: function(options) {\n", " this.options = options || {};\n", " this.line = mpld3.get_element(this.options.props.idline);\n", " _.bindAll(this, 'render');\n", " this.model.bind('change:line', this.render);\n", " },\n", "\n", " /**\n", " Update line when model changes, f.e. new data is calculated\n", " inside notebook and updated to Backbone model.\n", " */\n", " render: function() {\n", " this.line.elements().transition()\n", " .attr(\"d\", this.line.datafunc(this.model.get('line')))\n", " .style(\"stroke\", \"black\");\n", " }\n", "\n", "});\n", "\n", "// PLUGIN START\n", "\n", "mpld3.register_plugin(\"myuserinterface\", MyUserInterfacePlugin);\n", "MyUserInterfacePlugin.prototype = Object.create(mpld3.Plugin.prototype);\n", "MyUserInterfacePlugin.prototype.constructor = MyUserInterfacePlugin;\n", "MyUserInterfacePlugin.prototype.requiredProps = [\"idline\", \"callback_func\"];\n", "MyUserInterfacePlugin.prototype.defaultProps = {}\n", "\n", "function MyUserInterfacePlugin(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", "};\n", "\n", "MyUserInterfacePlugin.prototype.draw = function() {\n", "\n", " // Some hacking to get proper layout.\n", " var div = $(\"#\" + this.fig.figid).attr(\"style\", \"border: 1px solid;\");\n", " var figdiv = div.find(\"div\");\n", " figdiv.attr(\"style\", \"display: inline;\");\n", "\n", " // Create LineModel\n", " var lineModel = new LineModel({\n", " callback_func: this.props.callback_func\n", " });\n", "\n", " // Create tools view\n", " var myel = $('
');\n", " div.append(myel);\n", " var toolsView = new ToolsView({\n", " el: myel,\n", " model: lineModel\n", " });\n", " toolsView.render();\n", "\n", " // Create canvas view which updates line visualization when the model is changed\n", " var canvasView = new CanvasView({\n", " el: figdiv,\n", " model: lineModel,\n", " props: this.props\n", " });\n", "\n", "};\n", "\"\"\"\n", "\n", " def __init__(self, line, callback_func):\n", " self.dict_ = {\"type\": \"myuserinterface\",\n", " \"idline\": mpld3.utils.get_id(line),\n", " \"callback_func\": callback_func}" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we do the actual calculation of the deflection using Python and display results:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "\n", "L = 1.0\n", "F = 3.0\n", "E = 100.0\n", "I = 0.1\n", "\n", "def v_(x, a):\n", " b = L - a\n", " v = a*b/L**2*(L+b)*x/L - b*(x/L)**3\n", " if x-a > 0.0:\n", " v += 1.0/L**2*(x-a)**3\n", " v *= F*L**2/(6.0*E*I)\n", " return v\n", "\n", "v = np.vectorize(v_)\n", "\n", "def runCalculation(a):\n", " \"\"\" \n", " \"\"\"\n", " x = np.linspace(0, L, 500)\n", " y = -v(x, a)*1000.0\n", " return map(list, list(zip(list(x), list(y))))\n", "\n", "fig, ax = plt.subplots(figsize=(8, 4))\n", "\n", "t = np.linspace(0, 1, 200)\n", "y = np.sin(t)\n", "ax.set_xlabel('x [m]')\n", "ax.set_ylabel('Deflection [mm]')\n", "ax.set_title('Euler-Bernoulli beam deflection line')\n", "\n", "# create the line object\n", "initial_data = np.array(runCalculation(0.5))\n", "line, = ax.plot(initial_data[:, 0], initial_data[:, 1], '-k', lw=3, alpha=0.5)\n", "ax.plot([0.975, 1.025, 1.00, 0.975], [-1, -1, 0, -1], '-k', lw=1)\n", "ax.plot([-0.025, 0.025, 0.000, -0.025], [-1, -1, 0, -1], '-k', lw=1)\n", "ax.set_ylim(-10, 5)\n", "ax.grid(lw=0.1, alpha=0.2)\n", "\n", "mpld3.plugins.connect(fig, MyUserInterface(line, callback_func=\"runCalculation\"))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\nYII=\n", "text": [ "" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note 2**: The line is updated only when force location is changed, but it should be trivial to extend this example use more tools. " ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 } ], "metadata": {} } ] }