diff --git a/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation) No Solutions-checkpoint.ipynb b/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation) No Solutions-checkpoint.ipynb new file mode 100644 index 0000000..239c0d2 --- /dev/null +++ b/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation) No Solutions-checkpoint.ipynb @@ -0,0 +1,448 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "431bdde7", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## A (brief) Introduction to Bayesian Reasoning and Statistics\n", + "\n", + "#### Bryan Scott, CIERA/Northwestern, \n", + "#### DSFP Session 19: Orientation for Cohort 7 \n", + "version 0.1 " + ] + }, + { + "cell_type": "markdown", + "id": "b570ae7f", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 1: Warm Up - Conditional Probability and the Law of Total Probability\n", + "\n", + "One of the main objects of Bayesian inference is the conditional probability distribution. This tells us what the chance of something happening given that we know something else happened are. For example,\n", + "\n", + "$$\n", + "p(Good | Dog) = 1 \n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "235467a4", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "A related concept is the law of total probability - this just formalizes the idea that the odds of something happening must involve a sum over all of the (conditional) ways it can happen. \n", + "\n", + "$$\n", + "p(B) = \\Sigma_n P(B | A_n) P(A_n)\n", + "$$\n", + "\n", + "for example,\n", + "\n", + "$$\n", + "p(Pet) = p(Pet| Own) p(Own) + p(Pet| Friendly) p(Friendly)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "e863d8b9", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "One more useful bit of probability theory is that conditional probabilities can be related to each other via a simple relationship:\n", + "\n", + "$$\n", + "p(A| B) = \\frac{P(B|A)P(A)}{P(B)}\n", + "$$\n", + "\n", + "which also holds if you swap $A \\rightarrow B$. This result is sometimes called Bayes' theorem, and the interpretation of this equation (which is simply a fact about conditional probabilities) gives rise to Bayesian statistics." + ] + }, + { + "cell_type": "markdown", + "id": "71d308dd", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 2: Prior Beliefs\n", + "\n", + "Let's consider the following problem. Suppose you're deciding whether to take the bus or walk to your destination. Unfortunately, you live in Chicago, so while there is a bus tracker app, it will tell you only a set of probable times you might expect the bus to arrive. Having previously solved this problem empirically, one learns not to rely on the bus tracker app's estimates. \n", + "\n", + "As such, you'll call the rate at which buses arrive $\\lambda$ and use the bus schedule to set a best guess $p_0(\\lambda)$ for the rate at which buses arrived. $\\lambda$ is a $\\textit{parameter}$ of some distribution we wish to infer. It's assumed distribution before we have observed any buses arriving, $p_0(\\lambda)$ is called the $\\textit{prior}$. " + ] + }, + { + "cell_type": "markdown", + "id": "1d89687a", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 3: Conditioning Beliefs on Evidence\n", + "\n", + "Now that we know how often we expect the bus to arrive, we need someway to update our knowledge of $\\lambda$ based on observing bus arrival times. This is called the $\\textbf{likelihood}$. It tells us how our observed data changes our beliefs about the value of some parameter. " + ] + }, + { + "cell_type": "markdown", + "id": "23aa62fc", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "While choosing a distribution that captures our prior beliefs about the value of a parameter often requires care, there are more clear rules governing the proper updating functions. It turns out that the right updating function for this problem is the $\\textit{Poisson Distribution}$.\n", + "\n", + "For most problems, you will instead use a $\\textit{Gaussian distribution}$." + ] + }, + { + "cell_type": "markdown", + "id": "eb144172", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 4: Bayes' Insight\n", + "\n", + "\n", + "The deep insight is that Bayesian probabilities are statements about the probability of a parameter taking on a certain value. This differs from the classical interpretation, where probability is about realizations of the data, rather than distributions over parameters. " + ] + }, + { + "cell_type": "markdown", + "id": "d7ab2844", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "For example, what we care about as bus riders is the rate at which buses arrive. If we believe the next bus will arrive soon, we will likely wait for it. If we believe the bus will arrive much later, perhaps we will walk. What we want to quantify is our beliefs about the value of the rate parameter of bus arrivals. " + ] + }, + { + "cell_type": "markdown", + "id": "068b5cbc", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "To make this quantitative, the probability distribution for the rate at which buses arrive $p(\\tau | \\lambda)$, conditioned on the time we've waited so far, is proportional to the product of our $\\textit{prior}$ belief about when a bus will arrive and the $\\textit{likelihood}$ - a function that tells us how our beliefs change as we observe (or don't observe) buses arriving. \n", + "\n", + "$$\n", + "p(\\lambda | \\tau) \\propto p_0(\\lambda) p(\\tau | \\lambda )\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "46eaab30", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "There is a missing normalization constant here, sometimes called the $\\textbf{evidence}$ or the $\\textbf{marginal likelihood}$ - we will return to this point in detail in the Bayesian inference session, but for now, you can calculate the evidence by asserting that $\\Sigma_{\\tau} p(\\lambda | \\tau) = 1$. For most problems we can neglect this constant since we only care about the maximum of the probability distribution. When it does matter, we often use the law of total probability to calculate this term. More on this in a future session." + ] + }, + { + "cell_type": "markdown", + "id": "8841241e", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "What this equation says is that my $\\textit{belief}$ about the frequency at which buses arrive depends on my prior belief about how often the bus should come and a factor that tells me how to update my belief based on how long I've been waiting at the bus stop." + ] + }, + { + "cell_type": "markdown", + "id": "967c18e1", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 5: Putting this into practice\n", + "\n", + "Now, in the rest of this notebook, work out the posterior estimate for the rate at which buses arrive based on your wait time so far. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9b79e6d2", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "9d4fae89", + "metadata": {}, + "source": [ + "The choice of prior is, in general, a subtle problem that we will return to. In the analysis of wait times, it is common to select a prior from the $\\Gamma$ distribution family described by the equation:\n", + "\n", + "$$\n", + "p_0 (\\lambda) = \\frac{\\beta^a \\lambda^{a-1} e^{-\\beta \\lambda}}{\\Gamma(a)}\n", + "$$\n", + "\n", + "Begin by discussing with your partner what each of these parameters means in the context of a wait time problem." + ] + }, + { + "cell_type": "markdown", + "id": "c46bb291", + "metadata": {}, + "source": [ + "$\\lambda$ is the rate (1/expected wait time); $\\Gamma$ is the normalization constant, and $\\beta$ is the scale factor." + ] + }, + { + "cell_type": "markdown", + "id": "c17524ed", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Next, either use a built in function from scipy or write your own function for the $\\Gamma(a)$ distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "0423cf69", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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7LOsXr2abt268fTTTwNw++23c//997Nq1Sq++eYbUlNTyc3NLekS8N3Wr1/PwYMHadCgAfFFv2G2aNGC3bt3O95z9+7dpKWllXxefJy/9rJMmjSJTz/9lFWrVjFv3jwApkyZQlZWFpmZmaxevZrbb78dgAceeIDly5ezdu1aTp065bgazs/P58EHH2TOnDmsWLGCMWPG8Lvf/Q6A559/3vW8i793land19KlS+nRowfXX38969atq9DX+qO/65dn1y74xz/c9zVqZK86W7Z07hOx+3/yExg0CFatgnfegUOHnMceOQLPPw/33APp6UEtX8HXX3/N8OHDSUpKIikpiRtvvLFk39q1a3niiSc4cuQIx48fZ/DgwSX7brzxRkSEbt260bRpU7p16wZA165dycrKomfPntSsWZMhQ4YA0K1bNxITE0lISKBbt25kFf0nnZ+fzwMPPEBmZiY1atQo6W7wlZaWRr9+/QC44447mDx5Mtdddx2tW7emffv2Je1Tpkyp1N/D0aNHOXLkCFdddRVgr6h//vOfk5uby+7du/nZz34G2AdaipXVnVO6T9gr/fr1Y/To0dxyyy2MGDECgH/961+MHz++5D+Whg0bAvD555/z3HPPcfLkSQ4dOkTXrl3P+95v3LiRtWvXMmjQIADOnj1bcnX+2GOP8dhjj1XbefTq1YsdO3ZQt25dFixYwE033cTmzZur/Loa6GXJzYWXXwa3Gz0dO8K4cVC3bvmvIwI9e0LnzvDxx7BokR3yWFpBAUydartpin6oVfUbPXo0c+fOpUePHkybNo3FixeX7EtMTAQgLi6u5OPizwsKCgBISEgo+TW+9HGlj3nhhRdo2rQpq1atorCw8LzALM23OyDUQz1zc3MZMGCA676ZM2fSuXNnjhw5QkFBAfHx8WRnZ9O8eXPHsc2bN2fXrl0ln5c+zl+7P6+++irLli3j448/pnfv3qxYscL1uLy8PCZOnEhGRgZpaWk89dRTjjHdxhi6du3K0qVLHV///PPP8/bbbzvar7zySiZPnlzmOQWiXqku1qFDhzJx4kQOHDhASkpKwK/hRrtc/CkshFdfdb+i7tEDfvnLwMK8tMREGDECHn0UkpOd+42B6dOhVKioquvXrx/z588nLy+P48ePn/erd25uLqmpqeTn57v+AAfD0aNHSU1NJS4ujhkzZnD27FnX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tI89ymigKxVNsrPho49g9eryj23QwI6KGTDAzgKpIp4GulLRaNs2O8xx48byj01KgiuvtNMOXHBBtZemqo8GulLRbNMmuwpSIMEeFwe9etlgb9PG/wyQKmxpoCsVCzZvho8/hg0BzryRlmbHsV96qf+FOFTY0UBXKpbs2AELF8L335d/8xRsd8zll0P//nYJPRXWNNCVikU//miXuFu61K6OFIhWrWywp6fr1AJhSgNdqViWmwtLlsDixXDsWGBfk5AAPXvaK/fOnXVMexjRQFdK2YeSVq6Ezz6D7dsD/7p69ewVe9++dlZIvZEaUhroSqnz7dxpZ3f87js4cybwr0tJsdML9Olj+9s13D2nga6UcnfqlA31r76yIV8RKSl2COQll0Dr1hruHtFAV0qVb9cu+OYbO7VARdczrVcPuneHHj2gUye71J6qFhroSqnAFRTAmjU22NesKX9CMF8JCdCxI3TrBl27gq4fHFRlBbrO2qOUOl98vO1GueQSOHnS3khdvtw+iRrIBWB+Pqxdazewgd61K3TpAh066HDIaqRX6EqpwBw7Zh9WWrHCTjdQmewQsWPdO3Wy4d62rT6lWkHa5aKUCq7cXDvb48qV8MMPFe+WKRYXZwO+XTto394GfJ06QS012migK6Wqz+nTsH49rFplu1nKW12pPM2a2WBv08aOnklN1QebStE+dKVU9UlMPNfnboydS2bNGhvy27dXvGtm3z67ff31uddv2dJeybdsabeUFB0m6UKv0JVS1efECTv74w8/2D8PHAjO69aqZWeLvOgi+4BTWpq9so+B1Zn0Cl0pFRp16thpA9KL8ufAAXtDdeNGux0+XLnXPXXKvs6mTefa4uJsqDdvbrcLL7TdNSkpMdNlo4GulPJOSordrrjCdsUcOmTncd+8GbZuhb17K//ahYWwZ4/dli8/156QAE2b2rBv1sx+XLxF2bJ8GuhKqdAQgUaN7HbZZbbtxAm7tN62bbb/PSvLXo1XRX6+XYc1O9u5r149O06+aVP7H03jxnZLSYG6dSOun14DXSkVPurUsU+YdutmPzcG9u+3wb5jh/0zO9uOrAmGY8fstnWrc1/NmjbYGzY892fxdsEFdgHuMOvK0UBXSoUvkXPdI3372rbCQhvyO3eeu/LetSvwud4DdebMuS4cf7XVr2+DvTjgGzQ411a/vv0NoE4dz670NdCVUpGl+OZns2Z2PdRix4/D7t12Kw7ivXvt9AXVwRg4csRuWVll11uv3vlbcrL9s1OnoC77p4GulIoOdevaScE6djzXZox90GnfPhvuP/54bjt40F7tV7fCwnPB7+vWWzXQlVIqICLnroo7dDh/X0GBDfX9++1wypwcux04YLeKLPxRWfXqBfXlNNCVUrEpPv5c/7wvY2wXzsGD52+HD9uhlocOVXzOeDfJyVV/jVI00JVSypeIDdvkZDvlgJv8fNuNcvjwuS6VI0fg6NFz27FjkJfn/31CcYUuIkOAvwE1gKnGmGd89icC04HewEFgpDEmK6iVKqVUOElIODduvSynT9t+/OIhksVbbq4dCRNE5Qa6iNQAXgIGAdnAchGZZ4xZX+qwe4HDxph2IjIKeBYYGdRKlVIqEiUm2i0lpdrfKpBR8ZcCW4wx24wxZ4DZwHCfY4YDbxZ9PAe4ViTCHrFSSqkIF0igNwd2lfo8u6jN9RhjTAFwFGjk+0IiMk5EMkQkIycnp3IVK6WUcuXpc6vGmCnGmHRjTHpjXThWKaWCKpBA3w2klfq8RVGb6zEiEg/Ux94cVUop5ZFAAn050F5EWotITWAUMM/nmHnA3UUf/wfwmQnVyhlKKRWjyh3lYowpEJEHgE+xwxbfMMasE5FJQIYxZh7wOjBDRLYAh7Chr5RSykMhW4JORHKAHeUclgIEac2qiBKr5w167rF47rF63lC5c29pjHG9CRmyQA+EiGT4WzsvmsXqeYOeeyyee6yeNwT/3MNrdnallFKVpoGulFJRItwDfUqoCwiRWD1v0HOPRbF63hDkcw/rPnSllFKBC/crdKWUUgHSQFdKqSgR8kAXkSEislFEtojIb1z2J4rIO0X7l4lIqxCUWS0COPdHRWS9iKwWkX+LSMtQ1Fkdyjv3UsfdLCJGRKJiWFsg5y0itxR939eJyEyva6wuAfx7v0hEPheR74v+zQ8NRZ3BJiJviMh+EVnrZ7+IyOSiv5fVItKr0m9mjAnZhn3ydCvQBqgJrAK6+BwzEXi16ONRwDuhrNnjcx8I1C76eEIsnXvRccnAEuBbID3UdXv0PW8PfA9cUPR5k1DX7eG5TwEmFH3cBcgKdd1BOvcrgV7AWj/7hwKfAAJcBiyr7HuF+go9ludaL/fcjTGfG2NOFn36LXZitGgQyPcd4A/YxVLKWMMrogRy3mOBl4wxhwGMMfs9rrG6BHLuBihek60+sMfD+qqNMWYJdkoUf4YD0431LdBARFIr816hDvSgzbUegQI599Luxf4vHg3KPfeiXzvTjDEfe1lYNQvke94B6CAiX4vIt0XLP0aDQM79KeAOEckGFgAPelNayFU0C/zSRaIjgIjcAaQDV4W6Fi+ISBzwV2B0iEsJhXhst8vV2N/IlohIN2PMkVAW5ZFbgWnGmP8WkcuxE/5dbIwpDHVhkSLUV+ixPNd6IOeOiFwH/A4YZow57VFt1a28c08GLgYWi0gWtl9xXhTcGA3ke54NzDPG5BtjtgObsAEf6QI593uBdwGMMUuBJOzkVdEuoCwIRKgDPZbnWi/33EXkEuA1bJhHS18qlHPuxpijxpgUY0wrY0wr7P2DYcaYjNCUGzSB/Hufi706R0RSsF0w2zyssboEcu47gWsBRKQzNtBjYa3KecBdRaNdLgOOGmP2VuqVwuAO8FDsVchW4HdFbZOwP8Bgv6nvAVuA74A2oa7Zw3P/F/AjkFm0zQt1zV6du8+xi4mCUS4Bfs8F2920HlgDjAp1zR6eexfga+wImEzgJ6GuOUjnPQvYC+RjfwO7FxgPjC/1PX+p6O9lTVX+reuj/0opFSVC3eWilFIqSDTQlVIqSmigK6VUlNBAV0qpKKGBrpRSUUIDXSmlooQGulJKRYn/Dw7UigAoy2leAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from scipy.stats import gamma\n", + "\n", + "a = 1.99\n", + "loc = 0\n", + "scale = 0.15\n", + "# here ppf means the percentile function\n", + "# they just use it here to cover the whole relevant spectrum of values\n", + "x = np.linspace(gamma.ppf(0.01, a, loc=loc, scale=scale), gamma.ppf(0.99, a, loc=loc, scale=scale), 100)\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x, gamma.pdf(x, a, loc=loc, scale=scale), 'r-', lw=5, alpha=0.6, \n", + " label='gamma pdf, loc={:.2f}, scale={:.2f}'.format(loc, scale))\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "95302231", + "metadata": {}, + "source": [ + "Next, we need to pick a likelihood function that updates our estimate of the rate based on observed wait times. We assume buses arrive as a Poisson process with a certain rate, in other words, our likelihood function is\n", + "\n", + "p(t | $\\lambda$) = $\\lambda t e^{-\\lambda t}$\n", + "\n", + "plot this as a function of $\\lambda$. You can use either a built in function or write your own. " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0d4a4b97", + "metadata": {}, + "outputs": [], + "source": [ + "def Poisson_process(t, lambd):\n", + " return lambd*t*np.exp(-lambd*t)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "6a75c0a1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "t = 5.\n", + "lambd = np.linspace(0, 1, num=50) # rate (1/wait time)\n", + "probs = Poisson_process(t, lambd)\n", + "\n", + "plt.plot(lambd, probs)\n", + "plt.axvline(x=1/t, c='g', ls ='--')" + ] + }, + { + "cell_type": "markdown", + "id": "69042209", + "metadata": {}, + "source": [ + "Next, we use Bayes' theorem to calculate the posterior estimate of the rate at which buses arrive based on the time we have waited.\n", + "\n", + "p($\\lambda$ | t) $\\propto$ p(t|$\\lambda$) p($\\lambda$)\n", + "\n", + "(note that we are ignoring the denominator here - you can calculate it by summing over the right hand side for all values of $\\lambda$ - it is just a normalization constant.)\n", + "\n", + "Plot your posteriors as a function of the unknown parameter $\\lambda$ for many different values of the observed wait time. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "4fd82781", + "metadata": {}, + "outputs": [], + "source": [ + "def likelihood(t, lambd):\n", + " return Poisson_process(t, lambd)*gamma.pdf(lambd, a, loc=loc, scale=scale)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "f7cf9266", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "t_array = np.arange(1, 6)\n", + "for t in t_array:\n", + " plt.plot(lambd, likelihood(t, lambd), label='t={:.1f}'.format(t))\n", + "plt.legend()\n" + ] + }, + { + "cell_type": "markdown", + "id": "01b6af59", + "metadata": {}, + "source": [ + "Based on your plots, answer the following questions: \n", + "- What happens to your estimate of the rate at which buses arrive as a function of how long you've waited for the first bus? What does this imply about your estimate of the time until the next bus will arrive?\n", + "- What does the shape of these distributions tell you about the $\\Gamma$ distribution and choice of Poisson likelihood for this problem. Is this behavior generalizable? \n", + "\n", + "(challenge) If you've answered the above questions, now solve this problem analytically and explicitly compute the expected time until the next bus arrives using your posterior distribution for the rate at which buses arrive. " + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "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.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation)-checkpoint.ipynb b/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation)-checkpoint.ipynb new file mode 100644 index 0000000..8727733 --- /dev/null +++ b/day0/.ipynb_checkpoints/Introduction to Bayesian Reasoning (Session 19 Orientation)-checkpoint.ipynb @@ -0,0 +1,394 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "38ef8a40", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "431bdde7", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## A (brief) Introduction to Bayesian Reasoning and Statistics\n", + "\n", + "#### Bryan Scott, CIERA/Northwestern, \n", + "#### DSFP Session 19: Orientation for Cohort 7 \n", + "version 0.1 " + ] + }, + { + "cell_type": "markdown", + "id": "b570ae7f", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 1: Warm Up - Conditional Probability and the Law of Total Probability\n", + "\n", + "One of the main objects of Bayesian inference is the conditional probability distribution. This tells us what the chance of something happening given that we know something else happened are. For example,\n", + "\n", + "$$\n", + "p(Good | Dog) = 1 \n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "235467a4", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "A related concept is the law of total probability - this just formalizes the idea that the odds of something happening must involve a sum over all of the (conditional) ways it can happen. \n", + "\n", + "$$\n", + "p(B) = \\Sigma_n P(B | A_n) P(A_n)\n", + "$$\n", + "\n", + "for example,\n", + "\n", + "$$\n", + "p(Pet) = p(Pet| Own) p(Own) + p(Pet| Friendly) p(Friendly)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "e863d8b9", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "One more useful bit of probability theory is that conditional probabilities can be related to each other via a simple relationship:\n", + "\n", + "$$\n", + "p(A| B) = \\frac{P(B|A)P(A)}{P(B)}\n", + "$$\n", + "\n", + "which also holds if you swap $A \\rightarrow B$. This result is sometimes called Bayes' theorem, and the interpretation of this equation (which is simply a fact about conditional probabilities) gives rise to Bayesian statistics." + ] + }, + { + "cell_type": "markdown", + "id": "71d308dd", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 2: Prior Beliefs\n", + "\n", + "Let's consider the following problem. Suppose you're deciding whether to take the bus or walk to your destination. Unfortunately, you live in Chicago, so while there is a bus tracker app, it will tell you only a set of probable times you might expect the bus to arrive. Having previously solved this problem empirically, one learns not to rely on the bus tracker app's estimates. \n", + "\n", + "As such, you'll call the rate at which buses arrive $\\lambda$ and use the bus schedule to set a best guess $p_0(\\lambda)$ for the rate at which buses arrived. $\\lambda$ is a $\\textit{parameter}$ of some distribution we wish to infer. It's assumed distribution before we have observed any buses arriving, $p_0(\\lambda)$ is called the $\\textit{prior}$. " + ] + }, + { + "cell_type": "markdown", + "id": "23aa62fc", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 3: Conditioning Beliefs on Evidence\n", + "\n", + "Now that we know how often we expect the bus to arrive, we need someway to update our knowledge of $\\lambda$ based on observing bus arrival times. This is called the $\\textbf{likelihood}$. It tells us how our observed data changes our beliefs about the value of some parameter. \n", + "\n", + "While choosing a distribution that captures our prior beliefs about the value of a parameter often requires care, there are more clear rules governing the proper updating functions. It turns out that the right updating function for this problem is the $\\textit{Poisson Distribution}$.\n", + "\n", + "For most problems, you will instead use a $\\textit{Gaussian distribution}$." + ] + }, + { + "cell_type": "markdown", + "id": "eb144172", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 4: Bayes' Insight\n", + "\n", + "\n", + "The deep insight is that Bayesian probabilities are statements about the probability of a parameter taking on a certain value. This differs from the classical interpretation, where probability is about realizations of the data, rather than distributions over parameters. " + ] + }, + { + "cell_type": "markdown", + "id": "d7ab2844", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "For example, what we care about as bus riders is the rate at which buses arrive. If we believe the next bus will arrive soon, we will likely wait for it. If we believe the bus will arrive much later, perhaps we will walk. What we want to quantify is our beliefs about the value of the rate parameter of bus arrivals. " + ] + }, + { + "cell_type": "markdown", + "id": "46eaab30", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "To make this quantitative, the probability distribution for the rate at which buses arrive $p(\\tau | \\lambda)$, conditioned on the time we've waited so far, is proportional to the product of our $\\textit{prior}$ belief about when a bus will arrive and the $\\textit{likelihood}$ - a function that tells us how our beliefs change as we observe (or don't observe) buses arriving. \n", + "\n", + "$$\n", + "p(\\lambda | \\tau) \\propto p_0(\\lambda) p(\\tau | \\lambda )\n", + "$$\n", + "\n", + "There is a missing normalization constant here, sometimes called the $\\textbf{evidence}$ or the $\\textbf{marginal likelihood}$ - we will return to this point in detail in the Bayesian inference session, but for now, you can calculate the evidence by asserting that $\\Sigma_{\\tau} p(\\lambda | \\tau) = 1$. For most problems we can neglect this constant since we only care about the maximum of the probability distribution. When it does matter, we often use the law of total probability to calculate this term. More on this in a future session." + ] + }, + { + "cell_type": "markdown", + "id": "8841241e", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "What this equation says is that my $\\textit{belief}$ about the frequency at which buses arrive depends on my prior belief about how often the bus should come and a factor that tells me how to update my belief based on how long I've been waiting at the bus stop." + ] + }, + { + "cell_type": "markdown", + "id": "967c18e1", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Part 5: Putting this into practice\n", + "\n", + "Now, in the rest of this notebook, work out the posterior estimate for the rate at which buses arrive based on your wait time so far. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9b79e6d2", + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.stats import gamma" + ] + }, + { + "cell_type": "markdown", + "id": "9d4fae89", + "metadata": {}, + "source": [ + "The choice of prior is, in general, a subtle problem that we will return to. In the analysis of wait times, it is common to select a prior from the $\\Gamma$ distribution family described by the equation:\n", + "\n", + "$$\n", + "p_0 (\\lambda) = \\frac{\\beta^a \\lambda^{a-1} e^{-\\beta \\lambda}}{\\Gamma(a)}\n", + "$$\n", + "\n", + "Begin by discussing with your partner what each of these parameters means in the context of a wait time problem." + ] + }, + { + "cell_type": "markdown", + "id": "c17524ed", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Next, either use a built in function from scipy or write your own function for the $\\Gamma(a)$ distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "40281475", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, 1)\n", + "\n", + "a = 1\n", + "\n", + "x = np.linspace(gamma.ppf(0.01, a), gamma.ppf(0.99, a), 100)\n", + "ax.plot(x, gamma.pdf(x, a),'b-', lw=5, alpha=0.6, label='a = 1')\n", + "\n", + "a = 2\n", + "\n", + "x = np.linspace(gamma.ppf(0.01, a), gamma.ppf(0.99, a), 100)\n", + "ax.plot(x, gamma.pdf(x, a),'r-', lw=5, alpha=0.6, label='a = 2')\n", + "\n", + "a = 3\n", + "\n", + "x = np.linspace(gamma.ppf(0.01, a), gamma.ppf(0.99, a), 100)\n", + "ax.plot(x, gamma.pdf(x, a),'y-', lw=5, alpha=0.6, label='a = 3')" + ] + }, + { + "cell_type": "markdown", + "id": "95302231", + "metadata": {}, + "source": [ + "Next, we need to pick a likelihood function that updates our estimate of the rate based on observed wait times. We assume buses arrive as a Poisson process with a certain rate, in other words, our likelihood function is\n", + "\n", + "p(t | $\\lambda$) = $\\lambda t e^{-\\lambda t}$\n", + "\n", + "plot this as a function of $\\lambda$. You can use either a built in function or write your own. " + ] + }, + { + "cell_type": "code", + "execution_count": 152, + "id": "1e652bb9", + "metadata": {}, + "outputs": [], + "source": [ + "def poisson(rate, time):\n", + " return rate*time*np.exp(-rate*time)" + ] + }, + { + "cell_type": "markdown", + "id": "69042209", + "metadata": {}, + "source": [ + "Next, we use Bayes' theorem to calculate the posterior estimate of the rate at which buses arrive based on the time we have waited.\n", + "\n", + "p($\\lambda$ | t) $\\propto$ p(t|$\\lambda$) p($\\lambda$)\n", + "\n", + "(note that we are ignoring the denominator here - you can calculate it by summing over the right hand side for all values of $\\lambda$ - it is just a normalization constant.)\n", + "\n", + "Plot your posteriors as a function of the unknown parameter $\\lambda$ for many different values of the observed wait time. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "74b4e9bf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "wait_time = 2\n", + "\n", + "plt.plot(x, gamma.pdf(x, a, scale = 1/wait_time)/np.sum(gamma.pdf(x, a, scale = 1/wait_time)), label = 'before')\n", + "plt.plot(x, (x*wait_time*np.exp(-x*wait_time) * gamma.pdf(x, a, scale = 1/(wait_time)))/np.sum(x*wait_time*np.exp(-x*wait_time)*gamma.pdf(x, a, scale = 1/(wait_time))), label = '0.2')\n", + "\n", + "wait_time = 4\n", + "\n", + "plt.plot(x, (x*wait_time*np.exp(-x*wait_time) * gamma.pdf(x, a, scale = 1/(wait_time)))/np.sum(x*wait_time*np.exp(-x*wait_time)*gamma.pdf(x, a, scale = 1/(wait_time))), label = '6')\n", + "\n", + "plt.ylabel('$p(\\lambda | observed_time)$')\n", + "plt.xlabel('$\\lambda$')\n", + "\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "01b6af59", + "metadata": {}, + "source": [ + "Based on your plots, answer the following questions: \n", + "- What happens to your estimate of the rate at which buses arrive as a function of how long you've waited for the first bus? What does this imply about your estimate of the time until the next bus will arrive?\n", + "- What does the shape of these distributions tell you about the $\\Gamma$ distribution and choice of Poisson likelihood for this problem. Is this behavior generalizable? \n", + "\n", + "(challenge) If you've answered the above questions, now solve this problem analytically and explicitly compute the expected time until the next bus arrives using your posterior distribution for the rate at which buses arrive. " + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "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.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/day0/IntroductiontoBayesianReasoning.ipynb b/day0/IntroductiontoBayesianReasoning.ipynb index 3612fa0..8727733 100644 --- a/day0/IntroductiontoBayesianReasoning.ipynb +++ b/day0/IntroductiontoBayesianReasoning.ipynb @@ -386,7 +386,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/day0/IntroductiontoBayesianReasoningNoSolutions.ipynb b/day0/IntroductiontoBayesianReasoningNoSolutions.ipynb index 8d9498c..239c0d2 100644 --- a/day0/IntroductiontoBayesianReasoningNoSolutions.ipynb +++ b/day0/IntroductiontoBayesianReasoningNoSolutions.ipynb @@ -201,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "id": "9b79e6d2", "metadata": {}, "outputs": [], @@ -225,12 +225,12 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "d06b8d20", + "cell_type": "markdown", + "id": "c46bb291", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "$\\lambda$ is the rate (1/expected wait time); $\\Gamma$ is the normalization constant, and $\\beta$ is the scale factor." + ] }, { "cell_type": "markdown", @@ -246,11 +246,47 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "id": "0423cf69", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD4CAYAAAD8Zh1EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAAsTAAALEwEAmpwYAAArwklEQVR4nO3deXhV1b3/8fc3JCQMAYQwRIjMswxCEBVQUSlIFSzeCs6IBQGHqr9q21vro/S2deitt1xHihZBARUVoSJeWkUcEAkYZpkDhEHCHIZAQtbvj5WEcPY+yUlyss/0fT3PfkjW3jnnuwn5sLP22muJMQallFKRLy7UBSillAoODXSllIoSGuhKKRUlNNCVUipKaKArpVSUiA/VG6ekpJhWrVqF6u2VUioirVix4oAxprHbvpAFeqtWrcjIyAjV2yulVEQSkR3+9mmXi1JKRQkNdKWUihLlBrqIpInI5yKyXkTWicgvXY65WkSOikhm0fZk9ZSrlFLKn0D60AuA/2eMWSkiycAKEVlkjFnvc9yXxpgbgl+iinT5+flkZ2eTl5cX6lKUihhJSUm0aNGChISEgL+m3EA3xuwF9hZ9nCsiG4DmgG+gK+UqOzub5ORkWrVqhYiEuhylwp4xhoMHD5KdnU3r1q0D/roK9aGLSCvgEmCZy+7LRWSViHwiIl39fP04EckQkYycnJyKvHVkyMuDPXtg61Y4fBh04jMA8vLyaNSokYa5UgESERo1alTh32oDHrYoInWB94GHjTHHfHavBFoaY46LyFBgLtDe9zWMMVOAKQDp6emRn3aFhZCZCUuWwI4dcPLk+fuTkqBZM+jUCfr3h8auQ0djgoa5UhVTmZ+ZgAJdRBKwYf62MeYD3/2lA94Ys0BEXhaRFGPMgQpXFAny8+GLL+Czz+DgQf/H5eVBVpbdFi6ELl1g4EDo1g004JRSQRbIKBcBXgc2GGP+6ueYZkXHISKXFr1uGUkXwQ4cgGeegffeKzvM3axfDy+9BH/7G+zfXz31qai2ePFibrjBjj04ffo01113HT179uSdd97x+zVPPfUUf/nLX6qlnu3bt9O3b1/atWvHyJEjOXPmjOtxf/7zn2nXrh0dO3bk008/LWlfuHAhHTt2pF27djzzzDPVUqOv0aNHM2fOnCq/jr9zKu3FF1+kXbt2iAgHDpy7vl28eDH169enZ8+e9OzZk0mTJlW5HgjsCr0fcCewRkQyi9r+E7gIwBjzKvAfwAQRKQBOAaNMNK6c8cMPMGUKnDhRtdfZsAGefhqGDoXBgyE+ZA/sqgj2/fffA5CZmRmyGn7961/zyCOPMGrUKMaPH8/rr7/OhAkTzjtm/fr1zJ49m3Xr1rFnzx6uu+46Nm3aBMD999/PokWLaNGiBX369GHYsGF06dIlFKdSIf7OqUaNGucd169fP2644Qauvvpqx2sMGDCAf/7zn0GtK5BRLl8BZfYPGGNeBF4MVlFh6YsvYNassm90xsVBw4a27zwnB06f9n9sQQHMm2ev2u+7D+rVC37N4ea++6r/PV57zbX5D3/4A2+99RaNGzcmLS2N3r1786tf/Yq///3vTJkyhTNnztCuXTtmzJhB7dq1GT16NLVq1eL7779n//79vPHGG0yfPp2lS5fSt29fpk2bBkDdunWZMGECCxYsIDU1lT/96U88/vjj7Ny5k//5n/9h2LBhZGVlceedd3Ki6ELgxRdf5IorrjivvqysLIYMGULv3r1ZuXIlXbt2Zfr06dSuXZuFCxfy8MMPU7t2bfr37w/A/v37ueOOO8jJyaFnz568//77tG3btty/nszMTMaPH8/Jkydp27Ytb7zxBhdccAFbtmxh/Pjx5OTkUKNGDd57771yX88Yw2effcbMmTMBuPvuu3nqqaccgf7RRx8xatQoEhMTad26Ne3ateO7774DoF27drRp0waAUaNG8dFHH5UZ6O+99x5PP/00NWrUoH79+ixZsoSzZ8/y61//moULFxIXF8fYsWN58MEHmTRpEvPnz+fUqVNcccUVvPbaa45+6RUrVvDoo49y/PhxUlJSmDZtGqmpqeX+Pfo7p8svv/y84y655JJyXyuY9EnRQKxcCTNnuoe5CHTvDo88YrtT/vhH+P3vbbfKn/4EN99c9s3QLVvs12RlVVv5sW758uW8//77rFq1ik8++eS8OYRGjBjB8uXLWbVqFZ07d+b1118v2Xf48GGWLl3KCy+8wLBhw3jkkUdYt24da9asKbkqPnHiBNdccw3r1q0jOTmZJ554gkWLFvHhhx/y5JP2+bomTZqwaNEiVq5cyTvvvMNDDz3kWufGjRuZOHEiGzZsoF69erz88svk5eUxduxY5s+fz4oVK9i3b1/Ja06dOpUBAwaQmZkZUJgD3HXXXTz77LOsXr2abt268fTTTwNw++23c//997Nq1Sq++eYbUlNTyc3NLekS8N3Wr1/PwYMHadCgAfFFv2G2aNGC3bt3O95z9+7dpKWllXxefJy/9rJMmjSJTz/9lFWrVjFv3jwApkyZQlZWFpmZmaxevZrbb78dgAceeIDly5ezdu1aTp065bgazs/P58EHH2TOnDmsWLGCMWPG8Lvf/Q6A559/3vW8i793land19KlS+nRowfXX38969atq9DX+qO/65dn1y74xz/c9zVqZK86W7Z07hOx+3/yExg0CFatgnfegUOHnMceOQLPPw/33APp6UEtX8HXX3/N8OHDSUpKIikpiRtvvLFk39q1a3niiSc4cuQIx48fZ/DgwSX7brzxRkSEbt260bRpU7p16wZA165dycrKomfPntSsWZMhQ4YA0K1bNxITE0lISKBbt25kFf0nnZ+fzwMPPEBmZiY1atQo6W7wlZaWRr9+/QC44447mDx5Mtdddx2tW7emffv2Je1Tpkyp1N/D0aNHOXLkCFdddRVgr6h//vOfk5uby+7du/nZz34G2AdaipXVnVO6T9gr/fr1Y/To0dxyyy2MGDECgH/961+MHz++5D+Whg0bAvD555/z3HPPcfLkSQ4dOkTXrl3P+95v3LiRtWvXMmjQIADOnj1bcnX+2GOP8dhjj1XbefTq1YsdO3ZQt25dFixYwE033cTmzZur/Loa6GXJzYWXXwa3Gz0dO8K4cVC3bvmvIwI9e0LnzvDxx7BokR3yWFpBAUydartpin6oVfUbPXo0c+fOpUePHkybNo3FixeX7EtMTAQgLi6u5OPizwsKCgBISEgo+TW+9HGlj3nhhRdo2rQpq1atorCw8LzALM23OyDUQz1zc3MZMGCA676ZM2fSuXNnjhw5QkFBAfHx8WRnZ9O8eXPHsc2bN2fXrl0ln5c+zl+7P6+++irLli3j448/pnfv3qxYscL1uLy8PCZOnEhGRgZpaWk89dRTjjHdxhi6du3K0qVLHV///PPP8/bbbzvar7zySiZPnlzmOQWiXqku1qFDhzJx4kQOHDhASkpKwK/hRrtc/CkshFdfdb+i7tEDfvnLwMK8tMREGDECHn0UkpOd+42B6dOhVKioquvXrx/z588nLy+P48ePn/erd25uLqmpqeTn57v+AAfD0aNHSU1NJS4ujhkzZnD27FnX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tI89ymigKxVNsrPho49g9eryj23QwI6KGTDAzgKpIp4GulLRaNs2O8xx48byj01KgiuvtNMOXHBBtZemqo8GulLRbNMmuwpSIMEeFwe9etlgb9PG/wyQKmxpoCsVCzZvho8/hg0BzryRlmbHsV96qf+FOFTY0UBXKpbs2AELF8L335d/8xRsd8zll0P//nYJPRXWNNCVikU//miXuFu61K6OFIhWrWywp6fr1AJhSgNdqViWmwtLlsDixXDsWGBfk5AAPXvaK/fOnXVMexjRQFdK2YeSVq6Ezz6D7dsD/7p69ewVe9++dlZIvZEaUhroSqnz7dxpZ3f87js4cybwr0tJsdML9Olj+9s13D2nga6UcnfqlA31r76yIV8RKSl2COQll0Dr1hruHtFAV0qVb9cu+OYbO7VARdczrVcPuneHHj2gUye71J6qFhroSqnAFRTAmjU22NesKX9CMF8JCdCxI3TrBl27gq4fHFRlBbrO2qOUOl98vO1GueQSOHnS3khdvtw+iRrIBWB+Pqxdazewgd61K3TpAh066HDIaqRX6EqpwBw7Zh9WWrHCTjdQmewQsWPdO3Wy4d62rT6lWkHa5aKUCq7cXDvb48qV8MMPFe+WKRYXZwO+XTto394GfJ06QS012migK6Wqz+nTsH49rFplu1nKW12pPM2a2WBv08aOnklN1QebStE+dKVU9UlMPNfnboydS2bNGhvy27dXvGtm3z67ff31uddv2dJeybdsabeUFB0m6UKv0JVS1efECTv74w8/2D8PHAjO69aqZWeLvOgi+4BTWpq9so+B1Zn0Cl0pFRp16thpA9KL8ufAAXtDdeNGux0+XLnXPXXKvs6mTefa4uJsqDdvbrcLL7TdNSkpMdNlo4GulPJOSordrrjCdsUcOmTncd+8GbZuhb17K//ahYWwZ4/dli8/156QAE2b2rBv1sx+XLxF2bJ8GuhKqdAQgUaN7HbZZbbtxAm7tN62bbb/PSvLXo1XRX6+XYc1O9u5r149O06+aVP7H03jxnZLSYG6dSOun14DXSkVPurUsU+YdutmPzcG9u+3wb5jh/0zO9uOrAmGY8fstnWrc1/NmjbYGzY892fxdsEFdgHuMOvK0UBXSoUvkXPdI3372rbCQhvyO3eeu/LetSvwud4DdebMuS4cf7XVr2+DvTjgGzQ411a/vv0NoE4dz670NdCVUpGl+OZns2Z2PdRix4/D7t12Kw7ivXvt9AXVwRg4csRuWVll11uv3vlbcrL9s1OnoC77p4GulIoOdevaScE6djzXZox90GnfPhvuP/54bjt40F7tV7fCwnPB7+vWWzXQlVIqICLnroo7dDh/X0GBDfX9++1wypwcux04YLeKLPxRWfXqBfXlNNCVUrEpPv5c/7wvY2wXzsGD52+HD9uhlocOVXzOeDfJyVV/jVI00JVSypeIDdvkZDvlgJv8fNuNcvjwuS6VI0fg6NFz27FjkJfn/31CcYUuIkOAvwE1gKnGmGd89icC04HewEFgpDEmK6iVKqVUOElIODduvSynT9t+/OIhksVbbq4dCRNE5Qa6iNQAXgIGAdnAchGZZ4xZX+qwe4HDxph2IjIKeBYYGdRKlVIqEiUm2i0lpdrfKpBR8ZcCW4wx24wxZ4DZwHCfY4YDbxZ9PAe4ViTCHrFSSqkIF0igNwd2lfo8u6jN9RhjTAFwFGjk+0IiMk5EMkQkIycnp3IVK6WUcuXpc6vGmCnGmHRjTHpjXThWKaWCKpBA3w2klfq8RVGb6zEiEg/Ux94cVUop5ZFAAn050F5EWotITWAUMM/nmHnA3UUf/wfwmQnVyhlKKRWjyh3lYowpEJEHgE+xwxbfMMasE5FJQIYxZh7wOjBDRLYAh7Chr5RSykMhW4JORHKAHeUclgIEac2qiBKr5w167rF47rF63lC5c29pjHG9CRmyQA+EiGT4WzsvmsXqeYOeeyyee6yeNwT/3MNrdnallFKVpoGulFJRItwDfUqoCwiRWD1v0HOPRbF63hDkcw/rPnSllFKBC/crdKWUUgHSQFdKqSgR8kAXkSEislFEtojIb1z2J4rIO0X7l4lIqxCUWS0COPdHRWS9iKwWkX+LSMtQ1Fkdyjv3UsfdLCJGRKJiWFsg5y0itxR939eJyEyva6wuAfx7v0hEPheR74v+zQ8NRZ3BJiJviMh+EVnrZ7+IyOSiv5fVItKr0m9mjAnZhn3ydCvQBqgJrAK6+BwzEXi16ONRwDuhrNnjcx8I1C76eEIsnXvRccnAEuBbID3UdXv0PW8PfA9cUPR5k1DX7eG5TwEmFH3cBcgKdd1BOvcrgV7AWj/7hwKfAAJcBiyr7HuF+go9ludaL/fcjTGfG2NOFn36LXZitGgQyPcd4A/YxVLKWMMrogRy3mOBl4wxhwGMMfs9rrG6BHLuBihek60+sMfD+qqNMWYJdkoUf4YD0431LdBARFIr816hDvSgzbUegQI599Luxf4vHg3KPfeiXzvTjDEfe1lYNQvke94B6CAiX4vIt0XLP0aDQM79KeAOEckGFgAPelNayFU0C/zSRaIjgIjcAaQDV4W6Fi+ISBzwV2B0iEsJhXhst8vV2N/IlohIN2PMkVAW5ZFbgWnGmP8WkcuxE/5dbIwpDHVhkSLUV+ixPNd6IOeOiFwH/A4YZow57VFt1a28c08GLgYWi0gWtl9xXhTcGA3ke54NzDPG5BtjtgObsAEf6QI593uBdwGMMUuBJOzkVdEuoCwIRKgDPZbnWi/33EXkEuA1bJhHS18qlHPuxpijxpgUY0wrY0wr7P2DYcaYjNCUGzSB/Hufi706R0RSsF0w2zyssboEcu47gWsBRKQzNtBjYa3KecBdRaNdLgOOGmP2VuqVwuAO8FDsVchW4HdFbZOwP8Bgv6nvAVuA74A2oa7Zw3P/F/AjkFm0zQt1zV6du8+xi4mCUS4Bfs8F2920HlgDjAp1zR6eexfga+wImEzgJ6GuOUjnPQvYC+RjfwO7FxgPjC/1PX+p6O9lTVX+reuj/0opFSVC3eWilFIqSDTQlVIqSmigK6VUlNBAV0qpKKGBrpRSUUIDXSmlooQGulJKRYn/Dw7UigAoy2leAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from scipy.stats import gamma\n", + "\n", + "a = 1.99\n", + "loc = 0\n", + "scale = 0.15\n", + "# here ppf means the percentile function\n", + "# they just use it here to cover the whole relevant spectrum of values\n", + "x = np.linspace(gamma.ppf(0.01, a, loc=loc, scale=scale), gamma.ppf(0.99, a, loc=loc, scale=scale), 100)\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x, gamma.pdf(x, a, loc=loc, scale=scale), 'r-', lw=5, alpha=0.6, \n", + " label='gamma pdf, loc={:.2f}, scale={:.2f}'.format(loc, scale))\n", + "ax.legend()" + ] }, { "cell_type": "markdown", @@ -266,11 +302,52 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "0d4a4b97", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "def Poisson_process(t, lambd):\n", + " return lambd*t*np.exp(-lambd*t)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "6a75c0a1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "t = 5.\n", + "lambd = np.linspace(0, 1, num=50) # rate (1/wait time)\n", + "probs = Poisson_process(t, lambd)\n", + "\n", + "plt.plot(lambd, probs)\n", + "plt.axvline(x=1/t, c='g', ls ='--')" + ] }, { "cell_type": "markdown", @@ -288,11 +365,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "id": "4fd82781", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "def likelihood(t, lambd):\n", + " return Poisson_process(t, lambd)*gamma.pdf(lambd, a, loc=loc, scale=scale)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "f7cf9266", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "t_array = np.arange(1, 6)\n", + "for t in t_array:\n", + " plt.plot(lambd, likelihood(t, lambd), label='t={:.1f}'.format(t))\n", + "plt.legend()\n" + ] }, { "cell_type": "markdown", @@ -324,7 +440,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/day1/.ipynb_checkpoints/Clustering-checkpoint.ipynb b/day1/.ipynb_checkpoints/Clustering-checkpoint.ipynb new file mode 100644 index 0000000..b85989b --- /dev/null +++ b/day1/.ipynb_checkpoints/Clustering-checkpoint.ipynb @@ -0,0 +1,4886 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "# Clustering\n", + "\n", + "##### Version 0.1\n", + "\n", + "***\n", + "By AA Miller (Northwestern/CIERA)\n", + "\n", + "10 Sep 2023" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "In this notebook, the two clustering methods discussed in [Lecture II](https://github.com/LSSTC-DSFP/Session-19/tree/main/day1/IntroductionToUnsupervisedLearning.ipynb), [KMeans](https://en.wikipedia.org/wiki/K-means_clustering) and [DBSCAN](https://en.wikipedia.org/wiki/DBSCAN), are used to perform clustering on the famous Iris data set. Using these algorithms it will be shown that identifying accurate clusters when labels are not present is challenging even with a small, low-dimensional, few-class data set.\n", + "\n", + "The notebook closes with a challenge problem using actual astronomical data (photometric measurements of galaxies in the SDSS data set) to attempt clustering on real world data where there are no labeled clusters that are known a priori." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Problem 1) Load and plot Iris data set" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1a**\n", + "\n", + "Import the iris data set from `scikit-learn`. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['setosa', 'versicolor', 'virginica'] ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']\n" + ] + }, + { + "data": { + "text/plain": [ + "dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn import datasets\n", + "\n", + "iris = datasets.load_iris() # complete\n", + "print(list(iris.target_names), list(iris.feature_names))\n", + "iris.keys()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1b**\n", + "\n", + "As a baseline for reference, make a scatter plot of the iris data in the sepal length-sepal width plane." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'sepal width (cm)')" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.scatter(iris.data[:, 0], iris.data[:, 1]) # complete\n", + "ax.set_xlabel('sepal length (cm)')# complete\n", + "ax.set_ylabel('sepal width (cm)')# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Problem 2) $k$-means clustering" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "As a subfield of unsupervised learning, clustering aims to group/separate sources in the multidimensional feature space. The \"unsupervised\" comes from the fact that there are no target labels provided to the algorithm, so the machine is asked to cluster the data \"on its own.\" The lack of labels means there is no (simple) method for validating the accuracy of the solution provided by the machine (though sometimes simple examination can show the results are **terrible**)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "\n", + "For this reason, \"classic\" unsupervised methods are not particularly useful for astronomy.$^\\dagger$ Supposing one did find some useful clustering structure, an adversarial researcher could always claim that the current feature space does not accurately capture the physics of the system and as such the clustering result is not interesting or, worse, erroneous." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "$^\\dagger$This is my (AAM) opinion and there are many others who disagree." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "We start today with the most famous, and simple, clustering algorithm: [$k$-means](https://en.wikipedia.org/wiki/K-means_clustering). $k$-means clustering looks to identify $k$ convex clusters, where $k$ is a user defined number. And here-in lies the rub: if we truly knew the number of clusters in advance, we likely wouldn't need to perform any clustering in the first place. This is the major downside to $k$-means. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "As a reminder from lecture, the pseudocode for $k$-means: \n", + "\n", + " initiate search by identifying k points (i.e. the cluster centers)\n", + " loop \n", + " assign each data point to the closest cluster center\n", + " update cluster centers based on mean location of cluster sources\n", + " if diff(new center - old center) < threshold:\n", + " stop (i.e. clusters are defined)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "The threshold is defined by the user, though in some cases the total number of iterations can also be used as a stopping criteria. An advantage of $k$-means is that the solution will always converge, though the solution may only be a local minimum. Disadvantages include the assumption of convexity, i.e. difficult to capture complex geometry, and the curse of dimensionality (though as discussed in lecture it is possible to apply dimensionality reduction techniques prior to applying clustering)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "In `scikit-learn` the [`KMeans`](http://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans) algorithm is implemented as part of the [`sklearn.cluster`](http://scikit-learn.org/stable/modules/classes.html#module-sklearn.cluster) module. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2a** \n", + "\n", + "Import `KMeans`" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "from sklearn.cluster import KMeans # complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2b** \n", + "\n", + "Fit a $k = 2$, $k$-means model to the iris data. Plot the resulting clusters in the sepal length-sepal width plane." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "KMeans(n_clusters=2)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Kcluster = KMeans(n_clusters=2) # complete\n", + "Kcluster.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 50, 51, 52, 54, 56, 58, 62, 63, 65, 68, 71, 72, 73,\n", + " 74, 75, 76, 77, 78, 83, 85, 86, 87, 91, 97, 100, 102,\n", + " 103, 104, 105, 107, 108, 109, 110, 111, 112, 115, 116, 117, 118,\n", + " 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132,\n", + " 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146,\n", + " 147, 148]),)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.where(Kmeans_preds==0)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "ax.scatter(iris.data[np.where(Kmeans_preds==0)[0], 0], iris.data[np.where(Kmeans_preds==0)[0], 1])\n", + "ax.scatter(iris.data[np.where(Kmeans_preds==1)[0], 0], iris.data[np.where(Kmeans_preds==1)[0], 1])\n", + "\n", + "# complete\n", + "# complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2c** \n", + "\n", + "Fit a $k = 3$, $k$-means model to the iris data. Plot the resulting clusters in the sepal length-sepal width plane." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "k = 3\n", + "Kcluster = KMeans(n_clusters=k) # complete\n", + "Kcluster.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])\n", + "\n", + "fig, ax = plt.subplots()\n", + "for i in range(k):\n", + " ax.scatter(iris.data[np.where(Kmeans_preds==i)[0], 0], iris.data[np.where(Kmeans_preds==i)[0], 1])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2d**\n", + "\n", + "Pretend that you do not know which iris sources belong to which class. Given this, which of the two clustering solutions ($k=2$ or $k=3$) would you identify as superior? \n", + "\n", + "Knowing that there are in fact 3 different clusters, which of the two clustering solutions would you identify as superior?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*write your answer here*\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + " **Problem 2e** \n", + " \n", + "How do the results change if the 3 cluster model is called with `n_init = 1` and `init = 'random'` options? Use `rs` for the random state [this allows me to cheat in service of making a point].\n", + "\n", + "*Note - the respective defaults for these two parameters are `auto` and `k-means++`, respectively. Read the docs to see why these choices are, likely, better than those in 2b. " + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "rs = 19\n", + "\n", + "Kcluster1 = KMeans(n_clusters=k, n_init=1,init='random', random_state=rs) # complete\n", + "Kcluster1.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds1 = Kcluster1.fit_predict(iris.data[:, :2])\n", + "# complete\n", + " \n", + "fig, ax = plt.subplots()\n", + "for i in range(k):\n", + " ax.scatter(iris.data[np.where(Kmeans_preds1==i)[0], 0], iris.data[np.where(Kmeans_preds1==i)[0], 1])\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "That doesn't look right at all! \n", + "\n", + "So in addition to not knowing the correct number of clusters in the data, we see that the results are also sensitive to how the cluster positions are initiated. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "$k$-means evaluates the Euclidean distance between individual sources and cluster centers, thus, the magnitude of the individual features has a strong effect on the final clustering outcome." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2f** \n", + "\n", + "Calculate the mean, standard deviation, min, and max of each feature in the iris data set. Based on these summaries, which feature is most important for clustering? " + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5.84333333 3.05733333 3.758 1.19933333]\n", + "[0.82530129 0.43441097 1.75940407 0.75969263]\n", + "[4.3 2. 1. 0.1]\n", + "[7.9 4.4 6.9 2.5]\n" + ] + } + ], + "source": [ + "print(iris.data.mean(axis=0)) # complete\n", + "print(iris.data.std(axis=0)) # complete\n", + "print(iris.data.min(axis=0)) # complete\n", + "print(iris.data.max(axis=0)) # complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*write your answer here*\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Since $k$-means is built on Euclidean distance measures in the feature space, it can be really useful to re-scale all the features prior to applying the clustering algorithm. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "(Two notes – (a) some algorithms are extremely sensitive to feature scaling so this is a always a good thing to keep in mind, and (b) the iris data set is small and of relatively similar scale so the effects will not be that dramatic)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "Imagine you are classifying stellar light curves: the data set will include binary white dwarf stars with periods of $\\sim 0.01 \\; \\mathrm{d}$ and Mira variables with periods of $\\sim 1000 \\; \\mathrm{d}$. Without re-scaling, this feature covers 6 orders of magnitude! Without rescaling all other features will add little weight to any final clustering solution." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "The two most common forms of re-scaling are to rescale to a guassian with mean $= 0$ and variance $= 1$, or to rescale the min and max of the feature to $[0, 1]$. The best normalization is problem dependent. The [`sklearn.preprocessing`](http://scikit-learn.org/stable/modules/classes.html#module-sklearn.preprocessing) module makes it easy to re-scale the feature set.$^\\dagger$ " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "$\\dagger$ For supervised methods, **it is essential that the same scaling used for the training set be used for all other data run through the model.** The testing, validation, and field observations cannot be re-scaled independently. This would result in meaningless final classifications/predictions." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2g** \n", + "\n", + "Re-scale the features to normal distributions, and perform $k$-means clustering on the iris data. How do the results compare to those obtained earlier? \n", + "\n", + "*Hint - you may find [`'StandardScaler()'`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html#sklearn.preprocessing.StandardScaler) within the `sklearn.preprocessing` module useful.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "scaler = StandardScaler().fit( # complete\n", + "\n", + "Kcluster = # complete\n", + "# complete\n", + " \n", + "fig, ax = plt.subplots()\n", + "ax.scatter( # complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*write your answer here*" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**How do I test the accuracy of my clusters?**\n", + "\n", + "Essentially - you don't. There are some methods that are available, but they essentially compare clusters to labeled samples, and if the samples are labeled it is likely that supervised learning is more useful anyway. If you are curious, `scikit-learn` does provide some [built-in functions for analyzing clustering](http://scikit-learn.org/stable/modules/clustering.html#clustering-performance-evaluation), but again, it is difficult to evaluate the validity of any newly discovered clusters. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**What if I don't know how many clusters are present in the data?**\n", + "\n", + "An excellent question, as you will almost never know this a priori. Many algorithms, like $k$-means, do require the number of clusters to be specified, but some other methods do not." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Problem 3) DBSCAN" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "During the lecture we saw that [`DBSCAN`](https://en.wikipedia.org/wiki/DBSCAN) can be used to identify clusters without the pre-specification of the number of clusters to search for. \n", + "\n", + "In brief, `DBSCAN` requires two parameters: `minPts`, the minimum number of points necessary for a cluster, and $\\epsilon$, a distance measure (see the lecture for the full pseudocode). " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "The general downsides for DBSCAN are that the results are highly dependent on the two tuning parameters, and that clusters of highly different densities can be difficult to recover (because $\\epsilon$ and `minPts` is specified for all clusters. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "In `scitkit-learn` the \n", + "[`DBSCAN`](http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html#sklearn.cluster.DBSCAN) algorithm is part of the `sklearn.cluster` module. $\\epsilon$ and `minPts` are set by `eps` and `min_samples`, respectively. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 3a** \n", + "\n", + "Cluster the iris data using `DBSCAN`. Use the `scikit-learn` defaults. Plot the results in the sepal width-sepal length plane. \n", + "\n", + "*Note - DBSCAN labels outliers as $-1$, and thus, `plt.scatter()`, will plot all these points as the same color.*\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "from sklearn.cluster import DBSCAN\n", + "\n", + "dbs = # complete\n", + "dbs.fit( # complete\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.scatter( # complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 3b**\n", + "\n", + "Adjust the tuning parameters to see how they affect the final clustering results. How does the use of `DBSCAN` compare to $k$-means? Can you obtain 3 clusters with `DBSCAN`? If not, given the knowledge that the iris dataset has 3 classes - does this invalidate `DBSCAN` as a viable algorithm?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "dbs = DBSCAN( # complete\n", + "dbs.fit(# complete\n", + " \n", + "fig, ax = plt.subplots()\n", + "ax.scatter( # complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*write your answer here*" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Problem 4) Cluster SDSS Galaxy Data\n", + "\n", + "The following query will select 10k likely galaxies from the SDSS database and return the results of that query into an [`astropy.Table`](http://docs.astropy.org/en/stable/table/) object. (For now, if you are not familiar with the SDSS DB schema, don't worry about this query, just know that it returns a bunch of photometric features.)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + " from astroquery.sdss import SDSS # enables direct queries to the SDSS database\n", + "\n", + " GALquery = \"\"\"SELECT TOP 5000 \n", + " p.dered_u - p.dered_g as ug, p.dered_g - p.dered_r as gr, \n", + " p.dered_g - p.dered_i as gi, p.dered_g - p.dered_z as gz, \n", + " p.petroRad_i, p.petroR50_i, p.deVAB_i, p.fracDev_i\n", + " FROM PhotoObjAll AS p JOIN specObjAll s ON s.bestobjid = p.objid\n", + " WHERE p.mode = 1 AND s.sciencePrimary = 1 AND p.clean = 1 AND p.type = 3\n", + " AND p.deVAB_i > -999 AND p.petroRad_i > -999 AND p.petroR50_i > -999 AND p.dered_r < 20\n", + " \"\"\"\n", + " SDSSgals = SDSS.query_sql(GALquery)\n", + " SDSSgals" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 4a** \n", + "\n", + "Download the [SDSS galaxy data](https://arch.library.northwestern.edu/downloads/7w62f868g?locale=en)\n", + "\n", + "Read in the file `galaxy_clustering.csv`, and convert the data into a feature array `X`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 4b** \n", + "\n", + "Using the SDSS galaxy data, identify interesting clusters within the data. This question is intentionally very open ended. If you uncover anything especially exciting you'll have a chance to share it with the group. Feel free to use the algorithms discussed above, or any other packages available via `sklearn`. Can you make sense of the clusters in the context of galaxy evolution? \n", + "\n", + "*Hint - don't fret if you know nothing about galaxy evolution (neither do I!). Just take a critical look at the clusters that are identified*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# complete\n", + "# complete\n", + "# complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# complete\n", + "# complete\n", + "# complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "*write your thoughts about the identified clusters here*" + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "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.9.7" + }, + "livereveal": { + "height": 768, + "scroll": true, + "start_slideshow_at": "selected", + "theme": "solarized", + "width": 1024 + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/day1/.ipynb_checkpoints/Dimensionality_reduction_no_solutions-checkpoint.ipynb b/day1/.ipynb_checkpoints/Dimensionality_reduction_no_solutions-checkpoint.ipynb new file mode 100644 index 0000000..3195511 --- /dev/null +++ b/day1/.ipynb_checkpoints/Dimensionality_reduction_no_solutions-checkpoint.ipynb @@ -0,0 +1,1358 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d90d3986", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Dimensionality Reduction Tutorial\n", + "\n", + "### Bryan Scott, CIERA/Northwestern\n", + "version 0.1, August 2023\n", + "\n", + "In this tutorial, we will begin by reading in postage stamp images from the Sloan Digital Sky Survey. The first part of the lesson will then decompose these images into their principle components using both our own implementation of the PCA procedure in numpy, and make use of the scikit-learn PCA implementation. Our learning goals are two fold - to gain familiarity with PCA and to gain experience with scikit-learn on a problem where we can straightforwardly implement our own version of the tools. \n", + "\n", + "In the second part of the tutorial, we will apply t-SNE to Cosmos2020 28-band photometry and visualize in 2D the separation of different objects in redshift as a function of their 28D fluxes.\n", + "\n", + "The challenge problem asks you to build a SOM from scratch. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "dae8731a", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import h5py" + ] + }, + { + "cell_type": "markdown", + "id": "37d7a40e", + "metadata": {}, + "source": [ + "## Problem 1: Principal Component Analysis" + ] + }, + { + "cell_type": "markdown", + "id": "c457be51", + "metadata": {}, + "source": [ + "### Preliminary: Download the images and load them into arrays called images and labels" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0eb43a93", + "metadata": {}, + "outputs": [], + "source": [ + "# To get the images and labels from file\n", + "with h5py.File('/Users/aizhanakhmetzhanova/Downloads/Galaxy10.h5', 'r') as F: # your path goes here \n", + " images = np.array(F['images'])\n", + " labels = np.array(F['ans'])\n", + "\n", + "# To convert to desirable type\n", + "labels = labels.astype(np.float32)\n", + "images = images.astype(np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2b72fd14", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((21785,), (21785, 69, 69, 3))" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "labels.shape, images.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8e781977", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.unique(labels)" + ] + }, + { + "cell_type": "markdown", + "id": "3b427dee", + "metadata": {}, + "source": [ + "### Part 0: A Gentle Introduction to the data\n", + "\n", + "The first step in any ML workflow is to 'worry' about the data. First, print out the dimensions of the images and labels arrays. Why does each array have the dimensionality that it does? Write your answer in the provided markdown cell below. " + ] + }, + { + "cell_type": "markdown", + "id": "0228dd9a", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "22cc8f30", + "metadata": {}, + "source": [ + "Now, let's visually inspect our data. In the Wide Field Image Processing session, we have/will cover how to generate false color images from multi-band photometry. For now, we can use the astropy implementation. Given the following help call, fill in the code block below to generate false color images for the first SDSS postage stamp. Do this for object 14001 in the provided h5 file." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8d38d8cc", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.visualization import make_lupton_rgb" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "efc0f0ff", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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AAAAgqHAAAAAABAMBQYAAACAYCgwAAAAAARDgQEAAAAgGAoMAAAAAMFQYAAAAAAIhgIDAAAAQDD79iTvxMJXP/1+T/vsGR2/OKt201Rr13MC5eamfur3YDCQsx7f813aSdbz8/rJtQPHKdY7gw05u7y8JGfNtNNrp0P9dNVKqZ/63XSsw7jUz2aumHYqce64saNYP0J5GulHjFYqWl/jqj5W1chxenCiZyvi6dxmZmWkXZeVYs6pUtXnIHKcjq0+qByHuZtN9cffNNYbLh0neavjNXGcEh/VHNeVj+RsafrxweoIRKV+XaVjciuue1GOWiyefN5o6M+kwvQ9tr+uP5MGpT63/d4FKXfN64/IbdbnFuXs88+flbNf//rTcjZJtNPEPe9GHp53vtxxPLcazTK9zVm8nvINBgAAAIBgXlOBcerUKYuiyG6//fa9n5VlaSdOnLAjR45Ys9m0m266yZ588snX2k8AAAAAV4FXXWA8+uij9olPfMLe9ra3XfTzu+66y+6++26799577dFHH7XV1VW7+eabrd/vv+bOAgAAANjfXlWBsbOzY+973/vsk5/8pC0sLOz9vCxLu+eee+zOO++02267za699lq7//77Lcsye+CBB4J1GgAAAMD+9KoKjA9/+MP24z/+4/ZjP/ZjF/38mWeesbW1Nbvlllv2flav1+3GG2+0Rx555BXbGo1G1uv1LvoFAAAA4Ork/lekHnzwQfvTP/1Te/TRR1/2e2tra2ZmtrKyctHPV1ZW7Bvf+MYrtnfq1Cn7t//233q7AQAAAGAfcn2DcebMGfvlX/5l+53f+R1rNBqXzEXf9E/ElWX5sp+95I477rBut7v368yZM54uAQAAANhHXN9gPPbYY7a+vm7vfOc79342mUzsi1/8ot177732ta99zcxe/Cbj8OHDe5n19fWXfavxknq9bvV6/dX0HQAAAMA+4/oG40d/9EftiSeesMcff3zv13XXXWfve9/77PHHH7c3velNtrq6aqdPn977/xmPx/bwww/bDTfcELzzAAAAAPYX1zcYrVbLrr322ot+Njc3Z0tLS3s/v/322+3kyZN2/PhxO378uJ08edLSNLX3vve94XoNAAAAYF9y/yXvy/nYxz5mg8HAPvShD9n29rZdf/319tBDD1mr1XK1s7m2ZZf4axsX8RzFbmJ0Vse7d7tdOTsL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from astropy.visualization import make_lupton_rgb\n", + "\n", + "i_data = images[14111, :, :, 0] # first band\n", + "r_data = images[14111, :, :, 1] # second band\n", + "g_data = images[14111, :, :, 2] # third band\n", + "\n", + "rgb = make_lupton_rgb(i_data, r_data, g_data,\n", + " minimum=0, Q=6, stretch=50) # Bonus Q: how does changing these paramters change the images?\n", + "\n", + "fig, ax = plt.subplots(figsize=(8,8))\n", + "ax.imshow(rgb, origin='lower')\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "id": "eb75dd66", + "metadata": {}, + "source": [ + "### Visualize individual classes \n", + "\n", + "The Galaxy10 dataset consists of the following classes: \n", + "\n", + "Galaxy10 dataset (21785 images)\n", + "- Class 0 (3461 images): Disk, Face-on, No Spiral\n", + "- Class 1 (6997 images): Smooth, Completely round\n", + "- Class 2 (6292 images): Smooth, in-between round\n", + "- Class 3 (394 images): Smooth, Cigar shaped\n", + "- Class 4 (1534 images): Disk, Edge-on, Rounded Bulge\n", + "- Class 5 (17 images): Disk, Edge-on, Boxy Bulge\n", + "- Class 6 (589 images): Disk, Edge-on, No Bulge\n", + "- Class 7 (1121 images): Disk, Face-on, Tight Spiral\n", + "- Class 8 (906 images): Disk, Face-on, Medium Spiral\n", + "- Class 9 (519 images): Disk, Face-on, Loose Spiral\n", + "\n", + "Before proceeding, what do you notice about these classes. Why is this potentially problematic? \n", + "\n", + "Now use the labels vector to visualize a member of each class: " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "bfdf3fcc", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABmZklEQVR4nO2dfZBc1Xnmn9vf3dM9PV/SzMhIWHYENggwH46CbEdyAdplMbteXHZisJd4ax2wsI3Wu4sjqLVFikgOSRGcsiMXrA3yJpT+WBsHr21ALoLYBLMmGAoMCcZBxkJoNJqvnpn+/jj7h8ygmfc50I3E3hnp+VVNlXT63HvPOffce/r2+9znDZxzDkIIIUQIRMJugBBCiJMXLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJC/Iann34an/rUp7B69WqkUilks1mcd955uPXWWzExMTFXb+PGjdi4cWN4DX0ddu/ejfe85z1IpVJYsWIFtmzZgtnZ2bCbJYSXWNgNEGIxcOedd2Lz5s04/fTT8d/+23/DGWecgXq9jn/8x3/EN77xDfzkJz/BvffeG3YzX5e/+Zu/wSc+8Qn8p//0n/AXf/EX+MUvfoEvfvGLeO655/Dggw+G3TwhKIG848TJzk9+8hN84AMfwCWXXILvfe97SCaT8z6v1Wq4//778W//7b8FgLmnoIcffvj/c0v9NJtNrFy5EmeddRYeeOCBufJ77rkHV111FX74wx/i0ksvDbGFQnD0c5w46dm+fTuCIMAdd9xhFiAASCQScwuQj5tvvhnr1q1DX18furu7cd555+Gb3/wmFn7He+ihh7Bx40b09/cjnU5j1apV+MhHPoJSqTRXZ+fOnTjnnHOQzWaRy+Xwrne9CzfeeOPrHv+xxx7DwYMH8alPfWpe+Uc/+lFks9lF/xQnTl70c5w4qWk2m3jooYdw/vnnY+XKlW96P7/61a9wzTXXYNWqVQCOLAqf+9zncODAAXzpS1+aq3PZZZfhAx/4AL71rW+hp6cHBw4cwP33349arYZMJoPdu3dj8+bN+NznPoc///M/RyQSwS9/+Us899xzr3v8n//85wCAs88+e155PB7Hu971rrnPhVhsaBESJzVjY2MolUpYvXr1Me3nrrvumvt3q9XCxo0b4ZzDV7/6Vfz3//7fEQQBnnjiCVQqFfzZn/0ZzjnnnLn6V1555dy//+Ef/gE9PT34y7/8y7myiy666A2PPz4+DgDo6+szn/X19eFXv/rVm+mWEG85+jlOiOPAQw89hIsvvhj5fB7RaBTxeBxf+tKXMD4+jtHRUQDAe97zHiQSCfzhH/4hdu3ahRdffNHs57d/+7cxNTWFj3/84/jbv/1bjI2NddSOIAg6KhcibLQIiZOagYEBZDIZ7Nu3703v46c//Sk2bdoE4IjK7h/+4R/w+OOP46abbgIAlMtlAMA73/lO/PjHP8by5ctx3XXX4Z3vfCfe+c534qtf/ercvj75yU/iW9/6Fl566SV85CMfwfLly7Fu3Trs2bPnddvQ398P4LUnoqOZmJigT0hCLAa0CImTmmg0iosuughPPPEEXn755Te1j927dyMej+N//+//jY997GNYv349LrjgAlr3Ax/4AL7//e+jUCjgsccew4UXXogtW7Zg9+7dc3U+9alP4dFHH0WhUMAPfvADOOfwoQ99CC+99JK3DWeddRYA4JlnnplX3mg08M///M9Yu3btm+qbEG81WoTESc/WrVvhnMOnP/1p1Go183m9Xsf3v/997/ZBECAWiyEajc6Vlctl/M//+T+920SjUaxbtw5f//rXAQA/+9nPTJ2uri5ceumluOmmm1Cr1fDss89697du3ToMDw/j7rvvnlf+v/7X/8Ls7CyuuOIK77ZChImECeKk58ILL8TOnTuxefNmnH/++fjMZz6DM888E/V6HU8++STuuOMOrF27Fpdffjnd/rLLLsNtt92GK6+8En/4h3+I8fFx/Pmf/7mRe3/jG9/AQw89hMsuuwyrVq1CpVLBt771LQDAxRdfDAD49Kc/jXQ6jfe9730YHh7GyMgIduzYgXw+j/e+973ePkSjUdx666345Cc/iWuuuQYf//jH8cILL+CGG27AJZdcgn/9r//1cRotIY4zTgjhnHPuqaeecldffbVbtWqVSyQSrqury5177rnuS1/6khsdHZ2rt2HDBrdhw4Z5237rW99yp59+uksmk+4d73iH27Fjh/vmN7/pALh9+/Y555z7yU9+4v79v//37tRTT3XJZNL19/e7DRs2uPvuu29uP7t27XIf/OAH3eDgoEskEm7FihXuYx/7mHv66afb6sM999zjzj77bJdIJNzQ0JD7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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABpE0lEQVR4nO2dfZBlZX3nv+fec+5r37493T3T3QMDjDiggPgCOmHUzFjKpFhw18WKUYxL3CojjhpYd5cEqZUxZWYMSVGY0mDBKozJUvPHKgbXqIxFHDZBVoJSIiQEw4jDS0/Tb7df7ts59z77x0gz3b/vI9285HTPfD9VXTXz3HPO83Kec5577u97vr/AOecghBBCpEAm7QYIIYQ4cdEiJIQQIjW0CAkhhEgNLUJCCCFSQ4uQEEKI1NAiJIQQIjW0CAkhhEgNLUJCCCFSQ4uQEEKI1NAiJMSv+OlPf4oPf/jD2Lx5MwqFAnp6evCmN70J119/PSYnJxe227FjB3bs2JFeQz187Wtfw/vf/36ceeaZyGQyOO2009JukhAvSJh2A4RYDdxyyy3YtWsXzjzzTPz3//7fcdZZZyGOY/zjP/4jvvzlL+OHP/wh7rjjjrSb+Wv5q7/6K4yOjuItb3kLut0u4jhOu0lCvCCBvOPEic4Pf/hDvP3tb8eFF16Ib37zm8jn84s+b7fb+O53v4t//+//PQAsPAX94Ac/+Ddu6a+n2+0ikzn648Yll1yCn/3sZ/jFL36RbqOEeAH0c5w44dmzZw+CIMDNN99sFiAAyOVyCwuQj89+9rPYunUr+vv70dvbize96U34yle+gqXf8e6++27s2LEDAwMDKBaLOOWUU/De974X9Xp9YZubbroJr3/969HT04NKpYLXvOY1+PSnP/2C/XhuARJiLaGf48QJTafTwd13343zzjsPmzZtetHH+cUvfoGPfvSjOOWUUwAA9913Hz75yU/iqaeewmc+85mFbS6++GK8/e1vx1e/+lX09fXhqaeewne/+120222USiXs378fu3btwic/+Un8+Z//OTKZDH7+85/jkUceeVn6K8RqQ4uQOKEZHx9HvV7H5s2bX9Jxbr311oV/d7td7NixA845fOELX8D/+B//A0EQ4IEHHkCz2cSf/dmf4fWvf/3C9pdddtnCv//hH/4BfX19+Iu/+IuFsne+850vqW1CrGb0/C7Ey8Ddd9+Nd73rXahWq8hms4iiCJ/5zGcwMTGBsbExAMAb3vAG5HI5/P7v/z727duHxx9/3BznLW95C6anp/GBD3wAf/M3f4Px8fF/664I8W+KFiFxQjM4OIhSqYRDhw696GP86Ec/ws6dOwEcVdn9wz/8A+6//35ce+21AIBGowEAOP300/H9738fGzZswMc//nGcfvrpOP300/GFL3xh4Vgf+tCH8NWvfhVPPPEE3vve92LDhg3YunUrDhw48BJ6KcTqRYuQOKHJZrN45zvfiQceeABPPvnkizrG/v37EUUR/s//+T943/veh23btuH888+n27797W/Ht771LdRqNdx333244IILcNVVV2H//v0L23z4wx/Gvffei1qthm9/+9twzuGSSy7BE0888aLaJ8RqRouQOOG55ppr4JzDRz7yEbTbbfN5HMf41re+5d0/CAKEYYhsNrtQ1mg08Fd/9VfefbLZLLZu3YovfelLAIAf//jHZptyuYyLLroI1157LdrtNh5++OGVdEuINYGECeKE54ILLsBNN92EXbt24bzzzsPHPvYxnH322YjjGD/5yU9w880345xzzsG73/1uuv/FF1+MG264AZdddhl+//d/HxMTE/jzP/9zI/f+8pe/jLvvvhsXX3wxTjnlFDSbTXz1q18FALzrXe8CAHzkIx9BsVjEW9/6VoyMjGB0dBR79+5FtVrFm9/85l/bj0ceeWRBRTc6Oop6vY7//b//NwDgrLPOwllnnfWSxkmIVwQnhHDOOffggw+6yy+/3J1yyikul8u5crns3vjGN7rPfOYzbmxsbGG77du3u+3bty/a96tf/ao788wzXT6fd6961avc3r173Ve+8hUHwB06dMg559wPf/hD9x//4390p556qsvn825gYMBt377d3XnnnQvH2bdvn3vHO97hhoaGXC6Xcxs3bnTve9/73E9/+tMXbP91113nANC/66677uUYIiFeduSYIIQQIjUUExJCCJEaWoSEEEKkhhYhIYQQqaFFSAghRGpoERJCCJEaWoSEEEKkxiv2supf/uVf4s/+7M/wzDPP4Oyzz8aNN96It7/97S+4X7fbxdNPP41KpYIgCF6p5gkhhHiFcM5hdnYWGzdufOE8V6/Ey0f79+93URS5W265xT3yyCPuyiuvdOVy2T3xxBMvuO/hw4e9L9zpT3/6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IYRIDS1CQgghUkOLkBBCiNRY1YvQX/7lX2Lz5s0oFAo477zz8H//7/9Nu0nL5p577sG73/1ubNy4EUEQ4Jvf/Oaiz51z2L17NzZu3IhisYgdO3bg4YcfTqexy2Tv3r1485vfjEqlgg0bNuA973kPHn300UXbrMV+3XTTTTj33HMX3ki/4IIL8J3vfGfh87XYp6Xs3bsXQRDgqquuWihbi/3avXs3giBY9Dc8PLzw+Vrs03M89dRT+N3f/V0MDAygVCrhDW94Ax544IGFz9dy334tbpWyf/9+F0WRu+WWW9wjjzzirrzySlcul90TTzyRdtOWxd/+7d+6a6+91n396193ANwdd9yx6PPPf/7zrlKpuK9//evuoYcecr/zO7/jRkZG3MzMTDoNXga/9Vu/5W699Vb3s5/9zD344IPu4osvdqeccoqbm5tb2GYt9uvOO+903/72t92jjz7qHn30UffpT3/aRVHkfvaznznn1mafjuVHP/qRO+2009y5557rrrzyyoXytdiv6667zp199tnumWeeWfgbGxtb+Hwt9sk55yYnJ92pp57qfu/3fs/9v//3/9yhQ4fc97//fffzn/98YZu12rcXYtUuQm95y1vcFVdcsajsNa95jfujP/qjlFr04lm6CHW7XTc8POw+//nPL5Q1m01XrVbdl7/85RRa+OIYGxtzANzBgwedc8dPv5xzbt26de5//s//ueb7NDs767Zs2eIOHDjgtm/fvrAIrdV+XXfdde71r389/Wyt9sk55/7wD//Qve1tb/N+vpb79kKsyp/j2u02HnjgAezcuXNR+c6dO3Hvvfem1KqXj0OHDmF0dHRR//L5PLZv376m+ler1QAA/f39AI6PfnU6Hezfvx/z8/O44IIL1nyfPv7xj+Piiy/Gu971rkXla7lfjz32GDZu3IjNmzfj/e9/Px5//HEAa7tPd955J84//3z89m//NjZs2IA3vvGNuOWWWxY+X8t9eyFW5SI0Pj6OTqeDoaGhReVDQ0MYHR1NqVUvH8/1YS33zzmHT33qU3jb296Gc845B8Da7tdDDz2Enp4e5PN5XHHFFbjjjjtw1llnrek+7d+/Hz/+8Y+xd+9e89la7dfWrVvxta99Dd/73vdwyy23YHR0FNu2bcPExMSa7RMAPP7447jpppuwZcsWfO9738MVV1yBP/iDP8DXvvY1AGv3fC2HVZfK4VieS+XwHM45U7aWWcv9+8QnPoGf/vSn+Pu//3vz2Vrs15lnnokHH3wQ09PT+PrXv47LL78cBw8eXPh8rfXp8OHDuPLKK3HXXXehUCh4t1tr/brooosW/v26170OF1xwAU4//XTs27cPv/EbvwFg7fUJOJpH7fzzz8eePXsAAG984xvx8MMP46abbsJ/+k//aWG7tdi3F2JVPgkNDg4im82aFX5sbMx8E1iLPKfmWav9++QnP4k777wTf/d3f7coa+Ja7lcul8OrX/1qnH/++di7dy9e//rX4wtf+MKa7dMDDzyAsbExnHfeeQjDEGEY4uDBg/iLv/gLhGG40Pa11q+llMtlvO51r8Njjz22Zs8VAIyMjOCss85aVPba174Wv/zlLwGs7WvrhViVi1Aul8N5552HAwcOLCo/cOAAtm3bllKrXj42b96M4eHhRf1rt9s4ePDgqu6fcw6f+MQn8I1vfAN33303Nm/evOjztdovhnMOrVZrzfbpne98Jx566CE8+OCDC3/nn38+PvjBD+LBBx/Eq171qjXZr6W0Wi380z/9E0ZGRtbsuQKAt771reZ1h3/5l3/BqaeeCuD4urYMaSkiXojnJNpf+cpX3COPPOKuuuoqVy6X3S9+8Yu0m7YsZmdn3U9+8hP3k5/8xAFwN9xwg/vJT36yIDH//Oc/76rVqvvGN77hHnroIfeBD3xg1cstP/axj7lqtep+8IMfLJLI1uv1hW3WYr+uueYad88997hDhw65n/70p+7Tn/60y2Qy7q677nLOrc0+MY5Vxzm3Nvv1X//rf3U/+MEP3OOPP+7uu+8+d8kll7hKpbJwX1iLfXLuqIw+DEP3J3/yJ+6xxx5z/+t//S9XKpXcX//1Xy9ss1b79kKs2kXIOee+9KUvuVNPPdXlcjn3pje9aUEKvBb4u7/7OwfA/F1++eXOuaOSy+uuu84NDw+7fD7vfvM3f9M99NBD6Tb6BWD9AeBuvfXWhW3WYr/+83/+zwvzbP369e6d73znwgLk3NrsE2PpIrQW+/XcuzFRFLmNGze6Sy+91D388MMLn6/FPj3Ht771LXfOOee4fD7vXvOa17ibb7550edruW+/DuUTEkIIkRqrMiYkhBDixECLkBBCiNTQIiSEECI1tAgJIYRIDS1CQgghUkOLkBBCiNTQIiSEECI1tAgJIYRIDS1CQgghUkOLkBBCiNTQIiSEECI1/j/Lnun5b7hMRQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABoZElEQVR4nO2dfZBmVX3nv/fteevn6e55YbpnwkBGM6CCL7zoyKiZsYDZYpFdFysmYgxxq4w4YGDdXRJko2NKZwxJUZjSYMEqDMlS849icFVkLOK4CbIShJJgMsFlxBFom5np9+f13nv2j5Fmun/fI9285HbPfD9VXTVznnPvPefcc+957vP73u8vcM45CCGEEAUQFt0AIYQQJy5ahIQQQhSGFiEhhBCFoUVICCFEYWgREkIIURhahIQQQhSGFiEhhBCFoUVICCFEYWgREkIIURhahIT4JT/60Y/wwQ9+EBs2bEClUkG9XsfZZ5+NG264AUeOHJmtt3XrVmzdurW4hhKeeeYZ/I//8T9w3nnnYfXq1ejv78c555yDW265BVmWFd08IbzERTdAiKXArbfeiu3bt+P000/Hf//v/x2ve93r0Ov18I//+I/44he/iO9///u46667im6ml4ceegh33HEHfu/3fg9/8id/giRJ8K1vfQsf+chH8MADD+DLX/5y0U0UghLIO06c6Hz/+9/HO97xDlx44YX42te+hnK5POfzbreLe+65B//hP/wHAJh9Cvrud7/7b9xSP2NjY6jX60iSZE75VVddhS984Qv42c9+hvXr1xfUOiH86Oc4ccKzc+dOBEGAW265xSxAAFAqlWYXIB+f+tSnsGnTJqxcuRL9/f04++yz8aUvfQnzv+Pdd9992Lp1K1atWoVqtYpTTjkF73nPe9BsNmfr3HzzzXjjG9+Ier2ORqOB17zmNfj4xz/+K4+/YsUKswABwFve8hYAwM9//vNfub0QRaGf48QJTZZluO+++3DOOee8pCeFn/70p/jwhz+MU045BQDwwAMP4KMf/SieeuopfOITn5itc/HFF+Md73gHvvzlL2NwcBBPPfUU7rnnHnS7XdRqNezZswfbt2/HRz/6UfzFX/wFwjDET37yE/z4xz9+Ue267777EMcxTjvttBfdNyFeSbQIiROaQ4cOodlsYsOGDS9pP7fddtvsv/M8x9atW+Gcw+c+9zn8yZ/8CYIgwEMPPYR2u40///M/xxvf+MbZ+pdddtnsv//hH/4Bg4OD+Mu//MvZsvPPP/9Ftenee+/FX//1X+Pqq6/GqlWrXtQ+hHil0c9xQrwM3HfffbjgggswMDCAKIqQJAk+8YlP4PDhwxgdHQUAvOlNb0KpVMIf/MEfYPfu3XjiiSfMft7ylrdgfHwc73vf+/C3f/u3OHTo0Itqzw9/+EO8973vxVvf+lbs2rXrJfVNiFcSLULihGb16tWo1Wo4cODAi97HD37wA2zbtg3AUZXdP/zDP+DBBx/E9ddfDwBotVoAgFe/+tX4zne+gzVr1uDKK6/Eq1/9arz61a/G5z73udl9feADH8CXv/xlPPnkk3jPe96DNWvWYNOmTdi7d++C2/Pwww/jwgsvxMaNG/HNb36TxrmEWCpoERInNFEU4fzzz8dDDz30ooP3e/bsQZIk+N//+3/jve99LzZv3oxzzz2X1n3HO96Br3/965iYmMADDzyA8847D9dccw327NkzW+eDH/wg7r//fkxMTOAb3/gGnHN417vehSeffPIF2/Lwww/jggsuwKmnnop7770XAwMDL6pPQvxboUVInPBcd911cM7hQx/6ELrdrvm81+vh61//unf7IAgQxzGiKJota7Va+Ou//mvvNlEUYdOmTfjCF74A4OjPZ/Pp6+vDRRddhOuvvx7dbhePPfbYr+zHI488ggsuuAAnn3wy9u7dixUrVvzK+kIsBSRMECc85513Hm6++WZs374d55xzDj7ykY/gjDPOQK/Xw8MPP4xbbrkFZ555Ji655BK6/cUXX4wbb7wRl112Gf7gD/4Ahw8fxl/8xV+Yn8G++MUv4r777sPFF1+MU045Be12e/Yl0gsuuAAA8KEPfQjVahVve9vbsHbtWoyMjGDXrl0YGBjAm9/8Zm8f9u/fP7uPz3zmM3j88cfx+OOPz37+6le/GieddNJLGichXhGcEMI559wjjzziLr/8cnfKKae4Uqnk+vr63FlnneU+8YlPuNHR0dl6W7ZscVu2bJmz7Ze//GV3+umnu3K57F71qle5Xbt2uS996UsOgDtw4IBzzrnvf//77j/9p//kTj31VFcul92qVavcli1b3N133z27n927d7t3vvOdbmhoyJVKJbdu3Tr33ve+1/3oRz/6lW2/7bbbHADv32233fZyDZMQLytyTBBC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PcdTTz2F3/3d38WqVatQq9Xwpje9CQ899NDs58u5b78St0TZs2ePS5LE3Xrrre7HP/6xu/rqq11fX5978skni27agvjmN7/prr/+eveVr3zFAXB33XXXnM8/+9nPukaj4b7yla+4Rx991P32b/+2W7t2rZucnCymwQvg3/27f+duu+0290//9E/ukUcecRdffLE75ZRT3PT09Gyd5divu+++233jG99w+/fvd/v373cf//jHXZIk7p/+6Z+cc8uzT8fygx/8wP36r/+6e8Mb3uCuvvrq2fLl2K9PfvKT7owzznDPPPPM7N/o6Ojs58uxT845d+TIEXfqqae63//933f/9//+X3fgwAH3ne98x/3kJz+ZrbNc+/ZCLNlF6C1veYu74oor5pS95jWvcX/8x39cUItePPMXoTzP3fDwsPvsZz87W9Zut93AwID74he/WEALXxyjo6MOgNu3b59z7vjpl3POrVixwv3P//k/l32fpqam3MaNG93evXvdli1bZheh5dqvT37yk+6Nb3wj/Wy59sk55/7oj/7Ivf3tb/d+vpz79kIsyZ/jut0uHnroIWzbtm1O+bZt23D//fcX1KqXjwMHDmBkZGRO/8rlMrZs2bKs+jcxMQEAWLlyJYDjo19ZlmHPnj2YmZnBeeedt+z7dOWVV+Liiy/GBRdcMKd8Offr8ccfx7p167Bhwwb8zu/8Dp544gkAy7tPd999N84991z81m/9FtasWYOzzjoLt9566+zny7lvL8SSXIQOHTqELMswNDQ0p3xoaAgjIyMFterl47k+LOf+OefwsY99DG9/+9tx5plnAlje/Xr00UdRr9dRLpdxxRVX4K677sLrXve6Zd2nPXv24Ic//CF27dplPluu/dq0aRPuuOMOfPvb38att96KkZERbN68GYcPH162fQKAJ554AjfffDM2btyIb3/727jiiivwh3/4h7jjjjsALN/ztRCWXCqHY3kulcNzOOdM2XJmOffvqquuwo9+9CP8/d//vflsOfbr9NNPxyOPPILx8XF85StfweWXX459+/bNfr7c+nTw4EFcffXVuPfee1GpVLz1llu/Lrrootl/v/71r8d5552HV7/61di9ezfe+ta3Alh+fQKO5lE799xzsXPnTgDAWWedhcceeww333wzfu/3fm+23nLs2wuxJJ+EVq9ejSiKzAo/OjpqvgksR55T8yzX/n30ox/F3Xffjb/7u7+bkzVxOferVCrhN37jN3Duuedi165deOMb34jPfe5zy7ZPDz30EEZHR3HOOecgjmPEcYx9+/bhL//yLxHH8Wzbl1u/5tPX14fXv/71ePzxx5ftuQKAtWvX4nWve92cste+9rX42c9+BmB5X1svxJJchEqlEs455xzs3bt3TvnevXuxefPmglr18rFhwwYMDw/P6V+328W+ffuWdP+cc7jqqqvw1a9+Fffddx82bNgw5/Pl2i+Gcw6dTmfZ9un888/Ho48+ikceeWT279xzz8X73/9+PPLII3jVq161LPs1n06ng3/+53/G2rVrl+25AoC3ve1t5nWHf/3Xf8Wpp54K4Pi6tgxFKSJeiOck2l/60pfcj3/8Y3fNNde4vr4+99Of/rTopi2Iqakp9/DDD7uHH37YAXA33nije/jhh2cl5p/97GfdwMCA++pXv+oeffRR9773vW/Jyy0/8pGPuIGBAffd7353jkS22WzO1lmO/bruuuvc9773PXfgwAH3ox/9yH384x93YRi6e++91zm3PPvEOFYd59zy7Nd//a//1X33u991TzzxhHvggQfcu971LtdoNGbvC8uxT84dldHHcew+85nPuMcff9z9r//1v1ytVnN/8zd/M1tnufbthViyi5Bzzn3hC19wp556qiuVSu7ss8+elQIvB/7u7/7OATB/l19+uXPuqOTyk5/8pBseHnblctn95m/+pnv00UeLbfQLwPoDwN12222zdZZjv/7zf/7Ps/PspJNOcueff/7sAuTc8uwTY/4itBz79dy7MUmSuHXr1rlLL73UPfbYY7OfL8c+PcfXv/51d+aZZ7pyuexe85rXuFtuuWXO58u5b78K5RMSQghRGEsyJiSEEOLEQIuQEEKIwtAiJIQQojC0CAkhhCgMLUJCCCEKQ4uQEEKIwtAiJIQQojC0CAkhhCgMLUJCCCEKQ4uQEEKIwtAiJIQQojD+P9BWGP6yWGV7AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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o96zzz7rPfvssx4A7/777/eeffbZhsT8y1/+spfL5bxvf/vb3vPPP+995CMfmfFyy0996lNeLpfznnzyySkS2WKx2KgzG+e1bt0676mnnvL27dvnPffcc97dd9/tRaNR7/HHH/c8b3bOiXGiOs7zZue8/vf//t/ek08+6b388sve008/7X3gAx/wstls431hNs7J847L6OPxuPelL33Je+mll7x/+Id/8DKZjPf3f//3jTqzdW5vxYzdhDzP87761a96Cxcu9JLJpHfVVVc1pMCzgX/+53/2AJi/W2+91fO845LLL37xi15PT4+XSqW8973vfd7zzz8f7qDfAjYfAN6DDz7YqDMb5/U//+f/bKyzuXPnetddd11jA/K82TknxvRNaDbO6/VnYxKJhDdv3jzv5ptv9l544YXG67NxTq/z3e9+11uyZImXSqW8iy++2NuyZcuU12fz3N4M5RMSQggRGjMyJiSEEOLcQJuQEEKI0NAmJIQQIjS0CQkhhAgNbUJCCCFCQ5uQEEKI0NAmJIQQIjS0CQkhhAgNbUJCCCFCQ5uQEEKI0NAmJIQQIjT+P+7/kRGU2pFnAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABpxklEQVR4nO2dfZBlZX3nv+e+v9/bL9NvMAwjDqggimBGBs2MhcwWi2xcrBhFXXS3jDhqYE2WBKmNY8rMGGJRmEKxYBVhs9RUpQQX16iMRRw2QVaCUBBICIQBhmF6evrt3tt938699+wfE3qm+/d9oC8MOd0z309VF8yvn3PO85zznPv0ub/v+f68IAgCCCGEECEQCbsDQgghTly0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAnxrzz22GP49Kc/jfXr1yOVSiGXy+Fd73oXrr/+ekxPTy+027JlC7Zs2RJeRx2ceuqp8DzP/Fx55ZVhd00IJ7GwOyDESuDWW2/Ftm3bcMYZZ+C//bf/hre97W3wfR9///d/j+985zv45S9/ibvvvjvsbr4qF1xwAb7xjW8sig0PD4fUGyFeHS1C4oTnl7/8JT73uc/hoosuwg9/+EMkk8mF31100UX4/d//ffz0pz8NsYfLp1Qq4T3veU/Y3RBi2ejrOHHCs2PHDnieh1tuuWXRAvQyiUQC/+E//IdX3MdXv/pVbNy4Ef39/SgUCnjXu96F7373u1jqD3zfffdhy5YtGBgYQDqdximnnIIPf/jDqNVqC21uvvlmvOMd70Aul0M+n8db3vIWfPnLXz42gxVihaEnIXFC0+l0cN999+Hcc8/F2rVrX/N+nnvuOXz2s5/FKaecAgB48MEH8cUvfhH79+/HH//xHy+0ueSSS/C+970P3/ve91AqlbB//3789Kc/RavVQiaTwa5du7Bt2zZ88YtfxDe+8Q1EIhE888wzePLJJ5fVj/vvvx/5fB6NRgMbNmzAf/kv/wVXX301otHoax6bEG8kWoTECc3k5CRqtRrWr1//uvZz2223Lfx/t9vFli1bEAQBvvnNb+K///f/Ds/z8PDDD6PRaODP//zP8Y53vGOh/eWXX77w/3/3d3+HUqmEv/iLv1iIXXjhhcvqwyWXXILzzjsPp512GmZmZvBXf/VX+IM/+AM8+uij+J//83++rvEJ8UahRUiIY8B9992HHTt24KGHHkKlUln0u4mJCQwPD+Od73wnEokEfvd3fxfbtm3D+973PrzpTW9a1PY3fuM3cNNNN+FjH/sYPvrRj+KCCy7A4ODgsvrwrW99a9G/f+u3fgt9fX246aab8KUvfQnnnHPO6xukEG8AygmJE5rBwUFkMhns3bv3Ne/jV7/6FbZu3QrgsMru7/7u7/DQQw/huuuuAwDU63UAwGmnnYaf//znGBoawuc//3mcdtppOO200/DNb35zYV+f/OQn8b3vfQ/PP/88PvzhD2NoaAgbN27E7t27X1PfPvGJTwA4/PWgECsRLULihCYajeLCCy/Eww8/jBdffPE17WPXrl2Ix+P4P//n/+AjH/kINm3ahPPOO4+2fd/73ocf/ehHKJfLePDBB3H++efj6quvxq5duxbafPrTn8YDDzyAcrmMH//4xwiCAB/84Afx/PPP99y3l4URkYhudbEy0cwUJzzXXnstgiDAZz7zGbRaLfN73/fxox/9yLm953mIxWKLkv/1ev0V8zDRaBQbN25c+Art17/+tWmTzWZx8cUX47rrrkOr1cITTzzRy7AAAHfccQcASLYtVizKCYkTnvPPPx8333wztm3bhnPPPRef+9zncOaZZ8L3fTzyyCO45ZZbcNZZZ+HSSy+l219yySW44YYbcPnll+N3f/d3MTU1hW984xtG7v2d73wH9913Hy655BKccsopaDQa+N73vgcA+MAHPgAA+MxnPoN0Oo0LLrgAo6OjGB8fx86dO1EsFvHud7/bOYY777wTd911Fy655BKsW7cOs7Oz+Ku/+ivs2rULn/rUpxYJIYRYUQRCiCAIguDRRx8NrrjiiuCUU04JEolEkM1mg3POOSf44z/+42BiYmKh3ebNm4PNmzcv2vZ73/tecMYZZwTJZDJ405veFOzcuTP47ne/GwAI9u7dGwRBEPzyl78M/uN//I/BunXrgmQyGQwMDASbN28O7rnnnoX93H777cH73//+YHh4OEgkEsHY2FjwkY98JHjsscdese+//OUvgwsvvDAYGRkJ4vF4kMlkgne/+93Bt7/97aDT6RyzcyTEscYLgiVv0wkhhBD/RignJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAiNN+xl1W9/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IZ/Po1qtYu3atdi3bx/10lqtVCqV425cx+OYgONzXMfjmACNayURBAGq1SrGxsYQIQUyj2bFfR0XiUQWVs6XK3kWCoVVc/J74Xgc1/E4JuD4HNfxOCZA41opFItWYs6QMEEIIURoaBESQggRGit6EUomk/jKV75C3/RfzRyP4zoexwQcn+M6HscEaFyrlRUnTBBCCHHisKKfhIQQQhzfaBESQggRGlqEhBBChIYWISGEEKGhRUgIIURorOhF6Nvf/jbWr1+PVCqFc889F//3//7fsLu0bO6//35ceumlGBsbg+d5+OEPf7jo90EQYPv27RgbG0M6ncaWLVvwxBNPhNPZZbJz5068+93vRj6fx9DQED70oQ/hqaeeWtRmNY7r5ptvxtlnn73wRvr555+Pn/zkJwu/X41jWsrOnTvheR6uvvrqhdhqHNf27dvhed6in5GRkYXfr8Yxvcz+/fvxiU98AgMDA8hkMnjnO9+Jhx9+eOH3q3lsr0iwQtm1a1cQj8eDW2+9NXjyySeDq666Kshms8Hzzz8fdteWxV//9V8H1113XfCDH/wgABDcfffdi37/9a9/Pcjn88EPfvCD4PHHHw9+53d+JxgdHQ0qlUo4HV4G/+7f/bvgtttuC/7hH/4hePTRR4NLLrkkOOWUU4K5ubmFNqtxXPfcc0/w4x//OHjqqaeCp556Kvjyl78cxOPx4B/+4R+CIFidYzqaX/3qV8Gpp54anH322cFVV121EF+N4/rKV74SnHnmmcGBAwcWfiYmJhZ+vxrHFARBMD09Haxbty741Kc+Ffy///f/gr179wY///nPg2eeeWahzWod26uxYheh3/iN3wiuvPLKRbG3vOUtwR/90R+F1KPXztJFqNvtBiMjI8HXv/71hVij0QiKxWLwne98J4QevjYmJiYCAMGePXuCIDh+xhUEQdDX1xf8j//xP1b9mKrVarBhw4Zg9+7dwebNmxcWodU6rq985SvBO97xDvq71TqmIAiCP/zDPwze+973On+/msf2aqzIr+NarRYefvhhbN26dVF869ateOCBB0Lq1bFj7969GB8fXzS+ZDKJzZs3r6rxlctlAEB/fz+A42NcnU4Hu3btwvz8PM4///xVP6bPf/7zuOSSS/CBD3xgUXw1j+vpp5/G2NgY1q9fj49+9KN49tlnAazuMd1zzz0477zz8Nu//dsYGhrCOeecg1tvvXXh96t5bK/GilyEJicn0el0MDw8vCg+PDyM8fHxkHp17Hh5DKt5fEEQ4Etf+hLe+9734qyzzgKwusf1+OOPI5fLIZlM4sorr8Tdd9+Nt73tbat6TLt27cKvf/1r7Ny50/xutY5r48aNuOOOO/Czn/0Mt956K8bHx7Fp0yZMTU2t2jEBwLPPPoubb74ZGzZswM9+9jNceeWV+L3f+z3ccccdAFbv9VoOK66Uw9G8XMrhZYIgMLHVzGoe3xe+8AU89thj+Nu//Vvzu9U4rjPOOAOPPvooZmdn8YMf/ABXXHEF9uzZs/D71Tamffv24aqrrsK9996LVCrlbLfaxnXxxRcv/P/b3/52nH/++TjttNNw++234z3veQ+A1Tcm4HAdtfPOOw87duwAAJxzzjl44okncPPNN+M//af/tNBuNY7t1ViRT0KDg4OIRqNmhZ+YmDB/CaxGXlbzrNbxffGLX8Q999yDv/mbv1lUNXE1jyuRSODNb34zzjvvPOzcuRPveMc78M1vfnPVjunhhx/GxMQEzj33XMRiMcRiMezZswd/8Rd/gVgsttD31TaupWSzWbz97W/H008/vWqvFQCMjo7ibW9726LYW9/6VrzwwgsAVve99WqsyEUokUjg3HPPxe7duxfFd+/ejU2bNoXUq2PH+vXrMTIysmh8rVYLe/bsWdHjC4IAX/jCF3DXXXfhvvvuw/r16xf9frWOixEEAZrN5qod04UXXojHH38cjz766MLPeeedh49//ON49NFH8aY3vWlVjmspzWYT//iP/4jR0dFVe60A4IILLjCvO/zzP/8z1q1bB+D4urcMYSkiXo2XJdrf/e53gyeffDK4+uqrg2w2Gzz33HNhd21ZVKvV4JFHHgkeeeSRAEBwww03BI888siCxPzrX/96UCwWg7vuuit4/PHHg4997GMrXm75uc99LigWi8EvfvGLRRLZWq220GY1juvaa68N7r///mDv3r3BY489Fnz5y18OIpFIcO+99wZBsDrHxDhaHRcEq3Ncv//7vx/84he/CJ599tngwQcfDD74wQ8G+Xx+4XNhNY4pCA7L6GOxWPCnf/qnwdNPPx38r//1v4JMJhP85V/+5UKb1Tq2V2PFLkJBEATf+ta3gnXr1gWJRCJ417vetSAFXg38zd/8TQDA/FxxxRVBEByWXH7lK18JRkZGgmQyGfzmb/5m8Pjjj4fb6VeBjQdAcNttty20WY3j+s//+T8vzLM1a9YEF1544cICFASrc0yMpYvQahzXy+/GxOPxYGxsLLjsssuCJ554YuH3q3FML/OjH/0oOOuss4JkMhm85S1vCW655ZZFv1/NY3slVE9ICCFEaKzInJAQQogTAy1CQgghQkOLkBBCiNDQIiSEECI0tAgJIYQIDS1CQgghQkOLkBBCiNDQIiSEECI0tAgJIYQIDS1CQgghQkOLkBBCiND4/314ZuiK86BpAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABuuElEQVR4nO2de5Ad1X3nv/24t+9z7rw0MxJIIGOBeRjMw1GQ7UguQFssZuPgihPjOITddcDCDqx3l0RQa4sUkRySonDKjlywPMTGlP4xOHgdY+TCiE0wa4JhIeDI2JJBSBqN5nEfc9/dffYPmUEzv+8xGh7pGen3qZoq6cw53eecPt3n3vl9+/tzjDEGiqIoipIAbtIdUBRFUY5fdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSlF/x/PPP4+qrr8bKlSuRyWRQKBRw3nnn4bbbbsPk5ORMvXXr1mHdunXJdZTw+OOPw3Ec68+1116bdBcVheIn3QFFWQjcdddd2LBhA0477TT89//+33HGGWeg2+3in//5n/GNb3wDP/rRj/DQQw8l3U0r5513Hn70ox+J8q1bt+L+++/H7/zO7yTQK0V5cxz1jlOOd370ox/hIx/5CC655BJ8+9vfRhAEs37f6XTwyCOP4D/8h/8AADPfgh5//PF/457OD2MM3vve9yKKIuzevRuuq3/4UBYeuiqV457NmzfDcRzceeedYgMCgHQ6PbMB2bjllluwevVq9Pf3o6enB+eddx7uvvtuzP2M99hjj2HdunUYGBhANpvFihUr8IlPfAKNRmOmztatW3HOOeegUCigWCzife97H2666aZ5j+uHP/whdu/ejauvvlo3IGXBon+OU45roijCY489hvPPPx/Lly9/y8f55S9/iWuuuQYrVqwAADz11FP4whe+gH379uFLX/rSTJ3LLrsMH/nIR3DPPfegt7cX+/btwyOPPIJOp4NcLoft27djw4YN+MIXvoC//uu/huu6+PnPf46XXnpp3n26++674bourr766rc8LkV5t9FNSDmuGR8fR6PRwMqVK9/Wce69996Zf8dxjHXr1sEYg69+9av4H//jf8BxHDzzzDNotVr4q7/6K5xzzjkz9a+88sqZf//TP/0Tent78Td/8zczZRdd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//zn8eCDD+Kxxx7DypUrZ/1+sY6LYYxBu91etGO66KKL8MILL+C5556b+bngggvw6U9/Gs899xze8573LMpxzaXdbuOnP/0pli5dumivFQB86EMfEq87/OxnP8NJJ50E4Ni6twRJKSLejNcl2nfffbd56aWXzA033GDy+bz55S9/mXTXjoparWaeffZZ8+yzzxoA5vbbbzfPPvvsjMT8K1/5iimVSubBBx80L7zwgvnUpz614OWWn/vc50ypVDKPP/74LIlso9GYqbMYx7Vx40bzxBNPmD179pjnn3/e3HTTTcZ1XfPoo48aYxbnmBhHquOMWZzj+q//9b+axx9/3Ozevds89dRT5mMf+5gpFoszz4XFOCZjDsvofd83f/EXf2Fefvll881vftPkcjnzd3/3dzN1FuvY3owFuwkZY8zXv/51c9JJJ5l0Om3OO++8GSnwYuCHP/yhASB+rrrqKmPMYcnll7/8ZTMyMmKCIDC/9Vu/ZV544YVkO/0msPEAMPfee+9MncU4rv/4H//jzDpbsmSJueiii2Y2IGMW55gYczehxTiu19+NSaVSZtmyZeaKK64wL7744szvF+OYXuc73/mOOeuss0wQBOZ973ufufPOO2f9fjGP7deh+YQURVGUxFiQMSFFURTl+EA3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREuP/AwtZE6BHuKwmAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABrxElEQVR4nO2de5AdZ3nmnz597pc5MxpJMxosCTnIBtsYsA2KBURmwd7yGm9YUxAwyRq2imALgx2ycWK8BYIiEnFSjrMFMWUvF7FZl1K7XGKWAFbKQd6scWIMKozJGhMrtmRrNNLczpk51+7z7R+KB828z2fP2HJ6Rnp+VVMlvacv39f9dX+nz/v08wbOOQchhBAiAVJJN0AIIcTpiyYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIf6Fn/zkJ/jABz6ATZs2IZ/Po1wu44ILLsCtt96KiYmJueUuueQSXHLJJck11EOtVsMtt9yCs846C8ViES972cvwrne9C48++mjSTRPCSzrpBgixHLjrrruwfft2nH322fi93/s9nHPOOeh2u/jhD3+IL3zhC/jBD36Ab3zjG0k38zm58sor8cMf/hA7duzARRddhEOHDuHTn/40Lr74YjzyyCPYuHFj0k0UwqBJSJz2/OAHP8B1112HSy+9FN/85jeRy+XmPrv00kvxu7/7u/jud7+bYAufn1/84he4//778V/+y3/B7/3e783FX/GKV2Dr1q34+te/jt/5nd9JsIVCcPRznDjt2blzJ4IgwJ133jlvAnqWbDaLf//v//1zbuNTn/oUtmzZglWrVqGvrw8XXHABvvjFL2KhP/B9992HSy65BIODgygUCtiwYQPe+c53otFozC1zxx134DWveQ3K5TIqlQpe+cpX4uMf//hz7j+TyQAAqtXqvHh/fz8AIJ/PP+f6QiSFnoTEaU0cx7jvvvtw4YUXYv369S94O//8z/+MD33oQ9iwYQMA4MEHH8RHPvIRPP300/jEJz4xt8wVV1yBN7/5zfjSl76E/v5+PP300/jud7+LTqeDYrGIPXv2YPv27fjIRz6CP/mTP0EqlcIvfvEL/OxnP3vO/W/cuBG//uu/jj/90z/FhRdeiNe//vU4dOgQPvrRj2LDhg14z3ve84L7JsRLihPiNGZ0dNQBcO95z3sWvc62bdvctm3bvJ/Hcey63a779Kc/7QYHB12v13POOfe//tf/cgDc/v37vetef/31rr+/f9FtOZFOp+M++MEPOgBzf+eff747cODAC9qeEP8a6Oc4IU4C9913H972trehWq0iDENkMhl84hOfwPj4OMbGxgAAr33ta5HNZvHbv/3b2L17N5544gmznTe84Q2YmprCe9/7XvzVX/0Vjh07tug2XHfddfja176GP/3TP8W+ffvwl3/5l8hms/g3/+bf4MknnzxpfRXipJL0LChEkkRR5IrFotuyZcui11n4JPT3f//3LgxD99a3vtX95V/+pfu///f/uoceesjdcsstDsC8J5H777/fvf3tb3elUskBcGeeeaa7/fbb523/S1/6krv44otdGIYuCAL3hje8wd17773P2abvfOc7DoD7n//zf86LT05Oumq16t7//vcvun9C/GuiJyFxWhOGId761rfi4YcfxqFDh17QNvbs2YNMJoP//b//N9797ndj69atuOiii+iyb37zm/Gtb30L09PTePDBB3HxxRfjxhtvxJ49e+aW+cAHPoAHHngA09PT+Pa3vw3nHN7+9rc/59PM/v37AQCvf/3r58X7+/vxile8Aj/96U9fUN+EeKnRJCROe26++WY45/DBD34QnU7HfN7tdvGtb33Lu34QBEin0wjDcC7WbDbx3//7f/euE4YhtmzZgs9//vMAgB/96EdmmVKphMsvvxy33HILOp3Oc750OjIyAuC4IOJExsfH8fOf/xxnnHGGd10hkkTqOHHac/HFF+OOO+7A9u3bceGFF+K6667Dueeei263ix//+Me48847cd555+HKK6+k619xxRW47bbbcPXVV+O3f/u3MT4+jj/5kz8xcu8vfOELuO+++3DFFVdgw4YNaLVa+NKXvgQAeNvb3gYA+OAHP4hCoYA3vvGNWLduHUZHR7Fr1y5Uq1XzlHMiV111FT7xiU/guuuuw6FDh3DBBRfg8OHD+OM//mM0Gg3ccMMNJ+loCXGSSfr3QCGWC/v373fXXHON27Bhg8tms65UKrnXve517hOf+IQbGxubW46p4770pS+5s88+2+VyOXfmmWe6Xbt2uS9+8YvzckI/+MEP3H/4D//Bbdy40eVyOTc4OOi2bdvm7rnnnrnt7N69273lLW9xQ0NDLpvNupGREffu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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABoIUlEQVR4nO2de5RdZZnmn33u51Sdc+qauoQkBAwoVxXsSLwkLiCzGHDGwaXdQju0s5aC8QLjzNAiazT22IlN97CwlzYuaIE4PUz+8dI4tkhcNGEUURplgWBHNAGSkEqlbudU1bmf880faYpUvc8ndQj0rkqe31q1IO/Zl+/b+9v7O/u8z37ewDnnIIQQQoRAJOwGCCGEOHnRJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNDQJCTEv/Dkk0/iIx/5CNauXYtUKoXOzk689a1vxS233IKJiYm55TZt2oRNmzaF11AP09PT+PSnP42VK1cimUzijDPOwC233IJmsxl204TwEgu7AUIsBe68805s2bIFZ555Jv7bf/tvOOuss1Cv1/FP//RP+PrXv46f/vSn+M53vhN2M700Gg1ceuml+M1vfoP/8T/+B8444wzcf//9+OxnP4sDBw7gr//6r8NuohCUQN5x4mTnpz/9Kd71rnfh0ksvxXe/+10kk8l5n9dqNdx///34d//u3wHA3FPQQw899K/cUj87d+7Ehz70IXzrW9/ClVdeORe/9tpr8bd/+7d45plncOaZZ4bYQiE4+jlOnPRs27YNQRDgjjvuMBMQACQSibkJyMcXv/hFrF+/Hj09PcjlcnjrW9+Kb3zjG1j4He/BBx/Epk2b0Nvbi3Q6jdWrV+P9738/SqXS3DK33347zj//fHR2diKbzeKNb3wjPve5z/3e/f/kJz9BEAS47LLL5sWvuOIKtFqtJf0UJ05u9HOcOKlpNpt48MEHccEFF2DVqlWvejvPPfccrr32WqxevRoA8Oijj+JTn/oUDh48iM9//vNzy1x++eV417vehbvuugtdXV04ePAg7r//ftRqNWQyGezcuRNbtmzBpz71KfzVX/0VIpEIfvvb3+KZZ575vfuv1WqIRCKIx+Pz4i9Nqk8++eSr7psQryeahMRJzdjYGEqlEtauXXtc27n77rvn/r/VamHTpk1wzuErX/kK/vt//+8IggCPP/44KpUK/vIv/xLnn3/+3PJXXXXV3P//5Cc/QVdX17wczsUXX/yK+z/rrLPQbDbx6KOP4p3vfOdc/Mc//jEAYHx8/Lj6J8TrhX6OE+I14MEHH8Qll1yCfD6PaDSKeDyOz3/+8xgfH8fo6CgA4M1vfjMSiQQ+9rGPYceOHdi7d6/Zzh/8wR9gamoKH/rQh/D3f//3GBsbW9T+r776avT09OBjH/sYfvazn2Fqagr/5//8n7nJLBLRpS6WJhqZ4qSmr68PmUwG+/bte9Xb+PnPf47NmzcDOKqy+8lPfoLHHnsMN998MwCgXC4DAE4//XT86Ec/wooVK/CJT3wCp59+Ok4//XR85StfmdvWhz/8Ydx11114/vnn8f73vx8rVqzA+vXrsWvXrlfsx/333w8AePvb347u7m586lOfwq233goAWLly5avunxCvJ5qExElNNBrFxRdfjMcffxwHDhx4VdvYuXMn4vE4/u///b/44Ac/iA0bNuDCCy+ky77rXe/C9773PRQKBTz66KO46KKLcMMNN2Dnzp1zy3zkIx/BI488gkKhgO9///twzuGKK67A888//3vb8ba3vQ3PPPMM9u3bh1/96ld48cUX8aY3vQkA8O53v/tV9U2I1xtNQuKk56abboJzDh/96EdRq9XM5/V6Hd/73ve86wdBgFgshmg0Ohcrl8v4X//rf3nXiUajWL9+Pb72ta8BAH7xi1+YZTo6OnDZZZfh5ptvRq1Ww9NPP72o/px66qk4++yzEY/H8T//5//E8PAwPvCBDyxqXSH+tZEwQZz0XHTRRbj99tuxZcsWXHDBBfj4xz+Os88+G/V6Hb/85S9xxx134JxzzsF73/teuv7ll1+OW2+9FVdddRU+9rGPYXx8HH/1V39l5N5f//rX8eCDD+Lyyy/H6tWrUalUcNdddwEALrnkEgDARz/6UaTTabzjHe/A0NAQRkZGsH37duTzebztbW/7vf24+eabce6552JoaAgvvPAC7rrrLvzsZz/D97//faTT6dfgSAnxOuCEEM4555544gl3zTXXuNWrV7tEIuE6OjrcW97yFvf5z3/ejY6Ozi23ceNGt3Hjxnnr3nXXXe7MM890yWTSnXbaaW779u3uG9/4hgPg9u3b55xz7qc//an7D//hP7g1a9a4ZDLpent73caNG9199903t50dO3a497znPW5gYMAlEgk3PDzsPvjBD7onn3zyFdv/8Y9/fK7tfX197v3vf/+i1hMiTOSYIIQQIjSUExJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExuv2surf/M3f4C//8i9x6NAhnH322bjtttvwrne96xXXa7VaePHFF5HNZhEEwevVPCGEEK8TzjlMT09jeHj4lc1zX4+Xj3bu3Oni8bi788473TPPPOOuv/5619HR4Z5//vlXXHf//v0OgP70pz/96W+Z/+3fv/8V7/mvy8uq69evx1vf+lbcfvvtc7E3velNeN/73oft27fPW7ZaraJarc79u1AoYPXq1ejvzyISeflJKJ1O0X0dPjxhYgsLex1d38Z8ZOL8AbG7p9fEUilrh1IsTNH1p6ZsvFGvm1gszi1WUmnbrlHS/1wuQ9fnD74NumScHINyqWy3SI61j0a5ZGKDnmfxKImxPa06xecObbfwq+KMiY1OTNO16+S8lMqeY0X6kM/ZczgwOETXz+XzJlYsFEzswIFDdP1S3Z6XOBkCuVyOrp/P9JlYoTBLl83l7DWQTNpbSLFYpOtXq7at5FDPOY8vhF3H7FwVi3x9Nq6HhwfostFOW2W3Qs51w/ODTUfCrl9tNk3syIsjfAMFe72kY7b/jQY5gABKJTteM5nF//gVI/vyHdeF9xbnHJrNJqamppAn49u/5mtArVbD448/js9+9rPz4ps3b8Yjjzxilt++fTu++MUvmngkEsybhHyPdOwnOxY7dluvhG9fxxpUvkQsZmPRKF+ftYHHPPsn8fb6yrbLl2VtWGz7fURIWz2Hig5MFov7NkD6yo4faxPgGVeePbFNsOPiGxeLHUP+tpIY2ZXvXLFx3c41EI3aSch/DbBxZZfz/RS/2DHo+yWfbdfXVnpcyCD0XQJRcl7ZsoFvA4u8tn3Hio6LNlIc7RxX39WxmP295sKEsbExNJtNDAzM/3YxMDCAkRE74990000oFApzf/v373+tmySEEGKJ8roJExbOgM45Oismk0njNgwAXV3d3m8ox8J+oknAPp7G6ZIAyM9JsRg/LKVZ+3PO4RFb+bJcso/RANDTa38OSXV3m1ilUqHrM/J5+7uLzzGZ9Svr+M+cAXnEnyLLJcnPkQDoiSmTnxNnG/wnrqBEfqYkyz1/iJetjtVtA8oJO/58vybWyC8c7GdeABgasj83sJ+I9r/wIl1/5BCPL5aODvbzs12uu5Of63zexmMx/iv91NQRE6uRg+U5rWA//+bIT5e+Y512dhSwX6P4FehpUcB/zirP2vh4xf4clc7ya6BnIGv3RX864/vPkPOaS9l7iO+nT9926b4y9j7CxrDvvCzEud83Bubzmj8J9fX1IRqNmqee0dFR83QkhBDi5OY1n4QSiQQuuOACU454165d2LBhw2u9OyGEEMuY1+XnuM985jP48Ic/jAsvvBAXXXQR7rjjDrzwwgu47rrrXo/dCSGEWKa8LpPQH/7hH2J8fBx/9md/hkOHDuGcc87BP/zDP2DNmjWvx+6EEEIsU143YcKWLVuwZcuW12vzQgghTgBet0noeKnNTs97p8CnWEsQscYsUVbV6/blP8Cj9iBKEQDo6+s3MdYunzquQeQik5NWcVcu8bb29NoXBVn7/S/q2djqFVwsMjtOVGdELdNBXugDACJOw+gI2WbNo7Yh5zBDJHddPT109XjSnpdYa9LE6mQ/AB9XLOaDvYRcY29lgr+syqiTlxcBYN0pwybGXiCdGrXKNgCYnLQv7Caj/LgG03ZsNYkKK0OUkAC/Bti4anj6Ok0PoT0x/Z5reIrsa5yNSwD5PnteTh+wLxw3GvYFVACYPGyPdyxqj0vcJ+UjAsVYp+2rT7HGb22+F9ktBXIOmBqX0Wo5lD0vdy9EBqZCCCFCQ5OQEEKI0NAkJIQQIjQ0CQkhhAiNJStMKJfK8wz0mNgAAAKSFO3ILD55x1ygWVIZAH73u+dpfDH7B7gNBhMx+Nra0dFpYgXi2F3yCCNYYn1kgjv4Bk2bVIwSe5URj2N4Knt8Q4sdAiYiGJsY5euTZPV+JvjwiA3YOWRWPgBQJAlc1n42VgE+BrqJ4KLfIyLJkWR1H/l6mUzwBPqRcXsMHaw7OwB0sS7ESdBzDa3osVY2ztn2J9g2AZTJdlMk2Z4k+wGAFBFGTHhsbwpjdrzEiG2Qj/Fxu90MGVf1ukeZQI4LY7FWOoD/3sBOF9uu105pgU9Uq9XCxITPcXs+ehISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFlhQr1Rn1dJ0p/stzGWPHOeDHTZI3hgsDZwdwbfFha/LwarR8PyhL43+1livewp+tGZtYndKKsRNMkT2PWKTRbXyDkoed6M7yIdy5CYL9F6vDARSYfnbXMmbmFiA98YZExO2OPqcw2JNO2r9T09vJQ3o526MY4mq+1yPnFPlZTtrpRJiXXP+sOkvLiLWcGM7239ga4uGxuyjhMA8Mzefybbte3Peep3MdcPNl4zHheCEll/YsK6O/jOFXNH8F0vmYx1h2B1nny1ixZu1zlej4qhJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcel0Zp5tT5aotQCuIpqiNioeKxyieOtfsYIum0imTKxIbGtozRRwFRKL+ZhdpMVPO3VvfHuvBLYPjqizuvt53Zkisf0pFW3722krI+GJ10iM2jl5VJdM8bbQmuT3wdRxPoXn8RIlNWqKTXtmZxJ8XEZ7rZIuiHnq8ZB6Qg06LunqKLEmkIVTRJkFAI4UqkqS/kc9t7aAxBpkXAJAgqjT0n32uKRS9r4AAB3kENZI+5nFFAAMDtrz0tPTZ2ITE2N0faaEa6f2EMN3v1qo5GtDHKcnISGEEOGhSUgIIURoaBISQggRGpqEhBBChMaSFSZ0dnYiGn15jqxUKnS5xdqr5DzWGMWCrRniExakM1ETY1YqXmECic2y9tO1gb4+a63BEuC+5CE7LqkVXPBRI8KEcoMkpclyAFCoEBEGOQJdnqQsO1t1luynawO5uN3CFKvl4knIMhGCzzaH0dNr7WVYPSgAmJ2dMbFpYo+SzvDednTZBPZU47CJ1TwJ9OxaK8SZmuLX2xgRJmRIsp7VngKAKomlibAgHeFtndp7xMTidXusUh4RSbk6aWLj5B4A8CR+jGTcU54kfC+xwmEihnSej4tiyR6tYtG21Wels2bNqSbmuzeNjtrx0o6QauGhcg7w7MqgJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcTMzM/Nse3x2Exyr4GAqMgBIE8XYgQNWKQIA8Qwv4LZYWB/a6deibWPaKPR2uEUKigFAhqhgkrat3TmurisdttutF8g2Pb5B7LhkmO2OZ31muxNLk+EeMCMXriJiBc0A3tbOTqt4YoUCASCRTJoYU+IlEtykqFq1Srbp4qyJRZJ8/+nAqusiCdsmAMjl7PfWzm6r4pqJcHVdsWqVXBkrWEMu6pNWkUJx5BKKZvitreE5hxQ2uMi5rntUk0x56YiadNpjuzNG7MdWrhwwseHhlXR9pihuNHzqNtvYgkc1yFhYQK/Vct7rZSF6EhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGgsWWFCo16fJ0zo6+uny7EE8JHRURPz2U1kczYpO+ZLyNE85eKFBQWSaOzLW2sPX7a+WLSJvp4em2z2CRhy+S4TG6lbGxQAKI7bNsTTtq+NJk/s05wuERZM0bWBqZrdQB8RkXAzJtBDGCM1chpNnjxtxw4pTs4hq/ETj3NhQTRq7aDYOUynuW3P88/tMbGJqhXR9Pd5kvUNKyIJqtyLJgN7XKIzNlaucCsZLs6xyzXJ+QcAx+o8kfXbqelFhtW/LGtjQdlut1CeousXx+x9JJ9n9wt+D8mT66WDiFhmq8wMCfA4alHYccmTce273y1cv9VyACRMEEIIscTRJCSEECI0NAkJIYQIDU1CQgghQmPJChO6urvn1RNib5UfxcaZC0LMk1RmdVvinkRhL6kRwxKgYyQhCdi3igEgm7X1RSYmeFsbnj4sxPemMhM2lAKPuwI5BPWS7dcBEvPB6s6gl2eFS0XbrgJRG9QdP1dpUs8mIPWQfGKDwaFhE/M5HjSbTRNbMTBkYuWSdTEAgGbLChOqFdvWkUMH6frJTjuGejK2/7m0xwUhYW8DpSO/pctmiA1A/1CXifnGYD1m188mbfsjnmH5hrXWHaBRq5nYwef30vVjpM6U77rq7rWipXS+z8SO7D9E1ye6AqBE3Fx81zW5NCZG7L6KRPDkg90bASBB2pAmIoQuT02smZn54pZmqwXuO2PRk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUKj7Uno4Ycfxnvf+14MDw8jCAJ897vfnfe5cw5bt27F8PAw0uk0Nm3ahKeffvq1aq8QQogTiLbVcbOzszj//PPxkY98BO9///vN57fccgtuvfVW3HPPPTjjjDPwpS99CZdeein27NmDrEddxMh3dSMWe1k1NHbEWvEAQAdRa5SIAoXZ2wDA5IS1N0l4nHiY4ofZq7C6N774NKv5UV+82mViwlqulDz1hJgSzKe3Y+4c8Q4S9NirMMFPnXn5ZHhb+9JWxZN2drhWxrk9TFfXChNrpuz+Wc0VgKsxa0SFBXB1HFPC+ZR4s7MzJsasfHxEk3bZjoRVnAUt7uNSnRwxsR6PQrRVtse79oI9hx0ez5gqqelUmSG2QTV+a5opTtk2Nezx9wnOWJ0mX62xGaKczSS7Tay328YAoH6QWD+R5VafYmsEAQA7glOHSU0zcr8DuBlQQGyXAG6zFZDWVh2vPxZZcG90jts+MdqehC677DJcdtll9DPnHG677TbcfPPNuPLKKwEAO3bswMDAAO69915ce+217e5OCCHECcxrmhPat28fRkZGsHnz5rlYMpnExo0b8cgjj9B1qtUqisXivD8hhBAnB6/pJDQycvSxfmBg/uPlwMDA3GcL2b59O/L5/NzfqlWrXssmCSGEWMK8Luq4IJhv7++cM7GXuOmmm1AoFOb+9u/f/3o0SQghxBLkNbXtGRwcBHD0iWho6GXbktHRUfN09BLJZBJJViNjZnqebQ8TIABAs2nTdyypzhKSAE8We3LtmCJ2PH3WxQM9PdbeBwCmp+1PjQWyzf48t9bo7Okh27SJ9Q5PzY8UsR0aGR+nyzIRRYaIBeKOJzpZ7aQ4zet7kqqkJFJAUrW+ekK1SZvAjRJxSn8/P1etqB2TqZRN9gNAPG6/y82WbI2XvGcMH5m0BifZtLWMiXrGsIvZJHAmZdtfJ2MFAKbHbHxtvydZTsQhLIEeI3ZUADCbs+sfPGytaBoe25/KPvsllemAUuT4AUAHsTjy1R4qF+zYjBAhC6tJBgBlch3GiFygs+U5Vk27L1oPia7NbcJ8lJglFhE8sBgAZBb2dfG6hNf2SWjt2rUYHBzErl275mK1Wg27d+/Ghg0bXstdCSGEOAFo+0loZmYGv/3ty+aG+/btwxNPPIGenh6sXr0aN9xwA7Zt24Z169Zh3bp12LZtGzKZDK666qrXtOFCCCGWP21PQv/0T/+E97znPXP//sxnPgMAuOaaa3DPPffgxhtvRLlcxpYtWzA5OYn169fjgQceaOsdISGEECcHbU9CmzZt+r0vIgVBgK1bt2Lr1q3H0y4hhBAnAUu2ntChQy8icoyi7tTTTqfLsbfN2dvSMzN2OQCIk+ThrMexgJRSQalhd+Z75ssxd4W8Xc5X3yQo2wRqD0lWT/r2z94W7yMNAFAnicoSaVfgEXF0kaRojuRJy74NkDe7x0iimJk4AEBu2Dom1HN2m9Ec73++w8ZrZftmPgDUyBgASYC3SI0jAIiVreCkmU6Y2NQR/g5dvGTHRYuoa2pTXJjQJHWmphItumwkZvvgSE2oSplfQ+Ux6yQRkJJUaVL3B+BuIo6l5kndIgCYnbHnMEb6BIBaDuw/bEUkceK6AnARQZqoKFpVfm9ijg3s5uYTIHQSwUTDIwSKxu2ybMmK5z3O1IJ7W7PVAjzikoXIwFQIIURoaBISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFl1XKPewLF2cxPjY3Q5ZsfDFDRjfHV0MHuaPFdM0TpBRK1SqXBVCNPrdHdbLd3MJK/ZMU2UKWybcU8tGGYZgjhXTKWJYqhBDFp8apsaOS5looLyiKCod1KCqo34BuKkXV2ZDhPr7fac65S12KmleY2fZp3UEyoTjyIursNQr1XyMQ5XDtL4yqFBE2tUrGKrVveolciweOGQtdIBgG5ih9NJauxMjXLFWIXUI8oS1ehCtdXc+uR67+7rN7FqlY/rGrEuSnjeYewibZiZXnz9rji7XxA17miRW2cxdR1z5HKe+mWTTMnmsfTq6bfnsEos0QKv4m3hdrm6kqEnISGEEKGhSUgIIURoaBISQggRGpqEhBBChMaSFSbE4rF5tj0+yiRRxqx4fHVraPLPk+wuNWwCsk6sZHzrM14k9YQ8TjTUjohZ6eQ99YjYMSgVeVI1wzx2CNleXksl7Wwv0mT/CXJMAcAR25UGyVXnPDV6qmVS94XUQ0rFuNggQlQEHaTuFQAkc9Z2pzRjhQnVEk+Ws4KPhRmbAO9MWmEFAOST9sBUytbfccrjkBQj14vzWAxNk9o7pRErYvC45iAFu122/4znvM6Qej6HC0dMzFcjqEjGe6bhEfKQdnV223PtPCKKaSI4KBHRFLuGfbB7G7uHAdx6q+4RUZQO2WVZ/xukThgAlBfYbLV+j7/oQvQkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0FiywoR4LI5I5OWEbSpl67MA3DGBvdPLkmwAT/Tx1BsQj5EaOb12/z5hQUCSpRkmIvCW2CFJVSKCGF61mq7O3kLPJXgCd3zCJlWZE8Pq09bR9bPkuM4cHDGx1rjvDWwb7+6xSeGsx3Ihu2LIxGodzMWAiwU6s70mFgn4GIwSbUOQsPWAWnX+FnmpZGvsxElitzvFE+ATh0dNLDZrBS9Zj1rgCKknlCK1aACgRg73QKbLxIoF2yeACxbYNexzTGA1vYoF2/7+lQN0febOMD7CHQsQtxdi98pVJpbq4ceq2LDtKpWIWIDvnceZEMnjmMAEUs4rTrEx5poS9PH1y2O+u+YroychIYQQoaFJSAghRGhoEhJCCBEamoSEEEKEhiYhIYQQobFk1XHlcnlePaFZoioB/JYVC+FWPkCChLmuB8gNWsUUU5D45C6VhrViKTMbDM/6rAtM9XeQ2KgAQJqokIoRnzrNkiG2N7ValS57ZMLWMolN2Bozp2St4s1Hs2yVfNEE3386bs8LGwHNCC/ykwisOi3BBgsAwNru1IjtT9RTTyhJbHuY68nKoZV0/eqULZZVm5k0sWyfHb8AMEnqX5UDrpqMkVsGW7JClGEA0CAKz06ixKvXiJIR3LrKkWsg6bFYYnY+vjsIO9vPPrvXszRZn2zgtNOscnXcUyutULAKR6au893buonFkK/W2fS4VQg2iDpwBaknBQDBgltD0zmA1TMi6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWSFCT3p3DzbnjFPHYwOYk0xS7KXvpxyLp83sVrZUzOjbBPI5boVG5TKNqF4dMMkqUjSn/2eRGOO9DVJ7IyqpOYKABTHbbsSXXRR9A7YBGTa2X2VxmwtFwCYIFYop5H2Rx0fgk2SGO/sssnmFW/wWBTlrG1OvMP666Q7uun6cVK7p+kRFjQbJLXdsGMlqPPvfMGsPS5jv7bikr41vK25qBVhHJiy4zLKRDQAYjl7Dsaa/BqIp8nYnLKhlb1cBNFK2jpBTVajyCN4YfV4enrsvpqek8US857LjdLOskxEMDtr++WIYAgA0LW42kEFz72RLVsi9c8AIEFECOR2hX0lbnEULFjWqZ6QEEKI5YAmISGEEKGhSUgIIURoaBISQggRGpqEhBBChMaSVcd1prOIRl6eI+seWcoYsbZgqpApjzeHiy+uUJyvDcxaw1fWjjWBWW74rIhKZAsusKcwlvUUACTrp2N8X2VS6Gy6bG04MtxdhR4BZu9SrlgVFwAk0rZfiS5SUcvjhZPusuq+RNaq6yJxq6IDgEjEKslaLW5l06hbxVMiSdR5Sd7WeNkqifpXn2pitaotXgcAzYYdg6kuq6QLsnxcr+0bNLGOEj8v//z8cyZWKtprKOtRPfZF7dicKNp9jXjGRZwUMWQFL6emrG0RwK+tPFHIArzYXpFY0fiuV37LsmOoSCxzAKCwUHIGeG4idHV6b+kgKjgAcOSeR9V1Hvu0zILCes4BWJxrj56EhBBChIcmISGEEKGhSUgIIURoaBISQggRGktWmHBk4jAix9RZ8QkTjpcSsbzIeIUFNgHMlu0Z4DVyKtPcTmchsQxP/kVTWRMr0gQuT6DXSV46m+X1QWINe1yYO013llvBzJCsZK7bJstjHnePTL/dbvepwyYWsOQtgCBpLXrqKdvXSITXnWlG7KXRRIsuWyUiBEajxmu5zE6ReLdtf6vG9xM4e2LTKSviODzN7aTSJbvd+gxfNkPuGPG83X/T8b6m+m27XMuKCApE7AAAmYwVEczMcBHDYuHiIi5QypHaRz5lQJkIebhtEF+/j4gwSs4el4RHGBGQWmVcmuIRHJBm+URbC7vQajn47kML0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCoy1hwvbt2/Htb38b//zP/4x0Oo0NGzbgL/7iL3DmmWfOLeOcwxe/+EXccccdmJycxPr16/G1r30NZ599dlsNy6ZzCxwT+HL93TZZz5J/4563kllOj4kVAP62NiMgtWQAIM3quZB+lUnNFACo1ydMrFS2Hciwmi/gfa1M89eaWapz1ap+E+tJ8Bo3h+t7TSxG6gFlOnhbu/tXmFgkbb8zJYnYAABaUXYO7HCPxDzJ/qiNRwKuokgEtl/N+qyJpVK8r8msbWt11opYgoDbU8zMTplYJGaPVYUPS8TqdruFMe44wK6AWs4elyJx3ACAWSJYmQ7sshk71AAAcXIKxsfste1L9rO4b9l02l6vDVL7aIzsH+COA2xXHl0BFQH0kViDCBB8G/bdw5jeYGh4pYlVPLXKphfcR44KE/gYWEhbT0K7d+/GJz7xCTz66KPYtWsXGo0GNm/ejNnZly+4W265Bbfeeiu++tWv4rHHHsPg4CAuvfRSTE8fn4JFCCHEiUdbT0L333//vH/ffffdWLFiBR5//HG8+93vhnMOt912G26++WZceeWVAIAdO3ZgYGAA9957L6699lqzzWq1imr1Ze8t5s0khBDixOS4ckIv6et7eo6+F7Nv3z6MjIxg8+bNc8skk0ls3LgRjzzyCN3G9u3bkc/n5/5WrVp1PE0SQgixjHjVk5BzDp/5zGfwzne+E+eccw4AYGRkBAAwMDAwb9mBgYG5zxZy0003oVAozP3t37//1TZJCCHEMuNVOyZ88pOfxJNPPokf//jH5rMgmJ8Bdc6Z2Eskk0kkk/ytdSGEECc2r2oS+tSnPoX77rsPDz/8ME455ZS5+ODg0bokIyMjGBoamouPjo6ap6NXYnjVEGLRl61LDkzxWiqjo1YxxrRdvpofTJ7mMwjqoOU9bLDhUQYxsrC1UBIN3gJWNyXZZU9hlSh4AKDhbNx5bHemicJwdtbWzUnVuOAkRZSA44ft03DXm06l6yd6SI2XwLa/5fH9cSSeILEkUZEBQISo61qOf5FyTaJCgl024VGntVKklouz7apXuAqquXK1iY1VZkwsXeXjIholx8AjuEqn7TGMZu14nZng18ChiUMmVif2LmnPuCxO2IZxFdribb64FQ+QSi1OHRePc9sfBm8XvzfViUo2Dntd+Kx0mGou7qtVRs63ryYTY2G/Wi1uccVo6+c45xw++clP4tvf/jYefPBBrF27dt7na9euxeDgIHbt2jUXq9Vq2L17NzZs2NDOroQQQpwEtPUk9IlPfAL33nsv/v7v/x7ZbHYuz5PP55FOpxEEAW644QZs27YN69atw7p167Bt2zZkMhlcddVVr0sHhBBCLF/amoRuv/12AMCmTZvmxe+++278yZ/8CQDgxhtvRLlcxpYtW+ZeVn3ggQeQzdqXSoUQQpzctDUJOefx3T+GIAiwdetWbN269dW2SQghxEnCkq0n1GrOr95SLvNEJ6sFksnY5F9fn61jAgBdXdZ2ZvaIx7KEJPViJAHfkeWptlSmy8QqJWvv0t01ZGIAkOm0T5P7f7vHxKoeYUScJEBnA57ALZHiQWzJkifR2SR2Qk2yzdF9++j6iYhNAOe6bQI51mPtfQCeAO4gCfgEtfcBQCx66mjyZZtWsAHY9Ws1/iWuo2mTuFGSbC5U+eXaIPvKJO24HFrBj5WL2OMy2WMFBABQIXWmpmfsC+YNT7Kd+e7EyLkqe8Q1cWeXzedtst5XJ6tBxqDv3uKz+lqIX/RkaUcwwQylGqTuj2cEI0MserqJFREA1Ih1UoGoFWjdIdh77lHbnsUhA1MhhBChoUlICCFEaGgSEkIIERqahIQQQoTGkhUmPPe73yJyjNXP4j0IeKLQVyMoFrOHIJflh6WjPGVilTJxIajw9YOYTeAmSO2hCkn0AkCzbh0TUjHb1/4evv8p8ra5j+Ehm8RmdZIqE7ytAXE3WHWKFVx0xfn3oGjZigASOZvUTUW55VMqYo9VPBa1sYjHcYEoQSOOvwXO3BHq5PsdEwAAQJIIC4KW7b9Ld9L1CzVb4yVRs1dMtcIEFEDDHhbiYfAv2+3oMbEz+m2/ZjJWcAMAjshbIg07XscPcYeU0pQdw0yYwAQIABch+MQCvb29i1q/4KvnQ8QZPLHP29pBxCnt1D/L5mz7fXXZEkUieIiTWmVE9AUAPT3z99VstjAxcZDvbAF6EhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEaS1YdV683EDlGdMS1NkA+z2tpLMRnN1GvW2uOuKe+SKtMVFBks9E0V5AUZuz6yRRR5/UO0/VffP6FRe0/382tOepEY1gm9joA4GZsnaAMUTYxFRwAFIliqNxp1Vn9g1bBAwC5Xqt4SnVadVgs8KjrYqyt9lhHIh65EKnnExAVGQAw56MaUWdFo54NsHjTquMinuKPEVLPqDNlj1U8wa+VMVKrq1HmiqsVvVY1mc3b8daqcYujUWqJZQ9gJs3bGrAaO0TdFiPnHwA8rjUUto3Vq21dtCY5VwBQLFpLsQqp01UY4/WIZsk9q4N0K+NR91WIkq/psShiddEYgceiqLxgvL9u9YSEEEKI1xJNQkIIIUJDk5AQQojQ0CQkhBAiNJasMCGTSc+z7Zn1JMQyxNqCWfHU69xehln8NDy1TBKkPkcqzfbF2zq0ao2JxYiIYWZ2hq6fWzFoYuOjVlhRmOHJxxQRXCRyfAhUiODA1VgCmK6OHMkrlyYnTKzqqb3kulklXpvA96U/IxEmQrCxwCNMCMi+gqins6T2UTxhRSjNuqfGinUYosKEZIT3toPURJomwpIOz/rVmG3A6sFT6LIxYrNUmrbntUashACgTGyuGg07Xmsef5k4EQukUnasJJPsoAITE8+bGLuHAP46Q4sllbJtyOWs4MZnu8NEAEyEMeipE9Wq2HOQ9ugPkuRwl8r2nnnEY1EUXyDwWkwB1JfQk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUJjyQoTkqkUosfUX2FvCgM8qcfrg/CMHHNc6Ozupsv25m08FrevYD+/bw9dfzZiE8jxVsLE9r14mK7f1WX3Xyd9nRjnIox0hjg+THMRRixtE4s9+S4TSzlP7aL6IbtNkpiPp7g7RYQkoCNEGBBLel6BJ8c6Qh0TPLWfHHExiNltAgBadtkYc1xIe9wdiAiiWScJfE+VnyhxTGCJ+YjnLfZMusPEOqf4cXVRe14OTNtzXZvlSf1s1m53epqJDfh5GZ+w2y0dtteLz0mFaYZSKd5XJnCijgcF7njAnCBYu3xuLl2kdk+KWD4wAQLAHRNann2xHtTbqCeU75svuGi1WjiwzwpWGHoSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERpLVh1XrVTm2fakPdYasyWr6ygQawlPyQ2UyLK2uspRolGrOOroIrY9np3tO/SibRdZzrf+i1O2FkucbCGdt9YgAFBm9iABV8uUrOsLupNWhROPcHuU7t5+E0uRGjupPLPn4bRgrWxiMV6jJwKrZHPsO5dPHUe/n3F1XCRiVX9EiIdo02NlQk432SSiHo+iaMwqLOPE9qdO7HEAoIOpw4a4bc/k7JiJjR2yg4WNSwDo7GY2V1b157ODQs2GmGLLZ53FLi2meAP8djrHsy++HF/QkWOYImrSyVGupiXiNjQ8bS2ReJ3cchOetnZ0zFfuHq2xJHWcEEKIJY4mISGEEKGhSUgIIURoaBISQggRGktWmLCQRp0nCfNMsOBZlhEQO584qRsEAJPE9qTRsvN455CtGwQARVLj5dARnwyCENikYLxm27+ma5iuHnNVE6vHueVIN6lz1GgSK5mop/ZSJGlik6Upu1yZ107qytj1kyTb7zy2QUFgBQsNYo8T94kNokTw4KuRErfLRojtT90jonBkDLHaSQlPUjmSsOsnSGymxdevt+y4iNb4NeRqtn7VGX1rTaxUs9sEgOeeO2JiuUErjPCUvQESdrwNDg6Z2OzsLF19eppbWi0WLkLwKRAWp0zwChhIfKZq7yFFz7joJffGOPi9rUSsh2pku87T1mp1vmip1fRV+rLoSUgIIURoaBISQggRGpqEhBBChIYmISGEEKGxbIQJrI4GAOT67Jv53d28vgbjyKgVBoyN2bfCAaBO4pm8fSt4haceUYXU/eglb6sXSR0QgKc5mYhiZpIn+/u6ukwsmrJv2wNAM2LbsDD5CACzNX6sq0SwcOiwTQo7x89rKtlnlyW1WFpNPoRbTduvaMOKEFoNLhYIiAgEARcmRCMkCRsngg1mgwDARW28FSXfD2P8O2NQt/1i7Y82ubsFcyyozXLBCUj9rEzKHsPurhV0deY6MkuEEVOznrftiRCnWrXr+1wQfO4GfNnFre/bJFuWiRB8jgls/UPE4YXVHQJ4PaRG2dd/0lay3YzHucYcBE/tKoaehIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERptTUK33347zjvvPORyOeRyOVx00UX4wQ9+MPe5cw5bt27F8PAw0uk0Nm3ahKeffvo1b7QQQogTg7bUcaeccgq+/OUv4w1veAMAYMeOHfj3//7f45e//CXOPvts3HLLLbj11ltxzz334IwzzsCXvvQlXHrppdizZw+y2cXXjWE0Glytc3D/CybGVCU5T40dRsJjGkLVMsTuYtJjG0TVMr29Jtab85wWsv+A1OgJSJsAoEYKjMwc4jYmaSKCGVhta8xE8p10/Saxw6lUbI2bSKSLrl8Yt6q7fMrG0gm7TQBgIh6Pa44H+/3MI04DAqsEihN7mZbHNqdJCgW1YiRG1H0AgJptWIPULoqleAcigVWsda44lS47Xvi1XZ+o04gIDgCQjdg2HBm1dbIqJa5u6+219XSYEs6rcCWnoB11Gqtd1NfH7y2srtli93N0X3YQs3HN6gYBoDZTdc+9iR0DR2Jpj0o5Fpu/bPP1su1573vfi3/7b/8tzjjjDJxxxhn48z//c3R2duLRRx+Fcw633XYbbr75Zlx55ZU455xzsGPHDpRKJdx7773t7EYIIcRJwqvOCTWbTezcuROzs7O46KKLsG/fPoyMjGDz5s1zyySTSWzcuBGPPPKIdzvVahXFYnHenxBCiJODtiehp556Cp2dnUgmk7juuuvwne98B2eddRZGRkYAAAMDA/OWHxgYmPuMsX37duTz+bm/VatWtdskIYQQy5S2J6EzzzwTTzzxBB599FF8/OMfxzXXXINnnnlm7vMgmP+7tXPOxI7lpptuQqFQmPvbv39/u00SQgixTGnbtieRSMwJEy688EI89thj+MpXvoI//dM/BQCMjIxgaOjl+h6jo6Pm6ehYkskkkklbO6ZeByLHzF2FMU+Sj2TlWJLNl/yLkWV9IoZ4wyb8WU4z7TmqZdKFyrStz9LwOGPEa6TGD0l+sjoiAJCN2URldzcXjCQ6bWa5RuoJHTnM6yHVyTGIkW02p7nFUJIkQGMp2/4oqZsDAM7VTCzStMcvIHWPACCoWcFDlC+KWMyOrViE1NMJbJsAoAnbryb53tYgAggAiMLGXZ30Nc47UC/b81qZ5fWAutLWJisSs+sXZ23dGwCokzpDcWaFU/Bl260IIZaxB8trL8Pa5LXyYfcRu1SptHgrHLZNnzCCwax4imP2HgIATMrlLV1E2nCECit8W5ifRmm1PLW3CMf9npBzDtVqFWvXrsXg4CB27do191mtVsPu3buxYcOG492NEEKIE5C2noQ+97nP4bLLLsOqVaswPT2NnTt34qGHHsL999+PIAhwww03YNu2bVi3bh3WrVuHbdu2IZPJ4Kqrrnq92i+EEGIZ09YkdPjwYXz4wx/GoUOHkM/ncd555+H+++/HpZdeCgC48cYbUS6XsWXLFkxOTmL9+vV44IEHjvsdISGEECcmbU1C3/jGN37v50EQYOvWrdi6devxtEkIIcRJgrzjhBBChMaSLWqXSscRPUYe51Og9AwOmlgu32Vi0Sj3bDkyetjEyh7bmzip/xYnIhCv1oUIdupjxHaHi6iQzxN1HNlmXzf3TGlNW2VRPMZtOIKK1dbUiTqu0uJF7WpZu90VXbax8QZX9iBq1VUusJYtrsXVdY0GOTFktEcdP1YBOYuB4xZB0ag9BinYWNSjbmuSscmaX/cU1WNvQLSIZUvE8e+cjbrdf3WW76snYgs2VpJWRVUt8XHRl7fquiaxIyoWfkfXZ3eBzk77cz+LAcDMjB1XpZLPXsfujd2HfFY4TKHX3d1jYj5LssOH7fuVTMXmfwHGks1ZmzAAKBTtdcgsinp67DXIaDZbmJg4uKhl9SQkhBAiNDQJCSGECA1NQkIIIUJDk5AQQojQWLLChFgsiugxtUd8JhzZmu1CZ8smWkszs3T9gFhTxD3SgljM2vmUSVLSl+jMZez6OeYQ5LHxSPd22X3FbGK+luL2LI2YTWG2PPV8RkdsonK8YR3O657aSz0xe8Zm6iT52eSu6UHZJvFjjQ67XItbLEXidv8uIDV+HD9XAanHEyf2OACQICKEZJSMqzgXxzhicVInaoNKk6/fgo23AlZ8iosNUsQiKdPJRRilWauaadbtd9m6RwjEBCMV0tcUqbMFADFSp6mjw+6/2uTtT5PzysQCANAgdkYzh+14TXssgjJ9XSbmiO1OhYiAAF89I1JjqI/vP+3svpK+Qk+LLF7AbIMYgUeEw9CTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQmPJChOinTlEoy/PkTHPW8VTExMmNlOxb0U32qj5kfUkRcsksR0jkglforKzs9O2i/SrUuFvm0dIQRsXs8tOVfl3i+lpe6zqdZ5ALBTtduPkDereXv4G9SB5M75B3BF6OokNBYA0SdYnHel/ndtL1GrExYA5BgSeekLkNfRIgx+rWIvUE2LuGnF+uQWOuTOQGkNEWAIAjabtV4O4ELQiXJjASjJl0lYEAgBwtmMVIkzo9IhrpiYnyTbtcSl7rvdyxQo+XOyIiRWn+for+q0IIZ3lfQ1IF3Il29aWp4BYnZyD/YcOsSXp+nSbrPaSZ/U0qR82S8QWPpg7xChxmGFtcGT8+tCTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNBYsuq4F6dGETmmnlDCowBhFjkZYrvT47MBITYUE9NWXQcA6Zy1N8nnreKtSeruAMDMjLXYYftnChgAeOG5fTS+EF/NEIbPdieTZ3WG7LHuWcHVcbEYUYwRK59YldcDisOq1mJEHYcaV6wFJB6NWSuXwKPCigT2vERafF8RZ+Ncx8a/8wWBjUeI7QmLAUCUSPliZF+tgFvpxMh2fTeGZGRx31vrNU9RLEIqY8darMDrXKWJYm16xNb/yuQ9ClViJzT54hhdlun7elO2nlLd44RTaTLbHbvVsTFP/TKiMGT3hqLHJixBVLrZNL9ee4jKdXbcevkUiM0ZYJ3G2hDH6UlICCFEeGgSEkIIERqahIQQQoSGJiEhhBChsWSFCQuJeRKNjiTqpkgs67ERSXTYZHeD2NsAwMS4TcqVy2W67PHAEpIAEIvZZO3Q8AoTm5nmxUEmxkmilJfjQYxYfhSLtv/JKM9AxtP2+02iZdvfk+K1XFIFW/+pMW5FDNEIP1Yua2MNUo8n6pEQNKI27tEwoElq5DBtSRDxiChIFrfBbHuIgAEAWlESJxY/ruW53GNEWJHwHNcmOV5VG2pWuOAlQsZLKmX3lfZY4cTrdgwFvYs7/gAw8YK1+PHZ5kSINKFIhnt5ig+MErmOY6x2k8fmi8GECTWfaIvdB7neg9o8+e5Di8MBWJxFkJ6EhBBChIYmISGEEKGhSUgIIURoaBISQggRGktWmNBIAMfmYWO+RCV5A7lUsAm5kfERun6+YTPzzpOQ68nZt4pTKfu69JHRUbq+I4nObNauP0lqJAHA2tPfYGJR8ga4rx7RigErAvC5Q7DE7oqVdv1DYwfo+tmqPV8re4ZMLGjypGw0sMclag0PgApP9rfqpJZKy4pQWp56QpGmPVdRlpQHECEOGS0iVmDNB4BIYD9ptuz3wyorcAOgHrXHupm0+2+xIkngIogaqecEANUmcXKI2DEY8dQuqtbssYoSwU2mwzqRAMDk/hdMLE7GKkvKH8XGVwxwh5F0R5eJvbjX1gMqeYQNdXK6skSYsGrVarp+oTBlYiMjtiYXtXYAFxZUily0VCR9GDhlkG+YML1ADNVqOZTLfF8L0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0Fiy6rh6vY7gmHpCI/u5uq2DKEDyHosfRleXrQ+SSHDF1PSErTsyPW2VaD5hzvBKu6+e3j4T86njRg69aGJFUt8j5+k/U/L57FFSxN8jlbQqqCZRkR3FqqNefM6ew+QsryeU7u83sVbO9qvZ5CqsZtUqzhoN+50rAK+xE5C6OYFHHQdiB9Qg6ria5ztfhKrW7DbrnrY2iTqtSax8WgmPjQpRwkWIuhAAokTdFmf1gEoJvn6T1P8i47UesdcKADQK9ho4ZYVVl1UavO7Nvmf2m9jMNLfe6s0OmBhTt3XluPXUZMUqT2NEhVatEt8jcEswZtvDahQBQIrUP6uV+RhgW8jlrHK4VLJ2WgCQXnBcWq0WAKnjhBBCLHE0CQkhhAgNTUJCCCFCQ5OQEEKI0FiywgQUGvCUepkPyajlSX0OlsAHgEPPHzSxmMe2p1Sy2+jwJAUZzE5n9LBN1qc99UXKZP9psv9YjJ/Wzqy1HZqpTtJlJyetOCJHEp0xYhkDANGIFUGUpqfsgh4vm2bCJrYruQ4TS6e5iCRI2WWDGEnWR7ntT400LHB8WaaNyBARRMx5BnRgj2Ek4CIEhiPChibZpvMIG6KB7UCCxACg6WomFieHpSNujz8ARLI2sR4kbLtaXbytU1nbryNFK1ZIJElBKQDZXnsN+IREM2V+z1hIxVNTrFwmtc4KBROLxxcvpGK3plKJd2A8btvlq10UIzfSWs0KJth94Wi75q9/VJiwOPQkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0DguYcL27dvxuc99Dtdffz1uu+02AIBzDl/84hdxxx13YHJyEuvXr8fXvvY1nH322W1tOxEHjs231jzJQxZnzgDO8a5Ok/oagac+SIIkBdkbzDFPopHti4kQmAABAFJpm1Rl9YgSSRsDgP5++wZ4uc73VRqzyV7W1+I0fys6nbIihnjaHsCRGlcmHJl83sSGuteaWJ6XnYGL2e2mYZOlAVkOABwRJjjPV7YmcReghgMeYUNA6gm1mGODT6hDP2Drc7FBQOoURTyCjSBil40Td4isR4SRiFjBQm3GjqHShE3gA0BHxF7Hvz1o63fl8rymVozc8nzXK7sLlAPrOFD3nRdyv8iQfaVJnTIA6O604gombpqY4NcgqyeUItclABwmAinapm6PO8QCwULLU4+K8aqfhB577DHccccdOO+88+bFb7nlFtx666346le/isceewyDg4O49NJLMe0pniaEEOLk5VVNQjMzM7j66qtx5513orv7ZY8n5xxuu+023HzzzbjyyitxzjnnYMeOHSiVSrj33ntfs0YLIYQ4MXhVk9AnPvEJXH755bjkkkvmxfft24eRkRFs3rx5LpZMJrFx40Y88sgjdFvVahXFYnHenxBCiJODtnNCO3fuxC9+8Qs89thj5rORkaO/Kw4MzM89DAwM4Pnn7W/8wNG80he/+MV2myGEEOIEoK0nof379+P666/H3/3d39Hk/0sECxKlzjkTe4mbbroJhUJh7m//fmu1LoQQ4sSkrSehxx9/HKOjo7jgggvmYs1mEw8//DC++tWvYs+ePQCOPhENDQ3NLTM6Omqejl4imUwimbTWK7V6bN7E1ZXn9jhUnUZsa7LE7gNYfM2Oo22ysQRRoPjUdQy2r1mPDYdH2GIoeWr07Nv7rIlFPd8l+vttPZeZGSsu8VmexGP2Swc71kV4atzMkA3PWmVV1eN4knRdJhbA2pBESd0jAAii1jbGkbo9ANAgsrkGqT3kEccBEftBhCjZolH+RS4gcfqdL+DfOQNiEcQUcwAQi1k7pRQ5Lr6+1mesGrM+NW5imRjff57YMfUP9PKdEZrESifp+ULdPWBrfU0RdVqxaNsPADUip62Te0OpwtcPGp5rY+H6HjUts/ipe9SwzDqI3ZtGRw/T9Rcu69zrpI67+OKL8dRTT+GJJ56Y+7vwwgtx9dVX44knnsBpp52GwcFB7Nq1a26dWq2G3bt3Y8OGDe3sSgghxElAW09C2WwW55xzzrxYR0cHent75+I33HADtm3bhnXr1mHdunXYtm0bMpkMrrrqqteu1UIIIU4IXnMX7RtvvBHlchlbtmyZe1n1gQceQDbLXW2FEEKcvBz3JPTQQw/N+3cQBNi6dSu2bt16vJsWQghxgrN06wktSFj7EuAsiT8zYxPzvho7zNqi4UneMRECq+fTzlMfs+HI53m2vbevy8SaJHn54kFbIwngfe1ayW04UsnFDQ1fLROWALUpbaAny5PK9bhdP562W+hI8WNVqdj1WS0VF/UkUOM22V5reurxROx2meuN85QIClidnyix3fFYT0WYnxCLeRSqARMseOoZMXFGJE3qTHkEJ82CtdhpEBFIitT9AYBEwV4vw6fY680nzhkvj5nYCLH9AYBZcm06Yj3VnR6k6x+esYIDfr146pc5u6xHnsXXJ7cxTzkhes9h90yfCCKTyc/7d6vVQrHIaw8tRAamQgghQkOTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQmPJquMymRgix6h5mLILABJxqwxhdhP5fBddPxazCphyiRfUqpHt5ojdRdJTVI4xetjaYPj6GiUqolwub2KFwhRdv7PTVoAjm/wXrGpsRfcQWY7DitrFiLZnctJTkIuIq17Ya30FgyovSjewetjEkrO2s1GPb1EsZs9rJMJ9kxyRvTFtWECsfAAgQgrAtcj3w6bHYohZD0UDUsCPqfAAtFrEYgi+Sm12Gy0yiBoRvn4rb8drR59VwjWctXgCAFe156BZs9dwpThL1891WTuqep0r6ZjFTipllXhHpibp+vGcHUNETOtVnCEgqjfH7w3HS6HA7nnEdsgjU16ohv1XKWonhBBCHC+ahIQQQoSGJiEhhBChoUlICCFEaCxZYUJ//wpEj7Eu8dnuMIuaQoHULKkfoeszDQCrGwQAg4PWYqajwyb7x8am+AZIopOJEHyJytHD1gZkzak2UesrODg6ahOo6dzih0BPj03KxpxNNAPAxKgVHAwN2fXTaW7vkkrZdo1OWhuQ3z7HK/ZWI1awkByumVg2sZKu3yCJ1WicF8mJx+12Wy17Xpse25wI+ypICvLUI/xYNchm40RY4Css2YrYvrZIPSMAaMVI7SRifdQg2wQAl7Lr1509frNVLkyIpG3tsYAcq1YnvwamS1bEkCG1swAgQuqclUtW8FCiSX2gJ2vtfGJkXJfI/QoACrPEuoos563pRe4tK1eeQpedJNcWvw/5hBEL4w4AP4cL0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCY8kKE6YmJxHxvHV9LKyeEGNsjCcPuTkBT76VyzbRxoQJ3d02BgBHRm3dEtb+Dk/RD7b/F55/zsSYMwIANEgGs1Lkx8+RAzMxYWuxxGKLf4O7QWofdfdzYQMj17T9973BPXZoxMSydbt+wuOYUE3YBHaug9e4qQZ2u/Eoqc8SeI5VnCTbk0QsQGr5AEBARAgRsmxAXBQAwLHEvk+YACv4YFsNPEKiJvnaOzZuBTcZ4jYAANXmtIlVGsTZIM3XnyXChGqTCz6SVRubmbTing6Pw0lk2o6Lcpkk+7m5AxUcLO5u56edump54m7hu97SC2pKtVotTExwN5SF6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaCxZddxCfFY2PsuKhXgELFQBkmFFPwAUiT3H735nbWM6POunqerN9ivmaezAoK3n0ySKM189IaatqXmUgCw6TlRM7fD887ava96wgi6b7bTnhdVpGjnMFTh9OduDWLzDxBrM8wZApWGVTa0ZPtgyGaJGTNvvdy7C1WkJ9l2QqdNiVkUHAEHcXsYtolkLHK+91CS78tUuajgbd2RfNaqZAxotpsSz7SrWuWSsULAKzcPEzqruKdHDmC5axR0ADPXbsTmY7zex2SqvRzQ6bcemz6KHwW4XTMXmvwfaD44csQpdgN9f21HHLQyrnpAQQohlgSYhIYQQoaFJSAghRGhoEhJCCBEaS1aYkM6kETmm0IrfnofV6LFLdeW5jUcbrjMYXmlrz0Sj9hA2PTYgDF+i7/UgRxKNzmPjwSx2jh/b12rV2qgAQIwcV7ZsxmPP0tFlxQLP/e5FE5sc50npNQOrTSwV5cKASMMOokiQMLFYxsYAwDWJFQ4RTESIKODoBmycShA8VjxNIhaotbiIoU4sfiqk/aUqT8DXnB1XFdL+8iy32arViJcOwSdEKhbt/n33gGzG2jRlm/YcJmPcTikas0KaWNza/hzyWoodn5VOgQipWMy33VTK1irzrb9Q2OAbqgw9CQkhhAgNTUJCCCFCQ5OQEEKI0NAkJIQQIjSWrDChXm/MqyeU8CQP6yTOluVuBUCRvMFcrPPkG6N/xYDdV7qLLjszY9+sLlPBBU80Prf3BRNj7gqnrLLOCgBQI4n96QoXBvD6S7ZdLKEJANmsTeoeOGBr/PgcD/K5xQkj0mk+hPP5HhPr7rDnypfUnTxi38Lv6+6ly87UJkwsniRvtkf5IK5UbbI92mHdHVpEAAEAQYN8lyTJcud5i73JhA1EbAAA9ZY9L8zxIOIRvLA6VVVnz8FsjbsQDBHByOzsfhsjdYMAYHCo28QOvHCELjtF6n+lIlbwUm/yfbWIuCdOakplPCoKWk+IBBfrYgBwsQNg6wEBQKWy+PpdCzfrHLBYbZOehIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERqahIQQQoTGklXHFcslBMHL6jivAmSRwYKnHlGDFB5JZ7jiq7PTKmNqRNnkg6nTZkm7Ep4aP7OkrX1Dtq1xj5XNWM3WaJkmdXOOsjg7pLxHtZhq2LYOkYVLHrXOWNGq81idp0SRj4sjRduvxilWNZhIcCseUqIHFY9lTJIo4WKzNROLeFRULmvPF7PNiXjsoIIGsY4itYNannpC7NqqVflxnZm157XVIsfao/BkiqsYUYwlAj6GZ8lxZSOoq8ta5rzUsoV4LhdUS1a5eaRAagR5+sruODGPfRiDnRdfXbXF4zkvRduvWabE8+x+oS1ayzmUy757y3z0JCSEECI0NAkJIYQIDU1CQgghQqOtSWjr1q0IgmDe3+Dg4Nznzjls3boVw8PDSKfT2LRpE55++unXvNFCCCFODNoWJpx99tn40Y9+NPfvaPRle5BbbrkFt956K+655x6cccYZ+NKXvoRLL70Ue/bsQTabbWs/9TpwjC6BWlAA3IaiRKxw6sSe5+j6NpbzJNsTSZvsZHYXxx6TY2FWKKtWDZpY3NPXIvHBKJEDM01EAQAwXbHJR1/dlcFV1qKmQRKNDU+itEk2PNhnLVPKHtudwgG7XeZw1OEpBtNNaqEcPHDItmmon66f77T9nylM0WVZTSNmTzPtqbETI8cgFrFjLfAICwImWAjsNgOPbU+lYZP9LfBlCzVbf6kJK3hxpG4QAMxG7L5Arqtqidd5Gn3R1oSqTNtxHWujTlbDc3NhlloB8Qlj1mEAlwB09ZD7IBHcAFxMlctZOywf+bzta8FzHzxC4qxVTBwEAOkF8VbLAUQcxGj757hYLIbBwcG5v/7+oxexcw633XYbbr75Zlx55ZU455xzsGPHDpRKJdx7773t7kYIIcRJQNuT0LPPPovh4WGsXbsWf/RHf4S9e/cCAPbt24eRkRFs3rx5btlkMomNGzfikUce8W6vWq2iWCzO+xNCCHFy0NYktH79enzzm9/ED3/4Q9x5550YGRnBhg0bMD4+jpGRow7JAwPznYoHBgbmPmNs374d+Xx+7m/VqlWvohtCCCGWI21NQpdddhne//7349xzz8Ull1yC73//+wCAHTt2zC1z7AumwNGf6RbGjuWmm25CoVCY+9u/39qyCyGEODE5LseEjo4OnHvuuXj22Wfxvve9DwAwMjKCoaGX30wfHR01T0fHkkwmkUzat9br9cY8YULGUw8oT95A5rVwOEzEcKiNekLd3TbZHo3yw9okCeSOpE1UthxP6NWJMIC9QT1bsIliAFQcwhK1R3dmt9sgx6rhEVF0Z60woFq1+xor8boxGeauQJKn2TRP1AakXRmSag3KvP+lwLarTlwMAKDSapnYSMP+rBwlCXgASMbtdpMxG4v7vjISwUJQt+4M0SjfgCM6mpkaH4O1iN1XqW6dJIqzk3T9kYKt3dOs2bbOlPkYbhIRQqNgT/bCRPnL2LhPmFAny3YMWsGKr9ZZqWhrUk2T8Vb2XUSLJOYR56SIOMcn2MiT+6tPtMTbMH+7zVYLwOJSK8f1nlC1WsWvf/1rDA0NYe3atRgcHMSuXbvmPq/Vati9ezc2bNhwPLsRQghxgtLWk9B//a//Fe9973uxevVqjI6O4ktf+hKKxSKuueYaBEGAG264Adu2bcO6deuwbt06bNu2DZlMBlddddXr1X4hhBDLmLYmoQMHDuBDH/oQxsbG0N/fj7e//e149NFHsWbNGgDAjTfeiHK5jC1btmBychLr16/HAw880PY7QkIIIU4O2pqEdu7c+Xs/D4IAW7duxdatW4+nTUIIIU4S5B0nhBAiNJZsPaHe3hwikZflccyeB+BqD2Yt4bP98YjuKEx1x2wwAk/NDtaHdNw2IPCpdeghsMv63svKEWXPmqEeumx52kqm4kQtFPfUF0mmrBLMkdEWY0EA9QqxESEnq26FaQCAyXGrzOkesH2NedSB6XiCb5jQTBMlX8L2K5ri3/kCsixTUsZq/GBHiUVPzNnXIhoRjzqOqPscqfsDAEHTxitE3XZkcoKuf+DFAyZWJ+qwuEfxRcoBYbDXWl8N9HE7pvEpq9o7fJjvKiAVgSJZO6478x10/TLpwt4Rq5jz1fhhtXuYGjaf5/XPslmrHPUp6YI4GW8eJR1jocq2RcaUDz0JCSGECA1NQkIIIUJDk5AQQojQ0CQkhBAiNJasMGFgYGBeXZ7x8TG6XJHUrGDJO5+woa/PJvWY3QUATB62ScU6yR7mPIlC1oYyq8fjESZwBz4iwvBY9aVZ7R6PMCCT7jSx3pxN9jYned2XIwdesEFyCsoee5V6mdSEIsdlosbXf0OPFWHkSZ2nUtkm1QHgwEHb/kQXF3FUirZOUVC3IoqOKn9fLknsfKLkHNY9FkMORERCE9B8YNSrpMZPgx+XWNXG3ay1OEqUrJUPAAxE7bU1UbbXQOGQp/4XO9+9Nlar8u/XjbI9BkxwAwBkCGJsxva101dPiN5zyLjmq9PrhZfv4jZj7HrxUSeWXIlFtp/RcrweFUNPQkIIIUJDk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUJjyarjJibGETnGZsRfqI5YfhArnOMp0PQSK4jty/Q0seJJc3Ud226K2NvEuAgLRyasFUqeWRSxim4Apg9bJVvaI2IZIoUIG7NEiegpoBdb5AHPxTzHqsfGy8RKpqfFz1UXsSypz9q2ujhfvzJt95Xu4wcrShSGrmrVYVNkmwDQGbEWQa7DKulqNa44izVtobl0R5ddjow1AGiR7daKHsUVsb2Jwx6XrihXAjJ7mCYpoNeY5ftnytNxUjxuZJxbVzEzppjHuytHlLNMsfbcwYN0fSpOIxXwfPX36lOLU9L5RHANYinmKw7a28uLQy6kzLyIADQWtKzVcqAeSwQ9CQkhhAgNTUJCCCFCQ5OQEEKI0NAkJIQQIjSWrDBhZGQCwTEOG77kG8t/x+NsYZ5QY4IHn91FDylTzkqXTxIBAQDMEmuMU06xAoC8pxZKOmcTpZMTNik7XeTtT5MMaNNTN6Y0OWVi5XEb68l30fU7BvpM7PBz1gqnPGLr/gDA4BmrTSzSZ49VZJYn65/9zT4aX0h3D0/Irlxziom1iAAAAJIta5sTDWyswgrEAKgcseewVbQiihqxzAGAbMpaLFVq7NK2ljMA5tljza0/OkWXnXiRJOH7V5hQJMPrMVUCUnuJDNe8R9iSIkqaOBnXhzy2P+w2MFvglmBdeVK/itlkeWuVkfpbbSikShnbh1KBCLE86zPRkq98Wp1ch1RXkffsbUG/jgoT+L1lIXoSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaCxZYUI8jnnChN+33ELaqqNBlvWtPz1NHAeIO0I2x5Pdg0M2gZxIJk1sfOzIce3f137mTcDqqwBAPWqT2KmoHS5Bg78VnSThni4r4ig2+P6jSbuvSITUzUnY4wd4EsDkuFQ8woxT+0iyvdWiyzIKEzbZne2w5x8AEqSeEBMhpNI8reyatl/j+0k9Jw9pIq6ZHudjcLGUSI0hAJianjKxRsMm4D2mHwCpH+ZIAr7Dk4Gvke0ODVkRjY8CKeiT99QPY/W7GuR6aed+Rcxg0OVxQeClf7iwgImWQIQ0zrN+o84cExaHnoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExpJVxw0MrJhXT4ipSgCgRNQqLOZToDARVcZjrbFQAQIAE8RzZHilVVb5KJesPYuvr7RNZNnhlSvpskyFNbH/EF226Wom1t9jVUSRKreyGXl2r91/1urzBoa66PqRuF324IStEbO6a5CuP9DfbWL1SasujEb5uWZ2QFNjo3TZTKdVl+XTRDHlEdfFyDlMJq2SruVR580WreXK5F6rjluxho+LesX2NUKUkABQm7Y2V6OT9ly3Bng9oRRRcwZE9ZeY5dcrixYLtk2s7hAA9JD9D6+0Fk0AMF22CsX6qB2Dvb1cXTcywq8ts02POK5E7i15YiXkI03uY74bfpnUHqqzS8PT2PrCekJO6jghhBDLAE1CQgghQkOTkBBCiNDQJCSEECI0lqwwIRqNIxp95TmS2bOwmE+Y0Ndnk4oNImwAgCmSvGP7OjLKE9iM7p4eE+vw2LukUlZYkO+yCXgfh0eslUx3j90mAKzosu1KVKwIoVaxwgoASDk7tHIdNln8myley6Ves7YvsU6bVJ6dtWIDAJh6cdLE3nTaGhNLkFo6AFAv2P13d/fSZXOkptLMjBULzB7h4yKZ6TCxSMaKEEpExAIAGSJiiHtECIwjLzxvYtEYvzUkUyQ+Y4UVo4d5Ta3UoLW0SqdsrAorAACAAknWWwkNt7MC+DU0epjva2KCjC2SrE977JQWbwm2+BpD7cCEVD47JGY1ViGCmZqnqfUF98w2dAl6EhJCCBEemoSEEEKEhiYhIYQQoaFJSAghRGgsWWHC5OQEIpGXa80cb40gWl8GQCd5273pScoudru+mhsF8mZ3jKzP6gYBPNHYDkQrgKDO3RlqEzaxXqnYN8j7MvzN9NhKK2yYKtpkddDi++/uHjKxasQu26zw9WOkPgo7q7VpLkJhLgII+L6miWlEitSJaiSsAAEAmvawoly1xx9NT+2mnBVMNOo2XV8r89pJhWm7r5hnDHf195tYZ5YsO32Yrj8+MW5iGWfX72KFcwDEYc9XjVwXPtcRFvcty8QNnd3cCeJ4qJO6Pe2t74mTmOc2SImRZaMewUd8QR9azgHlxTm/6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBCh0fYkdPDgQfzxH/8xent7kclk8OY3vxmPP/743OfOOWzduhXDw8NIp9PYtGkTnn766de00UIIIU4M2lLHTU5O4h3veAfe85734Ac/+AFWrFiB3/3ud+jq6ppb5pZbbsGtt96Ke+65B2eccQa+9KUv4dJLL8WePXuQzS5eWVIulxG8LI7zqtu4Ncaid4PJSavY8u3LF7fLLX7/Y2NWMcc1VECc1BIpN3g9H0Y9bk/3hEddFjSsQi9FOtYkKjAAmJmwxzXWaXvWWeP772zYkxgltYtyg7x2U4G48bgeqyKLegbLgWd/bWLJad7WChlDQxlrB5Vw3CKoY8jWRGoS1eKhCW77U5u18rrxw1adFvNc7q00sc3xDOLfTR0xsTGiw+oe4HWemMnUYWKbY6+Ko2QH7TmMEdVfkVhsAUCBWnLxvvb0EIshYtFTLvN9sfsFqxHkcQlDhig8GbMedZ3L2LbWPOe1o0SUk6StWY9yOL+g+FDLOYxjceq4tiahv/iLv8CqVatw9913z8VOPfXUuf93zuG2227DzTffjCuvvBIAsGPHDgwMDODee+/Ftdde287uhBBCnOC09XPcfffdhwsvvBAf+MAHsGLFCrzlLW/BnXfeOff5vn37MDIygs2bN8/FkskkNm7ciEceeYRus1qtolgszvsTQghxctDWJLR3717cfvvtWLduHX74wx/iuuuuw6c//Wl885vfBACMjBx9rB4YGJi33sDAwNxnC9m+fTvy+fzc36pVq15NP4QQQixD2pqEWq0W3vrWt2Lbtm14y1vegmuvvRYf/ehHcfvtt89bLjg2mYOjP9MtjL3ETTfdhEKhMPe3f//+NrsghBBiudJWTmhoaAhnnXXWvNib3vQmfOtb3wIADA4eTUaOjIxgaOhl25XR0VHzdPQSyWQSSU9y+1gWKwoAgAxJyPlWZ8IA357yeWtRk8tZG4tpz0+KHSTROEuSf6z9AJAiNT8yHTbZP1LkNXpKVZvATBR4Yj5BDliy2/a17HiNmwip25IkSd2hHD/3LKXpElaYEAsSdH22gd8dOmBivXkulqmS8xpE+eUyccSKOFzNHpdTB/lTfi1lj/U/v/AbE9vnqdFzyoBN1leZFY/nImgQEQga3OInRux0WDmdSoWvz6B2WJ5rgNlspVL2XB0s2XN9dGc2lCeCH4D3YZocV5/tD9092b/v3sTiTNjgte1pw74sSu4t0yVrsVQa96VL5u+r9XrVE3rHO96BPXv2zIv95je/wZo1R4uFrV27FoODg9i1a9fc57VaDbt378aGDRva2ZUQQoiTgLaehP7zf/7P2LBhA7Zt24YPfvCD+PnPf4477rgDd9xxB4CjP8PdcMMN2LZtG9atW4d169Zh27ZtyGQyuOqqq16XDgghhFi+tDUJve1tb8N3vvMd3HTTTfizP/szrF27FrfddhuuvvrquWVuvPFGlMtlbNmyBZOTk1i/fj0eeOCBtt4REkIIcXLQdimHK664AldccYX38yAIsHXrVmzduvV42iWEEOIkYMnWE0qn0/PqCZU8rxWzpNzQkE00+uoR0bAnUcjqAZVLNlbzJAqZMIHFfG2dGrGJwjgRQfC3woF4FxFseOwZWiTZmxu2b8FPvMCl982iTer2kHo8uaxNiAJALGEFB+W6FQAkHc+A9vdaJ4XDFVIjKcVdDKZJW+uepG6NiBjqRMTwbOEQXb8zYkUMB5q2r6UOPi4ON22/envtcfVd7DEsXlxTYvV8yHAbHl5J12dJ/AJxN/DV2DlyxLpGsLo/7bieMGEDwIUJMzPEScSzfpaM7XaEBUwI1Y7YgO2LHWsA6DnF/lKV7rP3i3FyDwSAOKxjAhYp2JCBqRBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNBYsuq4TCaNSOTlOdKvbrPxsTGmQuIKElazo8NrEWT3xWx3fLSjbFksbH2mqgG4ai7eyy1Lcj1dJjZyxKrzZitWLQQADVJjpVImiqs0X9/FbL9qgT1+1RRvPyORsN+54i2ujiMiMKQS/HJJdVhlUTRqbYtY3R8AKJJjlSY2KvDUl+nusFV6cqRfPq1Sq2rbNetRxzFLKUfGNVOxAVzJxq4rpuwCgHrdqrOYctZ3v2Aw1SvAryN2vTErH9+yzCLo0CG+f6a6YzHf/tlx8d1vykzJRs5VzaOuW6hRbcO1R09CQgghwkOTkBBCiNDQJCSEECI0NAkJIYQIjSUrTBgfL84rhOfL3/f12eQhS2r6aoYwG4spn+0NibVTH2Sx1FnRkzY2XG/w9g+eYm13erv5cTn8orXjKRRtArWfCAgAWrYF7AjWiL0PABTrpB4OScwXDnArnJmm3W6uyybwO/q55cqKqI3nY3zZwqSt8zMzbQUXHT4TX5LFzeR6bDDG072HRl40sQNtCGaYWCDHhBHgtjvtiGvKZXte2DXk0xUc77UVJ/WQfPeGWGxxt0efCIIJA9hxzecXX+eJHX+fpRljgNSe8pEiNcEG7S0EALB///z7hcdNi6InISGEEKGhSUgIIURoaBISQggRGpqEhBBChIYmISGEEKGxZNVx9XoDx4jj4LPd6e62KqJ02ipwmCrntaCLKlsWb/vDiGW47U7/CtvXTMZWpXvu4H66fjZKLGoqvK2FImlrzS4761HHJYiSrUVUWNOeYzU7btVxq1atMrEOagMDVPftM7FMT9LEujwFyYKsjUc8Fj/lslUsRYjqL+rpKxsVWaKka/gUR0QJd7xWNqwgGwCMj1vrJmZv09nJlYCsKFw77WK0o85rR13H7hlsX/39toAiwJVsrFCeT4k4Tq6BdpRwjHYshhhsrB9df/6/26hppychIYQQ4aFJSAghRGhoEhJCCBEamoSEEEKExpIVJsTjsXm2PazuD8CTfyzmS36yfJxvX4vUFXgXzHnq/Cyk4LFcYSKE/v5+EysSex0AOPjcQbJNblmSidl4qcZqudDVUSLHoEYOdjbL959dY5O9rbgVFpRrLbp+mRzDsfExE4tl7DYBnsCtVnimlSWbs0QwUfec12gvqRsTT5jYwcnDdP3SIutU+a4BVk/HX8+Hhg2TxMrIRztt5RY/Nui30ll87SJ2b2C2P7EYr4kVI6IdJnbw7Z+LEBZ/rBhjY/zeMDTUZ2JsXC+29lKr5VBm9cMIehISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFlhwkLHBH/yjiVl7XK+N4J7emx9jZkJ+1b40Y3w8EJ8ecIySTQ60i7fW9HPPWedEBIJm8BmCcWj22Uxnmhk4gwmYvAngG2M1W7yndeg175FPnVk0i7XRlLZEcHKM0//lq6fZWIBjzuES9vLKJOzhVfGiNsAAERI3Zo9e39nYnXP+FvseWnPmICPwYzHzWMx+z+6PhOiHJ9jQjt95fHF779eZyIOfg1xwQVbju+Lrb/Y+x3Aj3Uvua4AIEWcQ5i4ZLFtbbW4YIihJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcfE45qnj/GoX+4HHiYbC7Fl8tjmLlRclvCo6+0HsOO1VDhx4YdHr9/XZA+Oz4WC0Yw8yOGhVh43AqtPGPBZDZaJk617RbWKzo6O8AaSpnaxGD7jlygSp5dLjURZNk9pBlaKtZzTmUT1mGva8HGFj0DOuWD0fXg/IUzuKjAF/eRk2BhanpAS4CotZ4fRZF5l/Wdbui8V845qpy/L5xd8w2rkGFruobzl2Dti59ikZ21H9jY5aSyh2rPz2Z/Pb0Gr5il9Z9CQkhBAiNDQJCSGECA1NQkIIIUJjyeWEnHP/8t+F8Xa24d/uQthvl75lscg2+FZvkQ/4/he3n6Pr2zeT2/k91tvVRba1rXYFNuY822TrN5uL72uThBtsm779k7B/WRtvksHiO3yLHoPe9Rd7rPhb7Gxf3jFM2trO2/GsXXysHd/+fdcwC7d3vRz/tXV867Pg8V2XR+OLG4OLHRcv38dfuW2Ba+eo/itw4MABrFq1KuxmCCGEOE7279+PU0455fcus+QmoVarhRdffBHZbBbT09NYtWoV9u/fj1yOK5OWI8Vi8YTr14nYJ+DE7NeJ2CdA/VpKOOcwPT2N4eFhRCK/P+uz5H6Oi0QiczPnS5VVc7ncsjn47XAi9utE7BNwYvbrROwToH4tFbic3CJhghBCiNDQJCSEECI0lvQklEwm8YUvfAHJZDLsprymnIj9OhH7BJyY/ToR+wSoX8uVJSdMEEIIcfKwpJ+EhBBCnNhoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGgs6Unob/7mb7B27VqkUilccMEF+H//7/+F3aRF8/DDD+O9730vhoeHEQQBvvvd78773DmHrVu3Ynh4GOl0Gps2bcLTTz8dTmMXyfbt2/G2t70N2WwWK1aswPve9z7s2bNn3jLLsV+33347zjvvvLk30i+66CL84Ac/mPt8OfZpIdu3b0cQBLjhhhvmYsuxX1u3bkUQBPP+BgcH5z5fjn16iYMHD+KP//iP0dvbi0wmgze/+c14/PHH5z5fzn37vbglys6dO108Hnd33nmne+aZZ9z111/vOjo63PPPPx920xbFP/zDP7ibb77Zfetb33IA3He+8515n3/5y1922WzWfetb33JPPfWU+8M//EM3NDTkisViOA1eBP/m3/wbd/fdd7tf/epX7oknnnCXX365W716tZuZmZlbZjn267777nPf//733Z49e9yePXvc5z73ORePx92vfvUr59zy7NOx/PznP3ennnqqO++889z1118/F1+O/frCF77gzj77bHfo0KG5v9HR0bnPl2OfnHNuYmLCrVmzxv3Jn/yJ+9nPfub27dvnfvSjH7nf/va3c8ss1769Ekt2EvqDP/gDd911182LvfGNb3Sf/exnQ2rRq2fhJNRqtdzg4KD78pe/PBerVCoun8+7r3/96yG08NUxOjrqALjdu3c7506cfjnnXHd3t/vbv/3bZd+n6elpt27dOrdr1y63cePGuUloufbrC1/4gjv//PPpZ8u1T84596d/+qfune98p/fz5dy3V2JJ/hxXq9Xw+OOPY/PmzfPimzdvxiOPPBJSq1479u3bh5GRkXn9SyaT2Lhx47LqX6FQAAD09PQAODH61Ww2sXPnTszOzuKiiy5a9n36xCc+gcsvvxyXXHLJvPhy7tezzz6L4eFhrF27Fn/0R3+EvXv3Aljefbrvvvtw4YUX4gMf+ABWrFiBt7zlLbjzzjvnPl/OfXslluQkNDY2hmaziYGBgXnxgYEBjIyMhNSq146X+rCc++ecw2c+8xm8853vxDnnnANgeffrqaeeQmdnJ5LJJK677jp85zvfwVlnnbWs+7Rz50784he/wPbt281ny7Vf69evxze/+U388Ic/xJ133omRkRFs2LAB4+Pjy7ZPALB3717cfvvtWLduHX74wx/iuuuuw6c//Wl885vfBLB8z9diWHKlHI7lpVIOL+GcM7HlzHLu3yc/+Uk8+eST+PGPf2w+W479OvPMM/HEE09gamoK3/rWt3DNNddg9+7dc58vtz7t378f119/PR544AGkUinvcsutX5dddtnc/5977rm46KKLcPrpp2PHjh14+9vfDmD59Qk4WkftwgsvxLZt2wAAb3nLW/D000/j9ttvx3/8j/9xbrnl2LdXYkk+CfX19SEajZoZfnR01HwTWI68pOZZrv371Kc+hfvuuw//+I//OK9q4nLuVyKRwBve8AZceOGF2L59O84//3x85StfWbZ9evzxxzE6OooLLrgAsVgMsVgMu3fvxl//9V8jFovNtX259WshHR0dOPfcc/Hss88u23MFAENDQzjrrLPmxd70pjfhhRdeALC8r61XYklOQolEAhdccAF27do1L75r1y5s2LAhpFa9dqxduxaDg4Pz+ler1bB79+4l3T/nHD75yU/i29/+Nh588EGsXbt23ufLtV8M5xyq1eqy7dPFF1+Mp556Ck888cTc34UXXoirr74aTzzxBE477bRl2a+FVKtV/PrXv8bQ0NCyPVcA8I53vMO87vCb3/wGa9asAXBiXVuGsBQRr8RLEu1vfOMb7plnnnE33HCD6+jocM8991zYTVsU09PT7pe//KX75S9/6QC4W2+91f3yl7+ck5h/+ctfdvl83n372992Tz31lPvQhz605OWWH//4x10+n3cPPfTQPIlsqVSaW2Y59uumm25yDz/8sNu3b5978skn3ec+9zkXiUTcAw884Jxbnn1iHKuOc2559uu//Jf/4h566CG3d+9e9+ijj7orrrjCZbPZufvCcuyTc0dl9LFYzP35n/+5e/bZZ93//t//22UyGfd3f/d3c8ss1769Ekt2EnLOua997WtuzZo1LpFIuLe+9a1zUuDlwD/+4z86AObvmmuucc4dlVx+4QtfcIODgy6ZTLp3v/vd7qmnngq30a8A6w8Ad/fdd88tsxz79Z/+03+aG2f9/f3u4osvnpuAnFuefWIsnISWY79eejcmHo+74eFhd+WVV7qnn3567vPl2KeX+N73vufOOeccl0wm3Rvf+EZ3xx13zPt8Offt96F6QkIIIUJjSeaEhBBCnBxoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExv8HAWDS0eDRYOQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for i in range(10):\n", + " indices = np.where(labels == i)[0][0]\n", + " \n", + " i_data = images[indices, :, :, 0] # first band\n", + " r_data = images[indices, :, :, 1] # second band\n", + " g_data = images[indices, :, :, 2] # third band\n", + "\n", + " rgb = make_lupton_rgb(i_data, r_data, g_data,\n", + " minimum=0, Q=6, stretch=50) # Bonus Q: how does changing these paramters change the images?\n", + "\n", + "\n", + "\n", + " plt.imshow(rgb) # what goes here?\n", + " plt.title('Class {}'.format(i))\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "be79fcf8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 28, 32, 35, ..., 21768, 21769, 21775]),)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.where(labels == 0)" + ] + }, + { + "cell_type": "markdown", + "id": "5645ec49", + "metadata": {}, + "source": [ + "### Part 1: Principal Components and the Singular Value Decomposition\n", + "\n", + "Can we distinguish galaxy types based on their PCA components? Let's find out! Let's attempt to distinguish between smooth and round objects in Class 1 from the boxy and edge on spirals in Class 4. Start by using the tools you wrote above to visualize an example from each class." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1be9403c", + "metadata": {}, + "outputs": [], + "source": [ + "# class 1 visualization" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "31d51e06", + "metadata": {}, + "outputs": [], + "source": [ + "# class 4 visualization" + ] + }, + { + "cell_type": "markdown", + "id": "3073153e", + "metadata": {}, + "source": [ + "Now perform the singular value decomposition using the numpy implementation. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "13ed3ae5", + "metadata": {}, + "outputs": [], + "source": [ + "# first, what does the SVD take as arguments and, in terms of the PCA framework, what does it return? \n", + "# Answer in the provided markdown cell below. " + ] + }, + { + "cell_type": "markdown", + "id": "c5e400cd", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "2adcacec", + "metadata": {}, + "outputs": [], + "source": [ + "# Now, you may have noticed that our image array isn't structured in such a way that we can perform PCA \n", + "# on it directly.\n", + "# What shape should the image array have, use np.reshape to reshape the array.\n", + "indices = np.where(labels == 0)[0]\n", + " \n", + "images_of_class = images[indices][:, :, :, 0] #fill this in for the class you want to compute the PCA for\n", + "images_of_class_mean_subtracted = images_of_class - images_of_class.mean(axis=0)# recenter\n", + "images_reshape = images_of_class_mean_subtracted.reshape(-1, 69**2) # what shape should this have?" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "1fc8982f", + "metadata": {}, + "outputs": [], + "source": [ + "# perform the SVD \n", + "\n", + "U, S, Vh = np.linalg.svd(images_reshape)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "fe18023e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCw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Y2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od+LqS6PX1dfzHf/zH+Od//udxd3f3u+u08f9BHA6H8Z//+Z/j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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot the Principal components\n", + "\n", + "h, w = 69, 69\n", + "\n", + "def plot_gallery(images, h, w, n_row=3, n_col=4):\n", + " \"\"\"Helper function to plot a gallery of portraits \n", + " #from sklearn documentation\"\"\"\n", + " plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))\n", + " plt.subplots_adjust(bottom=0, left=0.01, right=0.99, top=0.90, hspace=0.35)\n", + " for i in range(n_row * n_col):\n", + " plt.subplot(n_row, n_col, i + 1)\n", + " plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)\n", + " plt.xticks(())\n", + " plt.yticks(())\n", + " \n", + "plot_gallery(Vh, h, w)" + ] + }, + { + "cell_type": "markdown", + "id": "b4bcb12c", + "metadata": {}, + "source": [ + "### Part 2: Practicing with the Scikit-learn Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a797997", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.decomposition import PCA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6be6ca31", + "metadata": {}, + "outputs": [], + "source": [ + "X_train = " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e857846", + "metadata": {}, + "outputs": [], + "source": [ + "n_components = \n", + "\n", + "pca = PCA().fit()\n", + "\n", + "eigengalaxies = pca.components_.reshape(())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95e031be", + "metadata": {}, + "outputs": [], + "source": [ + "plot_gallery()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8cf3e8a", + "metadata": {}, + "outputs": [], + "source": [ + "# pca.transform() will provide the appropriate weights for each principal component. \n", + "# write a loop or a vectorized computation to sum over the principal components and reconstruct \n", + "# an image of a given galaxy (perhaps the one at index 10, or pick your favorite). \n", + "\n", + "reconstruction = \n", + "\n", + "for i in range():\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "36d5e667", + "metadata": {}, + "source": [ + "## Problem 2: t-distributed Stochastic Neighbor Embedding" + ] + }, + { + "cell_type": "markdown", + "id": "a4a10ec3", + "metadata": {}, + "source": [ + "Begin by reading in the supplied cosmos 2020 28 band photometry. Print out the catalog and some summary statistics. Make sure you understand the structure of the supplied data file, and check that it has been cleaned of anamolous values (for example, -99 is often used as a flag value, and many data files contain NaNs). " + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "cfefbe51", + "metadata": {}, + "outputs": [], + "source": [ + "cosmos_2020 = pd.read_csv('cosmos_2020_28_band.csv', index_col = 0)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "632d88da", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Int64Index: 499 entries, 11 to 9998\n", + "Data columns (total 29 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 GALEX_NUV 499 non-null float64\n", + " 1 GALEX_FUV 499 non-null float64\n", + " 2 IRAC_CH1 499 non-null float64\n", + " 3 IRAC_CH2 499 non-null float64\n", + " 4 IRAC_CH3 499 non-null float64\n", + " 5 IRAC_CH4 499 non-null float64\n", + " 6 IB427 499 non-null float64\n", + " 7 IB464 499 non-null float64\n", + " 8 IA484 499 non-null float64\n", + " 9 IB505 499 non-null float64\n", + " 10 IA527 499 non-null float64\n", + " 11 IB574 499 non-null float64\n", + " 12 IA624 499 non-null float64\n", + " 13 IA679IB709 499 non-null float64\n", + " 14 IA738 499 non-null float64\n", + " 15 IA767 499 non-null float64\n", + " 16 IB827 499 non-null float64\n", + " 17 NB711 499 non-null float64\n", + " 18 NB816 499 non-null float64\n", + " 19 Y 499 non-null float64\n", + " 20 J 499 non-null float64\n", + " 21 H 499 non-null float64\n", + " 22 Ks 499 non-null float64\n", + " 23 NB118g 499 non-null float64\n", + " 24 r 499 non-null float64\n", + " 25 i 499 non-null float64\n", + " 26 z 499 non-null float64\n", + " 27 hsc_y 499 non-null float64\n", + " 28 redshift 499 non-null float64\n", + "dtypes: float64(29)\n", + "memory usage: 117.0 KB\n" + ] + } + ], + "source": [ + "cosmos_2020.info(verbose=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "ce8fd5ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.isnull().values.any()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f99cf5b5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['GALEX_NUV', 'GALEX_FUV', 'IRAC_CH1', 'IRAC_CH2', 'IRAC_CH3',\n", + " 'IRAC_CH4', 'IB427', 'IB464', 'IA484', 'IB505', 'IA527', 'IB574',\n", + " 'IA624', 'IA679IB709', 'IA738', 'IA767', 'IB827', 'NB711', 'NB816', 'Y',\n", + " 'J', 'H', 'Ks', 'NB118g', 'r', 'i', 'z', 'hsc_y', 'redshift'],\n", + " dtype='object')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0277e0ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GALEX_NUV 0\n", + "GALEX_FUV 0\n", + "IRAC_CH1 0\n", + "IRAC_CH2 0\n", + "IRAC_CH3 0\n", + "IRAC_CH4 0\n", + "IB427 0\n", + "IB464 0\n", + "IA484 0\n", + "IB505 0\n", + "IA527 0\n", + "IB574 0\n", + "IA624 0\n", + "IA679IB709 0\n", + "IA738 0\n", + "IA767 0\n", + "IB827 0\n", + "NB711 0\n", + "NB816 0\n", + "Y 0\n", + "J 0\n", + "H 0\n", + "Ks 0\n", + "NB118g 0\n", + "r 0\n", + "i 0\n", + "z 0\n", + "hsc_y 0\n", + "redshift 0\n", + "dtype: int64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(cosmos_2020==-99).sum()" + ] + }, + { + "cell_type": "markdown", + "id": "c42f145e", + "metadata": {}, + "source": [ + "For this part, we will use the built in TSNE methods in the sci-kit learn package. These are located in sklearn-manifold (many dimensionality reduction techniques are examples of manifold learning). " + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "edf3df4a", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.manifold import TSNE" + ] + }, + { + "cell_type": "markdown", + "id": "3ec63480", + "metadata": {}, + "source": [ + "Next, define a dictionary object to contain the TSNE object and it's hyperparameters. The one we will focus on, in particular, is the perplexity. For now, set the perplexity to a reasonable value between 5 and 50. " + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "56d8abf6", + "metadata": {}, + "outputs": [], + "source": [ + "tSNE = TSNE(\n", + " perplexity = 1, #10,\n", + " n_components=2,\n", + " n_iter=2000,\n", + " n_iter_without_progress=200,\n", + " n_jobs=2,\n", + " random_state=0,\n", + " init = 'pca',\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "204998cf", + "metadata": {}, + "source": [ + "Our goal here is to see how well tSNE can visualize class separations between objects at different redshifts. As such, we will need to generate a labels data vector to use with our tSNE embedding. As you may have noticed, the redshift values in the catalog have already been binned for you. As such, the labels are contained in the redshift column of the cosmos 2020 catalog. Define a labels data series. \n", + "\n", + "After doing that, you'll want to drop the redshift column from your data vector so that tSNE isn't using redshift as a variable in its distance calculations." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "b0b93518", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GALEX_NUVGALEX_FUVIRAC_CH1IRAC_CH2IRAC_CH3IRAC_CH4IB427IB464IA484IB505...NB816YJHKsNB118grizhsc_y
1124.36566824.63376122.92256825.19005625.04441826.42434525.06069424.98783324.93393925.170378...23.82532423.71949423.72093423.64277923.45764724.96764124.50982923.99010423.89099623.821889
3125.70582725.54770824.42263523.22081426.11355726.45966925.73852125.79411625.87129626.348288...25.20818324.75626924.95086825.24721724.86166025.93265425.71496325.53674125.55678725.168275
7222.57134022.50566821.59079723.03950923.87523323.79239123.63201023.59239823.32745323.048386...22.16460022.07278522.02619521.84618522.17277223.60020222.69758122.48269022.29923522.055720
8423.08802823.37202122.87216723.47821324.51750624.56366424.40577724.40329224.31450924.345500...23.08294223.26832223.27516923.01324723.44322124.31734324.15955623.76854623.45740423.309568
11224.88454024.80420422.67995422.98547626.30096325.71145025.90009526.53122425.92620025.554514...24.71601824.82849224.69724124.64009625.18362325.91398325.65620825.51024924.90704624.635006
..................................................................
994821.54630221.48329721.15680022.85840224.14822223.73110723.72283523.63130823.80832623.855400...22.52593122.09394221.91851621.74305122.31267023.78371323.56657523.30885223.06925922.824249
995123.47820123.40399323.32254122.52947524.97645225.26048224.89649825.05757025.05242024.949639...23.94570023.70519223.48932623.49633423.58939325.03907924.82444824.72459824.35013023.974294
997022.42308022.38833922.80758123.13148927.28687727.58958826.96904629.02020326.92122626.769342...24.32830723.71996423.10931022.75796923.38122026.95863326.70538825.86653825.26083424.573256
998025.90605426.34628922.83831922.59948926.46959026.56336926.55927826.07877727.00908727.415417...26.45111125.74856825.69602325.92146425.98797926.72234526.67700226.79140027.04230326.607488
999822.80175022.59989122.49645522.67040726.18290426.75688526.06553425.64663925.49045225.502780...24.67887823.89053523.55524423.19699223.88010025.76134525.47913625.16340724.89527824.832618
\n", + "

499 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " GALEX_NUV GALEX_FUV IRAC_CH1 IRAC_CH2 IRAC_CH3 IRAC_CH4 \\\n", + "11 24.365668 24.633761 22.922568 25.190056 25.044418 26.424345 \n", + "31 25.705827 25.547708 24.422635 23.220814 26.113557 26.459669 \n", + "72 22.571340 22.505668 21.590797 23.039509 23.875233 23.792391 \n", + "84 23.088028 23.372021 22.872167 23.478213 24.517506 24.563664 \n", + "112 24.884540 24.804204 22.679954 22.985476 26.300963 25.711450 \n", + "... ... ... ... ... ... ... \n", + "9948 21.546302 21.483297 21.156800 22.858402 24.148222 23.731107 \n", + "9951 23.478201 23.403993 23.322541 22.529475 24.976452 25.260482 \n", + "9970 22.423080 22.388339 22.807581 23.131489 27.286877 27.589588 \n", + "9980 25.906054 26.346289 22.838319 22.599489 26.469590 26.563369 \n", + "9998 22.801750 22.599891 22.496455 22.670407 26.182904 26.756885 \n", + "\n", + " IB427 IB464 IA484 IB505 ... NB816 Y \\\n", + "11 25.060694 24.987833 24.933939 25.170378 ... 23.825324 23.719494 \n", + "31 25.738521 25.794116 25.871296 26.348288 ... 25.208183 24.756269 \n", + "72 23.632010 23.592398 23.327453 23.048386 ... 22.164600 22.072785 \n", + "84 24.405777 24.403292 24.314509 24.345500 ... 23.082942 23.268322 \n", + "112 25.900095 26.531224 25.926200 25.554514 ... 24.716018 24.828492 \n", + "... ... ... ... ... ... ... ... \n", + "9948 23.722835 23.631308 23.808326 23.855400 ... 22.525931 22.093942 \n", + "9951 24.896498 25.057570 25.052420 24.949639 ... 23.945700 23.705192 \n", + "9970 26.969046 29.020203 26.921226 26.769342 ... 24.328307 23.719964 \n", + "9980 26.559278 26.078777 27.009087 27.415417 ... 26.451111 25.748568 \n", + "9998 26.065534 25.646639 25.490452 25.502780 ... 24.678878 23.890535 \n", + "\n", + " J H Ks NB118g r i \\\n", + "11 23.720934 23.642779 23.457647 24.967641 24.509829 23.990104 \n", + "31 24.950868 25.247217 24.861660 25.932654 25.714963 25.536741 \n", + "72 22.026195 21.846185 22.172772 23.600202 22.697581 22.482690 \n", + "84 23.275169 23.013247 23.443221 24.317343 24.159556 23.768546 \n", + "112 24.697241 24.640096 25.183623 25.913983 25.656208 25.510249 \n", + "... ... ... ... ... ... ... \n", + "9948 21.918516 21.743051 22.312670 23.783713 23.566575 23.308852 \n", + "9951 23.489326 23.496334 23.589393 25.039079 24.824448 24.724598 \n", + "9970 23.109310 22.757969 23.381220 26.958633 26.705388 25.866538 \n", + "9980 25.696023 25.921464 25.987979 26.722345 26.677002 26.791400 \n", + "9998 23.555244 23.196992 23.880100 25.761345 25.479136 25.163407 \n", + "\n", + " z hsc_y \n", + "11 23.890996 23.821889 \n", + "31 25.556787 25.168275 \n", + "72 22.299235 22.055720 \n", + "84 23.457404 23.309568 \n", + "112 24.907046 24.635006 \n", + "... ... ... \n", + "9948 23.069259 22.824249 \n", + "9951 24.350130 23.974294 \n", + "9970 25.260834 24.573256 \n", + "9980 27.042303 26.607488 \n", + "9998 24.895278 24.832618 \n", + "\n", + "[499 rows x 28 columns]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.drop(columns='redshift')" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "6351c4ce", + "metadata": {}, + "outputs": [], + "source": [ + "labels = cosmos_2020['redshift']\n", + "new_data = cosmos_2020.drop(columns='redshift')" + ] + }, + { + "cell_type": "markdown", + "id": "d1096106", + "metadata": {}, + "source": [ + "In sklearn, we use the fit_transform method to simultaneously fit and apply the learned transformation to the data. Since this is an unsupervised problem, this is as straightforward as providing the fit_transform method the data and a labels vector. " + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "16bd2cee", + "metadata": {}, + "outputs": [], + "source": [ + "tSNE = TSNE(\n", + " perplexity = 5, #10,\n", + " n_components=2,\n", + " n_iter=2000,\n", + " n_iter_without_progress=200,\n", + " n_jobs=2,\n", + " random_state=0,\n", + " init = 'pca',\n", + " )\n", + "tSNE_map = tSNE.fit_transform(new_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "c5b1e3c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(499, 2)" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tSNE_map.shape" + ] + }, + { + "cell_type": "markdown", + "id": "a3f02e34", + "metadata": {}, + "source": [ + "We can then plot the 2D representation of the labelled 28D photometric space. " + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "e9ee41e3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x, y = tSNE_map[:, 0], tSNE_map[:, 1]\n", + "colormap = ['r', 'b', 'g', 'y', 'm', 'k', 'c']\n", + "\n", + "#labels = \n", + "\n", + "for i,label in enumerate(labels.unique()):\n", + " indices = np.where(labels==label)\n", + " plt.scatter(x[indices], y[indices], c=colormap[i], label='z={:.2f}'.format(label))\n", + "plt.legend(loc = 'best') " + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "6d5f83aa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.1 , 1. , 2. , 1.5 , 3. , 2.5 , 0.01])" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "labels.unique()" + ] + }, + { + "cell_type": "markdown", + "id": "920fdd41", + "metadata": {}, + "source": [ + "Finally, repeat this exercise for different values of the perplexity. How does changing the perplexity change your 2D map?\n", + "\n", + "What other - perhaps unstated - hyperparameter choice impacts your ability to do the class separation or interpret your 2D map? If this were a problem to come up in your research, how might you use your knowledge of the photometry and galaxy SEDs to improve the class separation in the 2D SNE plane?" + ] + }, + { + "cell_type": "markdown", + "id": "582b93f0", + "metadata": {}, + "source": [ + "## [Optional] Challenge Problem: Implementing your own SOM\n", + "\n", + "(Very rough) pseudo code for a SOM implementation is provided below: \n", + "\n", + "$\\textit{If you attempt this exercise, please provide feedback as this is intended as a problem for a future session.}$" + ] + }, + { + "cell_type": "raw", + "id": "f3437087", + "metadata": {}, + "source": [ + "Convenience functions: \n", + "\n", + "distance:\n", + " given two data points, compute the distance\n", + "\n", + "best_matching_unit:\n", + " for a given data point:\n", + " Compute all distances to cells in the SOM\n", + " update the shortest distance\n", + " return shortest distance\n", + "\n", + "decay: \n", + " for a given step in the training:\n", + " adjust neighborhood size and learning rate to ensure convergence\n", + "\n", + "Training routine:\n", + "For each step in the training: \n", + " update the hyperparameters (learning_rate, neighborhood size)\n", + " Pick a random data point \n", + " determine the winning cell in the SOM (closest match to the data)\n", + " for all points near the winner, move them closer" + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "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.8.17" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/day1/.ipynb_checkpoints/Introduction_to_ML_tutorial_no_solutions-checkpoint.ipynb b/day1/.ipynb_checkpoints/Introduction_to_ML_tutorial_no_solutions-checkpoint.ipynb new file mode 100644 index 0000000..9b1af58 --- /dev/null +++ b/day1/.ipynb_checkpoints/Introduction_to_ML_tutorial_no_solutions-checkpoint.ipynb @@ -0,0 +1,544 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "75dba511", + "metadata": {}, + "source": [ + "# Tutorial for Introduction to ML Lecture\n", + "\n", + "version 0.1, September 2023\n", + "\n", + "Bryan Scott, CIERA/Northwestern" + ] + }, + { + "cell_type": "markdown", + "id": "c73c6b0f", + "metadata": {}, + "source": [ + "## Problem 1: Bayes Classifiers" + ] + }, + { + "cell_type": "markdown", + "id": "07842041", + "metadata": {}, + "source": [ + "A good starting point for Machine Learning is the Bayes classifier. The basic idea is to assign the most probable label to each data point using Bayes theorem, we take:\n", + "\n", + "$$\n", + "p(y | x_n) \\propto p(y)p(x_i, ..., x_n | y)\n", + "$$\n", + "\n", + "where y is a label for a data point and the $x_n$ are the features of the data that we want to use to classify each data point. A $\\textit{Naive} Bayes$ classifier makes an important simplifying assumptions that gives it the name - it assumes that the conditional probabilities are independent, $p(x_i, ..., x_n | y) = p(x_i|y)... p(x_n | y)$. That is, the probability of observing any individual feature doesn't depend on any of the other features. Our task is to construct this classifier from a set of examples we've observed previously and compare it to new data. " + ] + }, + { + "cell_type": "markdown", + "id": "40084db8", + "metadata": {}, + "source": [ + "### Part 0: Load and split the data" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5a1d0a57", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/aizhanakhmetzhanova/opt/anaconda3/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5\n", + " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from scipy.stats import norm\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e543f3b7", + "metadata": {}, + "outputs": [], + "source": [ + "#lsst_data[0:1000].to_csv('session_19_DC2_subset.csv')" + ] + }, + { + "cell_type": "markdown", + "id": "3c682ccc", + "metadata": {}, + "source": [ + "### Loading and splitting the data. \n", + "\n", + "Read in the data, then start by selecting the id, fluxes, and object truth type in the lsst data file you've been provided. \n", + "\n", + "Once you have selected those, randomly split the data into two arrays, one containing 80% of the data, and a second array containing 20% of the data. " + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "94094b3b", + "metadata": {}, + "outputs": [], + "source": [ + "lsst_data = pd.read_csv('simulated_extragalactic_data.csv') #path to your data\n", + "\n", + "lsst_data_to_classify = lsst_data[['id', 'flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z', 'truth_type']]\n", + "lsst_data_to_classify = lsst_data_to_classify[~(lsst_data_to_classify['truth_type'] == 3)]\n", + "#random_data = \n", + "\n", + "train_data = lsst_data_to_classify.sample(frac = 0.8)\n", + "test_data = lsst_data_to_classify.drop(train_data.index)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "491088f8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2])" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lsst_data_to_classify['truth_type'].unique()" + ] + }, + { + "cell_type": "markdown", + "id": "99f2de21", + "metadata": {}, + "source": [ + "### Part 1: Estimate Class Frequency in the training set\n", + "\n", + "One of the ingredients in our classifier is p(y), the unconditional class probabilities. \n", + "\n", + "We can get this by counting the number of rows belonging to each class in train_data and dividing by the length of the training data set. " + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "0186b8f1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.8320802005012531 0.16791979949874686\n" + ] + } + ], + "source": [ + "def estimate_class_probabilities(x_train):\n", + " \"\"\"\n", + " Computes unconditional class probabilities. \n", + " \n", + " Args:\n", + " x_train (array): training data for the classifier\n", + " \n", + " Returns:\n", + " ints p1, p2: unconditional probability of an element of the training set belonging to class 1\n", + " \"\"\"\n", + " len_dset = x_train.shape[0]\n", + " p1 = (x_train['truth_type']==1).sum()/len_dset\n", + " p2 = (x_train['truth_type']==2).sum()/len_dset\n", + " return p1, p2\n", + "\n", + "p1, p2 = estimate_class_probabilities(train_data)\n", + "print(p1, p2)" + ] + }, + { + "cell_type": "markdown", + "id": "ca1aa268", + "metadata": {}, + "source": [ + "### Part 2: Feature Likelihoods\n", + "\n", + "We are assuming that the relationship between the classes and feature probabilities are related via:\n", + "\n", + "$p(x_i, ..., x_n | y) = p(x_i|y)... p(x_n | y)$\n", + "\n", + "however, we still need to make an assumption about the functional form of the $p(x_i | y)$. As a simple case, we will assume $p(x_i | y)$ follows a Gaussian distribution given by:\n", + "\n", + "$$\n", + "p(x_i | y) = \\frac{1}{\\sqrt{2 \\pi \\sigma_y}} \\exp{\\left(-\\frac{(x_i - \\mu)^2}{\\sigma_y^2}\\right)}\n", + "$$\n", + "\n", + "and we will make a maximum likelihood estimate of $\\mu$ and $\\sigma_y$ from the data. This means using empirical estimates $\\bar{x}$ and $\\hat{\\sigma}$ as estimators of the true parameters $\\mu$ and $\\sigma_y$. \n", + "\n", + "Write a fitting function that takes the log of the fluxes and returns an estimate of the parameters of the per-feature likelihoods for each class." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "609b65b7", + "metadata": {}, + "outputs": [], + "source": [ + "def per_feature_likelihood_parameters(x_train, label):\n", + " \"\"\"\"\n", + " Computes MAP estimates for the class conditional likelihood. \n", + " \n", + " Args:\n", + " x_train (array or pd series): training data for the classifier\n", + " label (int): training labels for the classifier \n", + " \n", + " Returns:\n", + " means, stdevs (array): MAP estimates of the Gaussian conditional probability distributions for a specific class\n", + " \"\"\"\n", + " #x_train_class = train_data.loc[train_data['truth_type'] == label]\n", + " #means = x_train_class.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']].mean()\n", + " #stdevs = x_train_class.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']].std()\n", + " \n", + " means = np.log(train_data.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]).mean()\n", + " stdevs = np.log(train_data.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]).std()\n", + " \n", + " return means, stdevs\n" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "90590520", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 6.971252\n", + "flux_i 8.307006\n", + "flux_r 7.761517\n", + "flux_u 5.278125\n", + "flux_y 8.661954\n", + "flux_z 8.542979\n", + "dtype: float64" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "per_feature_likelihood_parameters(train_data, 2)[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "12289872", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 3.569217\n", + "flux_i 3.220594\n", + "flux_r 3.387434\n", + "flux_u 3.922922\n", + "flux_y 3.135953\n", + "flux_z 3.160724\n", + "dtype: float64" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "per_feature_likelihood_parameters(train_data, 2)[1]" + ] + }, + { + "cell_type": "markdown", + "id": "16dbeb61", + "metadata": {}, + "source": [ + "### Part 3: MAP Estimates of the Class Probabilities\n", + "\n", + "Now that we have the unconditional class probabilities and the parameters of the per feature likelihoods in hand, we can put this all together to build the classifier. Use the methods you have already written to write a function that takes in the training data and returns fit parameters. Once you have done that, write a method that takes the fit parameters as an argument and predicts the class of new (and unseen) data. " + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "05a17f4d", + "metadata": {}, + "outputs": [], + "source": [ + "# build the classifier\n", + "\n", + "# solved \n", + "\n", + "def fit(x_train):\n", + " \"\"\"\"\n", + " Convenience function to perform fitting on the training data\n", + " \n", + " Args:\n", + " x_train (array or pd series): training data for the classifier\n", + " \n", + " Returns:\n", + " p1, p2, class_1_mean, class_2_mean, class_1_std, class_2_std: see documentation for per_feature_likelihood_parameters\n", + " \"\"\"\n", + " \n", + " # compute probabilities and MAP estimates of the Gaussian distribution's parameters using the methods you wrote above\n", + " p1, p2 = estimate_class_probabilities(x_train)\n", + " \n", + " class_1_mean, class_1_std = per_feature_likelihood_parameters(x_train, 1)\n", + " class_2_mean, class_2_std = per_feature_likelihood_parameters(x_train, 2)\n", + " return p1, p2, class_1_mean, class_2_mean, class_1_std, class_2_std\n" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "9d3c7074", + "metadata": {}, + "outputs": [], + "source": [ + " p1, p2, class_1_mean, class_2_mean, class_1_std, class_2_std = fit(train_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "a9015d0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 3.175449\n", + "flux_i 3.753061\n", + "flux_r 3.482477\n", + "flux_u 2.768780\n", + "flux_y 4.096621\n", + "flux_z 3.942157\n", + "dtype: float64" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "class_1_mean" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "8c0aec66", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 0.017422\n", + "15 0.033539\n", + "19 0.032811\n", + "22 -0.000089\n", + "23 0.005145\n", + " ... \n", + "988 2.062806\n", + "990 1387.455468\n", + "995 0.133647\n", + "996 -0.005612\n", + "998 0.057714\n", + "Length: 200, dtype: float64" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.product((np.log(test_data[['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]) - class_1_mean)/class_1_std, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "id": "01867cba", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def predict(x_test, class_probability, class_means, class_dev):\n", + " \"\"\"\"\n", + " Predict method\n", + " \n", + " Args:\n", + " x_test (array): data to perform classification on\n", + " class_probability (array): unconditional class probabilities\n", + " class_means, class_dev (array): MAP estimates produced by the fit method\n", + " \n", + " Returns:\n", + " predict_List (list): class membership predictions\n", + " \"\"\"\n", + " x_test = np.log(x_test[['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']])\n", + " class_1_mean = class_means[0]\n", + " class_2_mean = class_means[1]\n", + " \n", + " class_1_std = class_dev[0]\n", + " class_2_std = class_dev[1]\n", + " \n", + " # compute probabilities of an element of the test set belonging to class 1 or 2\n", + " likelihood_1 = np.exp(-(x_test - class_1_mean)**2/class_1_std**2)/np.sqrt(2*np.pi)/class_1_std\n", + " posterior_1 = np.array(class_probability[0]*np.product(likelihood_1, axis=1))\n", + " \n", + " likelihood_2 = np.exp(-(x_test - class_2_mean)**2/class_2_std**2)/np.sqrt(2*np.pi)/class_2_std\n", + " posterior_2 = np.array(class_probability[1]*np.product(likelihood_2, axis=1))\n", + " #print(posterior_1 > posterior_2)\n", + " predict_list = []\n", + " for i in range(len(x_test)):\n", + " if posterior_1[i] > posterior_2[i]:\n", + " predict_list.append(1)\n", + " else:\n", + " predict_list.append(2)\n", + " \n", + " return predict_list" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "4e28f694", + "metadata": {}, + "outputs": [], + "source": [ + "predict_list = predict(test_data, [p1, p2], [class_1_mean,class_2_mean] , [class_1_std, class_2_std])" + ] + }, + { + "cell_type": "markdown", + "id": "8067d9e3", + "metadata": {}, + "source": [ + "### Part 4: Metrics\n", + "\n", + "After creating a classifier, you now want to evaluate it in terms of how often it correctly and incorrectly classifies the objects in your training set. To do this, we'll design a confusion matrix. A confusion matrix is a matrix whose entries are the counts of the predicted vs actual class. For example, the first entry is the count of objects that are predicted to be of class 1 and actually are of class 1 and so on, while the off-diagonal elements would be instances of class 1 that are predicted to be of class 2, and instances of class 2 that are predicted to be of class 1. " + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "a366c561", + "metadata": {}, + "outputs": [], + "source": [ + "def plot_confusion_matrix(df_confusion, cmap=):\n", + " \"\"\"\n", + " \n", + " Convenience function to plot the confusion matrix from a pd.crosstab object. Hint: use plt.matshow and choose a sensible color map.\n", + " \n", + " Args:\n", + " df_confusion (pd.crosstab): A pd.crosstab object.\n", + " \n", + " Returns:\n", + " null \n", + " \"\"\"\n", + " \n", + " \n", + " plt.matshow()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "id": "4d98198f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "176" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(np.array(predict_list) == np.array(test_data[['truth_type']]).reshape(200,)).sum()" + ] + }, + { + "cell_type": "markdown", + "id": "cb4c8763", + "metadata": {}, + "source": [ + "## Problem 2: The Cramer-Rao bound (pen & paper, challenging, optional)\n", + "\n", + "As we saw in the lecture, the Cramer-Rao bound is an important result in statistics that has intuitive consequences for many applied problems in ML. The proof of the Cramer-Rao bound can be insightful to work through. \n", + "\n", + "The starting point for the proof of the bound is the Cauchy-Schwarz inequality, which can be used to show that:\n", + "\n", + "$$\n", + "[Cov(U, V)]^2 \\le Var(U)Var(V)\n", + "$$\n", + "\n", + "Starting from the definitions that U = T(X), where T(X) is an estimator of some parameter $\\theta$ of the distribution $f(X|\\theta)$ from which the data is sampled, and V = $\\frac{\\partial}{\\partial \\theta} log f(X |\\theta)$. Use the Cauchy-Schwarz inequality to show the Cramer-Rao bound for these choices of U and V. \n", + "\n", + "$\\textit{Hint:}$ you will need the fact that the $\\mathbb{E}(V) = 0$, where $\\mathbb{E}$ is the expectation of a random variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1432f12", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/day1/Clustering.ipynb b/day1/Clustering.ipynb index 79453f5..b85989b 100644 --- a/day1/Clustering.ipynb +++ b/day1/Clustering.ipynb @@ -2,9 +2,8 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { - "editable": true, "slideshow": { "slide_type": "skip" }, @@ -21,7 +20,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -41,7 +39,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -56,7 +53,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -81,17 +77,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['setosa', 'versicolor', 'virginica'] ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']\n" + ] + }, + { + "data": { + "text/plain": [ + "dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from sklearn import datasets\n", "\n", - "iris = # complete" + "iris = datasets.load_iris() # complete\n", + "print(list(iris.target_names), list(iris.feature_names))\n", + "iris.keys()" ] }, { @@ -109,18 +125,1009 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'sepal width (cm)')" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "fig, ax = plt.subplots()\n", - "ax.scatter( # complete\n", - "# complete\n", - "# complete\n", + "ax.scatter(iris.data[:, 0], iris.data[:, 1]) # complete\n", + "ax.set_xlabel('sepal length (cm)')# complete\n", + "ax.set_ylabel('sepal width (cm)')# complete\n", "# complete" ] }, @@ -183,7 +1190,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -203,7 +1209,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -239,7 +1244,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "slide" @@ -247,7 +1252,7 @@ }, "outputs": [], "source": [ - "from sklearn.cluster import # complete" + "from sklearn.cluster import KMeans # complete" ] }, { @@ -265,19 +1270,1067 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { "slideshow": { "slide_type": "slide" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "KMeans(n_clusters=2)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Kcluster = KMeans(n_clusters=2) # complete\n", + "Kcluster.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, "outputs": [], "source": [ - "Kcluster = # complete\n", - "Kcluster.fit( # complete\n", - "\n", + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 50, 51, 52, 54, 56, 58, 62, 63, 65, 68, 71, 72, 73,\n", + " 74, 75, 76, 77, 78, 83, 85, 86, 87, 91, 97, 100, 102,\n", + " 103, 104, 105, 107, 108, 109, 110, 111, 112, 115, 116, 117, 118,\n", + " 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132,\n", + " 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146,\n", + " 147, 148]),)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.where(Kmeans_preds==0)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ "fig, ax = plt.subplots()\n", - "ax.scatter( # complete\n", + "\n", + "ax.scatter(iris.data[np.where(Kmeans_preds==0)[0], 0], iris.data[np.where(Kmeans_preds==0)[0], 1])\n", + "ax.scatter(iris.data[np.where(Kmeans_preds==1)[0], 0], iris.data[np.where(Kmeans_preds==1)[0], 1])\n", + "\n", + "# complete\n", "# complete\n", "# complete\n", "# complete" @@ -298,19 +2351,1003 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "Kcluster = # complete\n", - "# complete\n", + "k = 3\n", + "Kcluster = KMeans(n_clusters=k) # complete\n", + "Kcluster.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds = Kcluster.fit_predict(iris.data[:, :2])\n", "\n", "fig, ax = plt.subplots()\n", - "ax.scatter( # complete" + "for i in range(k):\n", + " ax.scatter(iris.data[np.where(Kmeans_preds==i)[0], 0], iris.data[np.where(Kmeans_preds==i)[0], 1])\n" ] }, { @@ -342,7 +3379,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -358,22 +3394,1007 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "rs = 19\n", - "Kcluster1 = KMeans( # complete\n", + "\n", + "Kcluster1 = KMeans(n_clusters=k, n_init=1,init='random', random_state=rs) # complete\n", + "Kcluster1.fit(iris.data[:, :2]) # complete\n", + "Kmeans_preds1 = Kcluster1.fit_predict(iris.data[:, :2])\n", "# complete\n", " \n", "fig, ax = plt.subplots()\n", - "ax.scatter( # complete" + "for i in range(k):\n", + " ax.scatter(iris.data[np.where(Kmeans_preds1==i)[0], 0], iris.data[np.where(Kmeans_preds1==i)[0], 1])\n", + "\n" ] }, { @@ -415,18 +4436,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5.84333333 3.05733333 3.758 1.19933333]\n", + "[0.82530129 0.43441097 1.75940407 0.75969263]\n", + "[4.3 2. 1. 0.1]\n", + "[7.9 4.4 6.9 2.5]\n" + ] + } + ], "source": [ - "# complete\n", - "# complete\n", - "# complete\n", - "# complete\n", + "print(iris.data.mean(axis=0)) # complete\n", + "print(iris.data.std(axis=0)) # complete\n", + "print(iris.data.min(axis=0)) # complete\n", + "print(iris.data.max(axis=0)) # complete\n", "# complete\n", "# complete" ] @@ -467,7 +4499,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -480,7 +4511,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -814,7 +4844,6 @@ { "cell_type": "markdown", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -842,7 +4871,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.9.7" }, "livereveal": { "height": 768, diff --git a/day1/DimensionalityReductionNoSolutions.ipynb b/day1/DimensionalityReductionNoSolutions.ipynb index ce2e91a..3195511 100644 --- a/day1/DimensionalityReductionNoSolutions.ipynb +++ b/day1/DimensionalityReductionNoSolutions.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "dae8731a", "metadata": {}, "outputs": [], @@ -53,13 +53,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "0eb43a93", "metadata": {}, "outputs": [], "source": [ "# To get the images and labels from file\n", - "with h5py.File('', 'r') as F: # your path goes here \n", + "with h5py.File('/Users/aizhanakhmetzhanova/Downloads/Galaxy10.h5', 'r') as F: # your path goes here \n", " images = np.array(F['images'])\n", " labels = np.array(F['ans'])\n", "\n", @@ -68,6 +68,48 @@ "images = images.astype(np.float32)" ] }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2b72fd14", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((21785,), (21785, 69, 69, 3))" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "labels.shape, images.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8e781977", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.unique(labels)" + ] + }, { "cell_type": "markdown", "id": "3b427dee", @@ -94,7 +136,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "8d38d8cc", "metadata": {}, "outputs": [], @@ -104,20 +146,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "efc0f0ff", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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AAAAgqHAAAAAABAMBQYAAACAYCgwAAAAAARDgQEAAAAgGAoMAAAAAMFQYAAAAAAIhgIDAAAAQDD79iTvxMJXP/1+T/vsGR2/OKt201Rr13MC5eamfur3YDCQsx7f813aSdbz8/rJtQPHKdY7gw05u7y8JGfNtNNrp0P9dNVKqZ/63XSsw7jUz2aumHYqce64saNYP0J5GulHjFYqWl/jqj5W1chxenCiZyvi6dxmZmWkXZeVYs6pUtXnIHKcjq0+qByHuZtN9cffNNYbLh0neavjNXGcEh/VHNeVj+RsafrxweoIRKV+XaVjciuue1GOWiyefN5o6M+kwvQ9tr+uP5MGpT63/d4FKXfN64/IbdbnFuXs88+flbNf//rTcjZJtNPEPe9GHp53vtxxPLcazTK9zVm8nvINBgAAAIBgXlOBcerUKYuiyG6//fa9n5VlaSdOnLAjR45Ys9m0m266yZ588snX2k8AAAAAV4FXXWA8+uij9olPfMLe9ra3XfTzu+66y+6++26799577dFHH7XV1VW7+eabrd/vv+bOAgAAANjfXlWBsbOzY+973/vsk5/8pC0sLOz9vCxLu+eee+zOO++02267za699lq7//77Lcsye+CBB4J1GgAAAMD+9KoKjA9/+MP24z/+4/ZjP/ZjF/38mWeesbW1Nbvlllv2flav1+3GG2+0Rx555BXbGo1G1uv1LvoFAAAA4Ork/lekHnzwQfvTP/1Te/TRR1/2e2tra2ZmtrKyctHPV1ZW7Bvf+MYrtnfq1Cn7t//233q7AQAAAGAfcn2DcebMGfvlX/5l+53f+R1rNBqXzEXf9E/ElWX5sp+95I477rBut7v368yZM54uAQAAANhHXN9gPPbYY7a+vm7vfOc79342mUzsi1/8ot177732ta99zcxe/Cbj8OHDe5n19fWXfavxknq9bvV6/dX0HQAAAMA+4/oG40d/9EftiSeesMcff3zv13XXXWfve9/77PHHH7c3velNtrq6aqdPn977/xmPx/bwww/bDTfcELzzAAAAAPYX1zcYrVbLrr322ot+Njc3Z0tLS3s/v/322+3kyZN2/PhxO378uJ08edLSNLX3vve94XoNAAAAYF9y/yXvy/nYxz5mg8HAPvShD9n29rZdf/319tBDD1mr1XK1s7m2ZZf4axsX8RzFbmJ0Vse7d7tdOTsL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "from astropy.visualization import make_lupton_rgb\n", "\n", - "i_data = images[14001, :, :, 0] # first band\n", - "r_data = images[14001, :, :, 1] # second band\n", - "g_data = images[14001, :, :, 2] # third band\n", + "i_data = images[14111, :, :, 0] # first band\n", + "r_data = images[14111, :, :, 1] # second band\n", + "g_data = images[14111, :, :, 2] # third band\n", "\n", - "rgb = make_lupton_rgb(), # fill this in - what band goes here?\n", - " ), # fill this in - what band goes here?\n", - " ), # fill this in - and finally what band goes here?\n", + "rgb = make_lupton_rgb(i_data, r_data, g_data,\n", " minimum=0, Q=6, stretch=50) # Bonus Q: how does changing these paramters change the images?\n", "\n", "fig, ax = plt.subplots(figsize=(8,8))\n", @@ -153,17 +204,152 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "bfdf3fcc", - "metadata": {}, - "outputs": [], + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABmZklEQVR4nO2dfZBc1Xnmn9vf3dM9PV/SzMhIWHYENggwH46CbEdyAdplMbteXHZisJd4ax2wsI3Wu4sjqLVFikgOSRGcsiMXrA3yJpT+WBsHr21ALoLYBLMmGAoMCcZBxkJoNJqvnpn+/jj7h8ygmfc50I3E3hnp+VVNlXT63HvPOffce/r2+9znDZxzDkIIIUQIRMJugBBCiJMXLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJC/Iann34an/rUp7B69WqkUilks1mcd955uPXWWzExMTFXb+PGjdi4cWN4DX0ddu/ejfe85z1IpVJYsWIFtmzZgtnZ2bCbJYSXWNgNEGIxcOedd2Lz5s04/fTT8d/+23/DGWecgXq9jn/8x3/EN77xDfzkJz/BvffeG3YzX5e/+Zu/wSc+8Qn8p//0n/AXf/EX+MUvfoEvfvGLeO655/Dggw+G3TwhKIG848TJzk9+8hN84AMfwCWXXILvfe97SCaT8z6v1Wq4//778W//7b8FgLmnoIcffvj/c0v9NJtNrFy5EmeddRYeeOCBufJ77rkHV111FX74wx/i0ksvDbGFQnD0c5w46dm+fTuCIMAdd9xhFiAASCQScwuQj5tvvhnr1q1DX18furu7cd555+Gb3/wmFn7He+ihh7Bx40b09/cjnU5j1apV+MhHPoJSqTRXZ+fOnTjnnHOQzWaRy+Xwrne9CzfeeOPrHv+xxx7DwYMH8alPfWpe+Uc/+lFks9lF/xQnTl70c5w4qWk2m3jooYdw/vnnY+XKlW96P7/61a9wzTXXYNWqVQCOLAqf+9zncODAAXzpS1+aq3PZZZfhAx/4AL71rW+hp6cHBw4cwP33349arYZMJoPdu3dj8+bN+NznPoc///M/RyQSwS9/+Us899xzr3v8n//85wCAs88+e155PB7Hu971rrnPhVhsaBESJzVjY2MolUpYvXr1Me3nrrvumvt3q9XCxo0b4ZzDV7/6Vfz3//7fEQQBnnjiCVQqFfzZn/0ZzjnnnLn6V1555dy//+Ef/gE9PT34y7/8y7myiy666A2PPz4+DgDo6+szn/X19eFXv/rVm+mWEG85+jlOiOPAQw89hIsvvhj5fB7RaBTxeBxf+tKXMD4+jtHRUQDAe97zHiQSCfzhH/4hdu3ahRdffNHs57d/+7cxNTWFj3/84/jbv/1bjI2NddSOIAg6KhcibLQIiZOagYEBZDIZ7Nu3703v46c//Sk2bdoE4IjK7h/+4R/w+OOP46abbgIAlMtlAMA73/lO/PjHP8by5ctx3XXX4Z3vfCfe+c534qtf/ercvj75yU/iW9/6Fl566SV85CMfwfLly7Fu3Trs2bPnddvQ398P4LUnoqOZmJigT0hCLAa0CImTmmg0iosuughPPPEEXn755Te1j927dyMej+N//+//jY997GNYv349LrjgAlr3Ax/4AL7//e+jUCjgsccew4UXXogtW7Zg9+7dc3U+9alP4dFHH0WhUMAPfvADOOfwoQ99CC+99JK3DWeddRYA4JlnnplX3mg08M///M9Yu3btm+qbEG81WoTESc/WrVvhnMOnP/1p1Go183m9Xsf3v/997/ZBECAWiyEajc6Vlctl/M//+T+920SjUaxbtw5f//rXAQA/+9nPTJ2uri5ceumluOmmm1Cr1fDss89697du3ToMDw/j7rvvnlf+v/7X/8Ls7CyuuOIK77ZChImECeKk58ILL8TOnTuxefNmnH/++fjMZz6DM888E/V6HU8++STuuOMOrF27Fpdffjnd/rLLLsNtt92GK6+8En/4h3+I8fFx/Pmf/7mRe3/jG9/AQw89hMsuuwyrVq1CpVLBt771LQDAxRdfDAD49Kc/jXQ6jfe9730YHh7GyMgIduzYgXw+j/e+973ePkSjUdx666345Cc/iWuuuQYf//jH8cILL+CGG27AJZdcgn/9r//1cRotIY4zTgjhnHPuqaeecldffbVbtWqVSyQSrqury5177rnuS1/6khsdHZ2rt2HDBrdhw4Z5237rW99yp59+uksmk+4d73iH27Fjh/vmN7/pALh9+/Y555z7yU9+4v79v//37tRTT3XJZNL19/e7DRs2uPvuu29uP7t27XIf/OAH3eDgoEskEm7FihXuYx/7mHv66afb6sM999zjzj77bJdIJNzQ0JD7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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABpE0lEQVR4nO2dfZBlZX3nv+fec+5r37493T3T3QMDjDiggPgCOmHUzFjKpFhw18WKUYxL3CojjhpYd5cEqZUxZWYMSVGY0mDBKozJUvPHKgbXqIxFHDZBVoJSIiQEw4jDS0/Tb7df7ts59z77x0gz3b/vI9285HTPfD9VXTXz3HPO83Kec5577u97vr/AOecghBBCpEAm7QYIIYQ4cdEiJIQQIjW0CAkhhEgNLUJCCCFSQ4uQEEKI1NAiJIQQIjW0CAkhhEgNLUJCCCFSQ4uQEEKI1NAiJMSv+OlPf4oPf/jD2Lx5MwqFAnp6evCmN70J119/PSYnJxe227FjB3bs2JFeQz187Wtfw/vf/36ceeaZyGQyOO2009JukhAvSJh2A4RYDdxyyy3YtWsXzjzzTPz3//7fcdZZZyGOY/zjP/4jvvzlL+OHP/wh7rjjjrSb+Wv5q7/6K4yOjuItb3kLut0u4jhOu0lCvCCBvOPEic4Pf/hDvP3tb8eFF16Ib37zm8jn84s+b7fb+O53v4t//+//PQAsPAX94Ac/+Ddu6a+n2+0ikzn648Yll1yCn/3sZ/jFL36RbqOEeAH0c5w44dmzZw+CIMDNN99sFiAAyOVyCwuQj89+9rPYunUr+vv70dvbize96U34yle+gqXf8e6++27s2LEDAwMDKBaLOOWUU/De974X9Xp9YZubbroJr3/969HT04NKpYLXvOY1+PSnP/2C/XhuARJiLaGf48QJTafTwd13343zzjsPmzZtetHH+cUvfoGPfvSjOOWUUwAA9913Hz75yU/iqaeewmc+85mFbS6++GK8/e1vx1e/+lX09fXhqaeewne/+120222USiXs378fu3btwic/+Un8+Z//OTKZDH7+85/jkUceeVn6K8RqQ4uQOKEZHx9HvV7H5s2bX9Jxbr311oV/d7td7NixA845fOELX8D/+B//A0EQ4IEHHkCz2cSf/dmf4fWvf/3C9pdddtnCv//hH/4BfX19+Iu/+IuFsne+850vqW1CrGb0/C7Ey8Ddd9+Nd73rXahWq8hms4iiCJ/5zGcwMTGBsbExAMAb3vAG5HI5/P7v/z727duHxx9/3BznLW95C6anp/GBD3wAf/M3f4Px8fF/664I8W+KFiFxQjM4OIhSqYRDhw696GP86Ec/ws6dOwEcVdn9wz/8A+6//35ce+21AIBGowEAOP300/H9738fGzZswMc//nGcfvrpOP300/GFL3xh4Vgf+tCH8NWvfhVPPPEE3vve92LDhg3YunUrDhw48BJ6KcTqRYuQOKHJZrN45zvfiQceeABPPvnkizrG/v37EUUR/s//+T943/veh23btuH888+n27797W/Ht771LdRqNdx333244IILcNVVV2H//v0L23z4wx/Gvffei1qthm9/+9twzuGSSy7BE0888aLaJ8RqRouQOOG55ppr4JzDRz7yEbTbbfN5HMf41re+5d0/CAKEYYhsNrtQ1mg08Fd/9VfefbLZLLZu3YovfelLAIAf//jHZptyuYyLLroI1157LdrtNh5++OGVdEuINYGECeKE54ILLsBNN92EXbt24bzzzsPHPvYxnH322YjjGD/5yU9w880345xzzsG73/1uuv/FF1+MG264AZdddhl+//d/HxMTE/jzP/9zI/f+8pe/jLvvvhsXX3wxTjnlFDSbTXz1q18FALzrXe8CAHzkIx9BsVjEW9/6VoyMjGB0dBR79+5FtVrFm9/85l/bj0ceeWRBRTc6Oop6vY7//b//NwDgrLPOwllnnfWSxkmIVwQnhHDOOffggw+6yy+/3J1yyikul8u5crns3vjGN7rPfOYzbmxsbGG77du3u+3bty/a96tf/ao788wzXT6fd6961avc3r173Ve+8hUHwB06dMg559wPf/hD9x//4390p556qsvn825gYMBt377d3XnnnQvH2bdvn3vHO97hhoaGXC6Xcxs3bnTve9/73E9/+tMXbP91113nANC/66677uUYIiFeduSYIIQQIjUUExJCCJEaWoSEEEKkhhYhIYQQqaFFSAghRGpoERJCCJEaWoSEEEKkxiv2supf/uVf4s/+7M/wzDPP4Oyzz8aNN96It7/97S+4X7fbxdNPP41KpYIgCF6p5gkhhHiFcM5hdnYWGzdufOE8V6/Ey0f79+93URS5W265xT3yyCPuyiuvdOVy2T3xxBMvuO/hw4e9L9zpT3/6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IYRIDS1CQgghUkOLkBBCiNRY1YvQX/7lX2Lz5s0oFAo477zz8H//7/9Nu0nL5p577sG73/1ubNy4EUEQ4Jvf/Oaiz51z2L17NzZu3IhisYgdO3bg4YcfTqexy2Tv3r1485vfjEqlgg0bNuA973kPHn300UXbrMV+3XTTTTj33HMX3ki/4IIL8J3vfGfh87XYp6Xs3bsXQRDgqquuWihbi/3avXs3giBY9Dc8PLzw+Vrs03M89dRT+N3f/V0MDAygVCrhDW94Ax544IGFz9dy334tbpWyf/9+F0WRu+WWW9wjjzzirrzySlcul90TTzyRdtOWxd/+7d+6a6+91n396193ANwdd9yx6PPPf/7zrlKpuK9//evuoYcecr/zO7/jRkZG3MzMTDoNXga/9Vu/5W699Vb3s5/9zD344IPu4osvdqeccoqbm5tb2GYt9uvOO+903/72t92jjz7qHn30UffpT3/aRVHkfvaznznn1mafjuVHP/qRO+2009y5557rrrzyyoXytdiv6667zp199tnumWeeWfgbGxtb+Hwt9sk55yYnJ92pp57qfu/3fs/9v//3/9yhQ4fc97//fffzn/98YZu12rcXYtUuQm95y1vcFVdcsajsNa95jfujP/qjlFr04lm6CHW7XTc8POw+//nPL5Q1m01XrVbdl7/85RRa+OIYGxtzANzBgwedc8dPv5xzbt26de5//s//ueb7NDs767Zs2eIOHDjgtm/fvrAIrdV+XXfdde71r389/Wyt9sk55/7wD//Qve1tb/N+vpb79kKsyp/j2u02HnjgAezcuXNR+c6dO3Hvvfem1KqXj0OHDmF0dHRR//L5PLZv376m+ler1QAA/f39AI6PfnU6Hezfvx/z8/O44IIL1nyfPv7xj+Piiy/Gu971rkXla7lfjz32GDZu3IjNmzfj/e9/Px5//HEAa7tPd955J84//3z89m//NjZs2IA3vvGNuOWWWxY+X8t9eyFW5SI0Pj6OTqeDoaGhReVDQ0MYHR1NqVUvH8/1YS33zzmHT33qU3jb296Gc845B8Da7tdDDz2Enp4e5PN5XHHFFbjjjjtw1llnrek+7d+/Hz/+8Y+xd+9e89la7dfWrVvxta99Dd/73vdwyy23YHR0FNu2bcPExMSa7RMAPP7447jpppuwZcsWfO9738MVV1yBP/iDP8DXvvY1AGv3fC2HVZfK4VieS+XwHM45U7aWWcv9+8QnPoGf/vSn+Pu//3vz2Vrs15lnnokHH3wQ09PT+PrXv47LL78cBw8eXPh8rfXp8OHDuPLKK3HXXXehUCh4t1tr/brooosW/v26170OF1xwAU4//XTs27cPv/EbvwFg7fUJOJpH7fzzz8eePXsAAG984xvx8MMP46abbsJ/+k//aWG7tdi3F2JVPgkNDg4im82aFX5sbMx8E1iLPKfmWav9++QnP4k777wTf/d3f7coa+Ja7lcul8OrX/1qnH/++di7dy9e//rX4wtf+MKa7dMDDzyAsbExnHfeeQjDEGEY4uDBg/iLv/gLhGG40Pa11q+llMtlvO51r8Njjz22Zs8VAIyMjOCss85aVPba174Wv/zlLwGs7WvrhViVi1Aul8N5552HAwcOLCo/cOAAtm3bllKrXj42b96M4eHhRf1rt9s4ePDgqu6fcw6f+MQn8I1vfAN33303Nm/evOjztdovhnMOrVZrzfbpne98Jx566CE8+OCDC3/nn38+PvjBD+LBBx/Eq171qjXZr6W0Wi380z/9E0ZGRtbsuQKAt771reZ1h3/5l3/BqaeeCuD4urYMaSkiXojnJNpf+cpX3COPPOKuuuoqVy6X3S9+8Yu0m7YsZmdn3U9+8hP3k5/8xAFwN9xwg/vJT36yIDH//Oc/76rVqvvGN77hHnroIfeBD3xg1cstP/axj7lqtep+8IMfLJLI1uv1hW3WYr+uueYad88997hDhw65n/70p+7Tn/60y2Qy7q677nLOrc0+MY5Vxzm3Nvv1X//rf3U/+MEP3OOPP+7uu+8+d8kll7hKpbJwX1iLfXLuqIw+DEP3J3/yJ+6xxx5z/+t//S9XKpXcX//1Xy9ss1b79kKs2kXIOee+9KUvuVNPPdXlcjn3pje9aUEKvBb4u7/7OwfA/F1++eXOuaOSy+uuu84NDw+7fD7vfvM3f9M99NBD6Tb6BWD9AeBuvfXWhW3WYr/+83/+zwvzbP369e6d73znwgLk3NrsE2PpIrQW+/XcuzFRFLmNGze6Sy+91D388MMLn6/FPj3Ht771LXfOOee4fD7vXvOa17ibb7550edruW+/DuUTEkIIkRqrMiYkhBDixECLkBBCiNTQIiSEECI1tAgJIYRIDS1CQgghUkOLkBBCiNTQIiSEECI1tAgJIYRIDS1CQgghUkOLkBBCiNTQIiSEECI1/j/Lnun5b7hMRQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABoZElEQVR4nO2dfZBmVX3nv/fteevn6e55YbpnwkBGM6CCL7zoyKiZsYDZYpFdFysmYgxxq4w4YGDdXRJko2NKZwxJUZjSYMEqDMlS849icFVkLOK4CbIShJJgMsFlxBFom5np9+f13nv2j5Fmun/fI9285HbPfD9VXTVznnPvPefcc+957vP73u8vcM45CCGEEAUQFt0AIYQQJy5ahIQQQhSGFiEhhBCFoUVICCFEYWgREkIIURhahIQQQhSGFiEhhBCFoUVICCFEYWgREkIIURhahIT4JT/60Y/wwQ9+EBs2bEClUkG9XsfZZ5+NG264AUeOHJmtt3XrVmzdurW4hhKeeeYZ/I//8T9w3nnnYfXq1ejv78c555yDW265BVmWFd08IbzERTdAiKXArbfeiu3bt+P000/Hf//v/x2ve93r0Ov18I//+I/44he/iO9///u46667im6ml4ceegh33HEHfu/3fg9/8id/giRJ8K1vfQsf+chH8MADD+DLX/5y0U0UghLIO06c6Hz/+9/HO97xDlx44YX42te+hnK5POfzbreLe+65B//hP/wHAJh9Cvrud7/7b9xSP2NjY6jX60iSZE75VVddhS984Qv42c9+hvXr1xfUOiH86Oc4ccKzc+dOBEGAW265xSxAAFAqlWYXIB+f+tSnsGnTJqxcuRL9/f04++yz8aUvfQnzv+Pdd9992Lp1K1atWoVqtYpTTjkF73nPe9BsNmfr3HzzzXjjG9+Ier2ORqOB17zmNfj4xz/+K4+/YsUKswABwFve8hYAwM9//vNfub0QRaGf48QJTZZluO+++3DOOee8pCeFn/70p/jwhz+MU045BQDwwAMP4KMf/SieeuopfOITn5itc/HFF+Md73gHvvzlL2NwcBBPPfUU7rnnHnS7XdRqNezZswfbt2/HRz/6UfzFX/wFwjDET37yE/z4xz9+Ue267777EMcxTjvttBfdNyFeSbQIiROaQ4cOodlsYsOGDS9pP7fddtvsv/M8x9atW+Gcw+c+9zn8yZ/8CYIgwEMPPYR2u40///M/xxvf+MbZ+pdddtnsv//hH/4Bg4OD+Mu//MvZsvPPP/9Ftenee+/FX//1X+Pqq6/GqlWrXtQ+hHil0c9xQrwM3HfffbjgggswMDCAKIqQJAk+8YlP4PDhwxgdHQUAvOlNb0KpVMIf/MEfYPfu3XjiiSfMft7ylrdgfHwc73vf+/C3f/u3OHTo0Itqzw9/+EO8973vxVvf+lbs2rXrJfVNiFcSLULihGb16tWo1Wo4cODAi97HD37wA2zbtg3AUZXdP/zDP+DBBx/E9ddfDwBotVoAgFe/+tX4zne+gzVr1uDKK6/Eq1/9arz61a/G5z73udl9feADH8CXv/xlPPnkk3jPe96DNWvWYNOmTdi7d++C2/Pwww/jwgsvxMaNG/HNb36TxrmEWCpoERInNFEU4fzzz8dDDz30ooP3e/bsQZIk+N//+3/jve99LzZv3oxzzz2X1n3HO96Br3/965iYmMADDzyA8847D9dccw327NkzW+eDH/wg7r//fkxMTOAb3/gGnHN417vehSeffPIF2/Lwww/jggsuwKmnnop7770XAwMDL6pPQvxboUVInPBcd911cM7hQx/6ELrdrvm81+vh61//unf7IAgQxzGiKJota7Va+Ou//mvvNlEUYdOmTfjCF74A4OjPZ/Pp6+vDRRddhOuvvx7dbhePPfbYr+zHI488ggsuuAAnn3wy9u7dixUrVvzK+kIsBSRMECc85513Hm6++WZs374d55xzDj7ykY/gjDPOQK/Xw8MPP4xbbrkFZ555Ji655BK6/cUXX4wbb7wRl112Gf7gD/4Ahw8fxl/8xV+Yn8G++MUv4r777sPFF1+MU045Be12e/Yl0gsuuAAA8KEPfQjVahVve9vbsHbtWoyMjGDXrl0YGBjAm9/8Zm8f9u/fP7uPz3zmM3j88cfx+OOPz37+6le/GieddNJLGichXhGcEMI559wjjzziLr/8cnfKKae4Uqnk+vr63FlnneU+8YlPuNHR0dl6W7ZscVu2bJmz7Ze//GV3+umnu3K57F71qle5Xbt2uS996UsOgDtw4IBzzrnvf//77j/9p//kTj31VFcul92qVavcli1b3N133z27n927d7t3vvOdbmhoyJVKJbdu3Tr33ve+1/3oRz/6lW2/7bbbHADv32233fZyDZMQLytyTBBC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PcdTTz2F3/3d38WqVatQq9Xwpje9CQ899NDs58u5b78St0TZs2ePS5LE3Xrrre7HP/6xu/rqq11fX5978skni27agvjmN7/prr/+eveVr3zFAXB33XXXnM8/+9nPukaj4b7yla+4Rx991P32b/+2W7t2rZucnCymwQvg3/27f+duu+0290//9E/ukUcecRdffLE75ZRT3PT09Gyd5divu+++233jG99w+/fvd/v373cf//jHXZIk7p/+6Z+cc8uzT8fygx/8wP36r/+6e8Mb3uCuvvrq2fLl2K9PfvKT7owzznDPPPPM7N/o6Ojs58uxT845d+TIEXfqqae63//933f/9//+X3fgwAH3ne98x/3kJz+ZrbNc+/ZCLNlF6C1veYu74oor5pS95jWvcX/8x39cUItePPMXoTzP3fDwsPvsZz87W9Zut93AwID74he/WEALXxyjo6MOgNu3b59z7vjpl3POrVixwv3P//k/l32fpqam3MaNG93evXvdli1bZheh5dqvT37yk+6Nb3wj/Wy59sk55/7oj/7Ivf3tb/d+vpz79kIsyZ/jut0uHnroIWzbtm1O+bZt23D//fcX1KqXjwMHDmBkZGRO/8rlMrZs2bKs+jcxMQEAWLlyJYDjo19ZlmHPnj2YmZnBeeedt+z7dOWVV+Liiy/GBRdcMKd8Offr8ccfx7p167Bhwwb8zu/8Dp544gkAy7tPd999N84991z81m/9FtasWYOzzjoLt9566+zny7lvL8SSXIQOHTqELMswNDQ0p3xoaAgjIyMFterl47k+LOf+OefwsY99DG9/+9tx5plnAlje/Xr00UdRr9dRLpdxxRVX4K677sLrXve6Zd2nPXv24Ic//CF27dplPluu/dq0aRPuuOMOfPvb38att96KkZERbN68GYcPH162fQKAJ554AjfffDM2btyIb3/727jiiivwh3/4h7jjjjsALN/ztRCWXCqHY3kulcNzOOdM2XJmOffvqquuwo9+9CP8/d//vflsOfbr9NNPxyOPPILx8XF85StfweWXX459+/bNfr7c+nTw4EFcffXVuPfee1GpVLz1llu/Lrrootl/v/71r8d5552HV7/61di9ezfe+ta3Alh+fQKO5lE799xzsXPnTgDAWWedhcceeww333wzfu/3fm+23nLs2wuxJJ+EVq9ejSiKzAo/OjpqvgksR55T8yzX/n30ox/F3Xffjb/7u7+bkzVxOferVCrhN37jN3Duuedi165deOMb34jPfe5zy7ZPDz30EEZHR3HOOecgjmPEcYx9+/bhL//yLxHH8Wzbl1u/5tPX14fXv/71ePzxx5ftuQKAtWvX4nWve92cste+9rX42c9+BmB5X1svxJJchEqlEs455xzs3bt3TvnevXuxefPmglr18rFhwwYMDw/P6V+328W+ffuWdP+cc7jqqqvw1a9+Fffddx82bNgw5/Pl2i+Gcw6dTmfZ9un888/Ho48+ikceeWT279xzz8X73/9+PPLII3jVq161LPs1n06ng3/+53/G2rVrl+25AoC3ve1t5nWHf/3Xf8Wpp54K4Pi6tgxFKSJeiOck2l/60pfcj3/8Y3fNNde4vr4+99Of/rTopi2Iqakp9/DDD7uHH37YAXA33nije/jhh2cl5p/97GfdwMCA++pXv+oeffRR9773vW/Jyy0/8pGPuIGBAffd7353jkS22WzO1lmO/bruuuvc9773PXfgwAH3ox/9yH384x93YRi6e++91zm3PPvEOFYd59zy7Nd//a//1X33u991TzzxhHvggQfcu971LtdoNGbvC8uxT84dldHHcew+85nPuMcff9z9r//1v1ytVnN/8zd/M1tnufbthViyi5Bzzn3hC19wp556qiuVSu7ss8+elQIvB/7u7/7OATB/l19+uXPuqOTyk5/8pBseHnblctn95m/+pnv00UeLbfQLwPoDwN12222zdZZjv/7zf/7Ps/PspJNOcueff/7sAuTc8uwTY/4itBz79dy7MUmSuHXr1rlLL73UPfbYY7OfL8c+PcfXv/51d+aZZ7pyuexe85rXuFtuuWXO58u5b78K5RMSQghRGEsyJiSEEOLEQIuQEEKIwtAiJIQQojC0CAkhhCgMLUJCCCEKQ4uQEEKIwtAiJIQQojC0CAkhhCgMLUJCCCEKQ4uQEEKIwtAiJIQQojD+P9BWGP6yWGV7AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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o96zzz7rPfvssx4A7/777/eeffbZhsT8y1/+spfL5bxvf/vb3vPPP+995CMfmfFyy0996lNeLpfznnzyySkS2WKx2KgzG+e1bt0676mnnvL27dvnPffcc97dd9/tRaNR7/HHH/c8b3bOiXGiOs7zZue8/vf//t/ek08+6b388sve008/7X3gAx/wstls431hNs7J847L6OPxuPelL33Je+mll7x/+Id/8DKZjPf3f//3jTqzdW5vxYzdhDzP87761a96Cxcu9JLJpHfVVVc1pMCzgX/+53/2AJi/W2+91fO845LLL37xi15PT4+XSqW8973vfd7zzz8f7qDfAjYfAN6DDz7YqDMb5/U//+f/bKyzuXPnetddd11jA/K82TknxvRNaDbO6/VnYxKJhDdv3jzv5ptv9l544YXG67NxTq/z3e9+11uyZImXSqW8iy++2NuyZcuU12fz3N4M5RMSQggRGjMyJiSEEOLcQJuQEEKI0NAmJIQQIjS0CQkhhAgNbUJCCCFCQ5uQEEKI0NAmJIQQIjS0CQkhhAgNbUJCCCFCQ5uQEEKI0NAmJIQQIjT+P+7/kRGU2pFnAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABpxklEQVR4nO2dfZBlZX3nv+e+v9/bL9NvMAwjDqggimBGBs2MhcwWi2xcrBhFXXS3jDhqYE2WBKmNY8rMGGJRmEKxYBVhs9RUpQQX16iMRRw2QVaCUBBICIQBhmF6evrt3tt938699+wfE3qm+/d9oC8MOd0z309VF8yvn3PO85zznPv0ub/v+f68IAgCCCGEECEQCbsDQgghTly0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAnxrzz22GP49Kc/jfXr1yOVSiGXy+Fd73oXrr/+ekxPTy+027JlC7Zs2RJeRx2ceuqp8DzP/Fx55ZVhd00IJ7GwOyDESuDWW2/Ftm3bcMYZZ+C//bf/hre97W3wfR9///d/j+985zv45S9/ibvvvjvsbr4qF1xwAb7xjW8sig0PD4fUGyFeHS1C4oTnl7/8JT73uc/hoosuwg9/+EMkk8mF31100UX4/d//ffz0pz8NsYfLp1Qq4T3veU/Y3RBi2ejrOHHCs2PHDnieh1tuuWXRAvQyiUQC/+E//IdX3MdXv/pVbNy4Ef39/SgUCnjXu96F7373u1jqD3zfffdhy5YtGBgYQDqdximnnIIPf/jDqNVqC21uvvlmvOMd70Aul0M+n8db3vIWfPnLXz42gxVihaEnIXFC0+l0cN999+Hcc8/F2rVrX/N+nnvuOXz2s5/FKaecAgB48MEH8cUvfhH79+/HH//xHy+0ueSSS/C+970P3/ve91AqlbB//3789Kc/RavVQiaTwa5du7Bt2zZ88YtfxDe+8Q1EIhE888wzePLJJ5fVj/vvvx/5fB6NRgMbNmzAf/kv/wVXX301otHoax6bEG8kWoTECc3k5CRqtRrWr1//uvZz2223Lfx/t9vFli1bEAQBvvnNb+K///f/Ds/z8PDDD6PRaODP//zP8Y53vGOh/eWXX77w/3/3d3+HUqmEv/iLv1iIXXjhhcvqwyWXXILzzjsPp512GmZmZvBXf/VX+IM/+AM8+uij+J//83++rvEJ8UahRUiIY8B9992HHTt24KGHHkKlUln0u4mJCQwPD+Od73wnEokEfvd3fxfbtm3D+973PrzpTW9a1PY3fuM3cNNNN+FjH/sYPvrRj+KCCy7A4ODgsvrwrW99a9G/f+u3fgt9fX246aab8KUvfQnnnHPO6xukEG8AygmJE5rBwUFkMhns3bv3Ne/jV7/6FbZu3QrgsMru7/7u7/DQQw/huuuuAwDU63UAwGmnnYaf//znGBoawuc//3mcdtppOO200/DNb35zYV+f/OQn8b3vfQ/PP/88PvzhD2NoaAgbN27E7t27X1PfPvGJTwA4/PWgECsRLULihCYajeLCCy/Eww8/jBdffPE17WPXrl2Ix+P4P//n/+AjH/kINm3ahPPOO4+2fd/73ocf/ehHKJfLePDBB3H++efj6quvxq5duxbafPrTn8YDDzyAcrmMH//4xwiCAB/84Afx/PPP99y3l4URkYhudbEy0cwUJzzXXnstgiDAZz7zGbRaLfN73/fxox/9yLm953mIxWKLkv/1ev0V8zDRaBQbN25c+Art17/+tWmTzWZx8cUX47rrrkOr1cITTzzRy7AAAHfccQcASLYtVizKCYkTnvPPPx8333wztm3bhnPPPRef+9zncOaZZ8L3fTzyyCO45ZZbcNZZZ+HSSy+l219yySW44YYbcPnll+N3f/d3MTU1hW984xtG7v2d73wH9913Hy655BKccsopaDQa+N73vgcA+MAHPgAA+MxnPoN0Oo0LLrgAo6OjGB8fx86dO1EsFvHud7/bOYY777wTd911Fy655BKsW7cOs7Oz+Ku/+ivs2rULn/rUpxYJIYRYUQRCiCAIguDRRx8NrrjiiuCUU04JEolEkM1mg3POOSf44z/+42BiYmKh3ebNm4PNmzcv2vZ73/tecMYZZwTJZDJ405veFOzcuTP47ne/GwAI9u7dGwRBEPzyl78M/uN//I/BunXrgmQyGQwMDASbN28O7rnnnoX93H777cH73//+YHh4OEgkEsHY2FjwkY98JHjsscdese+//OUvgwsvvDAYGRkJ4vF4kMlkgne/+93Bt7/97aDT6RyzcyTEscYLgiVv0wkhhBD/RignJIQQIjS0CAkhhAgNLUJCCCFCQ4uQEEKI0NAiJIQQIjS0CAkhhAiNN+xl1W9/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IZ/Po1qtYu3atdi3bx/10lqtVCqV425cx+OYgONzXMfjmACNayURBAGq1SrGxsYQIQUyj2bFfR0XiUQWVs6XK3kWCoVVc/J74Xgc1/E4JuD4HNfxOCZA41opFItWYs6QMEEIIURoaBESQggRGit6EUomk/jKV75C3/RfzRyP4zoexwQcn+M6HscEaFyrlRUnTBBCCHHisKKfhIQQQhzfaBESQggRGlqEhBBChIYWISGEEKGhRUgIIURorOhF6Nvf/jbWr1+PVCqFc889F//3//7fsLu0bO6//35ceumlGBsbg+d5+OEPf7jo90EQYPv27RgbG0M6ncaWLVvwxBNPhNPZZbJz5068+93vRj6fx9DQED70oQ/hqaeeWtRmNY7r5ptvxtlnn73wRvr555+Pn/zkJwu/X41jWsrOnTvheR6uvvrqhdhqHNf27dvhed6in5GRkYXfr8Yxvcz+/fvxiU98AgMDA8hkMnjnO9+Jhx9+eOH3q3lsr0iwQtm1a1cQj8eDW2+9NXjyySeDq666Kshms8Hzzz8fdteWxV//9V8H1113XfCDH/wgABDcfffdi37/9a9/Pcjn88EPfvCD4PHHHw9+53d+JxgdHQ0qlUo4HV4G/+7f/bvgtttuC/7hH/4hePTRR4NLLrkkOOWUU4K5ubmFNqtxXPfcc0/w4x//OHjqqaeCp556Kvjyl78cxOPx4B/+4R+CIFidYzqaX/3qV8Gpp54anH322cFVV121EF+N4/rKV74SnHnmmcGBAwcWfiYmJhZ+vxrHFARBMD09Haxbty741Kc+Ffy///f/gr179wY///nPg2eeeWahzWod26uxYheh3/iN3wiuvPLKRbG3vOUtwR/90R+F1KPXztJFqNvtBiMjI8HXv/71hVij0QiKxWLwne98J4QevjYmJiYCAMGePXuCIDh+xhUEQdDX1xf8j//xP1b9mKrVarBhw4Zg9+7dwebNmxcWodU6rq985SvBO97xDvq71TqmIAiCP/zDPwze+973On+/msf2aqzIr+NarRYefvhhbN26dVF869ateOCBB0Lq1bFj7969GB8fXzS+ZDKJzZs3r6rxlctlAEB/fz+A42NcnU4Hu3btwvz8PM4///xVP6bPf/7zuOSSS/CBD3xgUXw1j+vpp5/G2NgY1q9fj49+9KN49tlnAazuMd1zzz0477zz8Nu//dsYGhrCOeecg1tvvXXh96t5bK/GilyEJicn0el0MDw8vCg+PDyM8fHxkHp17Hh5DKt5fEEQ4Etf+hLe+9734qyzzgKwusf1+OOPI5fLIZlM4sorr8Tdd9+Nt73tbat6TLt27cKvf/1r7Ny50/xutY5r48aNuOOOO/Czn/0Mt956K8bHx7Fp0yZMTU2t2jEBwLPPPoubb74ZGzZswM9+9jNceeWV+L3f+z3ccccdAFbv9VoOK66Uw9G8XMrhZYIgMLHVzGoe3xe+8AU89thj+Nu//Vvzu9U4rjPOOAOPPvooZmdn8YMf/ABXXHEF9uzZs/D71Tamffv24aqrrsK9996LVCrlbLfaxnXxxRcv/P/b3/52nH/++TjttNNw++234z3veQ+A1Tcm4HAdtfPOOw87duwAAJxzzjl44okncPPNN+M//af/tNBuNY7t1ViRT0KDg4OIRqNmhZ+YmDB/CaxGXlbzrNbxffGLX8Q999yDv/mbv1lUNXE1jyuRSODNb34zzjvvPOzcuRPveMc78M1vfnPVjunhhx/GxMQEzj33XMRiMcRiMezZswd/8Rd/gVgsttD31TaupWSzWbz97W/H008/vWqvFQCMjo7ibW9726LYW9/6VrzwwgsAVve99WqsyEUokUjg3HPPxe7duxfFd+/ejU2bNoXUq2PH+vXrMTIysmh8rVYLe/bsWdHjC4IAX/jCF3DXXXfhvvvuw/r16xf9frWOixEEAZrN5qod04UXXojHH38cjz766MLPeeedh49//ON49NFH8aY3vWlVjmspzWYT//iP/4jR0dFVe60A4IILLjCvO/zzP/8z1q1bB+D4urcMYSkiXo2XJdrf/e53gyeffDK4+uqrg2w2Gzz33HNhd21ZVKvV4JFHHgkeeeSRAEBwww03BI888siCxPzrX/96UCwWg7vuuit4/PHHg4997GMrXm75uc99LigWi8EvfvGLRRLZWq220GY1juvaa68N7r///mDv3r3BY489Fnz5y18OIpFIcO+99wZBsDrHxDhaHRcEq3Ncv//7vx/84he/CJ599tngwQcfDD74wQ8G+Xx+4XNhNY4pCA7L6GOxWPCnf/qnwdNPPx38r//1v4JMJhP85V/+5UKb1Tq2V2PFLkJBEATf+ta3gnXr1gWJRCJ417vetSAFXg38zd/8TQDA/FxxxRVBEByWXH7lK18JRkZGgmQyGfzmb/5m8Pjjj4fb6VeBjQdAcNttty20WY3j+s//+T8vzLM1a9YEF1544cICFASrc0yMpYvQahzXy+/GxOPxYGxsLLjsssuCJ554YuH3q3FML/OjH/0oOOuss4JkMhm85S1vCW655ZZFv1/NY3slVE9ICCFEaKzInJAQQogTAy1CQgghQkOLkBBCiNDQIiSEECI0tAgJIYQIDS1CQgghQkOLkBBCiNDQIiSEECI0tAgJIYQIDS1CQgghQkOLkBBCiND4/314ZuiK86BpAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABuuElEQVR4nO2de5Ad1X3nv/24t+9z7rw0MxJIIGOBeRjMw1GQ7UguQFssZuPgihPjOITddcDCDqx3l0RQa4sUkRySonDKjlywPMTGlP4xOHgdY+TCiE0wa4JhIeDI2JJBSBqN5nEfc9/dffYPmUEzv+8xGh7pGen3qZoq6cw53eecPt3n3vl9+/tzjDEGiqIoipIAbtIdUBRFUY5fdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSlF/x/PPP4+qrr8bKlSuRyWRQKBRw3nnn4bbbbsPk5ORMvXXr1mHdunXJdZTw+OOPw3Ec68+1116bdBcVheIn3QFFWQjcdddd2LBhA0477TT89//+33HGGWeg2+3in//5n/GNb3wDP/rRj/DQQw8l3U0r5513Hn70ox+J8q1bt+L+++/H7/zO7yTQK0V5cxz1jlOOd370ox/hIx/5CC655BJ8+9vfRhAEs37f6XTwyCOP4D/8h/8AADPfgh5//PF/457OD2MM3vve9yKKIuzevRuuq3/4UBYeuiqV457NmzfDcRzceeedYgMCgHQ6PbMB2bjllluwevVq9Pf3o6enB+eddx7uvvtuzP2M99hjj2HdunUYGBhANpvFihUr8IlPfAKNRmOmztatW3HOOeegUCigWCzife97H2666aZ5j+uHP/whdu/ejauvvlo3IGXBon+OU45roijCY489hvPPPx/Lly9/y8f55S9/iWuuuQYrVqwAADz11FP4whe+gH379uFLX/rSTJ3LLrsMH/nIR3DPPfegt7cX+/btwyOPPIJOp4NcLoft27djw4YN+MIXvoC//uu/huu6+PnPf46XXnpp3n26++674bourr766rc8LkV5t9FNSDmuGR8fR6PRwMqVK9/Wce69996Zf8dxjHXr1sEYg69+9av4H//jf8BxHDzzzDNotVr4q7/6K5xzzjkz9a+88sqZf//TP/0Tent78Td/8zczZRdd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//zn8eCDD+Kxxx7DypUrZ/1+sY6LYYxBu91etGO66KKL8MILL+C5556b+bngggvw6U9/Gs899xze8573LMpxzaXdbuOnP/0pli5dumivFQB86EMfEq87/OxnP8NJJ50E4Ni6twRJKSLejNcl2nfffbd56aWXzA033GDy+bz55S9/mXTXjoparWaeffZZ8+yzzxoA5vbbbzfPPvvsjMT8K1/5iimVSubBBx80L7zwgvnUpz614OWWn/vc50ypVDKPP/74LIlso9GYqbMYx7Vx40bzxBNPmD179pjnn3/e3HTTTcZ1XfPoo48aYxbnmBhHquOMWZzj+q//9b+axx9/3Ozevds89dRT5mMf+5gpFoszz4XFOCZjDsvofd83f/EXf2Fefvll881vftPkcjnzd3/3dzN1FuvY3owFuwkZY8zXv/51c9JJJ5l0Om3OO++8GSnwYuCHP/yhASB+rrrqKmPMYcnll7/8ZTMyMmKCIDC/9Vu/ZV544YVkO/0msPEAMPfee+9MncU4rv/4H//jzDpbsmSJueiii2Y2IGMW55gYczehxTiu19+NSaVSZtmyZeaKK64wL7744szvF+OYXuc73/mOOeuss0wQBOZ973ufufPOO2f9fjGP7deh+YQURVGUxFiQMSFFURTl+EA3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREkM3IUVRFCUxdBNSFEVREuP/AwtZE6BHuKwmAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABrxElEQVR4nO2de5AdZ3nmnz597pc5MxpJMxosCTnIBtsYsA2KBURmwd7yGm9YUxAwyRq2imALgx2ycWK8BYIiEnFSjrMFMWUvF7FZl1K7XGKWAFbKQd6scWIMKozJGhMrtmRrNNLczpk51+7z7R+KB828z2fP2HJ6Rnp+VVMlvacv39f9dX+nz/v08wbOOQchhBAiAVJJN0AIIcTpiyYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIf6Fn/zkJ/jABz6ATZs2IZ/Po1wu44ILLsCtt96KiYmJueUuueQSXHLJJck11EOtVsMtt9yCs846C8ViES972cvwrne9C48++mjSTRPCSzrpBgixHLjrrruwfft2nH322fi93/s9nHPOOeh2u/jhD3+IL3zhC/jBD36Ab3zjG0k38zm58sor8cMf/hA7duzARRddhEOHDuHTn/40Lr74YjzyyCPYuHFj0k0UwqBJSJz2/OAHP8B1112HSy+9FN/85jeRy+XmPrv00kvxu7/7u/jud7+bYAufn1/84he4//778V/+y3/B7/3e783FX/GKV2Dr1q34+te/jt/5nd9JsIVCcPRznDjt2blzJ4IgwJ133jlvAnqWbDaLf//v//1zbuNTn/oUtmzZglWrVqGvrw8XXHABvvjFL2KhP/B9992HSy65BIODgygUCtiwYQPe+c53otFozC1zxx134DWveQ3K5TIqlQpe+cpX4uMf//hz7j+TyQAAqtXqvHh/fz8AIJ/PP+f6QiSFnoTEaU0cx7jvvvtw4YUXYv369S94O//8z/+MD33oQ9iwYQMA4MEHH8RHPvIRPP300/jEJz4xt8wVV1yBN7/5zfjSl76E/v5+PP300/jud7+LTqeDYrGIPXv2YPv27fjIRz6CP/mTP0EqlcIvfvEL/OxnP3vO/W/cuBG//uu/jj/90z/FhRdeiNe//vU4dOgQPvrRj2LDhg14z3ve84L7JsRLihPiNGZ0dNQBcO95z3sWvc62bdvctm3bvJ/Hcey63a779Kc/7QYHB12v13POOfe//tf/cgDc/v37vetef/31rr+/f9FtOZFOp+M++MEPOgBzf+eff747cODAC9qeEP8a6Oc4IU4C9913H972trehWq0iDENkMhl84hOfwPj4OMbGxgAAr33ta5HNZvHbv/3b2L17N5544gmznTe84Q2YmprCe9/7XvzVX/0Vjh07tug2XHfddfja176GP/3TP8W+ffvwl3/5l8hms/g3/+bf4MknnzxpfRXipJL0LChEkkRR5IrFotuyZcui11n4JPT3f//3LgxD99a3vtX95V/+pfu///f/uoceesjdcsstDsC8J5H777/fvf3tb3elUskBcGeeeaa7/fbb523/S1/6krv44otdGIYuCAL3hje8wd17773P2abvfOc7DoD7n//zf86LT05Oumq16t7//vcvun9C/GuiJyFxWhOGId761rfi4YcfxqFDh17QNvbs2YNMJoP//b//N9797ndj69atuOiii+iyb37zm/Gtb30L09PTePDBB3HxxRfjxhtvxJ49e+aW+cAHPoAHHngA09PT+Pa3vw3nHN7+9rc/59PM/v37AQCvf/3r58X7+/vxile8Aj/96U9fUN+EeKnRJCROe26++WY45/DBD34QnU7HfN7tdvGtb33Lu34QBEin0wjDcC7WbDbx3//7f/euE4YhtmzZgs9//vMAgB/96EdmmVKphMsvvxy33HILOp3Oc750OjIyAuC4IOJExsfH8fOf/xxnnHGGd10hkkTqOHHac/HFF+OOO+7A9u3bceGFF+K6667Dueeei263ix//+Me48847cd555+HKK6+k619xxRW47bbbcPXVV+O3f/u3MT4+jj/5kz8xcu8vfOELuO+++3DFFVdgw4YNaLVa+NKXvgQAeNvb3gYA+OAHP4hCoYA3vvGNWLduHUZHR7Fr1y5Uq1XzlHMiV111FT7xiU/guuuuw6FDh3DBBRfg8OHD+OM//mM0Gg3ccMMNJ+loCXGSSfr3QCGWC/v373fXXHON27Bhg8tms65UKrnXve517hOf+IQbGxubW46p4770pS+5s88+2+VyOXfmmWe6Xbt2uS9+8YvzckI/+MEP3H/4D//Bbdy40eVyOTc4OOi2bdvm7rnnnrnt7N69273lLW9xQ0NDLpvNupGREffud7/b/eQnP3ne9h8+fNhdf/317hWveIXL5/NuZGTEXXHFFe4HP/jBSTk+QrwUBM4teJtOCCGE+FdCOSEhhBCJoUlICCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJoUlICCFEYrxkL6v++Z//Of74j/8Yhw8fxrnnnovbb78db37zm593vV6vh2eeeQaVSgVBELxUzRNCCPES4ZxDvV7HyMgIUqnnedZ5KV4+2rNnj8tkMu6uu+5yP/vZz9wNN9zgSqWSe/LJJ5933YMHD86zotef/vSnP/2tzL+DBw8+7z3/JXlZdcuWLbjgggtwxx13zMVe9apX4R3veAd27do1b9l2u412uz33/+npaWzYsAFr1lSQSv3ySaiY4Q9tg2vWLqpN40fHeHy8ZmIjI3yb1f4Bsv5RE3v6EN8X3WZfwcQKRc+y1X4T6x9YbWLdrvU/A4Bnnj5sYsFogywJrKlUTKzdaplYo9ul6weRjU2nbTA9aPsPAKtX95tYFNv1j41N0vUZ5VW2T8jwZXO5xVcijSPbrnJ+0MbKdvwAQK8Xm9j4uC3h0NfXT9dn1WDTWPxl3SXn8MioHSvH92WPy5q19nqJez26/uGnrUns1KQ9h92Ij6uoa491hyxaLPJxdcYZ60wsk8vSZXuxPS9xZGO12hRdf2J8gsYXkvbc2/r6+kysVCqbWETGHwA884y9Dz1bgddiD2KjYbdLDj/FAYgBTE1NmWq/CznpP8d1Oh08/PDD+IM/+IN58csuuwwPPPCAWX7Xrl341Kc+ZeKpVDBvEvI90qVPMI18Lnzrs5/8wtCzr7TdV0i2u5RfEU/s4y9jfFnWLtYm5/gxYfvy/eSZJo2I2LHyrM+iZPe0TQDvqyMpTN/6i90mPMPHNwYoxIyenZd0ml9uvR4bg2x93li23aVMQux7qK//fAza/QeeSYitT68B37giYRbzrU/b77mH2OkGADlW/nsLDdv1PQuy7dLrwlMMgV3bvn2xK5Yea8/aPhaTUjnpwoRjx44hjmMMDQ3Niw8NDWF0dNQsf/PNN2N6enru7+DBgye7SUIIIZYpL5kwYeEM6Jyjs2Iul6M/J7RqtXkzcVDkj5G9uN/ECkX7eJ3P865mM/YxtNWq02WnJu2zaL02Tpfl+7Ix9lMIaRIA/nPUUoi69qe3rmdnE0HTBsmyBc95KbBv52ST0w3Pz3kt29cMbMzzyyU9rvUJe64KfXwLa8r2Z85Uln9nmzhif/Z4ZuaAiVXqfKwUiyUTm2lP2eW6fP9svGZT9hoYGLA/EQL8WPl+4gHsT7JTU/bntEKB/xzGnpoq5GcnH82mHUTHjk2bWMfzM/H09JSJ5fP8p9d63R7XCvmZ2veEy34m5PAF2XlpkZ/EffvPkp/euuQeAPCf6Urk2vb1aWFbnQO8Q2gBJ/1JaPXq1QjD0Dz1jI2NmacjIYQQpzcnfRLKZrO48MILsXfv3nnxvXv3YuvWrSd7d0IIIVYwL8nPcR/72MfwW7/1W7joootw8cUX484778RTTz2Fa6+99qXYnRBCiBXKSzIJ/cZv/AbGx8fx6U9/GocPH8Z5552Hv/7rv8bGjRtfit0JIYRYobxkwoTt27dj+/btL9XmhRBCnAK8ZJPQi6XS1zfv/YFmg6s62Mui/bF9oSsIuKyjr8rUUXzZmTpRlxEFS3+VK8bYe2LspTxPV5EvWGVQq2VjsUdFx7Y75dkXirZdI0OrTGyw38YAoJSx6qwyUSZ1R5+h67eJMokp7gqel+9YdJq8w1vOkxdYwZVk6TTfVylnx9tMbFVMYcrzPgp5WTWasC+rPnOUv75QyVt1WZyybep0+EvMjdkZE+sjL0YD/P2lmLzUOUFetgWAmRm7L6ZOG1y9hq7PyGTscRk/xvdfm7ZKOt+9pUHjbAwsWgYHJtpjqtnnatfiWXy7mDqOqRZ9SrzJifkv5vZ6Ds0JIoclyMBUCCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJsWyFCflCfp45aOSx4WDJu3Tamgz63GPLxIbDxwxJlheJrqF/FU/WM44esU67sx4rG8Am+jIZm4ANPclDhtdUl1AiDsqVKneGLhJhQoYYMk5OcxfsOnE3r7PkaYH3tUjc1ZlpTZf7bKIzbttVXjNMlx3ot04gLWLgOdW0SXEAmCAihEre2t7U63xc5EtWLNDvsehhZLP2XLEYAKTZeSWCDZ8L9swvfm63ScYrszI6viyxkllrBRe+pD6/tnyiJev+XCDjrdlcvABgKTDRU5cIK3z3Nra+DyZC8NkZMdIL2tDrObD7FUNPQkIIIRJDk5AQQojE0CQkhBAiMTQJCSGESIxlK0yYnJiYVwXQl0D31bNZyFKSdD584oiFLKU0NKPkK5JDEqj1mk3gL0wSPgsTUSwF5sPQbczSZV2FVNuMbD2psuNtDUhj085uc2AtFwusHrLxJunBxFFbaPF43NYI8tXw7RFxBhMmRJ5jNUDO1+BqK3boekQgEbmMWbLa5/jAlj38jC3DDfA6Q+s3vNzEWMVhH2ybvus1RVwnaBVazzUQYLEuCM9VCns+TY+QiHWBbXIpJbcZ3PUFqJBrsF73iQXsviYn7bK+e+DC89UjFWh96ElICCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJoUlICCFEYixbdVy3CwTzxFRclVFJE3uTmlV1+NQ2xUWq6wCg4bXTmc/4MVvjCOD2JGybHscSFApWBcPUKotV8QF+ZY2vbshiCYg6KrBlZ5BLcyVhedBapgRE3ZZzXLOWcnb/6ZQ919UKt7fJpWz/Ux7BT9yyx9sRdVzgqfNEygkhgA1mszm6foGoMWttW8/IR4EMuNVrrDoPAEYPP21i9bpVaDLFGgAMrxtZdLsYzSZXGC5kaHgdjRcK7H5h2w/w2kNMSdftcosgJnorkfvNqkFrmXN8fTuu8nk7LvsG+blitFpP0vhixWy8xtIL3x6gJyEhhBAJoklICCFEYmgSEkIIkRiahIQQQiTGshUm9PUVkUr9UpkQeZJ/LCnK8vKzi8unAfBbBLHtdqgGwJeoJLVQyPp9aS4WYLWPWI2jZtOzf2Lb4hMgrBpcY2IDObt/X7I8JlYszHJlsJ9b0eTLdl+dtt1mZ2aKru9mZkwsyNr9V8l+AKBEkvUzU7z2UZfsq0dUGCmPMIG4GSEI7XmJO226/vSMFeLUyLIvO2MjXZ/RY2oJAIOr7bjIkBpDrRa3h2F1iliNol7M9x+TeK5UNrG+VXxclst22SfBLYq64+M2RhLzPmnTamI9VSZ1e4qk/QDQ6dnxNjVm73fM9ggAckTEkC5wxQBxxEI6Y5ftNBZ3c1yCLkFPQkIIIZJDk5AQQojE0CQkhBAiMTQJCSGESAxNQkIIIRJj2arjas0GghN8e3yWOUyrkSXBfl/hJ6JW8ZHOLK7Ik88iiIWZjYdPnceUcGz/zN7neNxalvgK8PlUbwupT3PFWEAUO6vLq0wsX+DqtEzWttV1rWVLq81VVN0Za1uTIv2PYJVtANAjSrrIc7W0iBSokLKKr2qhn64fEYVil9j+xJ6BkQmsvG4gsMv2Vfn+meLMZ9vDxkun0zGxmmdcNEhhv2bT2uNU+qxtEwBEXdtXdlq6Xa4YGydWPDWPbU+1attQIOoy4q4DgFuKZRq2XVGDj8GZpr3fNMj1nvbo84pnWOVpsc+2CQCOBUdMrJkjxQY9blCZhaLBHgBf/bwF6ElICCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJsWyFCd1uNK+eUNGXrScwy4iBVTYpDgD9Azbe9NTMYPYYfFlPApmEC0SYMLi6n67fmLUJzJBY+VQqfP2Y2MY0fEnRSZuszXgED4yQJLvTObt+use/B7F6RFkiLMiT/gNAkLXrZ8p2/Y7H8iRMW2FCyZMsz8MmyzMpG8tnuQgkCskxiKztDtkkAF5PKIQVlqSJbRPAa//4BCvdrhUhdEjtIt++mMUPE0aE5PwDvK1MCBTHPIPOruE+jzhpFRFyVPJ2DKUa9pgAwPQRa/sz6xFBMBqkhhrTQIxHXBnhmlYc0m3yZWtEhFCo2OmhWuXXS7Fv/rXdix0OjS9OmaAnISGEEImhSUgIIURiaBISQgiRGJqEhBBCJMayFSYMDq5C6oTkZNlT96U9Y10Exo8dM7E6cRsAeAK2TRKtAHDsmH3bmjs5eNwdSK6227XBcoUnhUPyZn2a1J3xwYQJkxP8uLC2ribnoK/Mk7rplN1AsWRr9KTJG/AA5rllPEtIasHkyDa9pO02myTRDgC9jP1+FticOACgTRLjbVLPJwavBxQUSD0dsv+Q1OIBgL6+1XbZnm1svWbHLwDMEsELExAAmHdNzu2LjEvmogDwOkV5kuxnMQAIyMCcIfWcfPtnVD1OEiUSz7K+ctMOZMl4DfL22k57bsPt2AoLjo4zYQO/34y3SNyj70qz2kMpKyQq5Pm+0t356/eCxVcU0pOQEEKIxNAkJIQQIjE0CQkhhEgMTUJCCCESY8mT0P33348rr7wSIyMjCIIA3/zmN+d97pzDjh07MDIygkKhgEsuuQSPPvroyWqvEEKIU4glq+NmZ2fxmte8Bh/4wAfwzne+03x+66234rbbbsNXvvIVnHXWWfjMZz6DSy+9FI899hgqHosVxsjIeqRPsE5hdh0AMEEsKzJEQdP01CNiyqA0UcAAwOrV1raFKeZ89YQYrK2sbhDAawexekiFolXlAEBIlHSFAu9rnljkFPttfZJqldshhbDnK0Nq3GTSXEUTkPPNbHscsXwBgG5k1VGxs/sKUz4Vj1UShqHH9oZst9OyliVtj4oplyGKKVJPyacYyxPFFVPH+eyoYo91EYOpSdn6MzPcnoZZ9DDYdQEAs22rMBwft2pYZs/jo0XOFXD8XmcbRlRkniFULVvrpGq+38Scx/YnbNpjleknbfUo3ljtoUyVL1xg6jhyy/Ud1eaCY9iLF6+OW/IkdPnll+Pyyy+nnznncPvtt+OWW27BVVddBQDYvXs3hoaGcPfdd+NDH/rQUncnhBDiFOak5oQOHDiA0dFRXHbZZXOxXC6Hbdu24YEHHqDrtNtt1Gq1eX9CCCFOD07qJDQ6OgoAGBqaXxp4aGho7rOF7Nq1C9Vqde5v/fr1J7NJQgghljEviTpu4dvuzjn6BjwA3HzzzZienp77O3jw4EvRJCGEEMuQk2rbMzw8DOD4E9G6devm4mNjY+bp6FlyuRxyOZvAW4jPhqPVshY7hSqpe+PRCtTJz3+rPPVFqv024Z8nCb3JCf6TIqsdVCXJfl+ieGZmwsQqff02VuHtZ6Sy/NiHzvYrl7dWLj7BCMv3M2FFNs33z760BL2eiXmFCURwErFGeerWpEjtHyaMAEAq9wDI2uMyXrfnDwCaM1bcUiQ1obJFvv+Ws8eg0LPHL5vjVjysppZPnJMmggF2/fbIuQKARs0m+5tdK5iIyHUNAFky3opFa93ELKqOx+2x8uyKQgUPnhx8g3wQsHaRaw0A6rG9j3TJsaIeW+C3vG5t8aKpPBExlEt8DB5dYP/lOf2Uk/oktGnTJgwPD2Pv3r1zsU6ng3379mHr1q0nc1dCCCFOAZb8JDQzM4Nf/OIXc/8/cOAA9u/fj1WrVmHDhg248cYbsXPnTmzevBmbN2/Gzp07USwWcfXVV5/UhgshhFj5LHkS+uEPf4i3vOUtc///2Mc+BgC45ppr8JWvfAU33XQTms0mtm/fjsnJSWzZsgX33nvvkt4REkIIcXqw5EnokksugSMv5z1LEATYsWMHduzY8WLaJYQQ4jRg2dYTmmrXEUa/TEJOznIXgVpkE3XVtE2oFTxJ5RpxPMh4HA9Wl9eaWIm8FR1FPhcCm+zur9onxJQn2V8s2X0V8laEkSVJdYDXgml7VIutGZtAnWrYWNAhb5UDyPTsvvKkX5kqP1Y9kkDuNYkLQoPvv05eCaiV7TZLVSsMAYBszh7XyFN7KFuwifFckbgozNo3+wGgHdnxGvdsrN3mKdwyeTs9hh3vceSpZ0TGQD7kghFWv4rlxcNyP10/ytlj1SEuCLXpKbr+sQlS0yu26/vETqwuWaFAhEwAOqQmFHNnqHmcKJjrAxMN9fXx6zWfs+cwE3vsEQjrCtbhpUEcZgAgHRKHlNygicXkmADAqvL8MRTHPUzA1kNiyMBUCCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJoUlICCFEYixbdVy73UYq/OUc2Yx5zQ+wmhlpq3ZJE8UcADiiYJn21B7Kz1iFHlPb+GqhMOKeVWz51HGMDlFsRR4FTJZY9KTTXDUY5qzqrBVZf5Mpj21OjriTxANWrdNJ8ba6jo2nSL9ij2KtRtrarE+ZWJDl38NiZ/c1S9YHgBxRx7VCu36rw1VU+dAqptLkuNanuNqol7X7KhZJfRhSzwkAYhDVYZOroMKubVeQscew5HkvkFk3BUS1mfGoHllNrMF+u69ymdfUYvR6fAzGsT0vxaK1Pjo6xe2Yoqa9CNi12e5x36Cot7iaSBnPva1cIufAozI+dsRaBLH2ryM2YQAwMjzfeDqKYvzTI1LHCSGEWOZoEhJCCJEYmoSEEEIkhiYhIYQQibFshQlhOo3wBGGCz64i02eT3SwpmUtxa4zVq+36zMrHR7tNEuBNLqJg1kHNpk3AMrsQAGg0bI0cRj7PxQaViu1rniSVAaBRsPGZKZu8rEX8WGXTVlyRK6+x20zxwiPTbZtATXXssqGvmAupKVUKbZ98Vjydtj2HR55+mi6bI/YqYcEmoHOeBHKW1JRiwo6paV6nqpGy4yUaskl1X+2mkGhLMuDimDzZRpcMoU6Xj+FebM8hG6+Da3n9sXTZCgN6AbF48iT1my0rDgk9NaWK7HrJ21izyc/LU5NHTKxBRE+Zuq8eEFmWiJ7Wrrb1oICl1RWbbhJxBtHRVEjtKQAohfOPS3eRogpAT0JCCCESRJOQEEKIxNAkJIQQIjE0CQkhhEiMZStMiKMIzv1yjkyneVMzJJx2NnnH3rQGuIih4CnaV+y3y7Ltdj31iELSB1+7GKyWC9umz7GB7SuXtYne4zuzNWZaXZusT3kS0Owd8LHOlIl12lwwMtux+w8bdl9xmzs2DFX7TaxSsCKETou/Qd4iIpChl72MLlso2QRwd9a+RT97bJyunwpsYrvVtAn8xpExuv6Rlk0CD4Q2gT7Yx5PKTGyQy/IxlCLlpxxJQveIEwgABGQDbAz7XD/SsPti4zomywFAx+NawQiydrtNUr8sDrgQqdpnj2FfxYowooiv3yB1poqk9pFPgFAh49JH5qi9DhrH7DkYdVyIFA7Nv46jSMIEIYQQKwBNQkIIIRJDk5AQQojE0CQkhBAiMTQJCSGESIxlq46rz9SROkFJk+7jVjT50MZbTavNarV4zY4sUeH4ag9ls1bJFZLaP6zGEMBVQBVPfQ7G1OQxE4uJCqXt6WuLWJbEAVe3AVbdNEDqtlQyVoUFABNd24bRCVtfpHaQq2jWEHVbp2HVbbPHeN2ZMyrWIihNhHhRh9vTxLFtV6V/NV22QOq2RERJ2PYIhkIS7+uz2+zbaO19AICVdGJWOGFApG0AAqLmTHkUlilicZMOiR2QpyYWVbmSdvU8daoKRDGWzdlYi4wVAKgUbVt9++oR1VqXqOPWrLFjDQDWr99oYgGxGDpyZJSuf6xmFWtMdFavc9ugMGXPQaPJ1YHdaaJGJKH6KFd4ji2wI4p73I6LoSchIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkxrIVJjRrDQQnJCx5+huISQ8iUs8nmuYJOZZ+HSxaawwAqBQH7XaJPUg55iKKsGcTham2TcpWStzKplhda2IdkugMc3z9Nkm2T9WsvQwAxMR2ZXDA7j/r2VdfylofNdL2O89Y24oVAKDXIJYjdXtci10uTEhH1nYnnCW1aFhCFgCmrWAjVeD1nPLEHiU1cIZdLsMT2AFJ9gcZ29fYIyxwHZKEr5Px3uJ97RERQjfFk/Wxs4l9ZsWT94l7yLhg34VTHmED0tY6i+Tf0XHcCicdkDHg6WtAxuu6gr0H5ImVDgBkMvba6BLBzjQO8v3XbB8CUo9o6jC/t/WqVtjgHL/lV4usdpJt/+rQHn8AcJPzr41IwgQhhBArAU1CQgghEkOTkBBCiMTQJCSEECIxNAkJIYRIjGWrjus2onluHhE86rZBqyLqy1vLk8BxxVpr3NpQ+JR0YckqW9otq6IKCvywupJVFk0Ry4788Dq6fqFq+5AmiqnYo0xCSBRrba5Cmp6ZMrFmZFVY1Ra3kmHWR32BVRGVS1xt025bdU1vxu4/RxREABCQ89qetWqf5hFrhQQAccuqBju81iGaJJ7L9ZtYKuBKwm6HFGprWyVerq9E188RdV6mZM+rT7HUIl4wvQ63cwqIui1LCiOGnu+3jhzENFHnlQrECghAKt9vYsySK0jxa8A5O4aCwGMxlLH9SmVs+6ngD0BEbLJaDWux42a5zVZf2m64TvS8XaKYA4CI+O4MruXX60DVquNSKTve1viKYAbz29WNY2DySb7swv0saikhhBDiJUCTkBBCiMTQJCSEECIxNAkJIYRIjGUrTKgW00idkHTPeOqbVIgNRV/JJtSCkFtzkHJCmKnx+hxPPXPYBkmzBldvouvnB23yb7ZuE8DZKk/Wp0tWmDBdJwn0Hk8ql8s2gZ3N8GR3KmsT42PTNtnPYgBQrfSbWD+p8XPGgLVBAYDpQzaB3KjZBG6B1acB0J21x2DyiG1rp8nPdXXNKhNrT1kbFACYPmbPwYZXvtLE+kd4Ujhg4pKuFRFkCp6aWlkSJ+M6iPi4iHtWmBAxLxwAKdhkeZeIGFgMADJZKzhgwoTQI65JEesp5zzKgEXC6nwBvHZSr2cPbLvNx0W3Y8frbH3K7j/k+181aMdgOs1FDLwBHksqQsjsfGJ7DmdqvChWkJk/hiNi5eRDT0JCCCESQ5OQEEKIxNAkJIQQIjE0CQkhhEiMJQkTdu3aha9//ev4f//v/6FQKGDr1q34oz/6I5x99tlzyzjn8KlPfQp33nknJicnsWXLFnz+85/Hueeeu6SGrUoXEZ6Q3Io8SbapIzYp3MvY5N1gmSf7WfKvUubJ+qeJi0D/8LCJOf5iPMKiTcquLa43sVKVJ7CRtck+R2rktCKebO92bbK51uLL1ok7QkRyxc7xBHLE8pyk9lEp5LVYgoLdbi5v1x8gNU8AINU6aoMN+wZ7X8G6awDA2tUjJhY77qSBnj1WA4NWcJHNeVwEYptYD0iyPMzzZG+YsiIG5lgQet52z+btvpoxqVEEoEfa6kIiLPAk21MeEYDZD6lndTxu++rc4mvX+EQIdF9EXNGBvbdETN0EoBfbPjBhRkyWO74+cdIg7fc5JrBbZnqS1+/KEYVVFNnxxmq1AVafFb9U9YT27duHD3/4w3jwwQexd+9eRFGEyy67DLOzvywsduutt+K2227D5z73OTz00EMYHh7GpZdeinqdK0iEEEKcvizpSei73/3uvP9/+ctfxtq1a/Hwww/j137t1+Ccw+23345bbrkFV111FQBg9+7dGBoawt13340PfehDZpvtdhvt9i+/cdQ88mghhBCnHi8qJzQ9PQ0AWLXq+E9aBw4cwOjoKC677LK5ZXK5HLZt24YHHniAbmPXrl2oVqtzf+vX25+nhBBCnJq84EnIOYePfexjeNOb3oTzzjsPADA6etwRemhoaN6yQ0NDc58t5Oabb8b09PTc38GDvN66EEKIU48X7Jhw/fXX4yc/+Qn+7u/+zny28A1w5xx9Kxw4/qSUy3HbdiGEEKc2L2gS+shHPoJ77rkH999/P84444y5+PC/KMVGR0exbt0va+KMjY2Zp6Pno5LOIzzBNmPGowBpEMVTi9Qe6nlUMbmB1SZWrFp7GwBww3bZXL+1THlmnCizAMSz1gqnMmD31SLWIACQhVU3latW3ZVOcSXgsbpVxjx17Bm6bLNuc3N9a21bB/v4sSoWSBuI4CpqcRuQQsqq3oqk5slglT/M57tWxRWRLztZUmMJAEJiJdO3yiohASDfR85Bzq7vPOfVpW0f0lm7fkBUaACQgv2ClybbRJZfA+wMuBl+XmJS4yYmyqqex0on6thBwBRvYchtg2LiRxSRekisnpUPn8VQh2y30bbXRcpjcVQgdZ5ysMpb3/6niJKt1eTnheFxOqOkydAk4jjmBgUAKPX3z/t/HMfA2NOL2veSfo5zzuH666/H17/+ddx3333YtGm+R9qmTZswPDyMvXv3zsU6nQ727duHrVu3LmVXQgghTgOW9CT04Q9/GHfffTf+6q/+CpVKZS7PU61WUSgUEAQBbrzxRuzcuRObN2/G5s2bsXPnThSLRVx99dUvSQeEEEKsXJY0Cd1xxx0AgEsuuWRe/Mtf/jLe//73AwBuuukmNJtNbN++fe5l1XvvvReVCn8pUAghxOnLkiahxVimB0GAHTt2YMeOHS+0TUIIIU4Tlm09ofxgCenwlymrwJMSyxBviixd1metYZOCvZinylqxtexokfIezcasDQKIiDgiT5Kyk40pun5/htQXKdoEfp8nKcvany576vHM2ONVm7GWHbkCt+eoVKyIgtXIaXjqERU7VoRQdXabOWJtAgC5nE0Al4tWRJIpcCubTMWKGJgIBQDSJbssEyEERGwBADli5RKmbLuClOdLIBlDKeIEk/IoVFMkg53O2dpPANCB3Ve7Y2PdNrf9AbGocSTms32JIzuGuzUr+MmU+LEOSI0gHz0yXnOBHZc+EUSW1Hnqdex4bTZ4X1usdg85V8Ui3/80EW35agxVC3ZsFUNS+4kIUwCgMjRfhBFFEfA4XdQgA1MhhBCJoUlICCFEYmgSEkIIkRiahIQQQiTGshUmtFMtxCckEfM8J4zSy2yyntElbz8DwEw4bWKel7UxNWXLUcwctW8FhxXuIjBYscnyPOnYWN22CQC6WZuADds2UZhO8wQ0Yrv++ipPQGeJk0GD1E0Z9LzFnyOH+5mjYyY2e8jGAGADOQTDedvWfMSl/6l+e6wzq62LQ54IEAAg3W+FAamiJ1mesUn4IEPcGdI8WZ7O2JpK6ZS9NAPHx3DYteIatmzgKfHiYAd8N82PS0TcGTKB3VfKMy5Y7Z8eSZZHbe4iEPbs9+ZiSMQlZLnjYVKPKMsv+HzGihAKga0T5YPVQIuJOKhc5E4cUcneG6ZnrItCdhW/OTINwqxHoFUitb5yGXJeM/xYBQvWX/j/50JPQkIIIRJDk5AQQojE0CQkhBAiMTQJCSGESAxNQkIIIRJj2arjatNTCFO/VOL0Od7U6qBVsGSIDUp9coKuPzlrLXZWeRRjpTUDdv1Rq3bpH7DLAUA3bZUlDVLNpRlZexwA6ExbG46ZhlXL+CyKzhhea2JpT3mSqG4/yJBT0Jezx//4BmxoZtq2NQp4W3OkTlG2aM9raa2t8QQAqT5iOVK0Hch61HG5Pqs48rjuAFmrGKNWOEQxBwDpFFmWqNBSPY/iLGe/S4bOqpPCyKdYI7WPPN9PM0RhF5B6Qj6LoJio3uIusfLx2PaEZLtBxqrjOh1+DbUcGW8edVw6Y094HFs1qs+mqzFjaw8ximWubnPEzufIUVv/axW5LwFAmtj5zJJ7CADMzFjlL4PVbgL+pX7Qc/z/udCTkBBCiMTQJCSEECIxNAkJIYRIDE1CQgghEmPZChPGxps4MQdZI8lPACgP2kQlq8/C099Ap2UTmJHnqAz0D5lYWLJWMBlPonG0dszEUqRlocc3aLHJvkqJiwXKRZvsT/V4UrWSswchiokNSdNaAQGethIfkVUVfqw2rNtkYoM5m4Dtq/TT9Xt5+/0qRYrspMueekKkTlOmxAdGQIamSxOxQMjXZ8l2UrYHKeexTEnZeECEDemIr+9iYhHk+X4aOhvvtGyyvtsjhbYAdInFT0Dq8YQeYUIEew4jIgxodXgCPl2116sLeV87xGInJmWS2D0EANqk2NjkMWtTlSZ1xgAgG9q2VgpEsJPjgpcKsQ+b9ggTpqetT1aXXK8sBgCNxvz4YgqgPouehIQQQiSGJiEhhBCJoUlICCFEYmgSEkIIkRjLVpiALnBibrXhkRbMkgR4MW8TnflVPFnfIonSWZJQBADXsVnJQtXWs8mVbX0YABggb2ZPtexb1WleSgWFnO1XuWRdELoex4Wphn0rukzq1gDAGWs3mlhEErChx3GhNWsToBkmTBjyuFOQ4xqQt9XDPE+AZsg5SJHX/VkpGgBIZ5iwgS8bpKwIgJgQIOWp88SiKSIACDwuBAGpBxSSrTIBAwCkiBIn5fl+mmJ1ekhfgx4/LyHZbkxqD3U8B7vLnCAKVtySzfL12XDtkjpZAHd9IOWQvLSb9hpgIoSSp/5YKWtrF2XL9roIS9zKo8ecY+rcxYEJE1gsQ5xAjuOTfj0/ehISQgiRGJqEhBBCJIYmISGEEImhSUgIIURiaBISQgiRGMtWHbdqsIDUCaqjZoOrL7pErNEmqpaQqEoAoNCzapunDh+iy7qpcRM78+yzTSzlqduSIoqfZtsq8aI2l5xlMyUTYzYahTS3wum1iGWHR+1SLVnFTpfUV5ltcLVNh/SrULDDrVribc2XrGwtS4ZAmOGKsSyx2AmI4i1IcblTilm5EBUcAKSI4ilFii8FxMoHAFJESMZ2xRRzgE/JZpVwqZ6n/SFRgXksghxpQxjYDjiPFQ2zc2GxdOyxU8rZ8VImqsOcx+Kq0bXjMhXz663RtmrQdsNeQ60mvwaK5J7TN2BVuu0Wv7fVJ4+aWKa/38R8tj15IuVjVj4A0CD9YveWYpErfxeq5nq9Hg4d4jXcFqInISGEEImhSUgIIURiaBISQgiRGJqEhBBCJMayFSZ0M5l5woT8ME9gZ4vEmqJJ7CayPNFZ7Os3sUGPPUorIglcklTshrzGzsy0TWA6EisPWSseAAjStq8Zkn8Nux57lhb5ztHPv4c4YvGSCm0CORPYYw0AxcCKOPqIPctgYMUWAMBK72QKpO5MidvD5MiB6ebtGPCJBcI8EbfkPMuSoZVJk+MXcBFESOocsXo+Qez5zsgEB2zZgI8LpEgHmO8QeD2hQtr2y1f6qknqAbVI7aDYU0+oR0QQSyFFanXFEbfpas5OmVirRe4tnnFRIKIbJk6C4zV+ZjpWmIC2vd+kOp7aS55+MZgdD4v5hA2l0vzrOI5jCROEEEIsfzQJCSGESAxNQkIIIRJDk5AQQojEWLbChPHxxrz6KavX8Td1G00rApiZsXVzfHUw1q4dMbHBVbzGTa1hC/3MNmZNjL1pDAAz01Mm1k/egKZv64O9Aw+kQ+tiEMQ8UVkp22V7Pd5WVjsIMRFckOMPAJnIvoVeJG+7l0iNJQDIEBFDSOqjBB4XAZD8NdFVIEv2AwAZ4q4Qsg0ASJOaVCHsOUh71g+JPULAnAVYpwCALctcDDyOD2y7zuOuAOauQGoM9Xy1j3rEnYDEHK38A4CMqy6p89Vu2+sSAJqxXbbRtvcLAJidseKaiWOjJpYn9csAYDUR9+QKVoiTKfJ6QIMvswKlZscKO5oNfg1Oz9p+tTy10vx1ghZHdsG1GUUeZQpBT0JCCCESQ5OQEEKIxNAkJIQQIjE0CQkhhEiMJU1Cd9xxB84//3z09fWhr68PF198Mb7zne/Mfe6cw44dOzAyMoJCoYBLLrkEjz766ElvtBBCiFODJanjzjjjDHz2s5/FK17xCgDA7t278eu//uv48Y9/jHPPPRe33norbrvtNnzlK1/BWWedhc985jO49NJL8dhjj6FS4fV8/MxXwTSa3NoinbbKnlrdKrsC8JofpWLZxMI+Xp8jJJYfTVKjZ+zoEbp+RJQ9xAkIZ/SdQdcvZaxCsDFjrTGyxN4HANKBVcC0u1xFFMOqaEKi+iunue1OyR5WlMiy+SxXUWWInU4+Y+1lCjk+rtgxSBF/nXSGq/OyRF2WYYV/AKSJCoqNS2Z7BAAh2W5AFGuBR3HEHHpioqXskdpZAODId1HnuGqyR9SIERVjetRR5HAH5C4UwlP7KCCqRVI3B56+pol1UiXHx3AqtOq0VtNeLw2iQgP48c5kyLhkVj4A0LJKPmZ71PTcG9n9Ju2p87RYooiPi6ML7nk9j+0SY0lPQldeeSX+3b/7dzjrrLNw1lln4Q//8A9RLpfx4IMPwjmH22+/HbfccguuuuoqnHfeedi9ezcajQbuvvvupexGCCHEacILzgnFcYw9e/ZgdnYWF198MQ4cOIDR0VFcdtllc8vkcjls27YNDzzwgHc77XYbtVpt3p8QQojTgyVPQo888gjK5TJyuRyuvfZafOMb38A555yD0dHjL3ENDQ3NW35oaGjuM8auXbtQrVbn/tavX7/UJgkhhFihLHkSOvvss7F//348+OCDuO6663DNNdfgZz/72dznwYI3pZ1zJnYiN998M6anp+f+Dh48uNQmCSGEWKEsOUuVzWbnhAkXXXQRHnroIfzZn/0Zfv/3fx8AMDo6inXr1s0tPzY2Zp6OTiSXyyGX44n0EykWuG1PIc8tL8iSNBqSwjWdnrXnAYCZWZuUmyJWPPk83xezE5qZmjSxSWJPAwD1rq0vUinY/qd9Fhyx7Zfz2PbkSGI8T5Kq5SoXBuRIQZmAxAp5PgRzRJjALIrCND//qdC2NUuSslnPF6RcYI9LzlPLhpUkIuWEkPJcbcQJB3RXKU/dGLL/LkmK91gCH0CP2P74Ess9ooLoErGCr3ZSmtghZchtqEdqLB1f1sKclzKe2ksBS8znfGPILrvujI0m5jwiiGzO3rMcOa5tIm4CeE0lVqMo8tzGW2RsZ7O8r6Ojh2l8IT5hw8I0Sq+3+LpPL/o9Iecc2u02Nm3ahOHhYezdu3fus06ng3379mHr1q0vdjdCCCFOQZb0JPTxj38cl19+OdavX496vY49e/bg+9//Pr773e8iCALceOON2LlzJzZv3ozNmzdj586dKBaLuPrqq1+q9gshhFjBLGkSOnLkCH7rt34Lhw8fRrVaxfnnn4/vfve7uPTSSwEAN910E5rNJrZv347JyUls2bIF99577wt4R0gIIcTpwJImoS9+8YvP+XkQBNixYwd27NjxYtokhBDiNEHecUIIIRJj2Ra16+vrQ+qEIlwFjyojR5QtlUq/ifkUa6yYU8tjTRFF1srGt10GW5apTTrT3EonICrC2rFjJlav8/eyBqpVE8sNcHVYSAp15TLEdocoiAAgDK1lSIpYwWQ9Sr4MUfGwWDplrXgAIAzsscqQrmY8ircMUxZ5rGSypFgcte1hkjkAKaJ6C6iSjbeVuQk5oniLPYqlgFjBpMj6ABARJVxAzkGQ9hS1I0KyICLqPI/tj4MdQwEpVJci6sZnt7CQTjxNl+x2rP1XTO4NLU9hR1YAz7cso5giRSjJ/W66xtW8IPcbpgYGgEqlb1Ft8qnjFloE9Xo9TEyQwpgEPQkJIYRIDE1CQgghEkOTkBBCiMTQJCSEECIxlq0wIZNJz6uzUfPUzGA+HpmiTaAXiVgBADIkqdyc5vVBotgm21st6/q9dt0wXb+fWNxEkU3etYg9EABkZ2wCMqjbtuY9pzVP9lUIrFgBADLE9iYkScmuZwTNxlbEUSS1e9JZ/j0oT5yLiiTZnw/5scqQGi0Z8p3Lkz9HjtjOZMj+ASAkVjTpkNS9Yf4+AP0qyIQFPZ8wgdi7ZEmRn8hjpROR7fqsYEC2ERJhBbP3AQBHxBHsDHaYggFA7JjHEWkriwFw5BqOOjYGAPVZKxCa6dpxHXnuTd0OuQaI2CDnE/d07LKNGbvNsschp9u1H8y2uT1Pq26PATsvXVJTjMXZ+PWhJyEhhBCJoUlICCFEYmgSEkIIkRiahIQQQiTGshUmNBrNeY4J3cCT/CNvRoc5+6ZwnsQAIJMmjgltLkyYnJyw+49suwoVflgHqra+SF/FtqtS5mKBbM7uK2zYBGBAkq8AUF672sRygwN02ZjVwyGHMPAk69NEhJBNExeDbJmvT9whQtKm0JPAzhHHhgwp3ON1TCDJdo/hATIpIrggC6dYBwD6VZDV+PEle4O07SsbA4GnRpAj4pyeR/ARM3eG2K4fE2cFAIh7ZF9gJ5Y7YSC0fUiRtvZi3v5O27orzDT4vaXdJp1NW2eBfIXXOiuToUlOFdKRR4TRJn1tWccF5u4BABUihOrM2vplANCcJqKl1fY+5HNWiBY4SfR6PdRqY3TZhehJSAghRGJoEhJCCJEYmoSEEEIkhiYhIYQQiaFJSAghRGIsW3XcunXrEJ6gJooCXpticsYq1saO2VirzddPE3Vcs+mxgiG1bzIZooyJuFqlPjtuYu2OVYEV8lyBUgitjUe2YCVrQczVNoy2x3IkLJHaPaRGT1gk/joASkV7rAoZVuOHrx+wuiXEiicVcMUZc23Jhdb2yKd4S4dWGZUJ+He2NFHHkdURMMuZJeA8tj3MzqdH7HXilEeFRRSCkUdxFZGaSl2ihOt6hmBE1HFs2dijGOu0rLys2bKKt4bHiqcd2WV7nppU6YIdRK5jY6mU3SYAOGKd1G7a+1Cjzq9BV7cWPR1ybbeowQ7QBFHCOV6/a+2QVcI50v+FdYOeZWGttDjmSkyGnoSEEEIkhiYhIYQQiaFJSAghRGJoEhJCCJEYy1aYMDy8DukTktPt2Nb2AIBcySa2xyeOmViTJAT/5RMT6e9fS5csFmzyLo5tsrtY5EndGHbZ8ckjJpbL8kRlMbvKxMoVWzsJJFELALNTNlHprAsIACA/bI9BumSHS86XrCeCj4BYsThWEAoAQrJ+lljhEMsZAGDNSjHLF4/tUIopC7xf2WyymNnuBL4aKywxz8QGpBYPAEQk3CEiiK5HGMGWbXuWpbV/SL/aPY+woGPPYY+IELpdngBvNO19oDZrB3GrY681AIjIuOplrAgHAFqz1r5r8qgVF6XaVkAAAHHL9ito2n716vzelCG3AUcEO+WREb5+lVhiESETAHTJtTU+be+jtdo0XX+hnU/kEZYw9CQkhBAiMTQJCSGESAxNQkIIIRJDk5AQQojEWLbChHa7jfiEt4NnPDV+IpIArVZtjZxZkmQE+BvAfZ76IEXiZNBo2kRdkyRPAaDdmzKxyWnbrtWrePIwTRwbclkrTEgXbB0RACitGTKxgGwTALppm8RnyX7yAjwAICb1bNi5ijL8e5BL2aEZEMcEeIQFSJHEftqu32MCBAARWR/ELeD4RmzIkVjAc+1wpA2OiBBiUrcHADqx7ReLdSN+ubd7dtl2j1tJRKRdHdiO8Xf4gYi4M/TIcQ1j3lZHrDBiZwUv/PwBEXG36HlqUrUj24uxMStMCDz1iApEdFNO22uzlOfXa9yxxyVVsCKKMMsdVtqkKNjsUV5PKN1nj2GjYe9jrRYXURw9Ol9g1fPUrmLoSUgIIURiaBISQgiRGJqEhBBCJIYmISGEEImhSUgIIURiLFt13NGjRxGGJ8yRGa63iYjkKENsRCKPbU+a2GA0Gtz2JpO2bWi0aiY261HyrRlabWLlwUETK3mUSUxx0opsv5gqBwDyaWtxlC5xJV42bZU5UWCtUAKPlUxA+pDOsXpMvJ5QSOKsRpAjyiyA19PpkRo5EVkO4PWAmGINAOKYxcl2Q67CYkq6HpEd+mx7uqR+VTuyx5qpEwGgE9lz1SXqOgDokDoxHeI7xKx8AKBL4qxVMasnBSCVtuM1R8oBdUn/j7fLjpdWi9vuTNdsfGDkZSZW9FyvKaIQJbcQZFpc9djq2vtQO7Jt6tX4vS3Vs9dQ7RhX8nVnrUXPeNPe27oe2WNxQf0w31hl6ElICCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJsWyFCVNTk/NqxQyvX0OXC4gIoD5jY80mT8hxeFKzPWUT83UiTAB3/UEvaxOFccomGt0sr9nR6tn9pyO7s0zeCiAAIJ21Sd28x7YnIhY3EanbEjk+hLI5ay+SDa3FUC7L10+nSbKX2Pb0mFoBQEwEB10iYgiJjQwAuBQTPPAENIjtDUgCngkQjmPXd6Sej/MKC+z6jZgJE7iIIyINY/Y8ANAlyzaInVDX09a2I9ZNRHATdfn6rQYR5xAdUUQsbwAgJlY23Q5RNgBIZ0j9rj47hkNS+wkAOkTgFJHMfs8jWGnMEtuduu1/usUH1qo+e28YqPLr5cnaL0wsQ+4Na9faYwIAxeL84xLHMY4cIfdGgp6EhBBCJIYmISGEEImhSUgIIURiaBISQgiRGC9KmLBr1y58/OMfxw033IDbb78dAOCcw6c+9SnceeedmJycxJYtW/D5z38e55577pK23e125wkTfETkreSliBBYjZ5a3ZNQ65A3k1lO01M35uChJ02sstqKBVYX++n6pdDWDQlJUtZ1+GvNraYVFgQZT7I9Z+PkZW2kiLPCv3xCYnbZmCTgAYDlxdlL+L56RswdoZ2y59qXVCarI/B9Z3NEMMEEGyQp/uyW7fp2qR5xNgCAiLkY9OwYYAIAgLtGMGEHwGsHxc4OwtjxMdgl9buaM8TFYJZfRLVJW+Om0bDjOs5ywU2qYC/YUsmKDQAgk7fimhbp/3SN3y+iGXvBFMj9Jl+2+wGAVGiFTK5gB0ZAjikARBlW04svWyjY+9DgaitwyhJxFcNjmEF5wU9CDz30EO68806cf/758+K33norbrvtNnzuc5/DQw89hOHhYVx66aWo17mVjRBCiNOXFzQJzczM4H3vex/uuusuDAz8soqpcw633347brnlFlx11VU477zzsHv3bjQaDdx9990nrdFCCCFODV7QJPThD38YV1xxBd72trfNix84cACjo6O47LLL5mK5XA7btm3DAw88QLfVbrdRq9Xm/QkhhDg9WHJOaM+ePfjRj36Ehx56yHw2OjoKABgaGpoXHxoawpNP2nwIcDyv9KlPfWqpzRBCCHEKsKQnoYMHD+KGG27AX/zFXyBPknbPEizI6jrnTOxZbr75ZkxPT8/9HTx4cClNEkIIsYJZ0pPQww8/jLGxMVx44YVzsTiOcf/99+Nzn/scHnvsMQDHn4jWrVs3t8zY2Jh5OnqWXC6HXM4qLjKZzDx1XIdYxgBArc5raSykUrHKMgAo5K0qpNnyyNu6RNlSsYcwW+UKktH6URNrEcVds8B9f9o1W/NjdnTcxPoa/LQOrXm5iQ1EHnVYzm6jlyfqMqI4A4C4S+rGkH25lKd2UmC/H7FaNCmPFU7AlHjEjsn35SggijcvzvbBESsfViPo+AfkuBDVoEfchojsq0vscWKPlU5EauxEHnVbBGsdFTtS44aoVgF+DFg9pm6br99p2f232zaWCvm4yjKbJ8+y6Yw9ru2aVd4eeWaMrs+ujELV1g/z3YXbpH5XlCbHxbN+szlpYkfH7D0IACLYfnU9Ndzo+gsUeqz2mY8lPQm99a1vxSOPPIL9+/fP/V100UV43/veh/379+PMM8/E8PAw9u7dO7dOp9PBvn37sHXr1qXsSgghxGnAkp6EKpUKzjvvvHmxUqmEwcHBufiNN96InTt3YvPmzdi8eTN27tyJYrGIq6+++uS1WgghxCnBSXfRvummm9BsNrF9+/a5l1XvvfdeVCqVk70rIYQQK5wXPQl9//vfn/f/IAiwY8cO7Nix48VuWgghxCnOsq0nVCjkkTqhfkwz4kmyBrHoISU7sGoVT6AXi2UTy3nqe0SR3Ua2aNNqoccKh4kgIlhhgsvy9Utp29ZsyoogqpHdDwAU8/0m1rG5TwBALmftTSoVW9MpTvFj1evZPvSIWKDrse2JSDxDRAQ+d5AesSeJu+RceeohBSETC3hqD5FD4FhiliTgj2+X7J/Z9sQ8hUubxWIxP1eAtd1xRGwAAIjseO05a6UT+4onOeZzZWPO8es1DO2yeWI54+tpl1haxcTiCAAaHXtc6rUpE0un+RgarFZNLJ+2quJuj3hvAUDejuESUSV3SDsBYGaSiLk8YoM1a61wjPXrySefput3u/Pvw/8qtj1CCCHEi0WTkBBCiMTQJCSEECIxNAkJIYRIDE1CQgghEmPZquOiKJqnjitwsQwypEgUYBUg9Qnuzp0OySGIPIqtplUMRcQGJGouvshUvmzXz2W5ui2IrDIozNm2lqvrTAwAihlrBxTXuVomXyaqQaKY64CroEKybCq054oVbwOAqEtsZ9LECsdXJ47a3rBKeXz1gCnefLuK7b5SRB0WeDrriJUNE5c5n+KMrJ+KbAd8VjroWcVb0OU2Wa5n1ahxaJdlVkIAEEekAN+sVXe1PNZT7Bw6YrsTxVz2eeyovQ8cneRWNk2iBHREMVbx+Gj2iOrNEXVcLvAUigtIAcCubVO2yC+CoawtSlcu831lMrawX50V92TixuNbmP9f5wDPfXAhehISQgiRGJqEhBBCJIYmISGEEImhSUgIIURiLFthQq3WnFfrpVDg9YDOHB4xsekpmyidqNu6OwAw+fSEifUVPRY/xOIlbFoRQXpVP10/X7bLzkQ2+ddq8wR0p1E3scA6piByNnl8fLs2q1jOWgECAJRKAyaWIsMl7alRkyLHKkWS1UGHr+8Cm2yNiRVOx1MPKGS1h1KkxpGv7EnaLttjXjrgdj5pUjvJ43DERQgsAe8TNjCPFGcT872I27vEbSu46ZAYAHRiIiIgd5F2lyelGzU7hhsNUs+ow5PtdWI9lCpawY2vdlN9zF7vtdooXbbQZ+85g4PWiofZcQFANmWvt8hZYUG9wWuidYinVkz6v2oVqVEEAOQQzszYmmQA0M3YfZWI7dBA4WV0/cnZ+bWLXNxDs2aPNUNPQkIIIRJDk5AQQojE0CQkhBAiMTQJCSGESIxlK0xYSJXU/QGAwUGbQA+JCwI1VgAQkjegVxX66bJpUtOoQxKFGU+istJvE4ilrq04e7TFE6VRzQoOhopWmBGm+f57DZts7qX4295RZJPFnbpVQfTSPAGcy5BKuk2b/PTVHWF1Y1jtoR4r5gMgJOcll7KZ2jDncyGw5zrweCb0HHFyYI4LHhUEEyaw9T0aECpM6KWIiMMjFpgl56UTcceBRtOKfmbS9lwdO8aT0kcP2Xi5eqaJZUI+hjs9OwZXFe3b/l1WVAxApWJFDJXKZrpsgdQpKpWYkwh3IWi37TGs1abJNm37AWDVqlUm1mxaEQMTK/jo67NiAwAoVOx9ICzaWFSfouuvLg3P+38vilF7XMIEIYQQyxxNQkIIIRJDk5AQQojE0CQkhBAiMTQJCSGESIxlq44b7CvMqycUkpohAK95MTFu64PkidIFACqVfhM7cb8n0muRGjekRkua2G0AQESWzREFSrVnFX8AMNmw+y+VrbVImcQAICK1SFozxPcHQI/U8+mRej7ZMlf2xB1r79LpWhVXxlfPJ8+saOz+Ux4VV0iUYCksrm4PACBr++886rh4keo4kLpDx5clFj0kFnU96rqU3W4rbZdtt7lirD5jr6GOR3XYJHZEzcgqzppdPoZniZ1Tb8a2P4p5W5nN1aq1tm5OihwTHz51WoqoKZm6LZfz1RNi9wui2vSsn05bSW+nY/d/7Bivh8SUcP39/Lx0nb1enzz0tF3OozJOL+hDbwmKPT0JCSGESAxNQkIIIRJDk5AQQojE0CQkhBAiMZatMCHfcQhPqP/SafAEehTYBObEuE1eZjK8ZsdM3VrZrCbWHACQJxY/WZJUbJO6NwCQalnbnR5ZdqLDa340m/YYtPOkPkk8RdePp+yymR7PNKZDG88ScUcmy9dntW8iUlAn8iQwM5FNCgekRky666mRw2x3yL4Cx61sWD0iXz2hmCTb0bPt75F6SgDgmB0REYZ0WryvPWKbU2dWPESYAgB1YtHU8ngE9QJ7vltEsNPLcCHQxPQhEyv12/1ns1wswARKTEjkiFgE4MIAn8XPmjUsiW9FPz4hE7PYYdd7ROzAAKDTsdvtEMFPq8XPaz5PbHc8+6rNWsHDqort6zSpUwUAk9Pz6wn1vIW6LHoSEkIIkRiahIQQQiSGJiEhhBCJoUlICCFEYixbYUJ7oo5U8MuE7UTTig0AIGNf1kbG5mnR7Xjqi6RtsjlNBAgAEJME7sSxKRNzfXz9VNY2jL0VvarPvgEOAOn8GrvNjk3UsnYCQHHQ1iep5EndHwApktiNWbLeJ8IgJyEdkgQ8cWEAgA4RDAQdu68eESAAQJq9rd4j23R8/ZBYKbS6fAzGsT0HLm2TuhFxjACAVGDHSypja9S0Yz6uuuQYjE/aWi5djwhksm0FM2HOIzhJ2XibOC74xkUrZdtVHz9iYue8itf4mZm153B83Ap5wtAnTODXBoPVJWMihK5HHMPqDLEaQ8z1BeC1i9assfcAH0vpa4q0lYk42kQcBQDNBfvy1c6i+170kkIIIcRJRpOQEEKIxNAkJIQQIjE0CQkhhEgMTUJCCCESY9mq4/J9RYQn1AQpeOpYOKJui0AW9vR0sGTVYTmiigGAPFGHFYYGTayb86jrSDgVWBVZ6LhlSURUf5mcDUak5gsA9Eg9m9hTo4YJ7NiSKXL8ASBTsIqxPLGXcWmu4HGkvknXWXuSbsTVOgHs+pm8VfuEnlouYdq2v93mNa1apH5Ur2ttUGY9tZuCwH4XLFesQtLjRIPmrN1uc9bWmOl6xnWG1M1pzHJ7llSG1Gki45LVbgKA/n6r+ApAtknaBAABGZhjY6MmVigQ2SyAcplc754xwOxwWD0eX62z2dkZE2M1hppNq070rc/UeazGEeC36GFks1YdVy7bekRZJj0G0K3NH2+9uAduJmTRk5AQQojE0CQkhBAiMTQJCSGESIwlTUI7duxAEATz/oaHh+c+d85hx44dGBkZQaFQwCWXXIJHH330pDdaCCHEqcGShQnnnnsu/uZv/mbu/ycm5W699Vbcdttt+MpXvoKzzjoLn/nMZ3DppZfiscceQ6XC7WF8jPzKGcickBxue5J39ekpGyRWODlSWwMA2jO2nlCGL4psxgoGSNkYNGs8AR0SO6BMn/0e0Jzk6z8za+09yn020Ztt8KRyZcomRftDa+UDAMVSv4kVBkhSOeUZQiQnGoMIAzJc2BCQvHZEbEgiZ8/f8Q3bY+CIFVDY5cKIILb1cGJS9wcAYiL46PasMKLdmqLrM4sbn+0MozZla/R0O/a4lirr6Pot0q+Jtk2KA8CqohVMzLTsuOzr66frv2xko4kxEYJPWJDqkZpabWvbc/SotQICgFe96jwTY2IFAJiZqZtYq2XHG6vb44MJG2o1btszM2PPQZZaf/Fr8MgRK9gYHx+ny27c+HITK5XI/Y6IcACgucC6idUT87Hkn+PS6TSGh4fn/p71MnLO4fbbb8ctt9yCq666Cueddx52796NRqOBu+++e6m7EUIIcRqw5Eno8ccfx8jICDZt2oT3vOc9eOKJJwAABw4cwOjoKC677LK5ZXO5HLZt24YHHnjAu712u41arTbvTwghxOnBkiahLVu24Ktf/Sq+973v4a677sLo6Ci2bt2K8fFxjI4ef/QbGhqat87Q0NDcZ4xdu3ahWq3O/a1fv/4FdEMIIcRKZEmT0OWXX453vvOdePWrX423ve1t+Pa3vw0A2L1799wywYIf851zJnYiN998M6anp+f+Dh48uJQmCSGEWMG8KMeEUqmEV7/61Xj88cfxjne8AwAwOjqKdet+mQAdGxszT0cnksvlaN2NqNuel/WfHJ+i69fJz3cZYpjA3n4GgHzeJqCLFVsLBgCyRPDgyASb8rxBDVJPpn3Evtne6/BJO0OS8F2S1O3UuIijV7fHoDJg34oGgDhv29Ahb6vnAp6AjMghcDFRK/R4X4PAihhcYBP43i849I17235fLRiQN/67PneJlt1uj9QjCkNP7aaUPS7Nhk1KNxv8zfiJIyQJ37WXdrHkuQ4De6xaHiHQBKwIoL9qxS2s/wB/M58JM1LERQLgLgBMWDBLXCQAIEPe+C8WuQiCCRNGR58xsTVr1tL1mRNGt2vb73Nc6BARQMc3XAkZciP09ZWdF9bWvEfEsSqaPwZ6cQ81LC618qLeE2q32/jHf/xHrFu3Dps2bcLw8DD27t0793mn08G+ffuwdevWF7MbIYQQpyhLehL6z//5P+PKK6/Ehg0bMDY2hs985jOo1Wq45pprEAQBbrzxRuzcuRObN2/G5s2bsXPnThSLRVx99dUvVfuFEEKsYJY0CR06dAjvfe97cezYMaxZswa/+qu/igcffBAbNx7X/t90001oNpvYvn07JicnsWXLFtx7771LfkdICCHE6cGSJqE9e/Y85+dBEGDHjh3YsWPHi2mTEEKI0wR5xwkhhEiMZVtPqNvpwJ1gXeJxpqA0GqyOBq+tETG1im9nA1YFlCdqm6BllV0A0PbY+SwkF3IbkLVVa6MR5ayVTrfM1TY5Urso6ONqmYgodqIeqfviUZfFXbt+Lke+88T8WEWkelEcMXUcXR0BGdrO2X31PPYijljZMBUcALRbdgxFRB2WCq0CCQDCjFVozk5PmtjEqFWmAUCnQ+yImJ1U06q9AKDeI+cl4H3NkppQjJn64l86r9WnTGxkZANdNiCKr1Vlew309XHVZypFzisrngVeu6fZtArT0dHDdH1mscPWn5ycoOszJWCaKHR9yl+mjvNZ/HAlno0VKnasAkC44J4VkGvNh56EhBBCJIYmISGEEImhSUgIIURiaBISQgiRGMtWmFCfnkJ4QhKR2fMAQIO4i7CEnE+YwPAl73okid5q2ARyPMVrseS7tl0psq/WkSm6fkSy8D1ieZTN8eRxMWtFCBG4iKFVtyKKPNkus/IBgF6DJEtTVnARevLcjli5OGdFBCx5DADM9SUmxZ/imNvLILb7CtNcWJDJEosjkoBmiWYAyMGOi27bLjs5wYUFa4ZsnaCoacfg5DSvsZOvDJtYf3WQL5u3IoBczp7Xep1bDB0etd6Q6dBeA36xgMcSawG+GkEsiV+r8bayscXEBh2Pl86hQ0+ZWIPcsHxWOsxSjMHsdZ4rzmCCCdbWTWedTdcfXjvfEirqRngCP1/UvvUkJIQQIjE0CQkhhEgMTUJCCCESQ5OQEEKIxNAkJIQQIjGWrTouigK4E9RxXaIgAoAMEZZUBklROo9SpE5UIThqFW8AMFuw6qRUzap4MrweGIKCVVEV8/YUhBl+WqIx267pGRvrP8OqnQAgPzxiYukOl6c1Z20BvUzOKpN6nqJ0jtjh9Mg5iLkICkz0lqJSOo+6jaires7uv93iyqYQVgmXzljbJABI5606LBPZDtQ9Vja92I5BVkAvm+PFFkuFfhPrpGz7Zye4PUyQsfvPlbk6jin8mBKOK1SBvkq/iYVEHdfrcduXHrGOiiI7Blt2+AIAjh61xyCOrT0NAGSzVp3WJMX+2m2+PmMp6rhSyY63mCl0PbY9bF8+xRw7X2zZ8XFuHRUvsHli7fShJyEhhBCJoUlICCFEYmgSEkIIkRiahIQQQiTGshUmtJpdpE6wqZnyOVCQhFoubRN9aSIAAICQJGWZlQ4AVLLWsiTO2URp65mjdP3DxHpoNWl/1lOzI02yralxu82wnydKHat7QxK9AJDLWxFCNmu/sywlAZnN22WJOw4AwBF7liAgCWzHrXR6MWkr6WrkSYDHKSJs8Fj8MCuZLLG3ybT4eel2F5fYzhJ7HABokvpZztn9h0SYAQBTUzaBnWE1hsCtZFhifPXqIRMDgGrV1uSanLDJ7o4n2Z8K7YCpEYuicnGArs8S8J0OP6/HjlnBxdSUrR3kE2GwY7WUGj+MkBSK8q3vEzwwmAiBtbXpsU9bGPfV6WLoSUgIIURiaBISQgiRGJqEhBBCJIYmISGEEImxbIUJjUYTJxgmLKEaEH8zfWDAJkQBIJ1miUJesyRDaomEzi7b9SQKPeYAdj+kRhAAz2vgJCntOa3T5I35TnuKLlvqW21ihcC2q9XgtVi6JDGZIW/2Z8jb7gAQplhik4gISI0hAECKJJtDm9hPZ/j+ERNhhOe4dkjtnzBt33bPF/kYTJHEfiZbtU2K+f7Hj46bWJW4c6SL3PFhsGwT6KT7AIByxbo2VCqkrZ56QK227euhZ/7ZxFYPcmFDPm+v14nxMRPLERERAFSIY0Mqxe0VZmdtTS2WwC8UuJCor88el4kJe65YLZ+Tge+ex5ictPeGpdQjWrgsq/3lQ09CQgghEkOTkBBCiMTQJCSEECIxNAkJIYRIDE1CQgghEmPZquMGVg0gPKGoTN5jjZEu2Dirw8FqlgDABLEMGZvg1hRBwapo8lRx5al91GeVRSFR0vV8RXYWSadtbUwAoE3UVeOkRhEArF1n21Cu2O8sM0RBBADtpj1WpbJVrKVS3IombFt1l0sRFVrI1W1MoBiQILPcAQBH6iS1274aN0SJRr7euS5va0xKGoUhGdcFXuMn6CP7z1glZ4/UAgKAiUl7DUSeOwNTx+WIndDsrK295YPVGOrrszEACIhCku3fdXmdqBSxnkqx4lUA+sj1ms9vMLFslqtZ2X2IbXN83CrmAK5OYzWCqlWrwjse76fxxe5rKeq4hRY/x217Fncf05OQEEKIxNAkJIQQIjE0CQkhhEgMTUJCCCESY9kKE1avHUL6hNoZs566LzOxrTvSprVIeH2SGqmPMX3MJv8AIMrY+GpSs2MgzW08SsTeI5v3WPQQWsTeg+WaZ+s8KczSjCzRCQABrLCgMUvqq0wcoeszGjNEsOH4sUrlSN2U0Cabs1kuAgkCkpjvkDFEahQBQCqwye5mkwtWQth9xcT6qdXkY7jVtIKNfIHYQXX5d0Zm05QjY63Z4HVzRg+T+leeUjTZrD0u1aqt3dNucyucgX4rrmC1hyplnmzP5+2xzuWsRU+jwfff6dgxND3NracKBXtcw3DxNXoYTCwQeSyOuDCAj/cXy2JrD/lqJy20Lur1epiYWJwdkZ6EhBBCJIYmISGEEImhSUgIIURiaBISQgiRGMtWmDAzUZvnmDAZ80TjdJcn1hfiS6gx+qsexwOyK3YAK/39dP0QtsZG3LKCiQatG8TJV21CsetJXjZJ7Z/B1TwhWV1ra5H0iDikHXMRRNy0ydann7T9Gn7ZMF1/YNjWM2qSZHMQ8O9R6ax1EYhje/x7PZ4UdinbVyZAON4Ge7yjrhUBUGEEgLhN2kCECSVPsp7VucoQI4icx4ljeN0aEyuusmIDACgU7Hjp67PLdjzChKBnj0tE1DXtDl+fCROY44HPxWBm1m439txbUilW08kud+wYEXaAOyYUKlYwsi77Mrp+p2PvDZmMdbfwMT09tehlF4vPRcFXU2kx6ElICCFEYmgSEkIIkRiahIQQQiSGJiEhhBCJseRJ6Omnn8Zv/uZvYnBwEMViEa997Wvx8MMPz33unMOOHTswMjKCQqGASy65BI8++uhJbbQQQohTgyWp4yYnJ/HGN74Rb3nLW/Cd73wHa9euxT/90z+h/wQ12K233orbbrsNX/nKV3DWWWfhM5/5DC699FI89thjqFQqi95Xe2YGYfBLhVMTXAXXaFi1BnNyyXpsKQZJfY8yqU8CALNHbe2dXN72KZPzqKgiK62ZqFu1C7PnAQBXtB3LDlhlUr7M2z960B7DjkdJVyT1fMrEYigz2E/X7zZsnaFMn1ULRR4l4gxRLE11bPvzHnVb2Lb2LExxlSP1oACgUrHjJV3gijH2XS7TI5eWx3oKXRvPpu24yma44qvTsOuPz9pjlcry669Usuq4wQpX4uVy9nwNFOw11Ejxa2CGWGoN9JNzwApCAag7q3B8ctpaR1VIPSYA6EVWnZfO8+styNg2pJ091mvW8eOaCq1EMUsKTbm8R7nL3YTsYh7bISZkW4JI2FNjaHHLOnKefCxpEvqjP/ojrF+/Hl/+8pfnYi9/+cvn7fj222/HLbfcgquuugoAsHv3bgwNDeHuu+/Ghz70oaXsTgghxCnOkn6Ou+eee3DRRRfhXe96F9auXYvXve51uOuuu+Y+P3DgAEZHR3HZZZfNxXK5HLZt24YHHniAbrPdbqNWq837E0IIcXqwpEnoiSeewB133IHNmzfje9/7Hq699lp89KMfxVe/+lUAwOjoKABgaGi+K+7Q0NDcZwvZtWsXqtXq3N/69etfSD+EEEKsQJY0CfV6PVxwwQXYuXMnXve61+FDH/oQPvjBD+KOO+6Yt1wQzM8nOOdM7FluvvlmTE9Pz/0dPHhwiV0QQgixUllSTmjdunU455xz5sVe9apX4Wtf+xoAYHj4uAXL6Ogo1q1bN7fM2NiYeTp6llwuh1zOJlzzlfw8255CxDNqs12blOuQ7JkjAgYAKBRtYjsK+YTJiCOb1OyRGkcAkCL2LGz9Lq38A5Qq1kqnSuxtUln+3aIybRPIBz1PqAWSbM6vX2dig4M2qQ0AeZLY7xHPkzqpUQQAqZQVAaRSNtE72+ZJ5T5S96a/ao9fJsMFKzlSEyqOiRcOPPWriEVPKsXHVf8aewxLJVsjJyQ1igAg6vXbNtXsWGt1+LEKSQ45m/LVubKJ/em6PYeOnCsACLM2nitawUoj4lY6LN1drfSbWOyxDULanpfYY2f01MEnTKyf1E5iNZYAbrvTIgKr8Ykpun6tTu4Ns/bewMRZS4brSOz+PfGFbViCLmFpT0JvfOMb8dhjj82L/fznP8fGjRsBAJs2bcLw8DD27t0793mn08G+ffuwdevWpexKCCHEacCSnoR+53d+B1u3bsXOnTvx7ne/G//wD/+AO++8E3feeSeA4z/D3Xjjjdi5cyc2b96MzZs3Y+fOnSgWi7j66qtfkg4IIYRYuSxpEnr961+Pb3zjG7j55pvx6U9/Gps2bcLtt9+O973vfXPL3HTTTWg2m9i+fTsmJyexZcsW3HvvvUt6R0gIIcTpwZJLObz97W/H29/+du/nQRBgx44d2LFjx4tplxBCiNOAZVtP6Jl6HakTFHWznld12Vu9JeIssHboDLr+2qFBE5s4wpP1NfJmclAkNUdKPAHdA4mzt5o9LgYheYs8IDnVFKlFA2Ces8WzjI6P02WbxLWh1ZoxsVlP3ZexMatynK7ZpOzgKiuAAIB8zgoDMmlSN4fEACCXt8nigNSdaXuEDW2S7E2leM2UdNom8ZkalL1B72tXt2P3nyZv8ANAoWTbFRK9R6/BXUdK5FilSI2f4+2y24iJw0ilYq8rAHBEBDBDEvjTHf6+YBST40IsUjzaIIxPWIeSmSleE6tQsNvN5WzG/Z+fsgIGAIjIvWlknRVoBQEfg1lycyiS+l/FaPFuMr66aizM2p9ZpAbC9YAav7UYZGAqhBAiMTQJCSGESAxNQkIIIRJDk5AQQojE0CQkhBAiMZatOq6BLoIT1GSsRhAAVKtWncYUILkcVybNzFjF1+QEV8sslpjUwgGALFFRlUg9o5avaAdhYtqqfdrj3IakSaR0PtuaBlFSHT78NFmSt7VB1FXVPrsvX32TySnbr2zWHr+YWAEBwPjkmA06O9zZNgGgr2jtkPrIuQKAUsnazsQRqWfU5ZKtQtmuHxCLn6jLz2ua1KipFOw225O2HhYAdInqc7bHFVdR1yq5otXWyqY1ac8fADR69hgERF3XIHZWAHD42GG7f2KHFTT5saqNWclW12N788qzX2ZipZIdw30VT+2jut1uHFvV3+Agf4cyM9xP1rf96nSsxRMAzM7a+xhTvfooFvi9YTH0Yofa+OL2pSchIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkxrIVJiyE2fMAQGeaJ1AXcuwYr1vDtusrrcEsK7okge+TNQyuHjax/rW2lkwntjVbAJ7Una3bZLOn9BI2nf0qu/8Bnjx86pln7P5JX1cNcSub1WWeLF0s5ZIVAawasMeq1+PHamraJqCnpydMzFdLppi1gpd6nZ/Z2dlZE0vNWHuXVIe3tVQhwgYyBropK3YAgHzWjtgssQ0qEGEMANTJsWp3bJ8AYKZhr6OIqEuyA7yvjtQT6pF+jUd8/2NkvBfJYVndx+tcBX12vOcH+BjOkbZOzlhxTt7jzVzutx8EEakp5rHtyZMx2GtZ0ZNPCMVEQ83m4kVPTODVX+W1k6IF+qA4dgAkTBBCCLHM0SQkhBAiMTQJCSGESAxNQkIIIRJDk5AQQojEWLbquEYjwokCH4/gC0wBkqWF4jhWlwSUPEtnyL6Yui7w2ICkrWAKaaJsajm+fosIAWtEbdPggi+kxo6Y2NSUtS0CgG7XqqCKxMWjQAqiAVxZlCb2NPSgAOg5u37d2QMQ9bgCpwGrrgodKf7mePtbLXsQZ2d5sUN2GVVDq0Qr9nhfgzH7XbCPFMCLPUXt2qSoWYcUG0y1eKG4HlFXpXNcSdcidkzdppWnRWluk9Xp2mVbRPXZbXPFV3XWXpv50J7Xcszb3wutYq1MbIMAIIrs+Tr8jFVIpj3uNpWybddA1ar2Chmuxx0bs+dr7JhVeHqGBVXCkVqJXti9LYq4FDCXm9+IOOLqSIaehIQQQiSGJiEhhBCJoUlICCFEYmgSEkIIkRjLVpjwYmCygqKncE2RLN3nWTZgiToSS3vWDz3J2oXM1ngCeXzGWpbUiI3KlCf5WOizidJ164bosp2OtQyZ7UyZ2Mwsb2urbePppl2/a91ljuPsMWzGRJhABAQAUMjbvubbgyZWqfAEdkiEASwGeGoapW270l0uTGgfsYKHdMa2K+jnVkiNhh0XjVlrxRN5rvaItDVT5AnoUnadiY2S/kczXDAShrYRA3lbjygOeZ2oZs+Oq1zKCgv6irz2U6PG6mQdpcuyUluVChlXZKwBwEydiEP67Hmt9o3Q9XsxqXU2ZbfZaHLrMma7w0cgFyGw8lV1z3lttefvi9lO+dCTkBBCiMTQJCSEECIxNAkJIYRIDE1CQgghEuOUFCYwZYJPmFAg8YLzHJa0jbNaKrkCT1SmPInthbSJCwIA1KatCGEJL0AjYu4KDV6jJk36midvm8cex4OQrD84YBPQ2QJPtncj264jzzxpYhNdLoyokn0NDp5hYgXPuWL4ahe12/aN/yBlv9/N1nmNnKmj1skiR45fNr2arz9jE+tNImLJr7bHBABa5JX7buipaUXqLz35T0+ZWLHKbQTWrF5rYkzw0enYYwoAs7PkWOesusV3rnLECWLaU5OsRC7D1YNWRFAu877W67b20NSU3VepyK/ifMFu98xNm0zsqYNP0PWZOMfHoWesE8P0Uduu6UXecZxPAUHQk5AQQojE0CQkhBAiMTQJCSGESAxNQkIIIRJDk5AQQojEWDHqOJ8mg2reyMJdzxbY+tyYAigQxVKxYhVjTBkG8NpBjtnDeNbP0NayGkd0dRw+fIwsy1WDq1dbJVYuZ6184thjZQNbd8UR1WHAxXmYmrC2M2NPWyVcocDbX85b2xamjPKpqJrECqXV4jVu2LI5cl6rHX6s2CmYiezxC9Ks+hUwmbKKsV5gR3Gpx9VSvbK1vWl5ag81iTqOWS9N16yS0wezl/FZ0bDB3SQFfZgSFABmZuxx9d1d0mS7qdAeq5kpfscYn7BtaDatajGIuHdVoWLPd0yOf7PJ+1ouL/72Ts+B70bCtzDvf845AJ7CZgvQk5AQQojE0CQkhBAiMTQJCSGESIxllxNy//Kq7WLfuGWLsV/5e54NxiQeeQzPI2e3nCI5BV+eoUss79meIs/6rA9LeDGZHlNfW1l5gsXGACAmxyqKiOW/53djZgXf69kOsJhvX13mTe+B5RTYNgF+DNiePKvT881ige9YL/JY+ez1eyS+lGXdEl6P5+eQbNNzXrHIMeBtP9uXb1dsu+QksmMC8D6wy83XVjbe2L5818BSyimwbSzF9WDhneiX9/Hn30jgljKC/hU4dOgQ1q9fn3QzhBBCvEgOHjyIM86wdlknsuwmoV6vh2eeeQaVSgX1eh3r16/HwYMH0dfHi1StRGq12inXr1OxT8Cp2a9TsU+A+rWccM6hXq9jZGQEKeKjeCLL7ue4VCo1N3MGwXHpYl9f34o5+EvhVOzXqdgn4NTs16nYJ0D9Wi5Uq/aVDoaECUIIIRJDk5AQQojEWNaTUC6Xwyc/+Un6pvtK5lTs16nYJ+DU7Nep2CdA/VqpLDthghBCiNOHZf0kJIQQ4tRGk5AQQojE0CQkhBAiMTQJCSGESAxNQkIIIRJjWU9Cf/7nf45NmzYhn8/jwgsvxP/5P/8n6SYtmvvvvx9XXnklRkZGEAQBvvnNb8773DmHHTt2YGRkBIVCAZdccgkeffTRZBq7SHbt2oXXv/71qFQqWLt2Ld7xjnfgsccem7fMSuzXHXfcgfPPP3/ujfSLL74Y3/nOd+Y+X4l9WsiuXbsQBAFuvPHGudhK7NeOHTsQBMG8v+Hh4bnPV2KfnuXpp5/Gb/7mb2JwcBDFYhGvfe1r8fDDD899vpL79py4ZcqePXtcJpNxd911l/vZz37mbrjhBlcqldyTTz6ZdNMWxV//9V+7W265xX3ta19zANw3vvGNeZ9/9rOfdZVKxX3ta19zjzzyiPuN3/gNt27dOler1ZJp8CL4t//237ovf/nL7qc//anbv3+/u+KKK9yGDRvczMzM3DIrsV/33HOP+/a3v+0ee+wx99hjj7mPf/zjLpPJuJ/+9KfOuZXZpxP5h3/4B/fyl7/cnX/++e6GG26Yi6/Efn3yk5905557rjt8+PDc39jY2NznK7FPzjk3MTHhNm7c6N7//ve7v//7v3cHDhxwf/M3f+N+8YtfzC2zUvv2fCzbSegNb3iDu/baa+fFXvnKV7o/+IM/SKhFL5yFk1Cv13PDw8Pus5/97Fys1Wq5arXqvvCFLyTQwhfG2NiYA+D27dvnnDt1+uWccwMDA+6//bf/tuL7VK/X3ebNm93evXvdtm3b5iahldqvT37yk+41r3kN/Wyl9sk5537/93/fvelNb/J+vpL79nwsy5/jOp0OHn74YVx22WXz4pdddhkeeOCBhFp18jhw4ABGR0fn9S+Xy2Hbtm0rqn/T09MAgFWrVgE4NfoVxzH27NmD2dlZXHzxxSu+Tx/+8IdxxRVX4G1ve9u8+Eru1+OPP46RkRFs2rQJ73nPe/DEE08AWNl9uueee3DRRRfhXe96F9auXYvXve51uOuuu+Y+X8l9ez6W5SR07NgxxHGMoaGhefGhoSGMjo4m1KqTx7N9WMn9c87hYx/7GN70pjfhvPPOA7Cy+/XII4+gXC4jl8vh2muvxTe+8Q2cc845K7pPe/bswY9+9CPs2rXLfLZS+7VlyxZ89atfxfe+9z3cddddGB0dxdatWzE+Pr5i+wQATzzxBO644w5s3rwZ3/ve93Dttdfiox/9KL761a8CWLnnazEsu1IOJ/JsKYdncc6Z2EpmJffv+uuvx09+8hP83d/9nflsJfbr7LPPxv79+zE1NYWvfe1ruOaaa7Bv3765z1danw4ePIgbbrgB9957L/L5vHe5ldavyy+/fO7fr371q3HxxRfjV37lV7B792786q/+KoCV1yfgeB21iy66CDt37gQAvO51r8Ojjz6KO+64A//xP/7HueVWYt+ej2X5JLR69WqEYWhm+LGxMfNNYCXyrJpnpfbvIx/5CO655x787d/+7byqiSu5X9lsFq94xStw0UUXYdeuXXjNa16DP/uzP1uxfXr44YcxNjaGCy+8EOl0Gul0Gvv27cN//a//Fel0eq7tK61fCymVSnj1q1+Nxx9/fMWeKwBYt24dzjnnnHmxV73qVXjqqacArOxr6/lYlpNQNpvFhRdeiL17986L7927F1u3bk2oVSePTZs2YXh4eF7/Op0O9u3bt6z755zD9ddfj69//eu47777sGnTpnmfr9R+MZxzaLfbK7ZPb33rW/HII49g//79c38XXXQR3ve+92H//v0488wzV2S/FtJut/GP//iPWLdu3Yo9VwDwxje+0bzu8POf/xwbN24EcGpdW4akFBHPx7MS7S9+8YvuZz/7mbvxxhtdqVRy//zP/5x00xZFvV53P/7xj92Pf/xjB8Dddttt7sc//vGcxPyzn/2sq1ar7utf/7p75JFH3Hvf+95lL7e87rrrXLVadd///vfnSWQbjcbcMiuxXzfffLO7//773YEDB9xPfvIT9/GPf9ylUil37733OudWZp8YJ6rjnFuZ/frd3/1d9/3vf9898cQT7sEHH3Rvf/vbXaVSmbsvrMQ+OXdcRp9Op90f/uEfuscff9z9j//xP1yxWHR/8Rd/MbfMSu3b87FsJyHnnPv85z/vNm7c6LLZrLvgggvmpMArgb/92791AMzfNddc45w7Lrn85Cc/6YaHh10ul3O/9mu/5h555JFkG/08sP4AcF/+8pfnllmJ/fpP/+k/zY2zNWvWuLe+9a1zE5BzK7NPjIWT0Ers17PvxmQyGTcyMuKuuuoq9+ijj859vhL79Czf+ta33HnnnedyuZx75Stf6e688855n6/kvj0XqickhBAiMZZlTkgIIcTpgSYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIYQQiaFJSAghRGJoEhJCCJEYmoSEEEIkhiYhIYQQiaFJSAghRGL8f9V48YB3hFD5AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGxCAYAAADLfglZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABoIUlEQVR4nO2de5RdZZnmn33u51Sdc+qauoQkBAwoVxXsSLwkLiCzGHDGwaXdQju0s5aC8QLjzNAiazT22IlN97CwlzYuaIE4PUz+8dI4tkhcNGEUURplgWBHNAGSkEqlbudU1bmf880faYpUvc8ndQj0rkqe31q1IO/Zl+/b+9v7O/u8z37ewDnnIIQQQoRAJOwGCCGEOHnRJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNDQJCTEv/Dkk0/iIx/5CNauXYtUKoXOzk689a1vxS233IKJiYm55TZt2oRNmzaF11AP09PT+PSnP42VK1cimUzijDPOwC233IJmsxl204TwEgu7AUIsBe68805s2bIFZ555Jv7bf/tvOOuss1Cv1/FP//RP+PrXv46f/vSn+M53vhN2M700Gg1ceuml+M1vfoP/8T/+B8444wzcf//9+OxnP4sDBw7gr//6r8NuohCUQN5x4mTnpz/9Kd71rnfh0ksvxXe/+10kk8l5n9dqNdx///34d//u3wHA3FPQQw899K/cUj87d+7Ehz70IXzrW9/ClVdeORe/9tpr8bd/+7d45plncOaZZ4bYQiE4+jlOnPRs27YNQRDgjjvuMBMQACQSibkJyMcXv/hFrF+/Hj09PcjlcnjrW9+Kb3zjG1j4He/BBx/Epk2b0Nvbi3Q6jdWrV+P9738/SqXS3DK33347zj//fHR2diKbzeKNb3wjPve5z/3e/f/kJz9BEAS47LLL5sWvuOIKtFqtJf0UJ05u9HOcOKlpNpt48MEHccEFF2DVqlWvejvPPfccrr32WqxevRoA8Oijj+JTn/oUDh48iM9//vNzy1x++eV417vehbvuugtdXV04ePAg7r//ftRqNWQyGezcuRNbtmzBpz71KfzVX/0VIpEIfvvb3+KZZ575vfuv1WqIRCKIx+Pz4i9Nqk8++eSr7psQryeahMRJzdjYGEqlEtauXXtc27n77rvn/r/VamHTpk1wzuErX/kK/vt//+8IggCPP/44KpUK/vIv/xLnn3/+3PJXXXXV3P//5Cc/QVdX17wczsUXX/yK+z/rrLPQbDbx6KOP4p3vfOdc/Mc//jEAYHx8/Lj6J8TrhX6OE+I14MEHH8Qll1yCfD6PaDSKeDyOz3/+8xgfH8fo6CgA4M1vfjMSiQQ+9rGPYceOHdi7d6/Zzh/8wR9gamoKH/rQh/D3f//3GBsbW9T+r776avT09OBjH/sYfvazn2Fqagr/5//8n7nJLBLRpS6WJhqZ4qSmr68PmUwG+/bte9Xb+PnPf47NmzcDOKqy+8lPfoLHHnsMN998MwCgXC4DAE4//XT86Ec/wooVK/CJT3wCp59+Ok4//XR85StfmdvWhz/8Ydx11114/vnn8f73vx8rVqzA+vXrsWvXrlfsx/333w8AePvb347u7m586lOfwq233goAWLly5avunxCvJ5qExElNNBrFxRdfjMcffxwHDhx4VdvYuXMn4vE4/u///b/44Ac/iA0bNuDCCy+ky77rXe/C9773PRQKBTz66KO46KKLcMMNN2Dnzp1zy3zkIx/BI488gkKhgO9///twzuGKK67A888//3vb8ba3vQ3PPPMM9u3bh1/96ld48cUX8aY3vQkA8O53v/tV9U2I1xtNQuKk56abboJzDh/96EdRq9XM5/V6Hd/73ve86wdBgFgshmg0Ohcrl8v4X//rf3nXiUajWL9+Pb72ta8BAH7xi1+YZTo6OnDZZZfh5ptvRq1Ww9NPP72o/px66qk4++yzEY/H8T//5//E8PAwPvCBDyxqXSH+tZEwQZz0XHTRRbj99tuxZcsWXHDBBfj4xz+Os88+G/V6Hb/85S9xxx134JxzzsF73/teuv7ll1+OW2+9FVdddRU+9rGPYXx8HH/1V39l5N5f//rX8eCDD+Lyyy/H6tWrUalUcNdddwEALrnkEgDARz/6UaTTabzjHe/A0NAQRkZGsH37duTzebztbW/7vf24+eabce6552JoaAgvvPAC7rrrLvzsZz/D97//faTT6dfgSAnxOuCEEM4555544gl3zTXXuNWrV7tEIuE6OjrcW97yFvf5z3/ejY6Ozi23ceNGt3Hjxnnr3nXXXe7MM890yWTSnXbaaW779u3uG9/4hgPg9u3b55xz7qc//an7D//hP7g1a9a4ZDLpent73caNG9199903t50dO3a497znPW5gYMAlEgk3PDzsPvjBD7onn3zyFdv/8Y9/fK7tfX197v3vf/+i1hMiTOSYIIQQIjSUExJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExuv2surf/M3f4C//8i9x6NAhnH322bjtttvwrne96xXXa7VaePHFF5HNZhEEwevVPCGEEK8TzjlMT09jeHj4lc1zX4+Xj3bu3Oni8bi788473TPPPOOuv/5619HR4Z5//vlXXHf//v0OgP70pz/96W+Z/+3fv/8V7/mvy8uq69evx1vf+lbcfvvtc7E3velNeN/73oft27fPW7ZaraJarc79u1AoYPXq1ejvzyISeflJKJ1O0X0dPjxhYgsLex1d38Z8ZOL8AbG7p9fEUilrh1IsTNH1p6ZsvFGvm1gszi1WUmnbrlHS/1wuQ9fnD74NumScHINyqWy3SI61j0a5ZGKDnmfxKImxPa06xecObbfwq+KMiY1OTNO16+S8lMqeY0X6kM/ZczgwOETXz+XzJlYsFEzswIFDdP1S3Z6XOBkCuVyOrp/P9JlYoTBLl83l7DWQTNpbSLFYpOtXq7at5FDPOY8vhF3H7FwVi3x9Nq6HhwfostFOW2W3Qs51w/ODTUfCrl9tNk3syIsjfAMFe72kY7b/jQY5gABKJTteM5nF//gVI/vyHdeF9xbnHJrNJqamppAn49u/5mtArVbD448/js9+9rPz4ps3b8Yjjzxilt++fTu++MUvmngkEsybhHyPdOwnOxY7dluvhG9fxxpUvkQsZmPRKF+ftYHHPPsn8fb6yrbLl2VtWGz7fURIWz2Hig5MFov7NkD6yo4faxPgGVeePbFNsOPiGxeLHUP+tpIY2ZXvXLFx3c41EI3aSch/DbBxZZfz/RS/2DHo+yWfbdfXVnpcyCD0XQJRcl7ZsoFvA4u8tn3Hio6LNlIc7RxX39WxmP295sKEsbExNJtNDAzM/3YxMDCAkRE74990000oFApzf/v373+tmySEEGKJ8roJExbOgM45Oismk0njNgwAXV3d3m8ox8J+oknAPp7G6ZIAyM9JsRg/LKVZ+3PO4RFb+bJcso/RANDTa38OSXV3m1ilUqHrM/J5+7uLzzGZ9Svr+M+cAXnEnyLLJcnPkQDoiSmTnxNnG/wnrqBEfqYkyz1/iJetjtVtA8oJO/58vybWyC8c7GdeABgasj83sJ+I9r/wIl1/5BCPL5aODvbzs12uu5Of63zexmMx/iv91NQRE6uRg+U5rWA//+bIT5e+Y512dhSwX6P4FehpUcB/zirP2vh4xf4clc7ya6BnIGv3RX864/vPkPOaS9l7iO+nT9926b4y9j7CxrDvvCzEud83Bubzmj8J9fX1IRqNmqee0dFR83QkhBDi5OY1n4QSiQQuuOACU454165d2LBhw2u9OyGEEMuY1+XnuM985jP48Ic/jAsvvBAXXXQR7rjjDrzwwgu47rrrXo/dCSGEWKa8LpPQH/7hH2J8fBx/9md/hkOHDuGcc87BP/zDP2DNmjWvx+6EEEIsU143YcKWLVuwZcuW12vzQgghTgBet0noeKnNTs97p8CnWEsQscYsUVbV6/blP8Cj9iBKEQDo6+s3MdYunzquQeQik5NWcVcu8bb29NoXBVn7/S/q2djqFVwsMjtOVGdELdNBXugDACJOw+gI2WbNo7Yh5zBDJHddPT109XjSnpdYa9LE6mQ/AB9XLOaDvYRcY29lgr+syqiTlxcBYN0pwybGXiCdGrXKNgCYnLQv7Caj/LgG03ZsNYkKK0OUkAC/Bti4anj6Ok0PoT0x/Z5reIrsa5yNSwD5PnteTh+wLxw3GvYFVACYPGyPdyxqj0vcJ+UjAsVYp+2rT7HGb22+F9ktBXIOmBqX0Wo5lD0vdy9EBqZCCCFCQ5OQEEKI0NAkJIQQIjQ0CQkhhAiNJStMKJfK8wz0mNgAAAKSFO3ILD55x1ygWVIZAH73u+dpfDH7B7gNBhMx+Nra0dFpYgXi2F3yCCNYYn1kgjv4Bk2bVIwSe5URj2N4Knt8Q4sdAiYiGJsY5euTZPV+JvjwiA3YOWRWPgBQJAlc1n42VgE+BrqJ4KLfIyLJkWR1H/l6mUzwBPqRcXsMHaw7OwB0sS7ESdBzDa3osVY2ztn2J9g2AZTJdlMk2Z4k+wGAFBFGTHhsbwpjdrzEiG2Qj/Fxu90MGVf1ukeZQI4LY7FWOoD/3sBOF9uu105pgU9Uq9XCxITPcXs+ehISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFlhQr1Rn1dJ0p/stzGWPHOeDHTZI3hgsDZwdwbfFha/LwarR8PyhL43+1livewp+tGZtYndKKsRNMkT2PWKTRbXyDkoed6M7yIdy5CYL9F6vDARSYfnbXMmbmFiA98YZExO2OPqcw2JNO2r9T09vJQ3o526MY4mq+1yPnFPlZTtrpRJiXXP+sOkvLiLWcGM7239ga4uGxuyjhMA8Mzefybbte3Peep3MdcPNl4zHheCEll/YsK6O/jOFXNH8F0vmYx1h2B1nny1ixZu1zlej4qhJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcel0Zp5tT5aotQCuIpqiNioeKxyieOtfsYIum0imTKxIbGtozRRwFRKL+ZhdpMVPO3VvfHuvBLYPjqizuvt53Zkisf0pFW3722krI+GJ10iM2jl5VJdM8bbQmuT3wdRxPoXn8RIlNWqKTXtmZxJ8XEZ7rZIuiHnq8ZB6Qg06LunqKLEmkIVTRJkFAI4UqkqS/kc9t7aAxBpkXAJAgqjT0n32uKRS9r4AAB3kENZI+5nFFAAMDtrz0tPTZ2ITE2N0faaEa6f2EMN3v1qo5GtDHKcnISGEEOGhSUgIIURoaBISQggRGpqEhBBChMaSFSZ0dnYiGn15jqxUKnS5xdqr5DzWGMWCrRniExakM1ETY1YqXmECic2y9tO1gb4+a63BEuC+5CE7LqkVXPBRI8KEcoMkpclyAFCoEBEGOQJdnqQsO1t1luynawO5uN3CFKvl4knIMhGCzzaH0dNr7WVYPSgAmJ2dMbFpYo+SzvDednTZBPZU47CJ1TwJ9OxaK8SZmuLX2xgRJmRIsp7VngKAKomlibAgHeFtndp7xMTidXusUh4RSbk6aWLj5B4A8CR+jGTcU54kfC+xwmEihnSej4tiyR6tYtG21Wels2bNqSbmuzeNjtrx0o6QauGhcg7w7MqgJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcTMzM/Nse3x2Exyr4GAqMgBIE8XYgQNWKQIA8Qwv4LZYWB/a6deibWPaKPR2uEUKigFAhqhgkrat3TmurisdttutF8g2Pb5B7LhkmO2OZ31muxNLk+EeMCMXriJiBc0A3tbOTqt4YoUCASCRTJoYU+IlEtykqFq1Srbp4qyJRZJ8/+nAqusiCdsmAMjl7PfWzm6r4pqJcHVdsWqVXBkrWEMu6pNWkUJx5BKKZvitreE5hxQ2uMi5rntUk0x56YiadNpjuzNG7MdWrhwwseHhlXR9pihuNHzqNtvYgkc1yFhYQK/Vct7rZSF6EhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGgsWWFCo16fJ0zo6+uny7EE8JHRURPz2U1kczYpO+ZLyNE85eKFBQWSaOzLW2sPX7a+WLSJvp4em2z2CRhy+S4TG6lbGxQAKI7bNsTTtq+NJk/s05wuERZM0bWBqZrdQB8RkXAzJtBDGCM1chpNnjxtxw4pTs4hq/ETj3NhQTRq7aDYOUynuW3P88/tMbGJqhXR9Pd5kvUNKyIJqtyLJgN7XKIzNlaucCsZLs6xyzXJ+QcAx+o8kfXbqelFhtW/LGtjQdlut1CeousXx+x9JJ9n9wt+D8mT66WDiFhmq8wMCfA4alHYccmTce273y1cv9VyACRMEEIIscTRJCSEECI0NAkJIYQIDU1CQgghQmPJChO6urvn1RNib5UfxcaZC0LMk1RmdVvinkRhL6kRwxKgYyQhCdi3igEgm7X1RSYmeFsbnj4sxPemMhM2lAKPuwI5BPWS7dcBEvPB6s6gl2eFS0XbrgJRG9QdP1dpUs8mIPWQfGKDwaFhE/M5HjSbTRNbMTBkYuWSdTEAgGbLChOqFdvWkUMH6frJTjuGejK2/7m0xwUhYW8DpSO/pctmiA1A/1CXifnGYD1m188mbfsjnmH5hrXWHaBRq5nYwef30vVjpM6U77rq7rWipXS+z8SO7D9E1ye6AqBE3Fx81zW5NCZG7L6KRPDkg90bASBB2pAmIoQuT02smZn54pZmqwXuO2PRk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUKj7Uno4Ycfxnvf+14MDw8jCAJ897vfnfe5cw5bt27F8PAw0uk0Nm3ahKeffvq1aq8QQogTiLbVcbOzszj//PPxkY98BO9///vN57fccgtuvfVW3HPPPTjjjDPwpS99CZdeein27NmDrEddxMh3dSMWe1k1NHbEWvEAQAdRa5SIAoXZ2wDA5IS1N0l4nHiY4ofZq7C6N774NKv5UV+82mViwlqulDz1hJgSzKe3Y+4c8Q4S9NirMMFPnXn5ZHhb+9JWxZN2drhWxrk9TFfXChNrpuz+Wc0VgKsxa0SFBXB1HFPC+ZR4s7MzJsasfHxEk3bZjoRVnAUt7uNSnRwxsR6PQrRVtse79oI9hx0ez5gqqelUmSG2QTV+a5opTtk2Nezx9wnOWJ0mX62xGaKczSS7Tay328YAoH6QWD+R5VafYmsEAQA7glOHSU0zcr8DuBlQQGyXAG6zFZDWVh2vPxZZcG90jts+MdqehC677DJcdtll9DPnHG677TbcfPPNuPLKKwEAO3bswMDAAO69915ce+217e5OCCHECcxrmhPat28fRkZGsHnz5rlYMpnExo0b8cgjj9B1qtUqisXivD8hhBAnB6/pJDQycvSxfmBg/uPlwMDA3GcL2b59O/L5/NzfqlWrXssmCSGEWMK8Luq4IJhv7++cM7GXuOmmm1AoFOb+9u/f/3o0SQghxBLkNbXtGRwcBHD0iWho6GXbktHRUfN09BLJZBJJViNjZnqebQ8TIABAs2nTdyypzhKSAE8We3LtmCJ2PH3WxQM9PdbeBwCmp+1PjQWyzf48t9bo7Okh27SJ9Q5PzY8UsR0aGR+nyzIRRYaIBeKOJzpZ7aQ4zet7kqqkJFJAUrW+ekK1SZvAjRJxSn8/P1etqB2TqZRN9gNAPG6/y82WbI2XvGcMH5m0BifZtLWMiXrGsIvZJHAmZdtfJ2MFAKbHbHxtvydZTsQhLIEeI3ZUADCbs+sfPGytaBoe25/KPvsllemAUuT4AUAHsTjy1R4qF+zYjBAhC6tJBgBlch3GiFygs+U5Vk27L1oPia7NbcJ8lJglFhE8sBgAZBb2dfG6hNf2SWjt2rUYHBzErl275mK1Wg27d+/Ghg0bXstdCSGEOAFo+0loZmYGv/3ty+aG+/btwxNPPIGenh6sXr0aN9xwA7Zt24Z169Zh3bp12LZtGzKZDK666qrXtOFCCCGWP21PQv/0T/+E97znPXP//sxnPgMAuOaaa3DPPffgxhtvRLlcxpYtWzA5OYn169fjgQceaOsdISGEECcHbU9CmzZt+r0vIgVBgK1bt2Lr1q3H0y4hhBAnAUu2ntChQy8icoyi7tTTTqfLsbfN2dvSMzN2OQCIk+ThrMexgJRSQalhd+Z75ssxd4W8Xc5X3yQo2wRqD0lWT/r2z94W7yMNAFAnicoSaVfgEXF0kaRojuRJy74NkDe7x0iimJk4AEBu2Dom1HN2m9Ec73++w8ZrZftmPgDUyBgASYC3SI0jAIiVreCkmU6Y2NQR/g5dvGTHRYuoa2pTXJjQJHWmphItumwkZvvgSE2oSplfQ+Ux6yQRkJJUaVL3B+BuIo6l5kndIgCYnbHnMEb6BIBaDuw/bEUkceK6AnARQZqoKFpVfm9ijg3s5uYTIHQSwUTDIwSKxu2ybMmK5z3O1IJ7W7PVAjzikoXIwFQIIURoaBISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFl1XKPewLF2cxPjY3Q5ZsfDFDRjfHV0MHuaPFdM0TpBRK1SqXBVCNPrdHdbLd3MJK/ZMU2UKWybcU8tGGYZgjhXTKWJYqhBDFp8apsaOS5looLyiKCod1KCqo34BuKkXV2ZDhPr7fac65S12KmleY2fZp3UEyoTjyIursNQr1XyMQ5XDtL4yqFBE2tUrGKrVveolciweOGQtdIBgG5ih9NJauxMjXLFWIXUI8oS1ehCtdXc+uR67+7rN7FqlY/rGrEuSnjeYewibZiZXnz9rji7XxA17miRW2cxdR1z5HKe+mWTTMnmsfTq6bfnsEos0QKv4m3hdrm6kqEnISGEEKGhSUgIIURoaBISQggRGpqEhBBChMaSFSbE4rF5tj0+yiRRxqx4fHVraPLPk+wuNWwCsk6sZHzrM14k9YQ8TjTUjohZ6eQ99YjYMSgVeVI1wzx2CNleXksl7Wwv0mT/CXJMAcAR25UGyVXnPDV6qmVS94XUQ0rFuNggQlQEHaTuFQAkc9Z2pzRjhQnVEk+Ws4KPhRmbAO9MWmEFAOST9sBUytbfccrjkBQj14vzWAxNk9o7pRErYvC45iAFu122/4znvM6Qej6HC0dMzFcjqEjGe6bhEfKQdnV223PtPCKKaSI4KBHRFLuGfbB7G7uHAdx6q+4RUZQO2WVZ/xukThgAlBfYbLV+j7/oQvQkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0FiywoR4LI5I5OWEbSpl67MA3DGBvdPLkmwAT/Tx1BsQj5EaOb12/z5hQUCSpRkmIvCW2CFJVSKCGF61mq7O3kLPJXgCd3zCJlWZE8Pq09bR9bPkuM4cHDGx1rjvDWwb7+6xSeGsx3Ihu2LIxGodzMWAiwU6s70mFgn4GIwSbUOQsPWAWnX+FnmpZGvsxElitzvFE+ATh0dNLDZrBS9Zj1rgCKknlCK1aACgRg73QKbLxIoF2yeACxbYNexzTGA1vYoF2/7+lQN0febOMD7CHQsQtxdi98pVJpbq4ceq2LDtKpWIWIDvnceZEMnjmMAEUs4rTrEx5poS9PH1y2O+u+YroychIYQQoaFJSAghRGhoEhJCCBEamoSEEEKEhiYhIYQQobFk1XHlcnlePaFZoioB/JYVC+FWPkCChLmuB8gNWsUUU5D45C6VhrViKTMbDM/6rAtM9XeQ2KgAQJqokIoRnzrNkiG2N7ValS57ZMLWMolN2Bozp2St4s1Hs2yVfNEE3386bs8LGwHNCC/ykwisOi3BBgsAwNru1IjtT9RTTyhJbHuY68nKoZV0/eqULZZVm5k0sWyfHb8AMEnqX5UDrpqMkVsGW7JClGEA0CAKz06ixKvXiJIR3LrKkWsg6bFYYnY+vjsIO9vPPrvXszRZn2zgtNOscnXcUyutULAKR6au893buonFkK/W2fS4VQg2iDpwBaknBQDBgltD0zmA1TMi6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWSFCT3p3DzbnjFPHYwOYk0xS7KXvpxyLp83sVrZUzOjbBPI5boVG5TKNqF4dMMkqUjSn/2eRGOO9DVJ7IyqpOYKABTHbbsSXXRR9A7YBGTa2X2VxmwtFwCYIFYop5H2Rx0fgk2SGO/sssnmFW/wWBTlrG1OvMP666Q7uun6cVK7p+kRFjQbJLXdsGMlqPPvfMGsPS5jv7bikr41vK25qBVhHJiy4zLKRDQAYjl7Dsaa/BqIp8nYnLKhlb1cBNFK2jpBTVajyCN4YfV4enrsvpqek8US857LjdLOskxEMDtr++WIYAgA0LW42kEFz72RLVsi9c8AIEFECOR2hX0lbnEULFjWqZ6QEEKI5YAmISGEEKGhSUgIIURoaBISQggRGpqEhBBChMaSVcd1prOIRl6eI+seWcoYsbZgqpApjzeHiy+uUJyvDcxaw1fWjjWBWW74rIhKZAsusKcwlvUUACTrp2N8X2VS6Gy6bG04MtxdhR4BZu9SrlgVFwAk0rZfiS5SUcvjhZPusuq+RNaq6yJxq6IDgEjEKslaLW5l06hbxVMiSdR5Sd7WeNkqifpXn2pitaotXgcAzYYdg6kuq6QLsnxcr+0bNLGOEj8v//z8cyZWKtprKOtRPfZF7dicKNp9jXjGRZwUMWQFL6emrG0RwK+tPFHIArzYXpFY0fiuV37LsmOoSCxzAKCwUHIGeG4idHV6b+kgKjgAcOSeR9V1Hvu0zILCes4BWJxrj56EhBBChIcmISGEEKGhSUgIIURoaBISQggRGktWmHBk4jAix9RZ8QkTjpcSsbzIeIUFNgHMlu0Z4DVyKtPcTmchsQxP/kVTWRMr0gQuT6DXSV46m+X1QWINe1yYO013llvBzJCsZK7bJstjHnePTL/dbvepwyYWsOQtgCBpLXrqKdvXSITXnWlG7KXRRIsuWyUiBEajxmu5zE6ReLdtf6vG9xM4e2LTKSviODzN7aTSJbvd+gxfNkPuGPG83X/T8b6m+m27XMuKCApE7AAAmYwVEczMcBHDYuHiIi5QypHaRz5lQJkIebhtEF+/j4gwSs4el4RHGBGQWmVcmuIRHJBm+URbC7vQajn47kML0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCoy1hwvbt2/Htb38b//zP/4x0Oo0NGzbgL/7iL3DmmWfOLeOcwxe/+EXccccdmJycxPr16/G1r30NZ599dlsNy6ZzCxwT+HL93TZZz5J/4563kllOj4kVAP62NiMgtWQAIM3quZB+lUnNFACo1ydMrFS2Hciwmi/gfa1M89eaWapz1ap+E+tJ8Bo3h+t7TSxG6gFlOnhbu/tXmFgkbb8zJYnYAABaUXYO7HCPxDzJ/qiNRwKuokgEtl/N+qyJpVK8r8msbWt11opYgoDbU8zMTplYJGaPVYUPS8TqdruFMe44wK6AWs4elyJx3ACAWSJYmQ7sshk71AAAcXIKxsfste1L9rO4b9l02l6vDVL7aIzsH+COA2xXHl0BFQH0kViDCBB8G/bdw5jeYGh4pYlVPLXKphfcR44KE/gYWEhbT0K7d+/GJz7xCTz66KPYtWsXGo0GNm/ejNnZly+4W265Bbfeeiu++tWv4rHHHsPg4CAuvfRSTE8fn4JFCCHEiUdbT0L333//vH/ffffdWLFiBR5//HG8+93vhnMOt912G26++WZceeWVAIAdO3ZgYGAA9957L6699lqzzWq1imr1Ze8t5s0khBDixOS4ckIv6et7eo6+F7Nv3z6MjIxg8+bNc8skk0ls3LgRjzzyCN3G9u3bkc/n5/5WrVp1PE0SQgixjHjVk5BzDp/5zGfwzne+E+eccw4AYGRkBAAwMDAwb9mBgYG5zxZy0003oVAozP3t37//1TZJCCHEMuNVOyZ88pOfxJNPPokf//jH5rMgmJ8Bdc6Z2Eskk0kkk/ytdSGEECc2r2oS+tSnPoX77rsPDz/8ME455ZS5+ODg0bokIyMjGBoamouPjo6ap6NXYnjVEGLRl61LDkzxWiqjo1YxxrRdvpofTJ7mMwjqoOU9bLDhUQYxsrC1UBIN3gJWNyXZZU9hlSh4AKDhbNx5bHemicJwdtbWzUnVuOAkRZSA44ft03DXm06l6yd6SI2XwLa/5fH9cSSeILEkUZEBQISo61qOf5FyTaJCgl024VGntVKklouz7apXuAqquXK1iY1VZkwsXeXjIholx8AjuEqn7TGMZu14nZng18ChiUMmVif2LmnPuCxO2IZxFdribb64FQ+QSi1OHRePc9sfBm8XvzfViUo2Dntd+Kx0mGou7qtVRs63ryYTY2G/Wi1uccVo6+c45xw++clP4tvf/jYefPBBrF27dt7na9euxeDgIHbt2jUXq9Vq2L17NzZs2NDOroQQQpwEtPUk9IlPfAL33nsv/v7v/x7ZbHYuz5PP55FOpxEEAW644QZs27YN69atw7p167Bt2zZkMhlcddVVr0sHhBBCLF/amoRuv/12AMCmTZvmxe+++278yZ/8CQDgxhtvRLlcxpYtW+ZeVn3ggQeQzdqXSoUQQpzctDUJOefx3T+GIAiwdetWbN269dW2SQghxEnCkq0n1GrOr95SLvNEJ6sFksnY5F9fn61jAgBdXdZ2ZvaIx7KEJPViJAHfkeWptlSmy8QqJWvv0t01ZGIAkOm0T5P7f7vHxKoeYUScJEBnA57ALZHiQWzJkifR2SR2Qk2yzdF9++j6iYhNAOe6bQI51mPtfQCeAO4gCfgEtfcBQCx66mjyZZtWsAHY9Ws1/iWuo2mTuFGSbC5U+eXaIPvKJO24HFrBj5WL2OMy2WMFBABQIXWmpmfsC+YNT7Kd+e7EyLkqe8Q1cWeXzedtst5XJ6tBxqDv3uKz+lqIX/RkaUcwwQylGqTuj2cEI0MserqJFREA1Ih1UoGoFWjdIdh77lHbnsUhA1MhhBChoUlICCFEaGgSEkIIERqahIQQQoTGkhUmPPe73yJyjNXP4j0IeKLQVyMoFrOHIJflh6WjPGVilTJxIajw9YOYTeAmSO2hCkn0AkCzbh0TUjHb1/4evv8p8ra5j+Ehm8RmdZIqE7ytAXE3WHWKFVx0xfn3oGjZigASOZvUTUW55VMqYo9VPBa1sYjHcYEoQSOOvwXO3BHq5PsdEwAAQJIIC4KW7b9Ld9L1CzVb4yVRs1dMtcIEFEDDHhbiYfAv2+3oMbEz+m2/ZjJWcAMAjshbIg07XscPcYeU0pQdw0yYwAQIABch+MQCvb29i1q/4KvnQ8QZPLHP29pBxCnt1D/L5mz7fXXZEkUieIiTWmVE9AUAPT3z99VstjAxcZDvbAF6EhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEaS1YdV683EDlGdMS1NkA+z2tpLMRnN1GvW2uOuKe+SKtMVFBks9E0V5AUZuz6yRRR5/UO0/VffP6FRe0/382tOepEY1gm9joA4GZsnaAMUTYxFRwAFIliqNxp1Vn9g1bBAwC5Xqt4SnVadVgs8KjrYqyt9lhHIh65EKnnExAVGQAw56MaUWdFo54NsHjTquMinuKPEVLPqDNlj1U8wa+VMVKrq1HmiqsVvVY1mc3b8daqcYujUWqJZQ9gJs3bGrAaO0TdFiPnHwA8rjUUto3Vq21dtCY5VwBQLFpLsQqp01UY4/WIZsk9q4N0K+NR91WIkq/psShiddEYgceiqLxgvL9u9YSEEEKI1xJNQkIIIUJDk5AQQojQ0CQkhBAiNJasMCGTSc+z7Zn1JMQyxNqCWfHU69xehln8NDy1TBKkPkcqzfbF2zq0ao2JxYiIYWZ2hq6fWzFoYuOjVlhRmOHJxxQRXCRyfAhUiODA1VgCmK6OHMkrlyYnTKzqqb3kulklXpvA96U/IxEmQrCxwCNMCMi+gqins6T2UTxhRSjNuqfGinUYosKEZIT3toPURJomwpIOz/rVmG3A6sFT6LIxYrNUmrbntUashACgTGyuGg07Xmsef5k4EQukUnasJJPsoAITE8+bGLuHAP46Q4sllbJtyOWs4MZnu8NEAEyEMeipE9Wq2HOQ9ugPkuRwl8r2nnnEY1EUXyDwWkwB1JfQk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUJjyQoTkqkUosfUX2FvCgM8qcfrg/CMHHNc6Ozupsv25m08FrevYD+/bw9dfzZiE8jxVsLE9r14mK7f1WX3Xyd9nRjnIox0hjg+THMRRixtE4s9+S4TSzlP7aL6IbtNkpiPp7g7RYQkoCNEGBBLel6BJ8c6Qh0TPLWfHHExiNltAgBadtkYc1xIe9wdiAiiWScJfE+VnyhxTGCJ+YjnLfZMusPEOqf4cXVRe14OTNtzXZvlSf1s1m53epqJDfh5GZ+w2y0dtteLz0mFaYZSKd5XJnCijgcF7njAnCBYu3xuLl2kdk+KWD4wAQLAHRNann2xHtTbqCeU75svuGi1WjiwzwpWGHoSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERpLVh1XrVTm2fakPdYasyWr6ygQawlPyQ2UyLK2uspRolGrOOroIrY9np3tO/SibRdZzrf+i1O2FkucbCGdt9YgAFBm9iABV8uUrOsLupNWhROPcHuU7t5+E0uRGjupPLPn4bRgrWxiMV6jJwKrZHPsO5dPHUe/n3F1XCRiVX9EiIdo02NlQk432SSiHo+iaMwqLOPE9qdO7HEAoIOpw4a4bc/k7JiJjR2yg4WNSwDo7GY2V1b157ODQs2GmGLLZ53FLi2meAP8djrHsy++HF/QkWOYImrSyVGupiXiNjQ8bS2ReJ3cchOetnZ0zFfuHq2xJHWcEEKIJY4mISGEEKGhSUgIIURoaBISQggRGktWmLCQRp0nCfNMsOBZlhEQO584qRsEAJPE9qTRsvN455CtGwQARVLj5dARnwyCENikYLxm27+ma5iuHnNVE6vHueVIN6lz1GgSK5mop/ZSJGlik6Upu1yZ107qytj1kyTb7zy2QUFgBQsNYo8T94kNokTw4KuRErfLRojtT90jonBkDLHaSQlPUjmSsOsnSGymxdevt+y4iNb4NeRqtn7VGX1rTaxUs9sEgOeeO2JiuUErjPCUvQESdrwNDg6Z2OzsLF19eppbWi0WLkLwKRAWp0zwChhIfKZq7yFFz7joJffGOPi9rUSsh2pku87T1mp1vmip1fRV+rLoSUgIIURoaBISQggRGpqEhBBChIYmISGEEKGxbIQJrI4GAOT67Jv53d28vgbjyKgVBoyN2bfCAaBO4pm8fSt4haceUYXU/eglb6sXSR0QgKc5mYhiZpIn+/u6ukwsmrJv2wNAM2LbsDD5CACzNX6sq0SwcOiwTQo7x89rKtlnlyW1WFpNPoRbTduvaMOKEFoNLhYIiAgEARcmRCMkCRsngg1mgwDARW28FSXfD2P8O2NQt/1i7Y82ubsFcyyozXLBCUj9rEzKHsPurhV0deY6MkuEEVOznrftiRCnWrXr+1wQfO4GfNnFre/bJFuWiRB8jgls/UPE4YXVHQJ4PaRG2dd/0lay3YzHucYcBE/tKoaehIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERptTUK33347zjvvPORyOeRyOVx00UX4wQ9+MPe5cw5bt27F8PAw0uk0Nm3ahKeffvo1b7QQQogTg7bUcaeccgq+/OUv4w1veAMAYMeOHfj3//7f45e//CXOPvts3HLLLbj11ltxzz334IwzzsCXvvQlXHrppdizZw+y2cXXjWE0Glytc3D/CybGVCU5T40dRsJjGkLVMsTuYtJjG0TVMr29Jtab85wWsv+A1OgJSJsAoEYKjMwc4jYmaSKCGVhta8xE8p10/Saxw6lUbI2bSKSLrl8Yt6q7fMrG0gm7TQBgIh6Pa44H+/3MI04DAqsEihN7mZbHNqdJCgW1YiRG1H0AgJptWIPULoqleAcigVWsda44lS47Xvi1XZ+o04gIDgCQjdg2HBm1dbIqJa5u6+219XSYEs6rcCWnoB11Gqtd1NfH7y2srtli93N0X3YQs3HN6gYBoDZTdc+9iR0DR2Jpj0o5Fpu/bPP1su1573vfi3/7b/8tzjjjDJxxxhn48z//c3R2duLRRx+Fcw633XYbbr75Zlx55ZU455xzsGPHDpRKJdx7773t7EYIIcRJwqvOCTWbTezcuROzs7O46KKLsG/fPoyMjGDz5s1zyySTSWzcuBGPPPKIdzvVahXFYnHenxBCiJODtiehp556Cp2dnUgmk7juuuvwne98B2eddRZGRkYAAAMDA/OWHxgYmPuMsX37duTz+bm/VatWtdskIYQQy5S2J6EzzzwTTzzxBB599FF8/OMfxzXXXINnnnlm7vMgmP+7tXPOxI7lpptuQqFQmPvbv39/u00SQgixTGnbtieRSMwJEy688EI89thj+MpXvoI//dM/BQCMjIxgaOjl+h6jo6Pm6ehYkskkkklbO6ZeByLHzF2FMU+Sj2TlWJLNl/yLkWV9IoZ4wyb8WU4z7TmqZdKFyrStz9LwOGPEa6TGD0l+sjoiAJCN2URldzcXjCQ6bWa5RuoJHTnM6yHVyTGIkW02p7nFUJIkQGMp2/4oqZsDAM7VTCzStMcvIHWPACCoWcFDlC+KWMyOrViE1NMJbJsAoAnbryb53tYgAggAiMLGXZ30Nc47UC/b81qZ5fWAutLWJisSs+sXZ23dGwCokzpDcWaFU/Bl260IIZaxB8trL8Pa5LXyYfcRu1SptHgrHLZNnzCCwax4imP2HgIATMrlLV1E2nCECit8W5ifRmm1PLW3CMf9npBzDtVqFWvXrsXg4CB27do191mtVsPu3buxYcOG492NEEKIE5C2noQ+97nP4bLLLsOqVaswPT2NnTt34qGHHsL999+PIAhwww03YNu2bVi3bh3WrVuHbdu2IZPJ4Kqrrnq92i+EEGIZ09YkdPjwYXz4wx/GoUOHkM/ncd555+H+++/HpZdeCgC48cYbUS6XsWXLFkxOTmL9+vV44IEHjvsdISGEECcmbU1C3/jGN37v50EQYOvWrdi6devxtEkIIcRJgrzjhBBChMaSLWqXSscRPUYe51Og9AwOmlgu32Vi0Sj3bDkyetjEyh7bmzip/xYnIhCv1oUIdupjxHaHi6iQzxN1HNlmXzf3TGlNW2VRPMZtOIKK1dbUiTqu0uJF7WpZu90VXbax8QZX9iBq1VUusJYtrsXVdY0GOTFktEcdP1YBOYuB4xZB0ag9BinYWNSjbmuSscmaX/cU1WNvQLSIZUvE8e+cjbrdf3WW76snYgs2VpJWRVUt8XHRl7fquiaxIyoWfkfXZ3eBzk77cz+LAcDMjB1XpZLPXsfujd2HfFY4TKHX3d1jYj5LssOH7fuVTMXmfwHGks1ZmzAAKBTtdcgsinp67DXIaDZbmJg4uKhl9SQkhBAiNDQJCSGECA1NQkIIIUJDk5AQQojQWLLChFgsiugxtUd8JhzZmu1CZ8smWkszs3T9gFhTxD3SgljM2vmUSVLSl+jMZez6OeYQ5LHxSPd22X3FbGK+luL2LI2YTWG2PPV8RkdsonK8YR3O657aSz0xe8Zm6iT52eSu6UHZJvFjjQ67XItbLEXidv8uIDV+HD9XAanHEyf2OACQICKEZJSMqzgXxzhicVInaoNKk6/fgo23AlZ8iosNUsQiKdPJRRilWauaadbtd9m6RwjEBCMV0tcUqbMFADFSp6mjw+6/2uTtT5PzysQCANAgdkYzh+14TXssgjJ9XSbmiO1OhYiAAF89I1JjqI/vP+3svpK+Qk+LLF7AbIMYgUeEw9CTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQmPJChOinTlEoy/PkTHPW8VTExMmNlOxb0U32qj5kfUkRcsksR0jkglforKzs9O2i/SrUuFvm0dIQRsXs8tOVfl3i+lpe6zqdZ5ALBTtduPkDereXv4G9SB5M75B3BF6OokNBYA0SdYnHel/ndtL1GrExYA5BgSeekLkNfRIgx+rWIvUE2LuGnF+uQWOuTOQGkNEWAIAjabtV4O4ELQiXJjASjJl0lYEAgBwtmMVIkzo9IhrpiYnyTbtcSl7rvdyxQo+XOyIiRWn+for+q0IIZ3lfQ1IF3Il29aWp4BYnZyD/YcOsSXp+nSbrPaSZ/U0qR82S8QWPpg7xChxmGFtcGT8+tCTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNBYsuq4F6dGETmmnlDCowBhFjkZYrvT47MBITYUE9NWXQcA6Zy1N8nnreKtSeruAMDMjLXYYftnChgAeOG5fTS+EF/NEIbPdieTZ3WG7LHuWcHVcbEYUYwRK59YldcDisOq1mJEHYcaV6wFJB6NWSuXwKPCigT2vERafF8RZ+Ncx8a/8wWBjUeI7QmLAUCUSPliZF+tgFvpxMh2fTeGZGRx31vrNU9RLEIqY8darMDrXKWJYm16xNb/yuQ9ClViJzT54hhdlun7elO2nlLd44RTaTLbHbvVsTFP/TKiMGT3hqLHJixBVLrZNL9ee4jKdXbcevkUiM0ZYJ3G2hDH6UlICCFEeGgSEkIIERqahIQQQoSGJiEhhBChsWSFCQuJeRKNjiTqpkgs67ERSXTYZHeD2NsAwMS4TcqVy2W67PHAEpIAEIvZZO3Q8AoTm5nmxUEmxkmilJfjQYxYfhSLtv/JKM9AxtP2+02iZdvfk+K1XFIFW/+pMW5FDNEIP1Yua2MNUo8n6pEQNKI27tEwoElq5DBtSRDxiChIFrfBbHuIgAEAWlESJxY/ruW53GNEWJHwHNcmOV5VG2pWuOAlQsZLKmX3lfZY4cTrdgwFvYs7/gAw8YK1+PHZ5kSINKFIhnt5ig+MErmOY6x2k8fmi8GECTWfaIvdB7neg9o8+e5Di8MBWJxFkJ6EhBBChIYmISGEEKGhSUgIIURoaBISQggRGktWmNBIAMfmYWO+RCV5A7lUsAm5kfERun6+YTPzzpOQ68nZt4pTKfu69JHRUbq+I4nObNauP0lqJAHA2tPfYGJR8ga4rx7RigErAvC5Q7DE7oqVdv1DYwfo+tmqPV8re4ZMLGjypGw0sMclag0PgApP9rfqpJZKy4pQWp56QpGmPVdRlpQHECEOGS0iVmDNB4BIYD9ptuz3wyorcAOgHrXHupm0+2+xIkngIogaqecEANUmcXKI2DEY8dQuqtbssYoSwU2mwzqRAMDk/hdMLE7GKkvKH8XGVwxwh5F0R5eJvbjX1gMqeYQNdXK6skSYsGrVarp+oTBlYiMjtiYXtXYAFxZUily0VCR9GDhlkG+YML1ADNVqOZTLfF8L0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0Fiy6rh6vY7gmHpCI/u5uq2DKEDyHosfRleXrQ+SSHDF1PSErTsyPW2VaD5hzvBKu6+e3j4T86njRg69aGJFUt8j5+k/U/L57FFSxN8jlbQqqCZRkR3FqqNefM6ew+QsryeU7u83sVbO9qvZ5CqsZtUqzhoN+50rAK+xE5C6OYFHHQdiB9Qg6ria5ztfhKrW7DbrnrY2iTqtSax8WgmPjQpRwkWIuhAAokTdFmf1gEoJvn6T1P8i47UesdcKADQK9ho4ZYVVl1UavO7Nvmf2m9jMNLfe6s0OmBhTt3XluPXUZMUqT2NEhVatEt8jcEswZtvDahQBQIrUP6uV+RhgW8jlrHK4VLJ2WgCQXnBcWq0WAKnjhBBCLHE0CQkhhAgNTUJCCCFCQ5OQEEKI0FiywgQUGvCUepkPyajlSX0OlsAHgEPPHzSxmMe2p1Sy2+jwJAUZzE5n9LBN1qc99UXKZP9psv9YjJ/Wzqy1HZqpTtJlJyetOCJHEp0xYhkDANGIFUGUpqfsgh4vm2bCJrYruQ4TS6e5iCRI2WWDGEnWR7ntT400LHB8WaaNyBARRMx5BnRgj2Ek4CIEhiPChibZpvMIG6KB7UCCxACg6WomFieHpSNujz8ARLI2sR4kbLtaXbytU1nbryNFK1ZIJElBKQDZXnsN+IREM2V+z1hIxVNTrFwmtc4KBROLxxcvpGK3plKJd2A8btvlq10UIzfSWs0KJth94Wi75q9/VJiwOPQkJIQQIjQ0CQkhhAgNTUJCCCFCQ5OQEEKI0DguYcL27dvxuc99Dtdffz1uu+02AIBzDl/84hdxxx13YHJyEuvXr8fXvvY1nH322W1tOxEHjs231jzJQxZnzgDO8a5Ok/oagac+SIIkBdkbzDFPopHti4kQmAABAFJpm1Rl9YgSSRsDgP5++wZ4uc73VRqzyV7W1+I0fys6nbIihnjaHsCRGlcmHJl83sSGuteaWJ6XnYGL2e2mYZOlAVkOABwRJjjPV7YmcReghgMeYUNA6gm1mGODT6hDP2Drc7FBQOoURTyCjSBil40Td4isR4SRiFjBQm3GjqHShE3gA0BHxF7Hvz1o63fl8rymVozc8nzXK7sLlAPrOFD3nRdyv8iQfaVJnTIA6O604gombpqY4NcgqyeUItclABwmAinapm6PO8QCwULLU4+K8aqfhB577DHccccdOO+88+bFb7nlFtx666346le/isceewyDg4O49NJLMe0pniaEEOLk5VVNQjMzM7j66qtx5513orv7ZY8n5xxuu+023HzzzbjyyitxzjnnYMeOHSiVSrj33ntfs0YLIYQ4MXhVk9AnPvEJXH755bjkkkvmxfft24eRkRFs3rx5LpZMJrFx40Y88sgjdFvVahXFYnHenxBCiJODtnNCO3fuxC9+8Qs89thj5rORkaO/Kw4MzM89DAwM4Pnn7W/8wNG80he/+MV2myGEEOIEoK0nof379+P666/H3/3d39Hk/0sECxKlzjkTe4mbbroJhUJh7m//fmu1LoQQ4sSkrSehxx9/HKOjo7jgggvmYs1mEw8//DC++tWvYs+ePQCOPhENDQ3NLTM6Omqejl4imUwimbTWK7V6bN7E1ZXn9jhUnUZsa7LE7gNYfM2Oo22ysQRRoPjUdQy2r1mPDYdH2GIoeWr07Nv7rIlFPd8l+vttPZeZGSsu8VmexGP2Swc71kV4atzMkA3PWmVV1eN4knRdJhbA2pBESd0jAAii1jbGkbo9ANAgsrkGqT3kEccBEftBhCjZolH+RS4gcfqdL+DfOQNiEcQUcwAQi1k7pRQ5Lr6+1mesGrM+NW5imRjff57YMfUP9PKdEZrESifp+ULdPWBrfU0RdVqxaNsPADUip62Te0OpwtcPGp5rY+H6HjUts/ipe9SwzDqI3ZtGRw/T9Rcu69zrpI67+OKL8dRTT+GJJ56Y+7vwwgtx9dVX44knnsBpp52GwcFB7Nq1a26dWq2G3bt3Y8OGDe3sSgghxElAW09C2WwW55xzzrxYR0cHent75+I33HADtm3bhnXr1mHdunXYtm0bMpkMrrrqqteu1UIIIU4IXnMX7RtvvBHlchlbtmyZe1n1gQceQDbLXW2FEEKcvBz3JPTQQw/N+3cQBNi6dSu2bt16vJsWQghxgrN06wktSFj7EuAsiT8zYxPzvho7zNqi4UneMRECq+fTzlMfs+HI53m2vbevy8SaJHn54kFbIwngfe1ayW04UsnFDQ1fLROWALUpbaAny5PK9bhdP562W+hI8WNVqdj1WS0VF/UkUOM22V5reurxROx2meuN85QIClidnyix3fFYT0WYnxCLeRSqARMseOoZMXFGJE3qTHkEJ82CtdhpEBFIitT9AYBEwV4vw6fY680nzhkvj5nYCLH9AYBZcm06Yj3VnR6k6x+esYIDfr146pc5u6xHnsXXJ7cxTzkhes9h90yfCCKTyc/7d6vVQrHIaw8tRAamQgghQkOTkBBCiNDQJCSEECI0NAkJIYQIDU1CQgghQmPJquMymRgix6h5mLILABJxqwxhdhP5fBddPxazCphyiRfUqpHt5ojdRdJTVI4xetjaYPj6GiUqolwub2KFwhRdv7PTVoAjm/wXrGpsRfcQWY7DitrFiLZnctJTkIuIq17Ya30FgyovSjewetjEkrO2s1GPb1EsZs9rJMJ9kxyRvTFtWECsfAAgQgrAtcj3w6bHYohZD0UDUsCPqfAAtFrEYgi+Sm12Gy0yiBoRvn4rb8drR59VwjWctXgCAFe156BZs9dwpThL1891WTuqep0r6ZjFTipllXhHpibp+vGcHUNETOtVnCEgqjfH7w3HS6HA7nnEdsgjU16ohv1XKWonhBBCHC+ahIQQQoSGJiEhhBChoUlICCFEaCxZYUJ//wpEj7Eu8dnuMIuaQoHULKkfoeszDQCrGwQAg4PWYqajwyb7x8am+AZIopOJEHyJytHD1gZkzak2UesrODg6ahOo6dzih0BPj03KxpxNNAPAxKgVHAwN2fXTaW7vkkrZdo1OWhuQ3z7HK/ZWI1awkByumVg2sZKu3yCJ1WicF8mJx+12Wy17Xpse25wI+ypICvLUI/xYNchm40RY4Css2YrYvrZIPSMAaMVI7SRifdQg2wQAl7Lr1509frNVLkyIpG3tsYAcq1YnvwamS1bEkCG1swAgQuqclUtW8FCiSX2gJ2vtfGJkXJfI/QoACrPEuoos563pRe4tK1eeQpedJNcWvw/5hBEL4w4AP4cL0ZOQEEKI0NAkJIQQIjQ0CQkhhAgNTUJCCCFCY8kKE6YmJxHxvHV9LKyeEGNsjCcPuTkBT76VyzbRxoQJ3d02BgBHRm3dEtb+Dk/RD7b/F55/zsSYMwIANEgGs1Lkx8+RAzMxYWuxxGKLf4O7QWofdfdzYQMj17T9973BPXZoxMSydbt+wuOYUE3YBHaug9e4qQZ2u/Eoqc8SeI5VnCTbk0QsQGr5AEBARAgRsmxAXBQAwLHEvk+YACv4YFsNPEKiJvnaOzZuBTcZ4jYAANXmtIlVGsTZIM3XnyXChGqTCz6SVRubmbTing6Pw0lk2o6Lcpkk+7m5AxUcLO5u56edump54m7hu97SC2pKtVotTExwN5SF6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaCxZddxCfFY2PsuKhXgELFQBkmFFPwAUiT3H735nbWM6POunqerN9ivmaezAoK3n0ySKM189IaatqXmUgCw6TlRM7fD887ava96wgi6b7bTnhdVpGjnMFTh9OduDWLzDxBrM8wZApWGVTa0ZPtgyGaJGTNvvdy7C1WkJ9l2QqdNiVkUHAEHcXsYtolkLHK+91CS78tUuajgbd2RfNaqZAxotpsSz7SrWuWSsULAKzcPEzqruKdHDmC5axR0ADPXbsTmY7zex2SqvRzQ6bcemz6KHwW4XTMXmvwfaD44csQpdgN9f21HHLQyrnpAQQohlgSYhIYQQoaFJSAghRGhoEhJCCBEaS1aYkM6kETmm0IrfnofV6LFLdeW5jUcbrjMYXmlrz0Sj9hA2PTYgDF+i7/UgRxKNzmPjwSx2jh/b12rV2qgAQIwcV7ZsxmPP0tFlxQLP/e5FE5sc50npNQOrTSwV5cKASMMOokiQMLFYxsYAwDWJFQ4RTESIKODoBmycShA8VjxNIhaotbiIoU4sfiqk/aUqT8DXnB1XFdL+8iy32arViJcOwSdEKhbt/n33gGzG2jRlm/YcJmPcTikas0KaWNza/hzyWoodn5VOgQipWMy33VTK1irzrb9Q2OAbqgw9CQkhhAgNTUJCCCFCQ5OQEEKI0NAkJIQQIjSWrDChXm/MqyeU8CQP6yTOluVuBUCRvMFcrPPkG6N/xYDdV7qLLjszY9+sLlPBBU80Prf3BRNj7gqnrLLOCgBQI4n96QoXBvD6S7ZdLKEJANmsTeoeOGBr/PgcD/K5xQkj0mk+hPP5HhPr7rDnypfUnTxi38Lv6+6ly87UJkwsniRvtkf5IK5UbbI92mHdHVpEAAEAQYN8lyTJcud5i73JhA1EbAAA9ZY9L8zxIOIRvLA6VVVnz8FsjbsQDBHByOzsfhsjdYMAYHCo28QOvHCELjtF6n+lIlbwUm/yfbWIuCdOakplPCoKWk+IBBfrYgBwsQNg6wEBQKWy+PpdCzfrHLBYbZOehIQQQoSGJiEhhBChoUlICCFEaGgSEkIIERqahIQQQoTGklXHFcslBMHL6jivAmSRwYKnHlGDFB5JZ7jiq7PTKmNqRNnkg6nTZkm7Ep4aP7OkrX1Dtq1xj5XNWM3WaJkmdXOOsjg7pLxHtZhq2LYOkYVLHrXOWNGq81idp0SRj4sjRduvxilWNZhIcCseUqIHFY9lTJIo4WKzNROLeFRULmvPF7PNiXjsoIIGsY4itYNannpC7NqqVflxnZm157XVIsfao/BkiqsYUYwlAj6GZ8lxZSOoq8ta5rzUsoV4LhdUS1a5eaRAagR5+sruODGPfRiDnRdfXbXF4zkvRduvWabE8+x+oS1ayzmUy757y3z0JCSEECI0NAkJIYQIDU1CQgghQqOtSWjr1q0IgmDe3+Dg4Nznzjls3boVw8PDSKfT2LRpE55++unXvNFCCCFODNoWJpx99tn40Y9+NPfvaPRle5BbbrkFt956K+655x6cccYZ+NKXvoRLL70Ue/bsQTabbWs/9TpwjC6BWlAA3IaiRKxw6sSe5+j6NpbzJNsTSZvsZHYXxx6TY2FWKKtWDZpY3NPXIvHBKJEDM01EAQAwXbHJR1/dlcFV1qKmQRKNDU+itEk2PNhnLVPKHtudwgG7XeZw1OEpBtNNaqEcPHDItmmon66f77T9nylM0WVZTSNmTzPtqbETI8cgFrFjLfAICwImWAjsNgOPbU+lYZP9LfBlCzVbf6kJK3hxpG4QAMxG7L5Arqtqidd5Gn3R1oSqTNtxHWujTlbDc3NhlloB8Qlj1mEAlwB09ZD7IBHcAFxMlctZOywf+bzta8FzHzxC4qxVTBwEAOkF8VbLAUQcxGj757hYLIbBwcG5v/7+oxexcw633XYbbr75Zlx55ZU455xzsGPHDpRKJdx7773t7kYIIcRJQNuT0LPPPovh4WGsXbsWf/RHf4S9e/cCAPbt24eRkRFs3rx5btlkMomNGzfikUce8W6vWq2iWCzO+xNCCHFy0NYktH79enzzm9/ED3/4Q9x5550YGRnBhg0bMD4+jpGRow7JAwPznYoHBgbmPmNs374d+Xx+7m/VqlWvohtCCCGWI21NQpdddhne//7349xzz8Ull1yC73//+wCAHTt2zC1z7AumwNGf6RbGjuWmm25CoVCY+9u/39qyCyGEODE5LseEjo4OnHvuuXj22Wfxvve9DwAwMjKCoaGX30wfHR01T0fHkkwmkUzat9br9cY8YULGUw8oT95A5rVwOEzEcKiNekLd3TbZHo3yw9okCeSOpE1UthxP6NWJMIC9QT1bsIliAFQcwhK1R3dmt9sgx6rhEVF0Z60woFq1+xor8boxGeauQJKn2TRP1AakXRmSag3KvP+lwLarTlwMAKDSapnYSMP+rBwlCXgASMbtdpMxG4v7vjISwUJQt+4M0SjfgCM6mpkaH4O1iN1XqW6dJIqzk3T9kYKt3dOs2bbOlPkYbhIRQqNgT/bCRPnL2LhPmFAny3YMWsGKr9ZZqWhrUk2T8Vb2XUSLJOYR56SIOMcn2MiT+6tPtMTbMH+7zVYLwOJSK8f1nlC1WsWvf/1rDA0NYe3atRgcHMSuXbvmPq/Vati9ezc2bNhwPLsRQghxgtLWk9B//a//Fe9973uxevVqjI6O4ktf+hKKxSKuueYaBEGAG264Adu2bcO6deuwbt06bNu2DZlMBlddddXr1X4hhBDLmLYmoQMHDuBDH/oQxsbG0N/fj7e//e149NFHsWbNGgDAjTfeiHK5jC1btmBychLr16/HAw880PY7QkIIIU4O2pqEdu7c+Xs/D4IAW7duxdatW4+nTUIIIU4S5B0nhBAiNJZsPaHe3hwikZflccyeB+BqD2Yt4bP98YjuKEx1x2wwAk/NDtaHdNw2IPCpdeghsMv63svKEWXPmqEeumx52kqm4kQtFPfUF0mmrBLMkdEWY0EA9QqxESEnq26FaQCAyXGrzOkesH2NedSB6XiCb5jQTBMlX8L2K5ri3/kCsixTUsZq/GBHiUVPzNnXIhoRjzqOqPscqfsDAEHTxitE3XZkcoKuf+DFAyZWJ+qwuEfxRcoBYbDXWl8N9HE7pvEpq9o7fJjvKiAVgSJZO6478x10/TLpwt4Rq5jz1fhhtXuYGjaf5/XPslmrHPUp6YI4GW8eJR1jocq2RcaUDz0JCSGECA1NQkIIIUJDk5AQQojQ0CQkhBAiNJasMGFgYGBeXZ7x8TG6XJHUrGDJO5+woa/PJvWY3QUATB62ScU6yR7mPIlC1oYyq8fjESZwBz4iwvBY9aVZ7R6PMCCT7jSx3pxN9jYned2XIwdesEFyCsoee5V6mdSEIsdlosbXf0OPFWHkSZ2nUtkm1QHgwEHb/kQXF3FUirZOUVC3IoqOKn9fLknsfKLkHNY9FkMORERCE9B8YNSrpMZPgx+XWNXG3ay1OEqUrJUPAAxE7bU1UbbXQOGQp/4XO9+9Nlar8u/XjbI9BkxwAwBkCGJsxva101dPiN5zyLjmq9PrhZfv4jZj7HrxUSeWXIlFtp/RcrweFUNPQkIIIUJDk5AQQojQ0CQkhBAiNDQJCSGECA1NQkIIIUJjyarjJibGETnGZsRfqI5YfhArnOMp0PQSK4jty/Q0seJJc3Ud226K2NvEuAgLRyasFUqeWRSxim4Apg9bJVvaI2IZIoUIG7NEiegpoBdb5AHPxTzHqsfGy8RKpqfFz1UXsSypz9q2ujhfvzJt95Xu4wcrShSGrmrVYVNkmwDQGbEWQa7DKulqNa44izVtobl0R5ddjow1AGiR7daKHsUVsb2Jwx6XrihXAjJ7mCYpoNeY5ftnytNxUjxuZJxbVzEzppjHuytHlLNMsfbcwYN0fSpOIxXwfPX36lOLU9L5RHANYinmKw7a28uLQy6kzLyIADQWtKzVcqAeSwQ9CQkhhAgNTUJCCCFCQ5OQEEKI0NAkJIQQIjSWrDBhZGQCwTEOG77kG8t/x+NsYZ5QY4IHn91FDylTzkqXTxIBAQDMEmuMU06xAoC8pxZKOmcTpZMTNik7XeTtT5MMaNNTN6Y0OWVi5XEb68l30fU7BvpM7PBz1gqnPGLr/gDA4BmrTSzSZ49VZJYn65/9zT4aX0h3D0/Irlxziom1iAAAAJIta5sTDWyswgrEAKgcseewVbQiihqxzAGAbMpaLFVq7NK2ljMA5tljza0/OkWXnXiRJOH7V5hQJMPrMVUCUnuJDNe8R9iSIkqaOBnXhzy2P+w2MFvglmBdeVK/itlkeWuVkfpbbSikShnbh1KBCLE86zPRkq98Wp1ch1RXkffsbUG/jgoT+L1lIXoSEkIIERqahIQQQoSGJiEhhBChoUlICCFEaCxZYUI8jnnChN+33ELaqqNBlvWtPz1NHAeIO0I2x5Pdg0M2gZxIJk1sfOzIce3f137mTcDqqwBAPWqT2KmoHS5Bg78VnSThni4r4ig2+P6jSbuvSITUzUnY4wd4EsDkuFQ8woxT+0iyvdWiyzIKEzbZne2w5x8AEqSeEBMhpNI8reyatl/j+0k9Jw9pIq6ZHudjcLGUSI0hAJianjKxRsMm4D2mHwCpH+ZIAr7Dk4Gvke0ODVkRjY8CKeiT99QPY/W7GuR6aed+Rcxg0OVxQeClf7iwgImWQIQ0zrN+o84cExaHnoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExpJVxw0MrJhXT4ipSgCgRNQqLOZToDARVcZjrbFQAQIAE8RzZHilVVb5KJesPYuvr7RNZNnhlSvpskyFNbH/EF226Wom1t9jVUSRKreyGXl2r91/1urzBoa66PqRuF324IStEbO6a5CuP9DfbWL1SasujEb5uWZ2QFNjo3TZTKdVl+XTRDHlEdfFyDlMJq2SruVR580WreXK5F6rjluxho+LesX2NUKUkABQm7Y2V6OT9ly3Bng9oRRRcwZE9ZeY5dcrixYLtk2s7hAA9JD9D6+0Fk0AMF22CsX6qB2Dvb1cXTcywq8ts02POK5E7i15YiXkI03uY74bfpnUHqqzS8PT2PrCekJO6jghhBDLAE1CQgghQkOTkBBCiNDQJCSEECI0lqwwIRqNIxp95TmS2bOwmE+Y0Ndnk4oNImwAgCmSvGP7OjLKE9iM7p4eE+vw2LukUlZYkO+yCXgfh0eslUx3j90mAKzosu1KVKwIoVaxwgoASDk7tHIdNln8myley6Ves7YvsU6bVJ6dtWIDAJh6cdLE3nTaGhNLkFo6AFAv2P13d/fSZXOkptLMjBULzB7h4yKZ6TCxSMaKEEpExAIAGSJiiHtECIwjLzxvYtEYvzUkUyQ+Y4UVo4d5Ta3UoLW0SqdsrAorAACAAknWWwkNt7MC+DU0epjva2KCjC2SrE977JQWbwm2+BpD7cCEVD47JGY1ViGCmZqnqfUF98w2dAl6EhJCCBEemoSEEEKEhiYhIYQQoaFJSAghRGgsWWHC5OQEIpGXa80cb40gWl8GQCd5273pScoudru+mhsF8mZ3jKzP6gYBPNHYDkQrgKDO3RlqEzaxXqnYN8j7MvzN9NhKK2yYKtpkddDi++/uHjKxasQu26zw9WOkPgo7q7VpLkJhLgII+L6miWlEitSJaiSsAAEAmvawoly1xx9NT+2mnBVMNOo2XV8r89pJhWm7r5hnDHf195tYZ5YsO32Yrj8+MW5iGWfX72KFcwDEYc9XjVwXPtcRFvcty8QNnd3cCeJ4qJO6Pe2t74mTmOc2SImRZaMewUd8QR9azgHlxTm/6ElICCFEaGgSEkIIERqahIQQQoSGJiEhhBCh0fYkdPDgQfzxH/8xent7kclk8OY3vxmPP/743OfOOWzduhXDw8NIp9PYtGkTnn766de00UIIIU4M2lLHTU5O4h3veAfe85734Ac/+AFWrFiB3/3ud+jq6ppb5pZbbsGtt96Ke+65B2eccQa+9KUv4dJLL8WePXuQzS5eWVIulxG8LI7zqtu4Ncaid4PJSavY8u3LF7fLLX7/Y2NWMcc1VECc1BIpN3g9H0Y9bk/3hEddFjSsQi9FOtYkKjAAmJmwxzXWaXvWWeP772zYkxgltYtyg7x2U4G48bgeqyKLegbLgWd/bWLJad7WChlDQxlrB5Vw3CKoY8jWRGoS1eKhCW77U5u18rrxw1adFvNc7q00sc3xDOLfTR0xsTGiw+oe4HWemMnUYWKbY6+Ko2QH7TmMEdVfkVhsAUCBWnLxvvb0EIshYtFTLvN9sfsFqxHkcQlDhig8GbMedZ3L2LbWPOe1o0SUk6StWY9yOL+g+FDLOYxjceq4tiahv/iLv8CqVatw9913z8VOPfXUuf93zuG2227DzTffjCuvvBIAsGPHDgwMDODee+/Ftdde287uhBBCnOC09XPcfffdhwsvvBAf+MAHsGLFCrzlLW/BnXfeOff5vn37MDIygs2bN8/FkskkNm7ciEceeYRus1qtolgszvsTQghxctDWJLR3717cfvvtWLduHX74wx/iuuuuw6c//Wl885vfBACMjBx9rB4YGJi33sDAwNxnC9m+fTvy+fzc36pVq15NP4QQQixD2pqEWq0W3vrWt2Lbtm14y1vegmuvvRYf/ehHcfvtt89bLjg2mYOjP9MtjL3ETTfdhEKhMPe3f//+NrsghBBiudJWTmhoaAhnnXXWvNib3vQmfOtb3wIADA4eTUaOjIxgaOhl25XR0VHzdPQSyWQSSU9y+1gWKwoAgAxJyPlWZ8IA357yeWtRk8tZG4tpz0+KHSTROEuSf6z9AJAiNT8yHTbZP1LkNXpKVZvATBR4Yj5BDliy2/a17HiNmwip25IkSd2hHD/3LKXpElaYEAsSdH22gd8dOmBivXkulqmS8xpE+eUyccSKOFzNHpdTB/lTfi1lj/U/v/AbE9vnqdFzyoBN1leZFY/nImgQEQga3OInRux0WDmdSoWvz6B2WJ5rgNlspVL2XB0s2XN9dGc2lCeCH4D3YZocV5/tD9092b/v3sTiTNjgte1pw74sSu4t0yVrsVQa96VL5u+r9XrVE3rHO96BPXv2zIv95je/wZo1R4uFrV27FoODg9i1a9fc57VaDbt378aGDRva2ZUQQoiTgLaehP7zf/7P2LBhA7Zt24YPfvCD+PnPf4477rgDd9xxB4CjP8PdcMMN2LZtG9atW4d169Zh27ZtyGQyuOqqq16XDgghhFi+tDUJve1tb8N3vvMd3HTTTfizP/szrF27FrfddhuuvvrquWVuvPFGlMtlbNmyBZOTk1i/fj0eeOCBtt4REkIIcXLQdimHK664AldccYX38yAIsHXrVmzduvV42iWEEOIkYMnWE0qn0/PqCZU8rxWzpNzQkE00+uoR0bAnUcjqAZVLNlbzJAqZMIHFfG2dGrGJwjgRQfC3woF4FxFseOwZWiTZmxu2b8FPvMCl982iTer2kHo8uaxNiAJALGEFB+W6FQAkHc+A9vdaJ4XDFVIjKcVdDKZJW+uepG6NiBjqRMTwbOEQXb8zYkUMB5q2r6UOPi4ON22/envtcfVd7DEsXlxTYvV8yHAbHl5J12dJ/AJxN/DV2DlyxLpGsLo/7bieMGEDwIUJMzPEScSzfpaM7XaEBUwI1Y7YgO2LHWsA6DnF/lKV7rP3i3FyDwSAOKxjAhYp2JCBqRBCiNDQJCSEECI0NAkJIYQIDU1CQgghQkOTkBBCiNBYsuq4TCaNSOTlOdKvbrPxsTGmQuIKElazo8NrEWT3xWx3fLSjbFksbH2mqgG4ai7eyy1Lcj1dJjZyxKrzZitWLQQADVJjpVImiqs0X9/FbL9qgT1+1RRvPyORsN+54i2ujiMiMKQS/HJJdVhlUTRqbYtY3R8AKJJjlSY2KvDUl+nusFV6cqRfPq1Sq2rbNetRxzFLKUfGNVOxAVzJxq4rpuwCgHrdqrOYctZ3v2Aw1SvAryN2vTErH9+yzCLo0CG+f6a6YzHf/tlx8d1vykzJRs5VzaOuW6hRbcO1R09CQgghwkOTkBBCiNDQJCSEECI0NAkJIYQIjSUrTBgfL84rhOfL3/f12eQhS2r6aoYwG4spn+0NibVTH2Sx1FnRkzY2XG/w9g+eYm13erv5cTn8orXjKRRtArWfCAgAWrYF7AjWiL0PABTrpB4OScwXDnArnJmm3W6uyybwO/q55cqKqI3nY3zZwqSt8zMzbQUXHT4TX5LFzeR6bDDG072HRl40sQNtCGaYWCDHhBHgtjvtiGvKZXte2DXk0xUc77UVJ/WQfPeGWGxxt0efCIIJA9hxzecXX+eJHX+fpRljgNSe8pEiNcEG7S0EALB///z7hcdNi6InISGEEKGhSUgIIURoaBISQggRGpqEhBBChIYmISGEEKGxZNVx9XoDx4jj4LPd6e62KqJ02ipwmCrntaCLKlsWb/vDiGW47U7/CtvXTMZWpXvu4H66fjZKLGoqvK2FImlrzS4761HHJYiSrUVUWNOeYzU7btVxq1atMrEOagMDVPftM7FMT9LEujwFyYKsjUc8Fj/lslUsRYjqL+rpKxsVWaKka/gUR0QJd7xWNqwgGwCMj1vrJmZv09nJlYCsKFw77WK0o85rR13H7hlsX/39toAiwJVsrFCeT4k4Tq6BdpRwjHYshhhsrB9df/6/26hppychIYQQ4aFJSAghRGhoEhJCCBEamoSEEEKExpIVJsTjsXm2PazuD8CTfyzmS36yfJxvX4vUFXgXzHnq/Cyk4LFcYSKE/v5+EysSex0AOPjcQbJNblmSidl4qcZqudDVUSLHoEYOdjbL959dY5O9rbgVFpRrLbp+mRzDsfExE4tl7DYBnsCtVnimlSWbs0QwUfec12gvqRsTT5jYwcnDdP3SIutU+a4BVk/HX8+Hhg2TxMrIRztt5RY/Nui30ll87SJ2b2C2P7EYr4kVI6IdJnbw7Z+LEBZ/rBhjY/zeMDTUZ2JsXC+29lKr5VBm9cMIehISQggRGpqEhBBChIYmISGEEKGhSUgIIURoLFlhwkLHBH/yjiVl7XK+N4J7emx9jZkJ+1b40Y3w8EJ8ecIySTQ60i7fW9HPPWedEBIJm8BmCcWj22Uxnmhk4gwmYvAngG2M1W7yndeg175FPnVk0i7XRlLZEcHKM0//lq6fZWIBjzuES9vLKJOzhVfGiNsAAERI3Zo9e39nYnXP+FvseWnPmICPwYzHzWMx+z+6PhOiHJ9jQjt95fHF779eZyIOfg1xwQVbju+Lrb/Y+x3Aj3Uvua4AIEWcQ5i4ZLFtbbW4YIihJyEhhBChoUlICCFEaGgSEkIIERqahIQQQoSGJiEhhBChsWTVcfE45qnj/GoX+4HHiYbC7Fl8tjmLlRclvCo6+0HsOO1VDhx4YdHr9/XZA+Oz4WC0Yw8yOGhVh43AqtPGPBZDZaJk617RbWKzo6O8AaSpnaxGD7jlygSp5dLjURZNk9pBlaKtZzTmUT1mGva8HGFj0DOuWD0fXg/IUzuKjAF/eRk2BhanpAS4CotZ4fRZF5l/Wdbui8V845qpy/L5xd8w2rkGFruobzl2Dti59ikZ21H9jY5aSyh2rPz2Z/Pb0Gr5il9Z9CQkhBAiNDQJCSGECA1NQkIIIUJjyeWEnHP/8t+F8Xa24d/uQthvl75lscg2+FZvkQ/4/he3n6Pr2zeT2/k91tvVRba1rXYFNuY822TrN5uL72uThBtsm779k7B/WRtvksHiO3yLHoPe9Rd7rPhb7Gxf3jFM2trO2/GsXXysHd/+fdcwC7d3vRz/tXV867Pg8V2XR+OLG4OLHRcv38dfuW2Ba+eo/itw4MABrFq1KuxmCCGEOE7279+PU0455fcus+QmoVarhRdffBHZbBbT09NYtWoV9u/fj1yOK5OWI8Vi8YTr14nYJ+DE7NeJ2CdA/VpKOOcwPT2N4eFhRCK/P+uz5H6Oi0QiczPnS5VVc7ncsjn47XAi9utE7BNwYvbrROwToH4tFbic3CJhghBCiNDQJCSEECI0lvQklEwm8YUvfAHJZDLsprymnIj9OhH7BJyY/ToR+wSoX8uVJSdMEEIIcfKwpJ+EhBBCnNhoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGgs6Unob/7mb7B27VqkUilccMEF+H//7/+F3aRF8/DDD+O9730vhoeHEQQBvvvd78773DmHrVu3Ynh4GOl0Gps2bcLTTz8dTmMXyfbt2/G2t70N2WwWK1aswPve9z7s2bNn3jLLsV+33347zjvvvLk30i+66CL84Ac/mPt8OfZpIdu3b0cQBLjhhhvmYsuxX1u3bkUQBPP+BgcH5z5fjn16iYMHD+KP//iP0dvbi0wmgze/+c14/PHH5z5fzn37vbglys6dO108Hnd33nmne+aZZ9z111/vOjo63PPPPx920xbFP/zDP7ibb77Zfetb33IA3He+8515n3/5y1922WzWfetb33JPPfWU+8M//EM3NDTkisViOA1eBP/m3/wbd/fdd7tf/epX7oknnnCXX365W716tZuZmZlbZjn267777nPf//733Z49e9yePXvc5z73ORePx92vfvUr59zy7NOx/PznP3ennnqqO++889z1118/F1+O/frCF77gzj77bHfo0KG5v9HR0bnPl2OfnHNuYmLCrVmzxv3Jn/yJ+9nPfub27dvnfvSjH7nf/va3c8ss1769Ekt2EvqDP/gDd911182LvfGNb3Sf/exnQ2rRq2fhJNRqtdzg4KD78pe/PBerVCoun8+7r3/96yG08NUxOjrqALjdu3c7506cfjnnXHd3t/vbv/3bZd+n6elpt27dOrdr1y63cePGuUloufbrC1/4gjv//PPpZ8u1T84596d/+qfune98p/fz5dy3V2JJ/hxXq9Xw+OOPY/PmzfPimzdvxiOPPBJSq1479u3bh5GRkXn9SyaT2Lhx47LqX6FQAAD09PQAODH61Ww2sXPnTszOzuKiiy5a9n36xCc+gcsvvxyXXHLJvPhy7tezzz6L4eFhrF27Fn/0R3+EvXv3Aljefbrvvvtw4YUX4gMf+ABWrFiBt7zlLbjzzjvnPl/OfXslluQkNDY2hmaziYGBgXnxgYEBjIyMhNSq146X+rCc++ecw2c+8xm8853vxDnnnANgeffrqaeeQmdnJ5LJJK677jp85zvfwVlnnbWs+7Rz50784he/wPbt281ny7Vf69evxze/+U388Ic/xJ133omRkRFs2LAB4+Pjy7ZPALB3717cfvvtWLduHX74wx/iuuuuw6c//Wl885vfBLB8z9diWHKlHI7lpVIOL+GcM7HlzHLu3yc/+Uk8+eST+PGPf2w+W479OvPMM/HEE09gamoK3/rWt3DNNddg9+7dc58vtz7t378f119/PR544AGkUinvcsutX5dddtnc/5977rm46KKLcPrpp2PHjh14+9vfDmD59Qk4WkftwgsvxLZt2wAAb3nLW/D000/j9ttvx3/8j/9xbrnl2LdXYkk+CfX19SEajZoZfnR01HwTWI68pOZZrv371Kc+hfvuuw//+I//OK9q4nLuVyKRwBve8AZceOGF2L59O84//3x85StfWbZ9evzxxzE6OooLLrgAsVgMsVgMu3fvxl//9V8jFovNtX259WshHR0dOPfcc/Hss88u23MFAENDQzjrrLPmxd70pjfhhRdeALC8r61XYklOQolEAhdccAF27do1L75r1y5s2LAhpFa9dqxduxaDg4Pz+ler1bB79+4l3T/nHD75yU/i29/+Nh588EGsXbt23ufLtV8M5xyq1eqy7dPFF1+Mp556Ck888cTc34UXXoirr74aTzzxBE477bRl2a+FVKtV/PrXv8bQ0NCyPVcA8I53vMO87vCb3/wGa9asAXBiXVuGsBQRr8RLEu1vfOMb7plnnnE33HCD6+jocM8991zYTVsU09PT7pe//KX75S9/6QC4W2+91f3yl7+ck5h/+ctfdvl83n372992Tz31lPvQhz605OWWH//4x10+n3cPPfTQPIlsqVSaW2Y59uumm25yDz/8sNu3b5978skn3ec+9zkXiUTcAw884Jxbnn1iHKuOc2559uu//Jf/4h566CG3d+9e9+ijj7orrrjCZbPZufvCcuyTc0dl9LFYzP35n/+5e/bZZ93//t//22UyGfd3f/d3c8ss1769Ekt2EnLOua997WtuzZo1LpFIuLe+9a1zUuDlwD/+4z86AObvmmuucc4dlVx+4QtfcIODgy6ZTLp3v/vd7qmnngq30a8A6w8Ad/fdd88tsxz79Z/+03+aG2f9/f3u4osvnpuAnFuefWIsnISWY79eejcmHo+74eFhd+WVV7qnn3567vPl2KeX+N73vufOOeccl0wm3Rvf+EZ3xx13zPt8Offt96F6QkIIIUJjSeaEhBBCnBxoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKEhiYhIYQQoaFJSAghRGhoEhJCCBEamoSEEEKExv8HAWDS0eDRYOQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "for i in range():\n", - " plt.imshow() # what goes here?\n", + "for i in range(10):\n", + " indices = np.where(labels == i)[0][0]\n", + " \n", + " i_data = images[indices, :, :, 0] # first band\n", + " r_data = images[indices, :, :, 1] # second band\n", + " g_data = images[indices, :, :, 2] # third band\n", + "\n", + " rgb = make_lupton_rgb(i_data, r_data, g_data,\n", + " minimum=0, Q=6, stretch=50) # Bonus Q: how does changing these paramters change the images?\n", + "\n", + "\n", + "\n", + " plt.imshow(rgb) # what goes here?\n", " plt.title('Class {}'.format(i))\n", " plt.show()" ] }, + { + "cell_type": "code", + "execution_count": 8, + "id": "be79fcf8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 28, 32, 35, ..., 21768, 21769, 21775]),)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.where(labels == 0)" + ] + }, { "cell_type": "markdown", "id": "5645ec49", @@ -176,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "1be9403c", "metadata": {}, "outputs": [], @@ -186,7 +372,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "31d51e06", "metadata": {}, "outputs": [], @@ -204,7 +390,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "13ed3ae5", "metadata": {}, "outputs": [], @@ -221,7 +407,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "2adcacec", "metadata": {}, "outputs": [], @@ -229,29 +415,42 @@ "# Now, you may have noticed that our image array isn't structured in such a way that we can perform PCA \n", "# on it directly.\n", "# What shape should the image array have, use np.reshape to reshape the array.\n", - "\n", - "images_of_class = #fill this in for the class you want to compute the PCA for\n", - "images_of_class_mean_subtracted = # recenter\n", - "images_reshape = # what shape should this have?" + "indices = np.where(labels == 0)[0]\n", + " \n", + "images_of_class = images[indices][:, :, :, 0] #fill this in for the class you want to compute the PCA for\n", + "images_of_class_mean_subtracted = images_of_class - images_of_class.mean(axis=0)# recenter\n", + "images_reshape = images_of_class_mean_subtracted.reshape(-1, 69**2) # what shape should this have?" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "1fc8982f", "metadata": {}, "outputs": [], "source": [ "# perform the SVD \n", - "\n" + "\n", + "U, S, Vh = np.linalg.svd(images_reshape)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "fe18023e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCwsLBwJRapXlhYWFhYWFhYWLgSi1QvLCwsLCwsLCwsXIlFqhcWFhYWFhYWFhauxCLVCwsLCwsLCwsLC1dikeqFhYWFhYWFhYWFK7FI9cLCwsLCwsLCwsKVWKR6YWFhYWFhYWFh4UosUr2wsLCwsLCw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Y2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od2KR6Y2NjY2NjY2Nj453YpHpjY2NjY2NjY2PjndikemNjY2NjY2NjY+Od+LqS6PX1dfzHf/zH+Od//udxd3f3u+u08f9BHA6H8Z//+Z/j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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# plot the Principal components\n", "\n", @@ -358,7 +557,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "id": "cfefbe51", "metadata": {}, "outputs": [], @@ -368,14 +567,153 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "632d88da", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Int64Index: 499 entries, 11 to 9998\n", + "Data columns (total 29 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 GALEX_NUV 499 non-null float64\n", + " 1 GALEX_FUV 499 non-null float64\n", + " 2 IRAC_CH1 499 non-null float64\n", + " 3 IRAC_CH2 499 non-null float64\n", + " 4 IRAC_CH3 499 non-null float64\n", + " 5 IRAC_CH4 499 non-null float64\n", + " 6 IB427 499 non-null float64\n", + " 7 IB464 499 non-null float64\n", + " 8 IA484 499 non-null float64\n", + " 9 IB505 499 non-null float64\n", + " 10 IA527 499 non-null float64\n", + " 11 IB574 499 non-null float64\n", + " 12 IA624 499 non-null float64\n", + " 13 IA679IB709 499 non-null float64\n", + " 14 IA738 499 non-null float64\n", + " 15 IA767 499 non-null float64\n", + " 16 IB827 499 non-null float64\n", + " 17 NB711 499 non-null float64\n", + " 18 NB816 499 non-null float64\n", + " 19 Y 499 non-null float64\n", + " 20 J 499 non-null float64\n", + " 21 H 499 non-null float64\n", + " 22 Ks 499 non-null float64\n", + " 23 NB118g 499 non-null float64\n", + " 24 r 499 non-null float64\n", + " 25 i 499 non-null float64\n", + " 26 z 499 non-null float64\n", + " 27 hsc_y 499 non-null float64\n", + " 28 redshift 499 non-null float64\n", + "dtypes: float64(29)\n", + "memory usage: 117.0 KB\n" + ] + } + ], "source": [ "cosmos_2020.info(verbose=True)" ] }, + { + "cell_type": "code", + "execution_count": 9, + "id": "ce8fd5ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.isnull().values.any()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f99cf5b5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['GALEX_NUV', 'GALEX_FUV', 'IRAC_CH1', 'IRAC_CH2', 'IRAC_CH3',\n", + " 'IRAC_CH4', 'IB427', 'IB464', 'IA484', 'IB505', 'IA527', 'IB574',\n", + " 'IA624', 'IA679IB709', 'IA738', 'IA767', 'IB827', 'NB711', 'NB816', 'Y',\n", + " 'J', 'H', 'Ks', 'NB118g', 'r', 'i', 'z', 'hsc_y', 'redshift'],\n", + " dtype='object')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0277e0ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GALEX_NUV 0\n", + "GALEX_FUV 0\n", + "IRAC_CH1 0\n", + "IRAC_CH2 0\n", + "IRAC_CH3 0\n", + "IRAC_CH4 0\n", + "IB427 0\n", + "IB464 0\n", + "IA484 0\n", + "IB505 0\n", + "IA527 0\n", + "IB574 0\n", + "IA624 0\n", + "IA679IB709 0\n", + "IA738 0\n", + "IA767 0\n", + "IB827 0\n", + "NB711 0\n", + "NB816 0\n", + "Y 0\n", + "J 0\n", + "H 0\n", + "Ks 0\n", + "NB118g 0\n", + "r 0\n", + "i 0\n", + "z 0\n", + "hsc_y 0\n", + "redshift 0\n", + "dtype: int64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(cosmos_2020==-99).sum()" + ] + }, { "cell_type": "markdown", "id": "c42f145e", @@ -386,7 +724,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "id": "edf3df4a", "metadata": {}, "outputs": [], @@ -404,13 +742,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 57, "id": "56d8abf6", "metadata": {}, "outputs": [], "source": [ "tSNE = TSNE(\n", - " perplexity = 10,\n", + " perplexity = 1, #10,\n", " n_components=2,\n", " n_iter=2000,\n", " n_iter_without_progress=200,\n", @@ -432,13 +770,398 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, + "id": "b0b93518", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GALEX_NUVGALEX_FUVIRAC_CH1IRAC_CH2IRAC_CH3IRAC_CH4IB427IB464IA484IB505...NB816YJHKsNB118grizhsc_y
1124.36566824.63376122.92256825.19005625.04441826.42434525.06069424.98783324.93393925.170378...23.82532423.71949423.72093423.64277923.45764724.96764124.50982923.99010423.89099623.821889
3125.70582725.54770824.42263523.22081426.11355726.45966925.73852125.79411625.87129626.348288...25.20818324.75626924.95086825.24721724.86166025.93265425.71496325.53674125.55678725.168275
7222.57134022.50566821.59079723.03950923.87523323.79239123.63201023.59239823.32745323.048386...22.16460022.07278522.02619521.84618522.17277223.60020222.69758122.48269022.29923522.055720
8423.08802823.37202122.87216723.47821324.51750624.56366424.40577724.40329224.31450924.345500...23.08294223.26832223.27516923.01324723.44322124.31734324.15955623.76854623.45740423.309568
11224.88454024.80420422.67995422.98547626.30096325.71145025.90009526.53122425.92620025.554514...24.71601824.82849224.69724124.64009625.18362325.91398325.65620825.51024924.90704624.635006
..................................................................
994821.54630221.48329721.15680022.85840224.14822223.73110723.72283523.63130823.80832623.855400...22.52593122.09394221.91851621.74305122.31267023.78371323.56657523.30885223.06925922.824249
995123.47820123.40399323.32254122.52947524.97645225.26048224.89649825.05757025.05242024.949639...23.94570023.70519223.48932623.49633423.58939325.03907924.82444824.72459824.35013023.974294
997022.42308022.38833922.80758123.13148927.28687727.58958826.96904629.02020326.92122626.769342...24.32830723.71996423.10931022.75796923.38122026.95863326.70538825.86653825.26083424.573256
998025.90605426.34628922.83831922.59948926.46959026.56336926.55927826.07877727.00908727.415417...26.45111125.74856825.69602325.92146425.98797926.72234526.67700226.79140027.04230326.607488
999822.80175022.59989122.49645522.67040726.18290426.75688526.06553425.64663925.49045225.502780...24.67887823.89053523.55524423.19699223.88010025.76134525.47913625.16340724.89527824.832618
\n", + "

499 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " GALEX_NUV GALEX_FUV IRAC_CH1 IRAC_CH2 IRAC_CH3 IRAC_CH4 \\\n", + "11 24.365668 24.633761 22.922568 25.190056 25.044418 26.424345 \n", + "31 25.705827 25.547708 24.422635 23.220814 26.113557 26.459669 \n", + "72 22.571340 22.505668 21.590797 23.039509 23.875233 23.792391 \n", + "84 23.088028 23.372021 22.872167 23.478213 24.517506 24.563664 \n", + "112 24.884540 24.804204 22.679954 22.985476 26.300963 25.711450 \n", + "... ... ... ... ... ... ... \n", + "9948 21.546302 21.483297 21.156800 22.858402 24.148222 23.731107 \n", + "9951 23.478201 23.403993 23.322541 22.529475 24.976452 25.260482 \n", + "9970 22.423080 22.388339 22.807581 23.131489 27.286877 27.589588 \n", + "9980 25.906054 26.346289 22.838319 22.599489 26.469590 26.563369 \n", + "9998 22.801750 22.599891 22.496455 22.670407 26.182904 26.756885 \n", + "\n", + " IB427 IB464 IA484 IB505 ... NB816 Y \\\n", + "11 25.060694 24.987833 24.933939 25.170378 ... 23.825324 23.719494 \n", + "31 25.738521 25.794116 25.871296 26.348288 ... 25.208183 24.756269 \n", + "72 23.632010 23.592398 23.327453 23.048386 ... 22.164600 22.072785 \n", + "84 24.405777 24.403292 24.314509 24.345500 ... 23.082942 23.268322 \n", + "112 25.900095 26.531224 25.926200 25.554514 ... 24.716018 24.828492 \n", + "... ... ... ... ... ... ... ... \n", + "9948 23.722835 23.631308 23.808326 23.855400 ... 22.525931 22.093942 \n", + "9951 24.896498 25.057570 25.052420 24.949639 ... 23.945700 23.705192 \n", + "9970 26.969046 29.020203 26.921226 26.769342 ... 24.328307 23.719964 \n", + "9980 26.559278 26.078777 27.009087 27.415417 ... 26.451111 25.748568 \n", + "9998 26.065534 25.646639 25.490452 25.502780 ... 24.678878 23.890535 \n", + "\n", + " J H Ks NB118g r i \\\n", + "11 23.720934 23.642779 23.457647 24.967641 24.509829 23.990104 \n", + "31 24.950868 25.247217 24.861660 25.932654 25.714963 25.536741 \n", + "72 22.026195 21.846185 22.172772 23.600202 22.697581 22.482690 \n", + "84 23.275169 23.013247 23.443221 24.317343 24.159556 23.768546 \n", + "112 24.697241 24.640096 25.183623 25.913983 25.656208 25.510249 \n", + "... ... ... ... ... ... ... \n", + "9948 21.918516 21.743051 22.312670 23.783713 23.566575 23.308852 \n", + "9951 23.489326 23.496334 23.589393 25.039079 24.824448 24.724598 \n", + "9970 23.109310 22.757969 23.381220 26.958633 26.705388 25.866538 \n", + "9980 25.696023 25.921464 25.987979 26.722345 26.677002 26.791400 \n", + "9998 23.555244 23.196992 23.880100 25.761345 25.479136 25.163407 \n", + "\n", + " z hsc_y \n", + "11 23.890996 23.821889 \n", + "31 25.556787 25.168275 \n", + "72 22.299235 22.055720 \n", + "84 23.457404 23.309568 \n", + "112 24.907046 24.635006 \n", + "... ... ... \n", + "9948 23.069259 22.824249 \n", + "9951 24.350130 23.974294 \n", + "9970 25.260834 24.573256 \n", + "9980 27.042303 26.607488 \n", + "9998 24.895278 24.832618 \n", + "\n", + "[499 rows x 28 columns]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cosmos_2020.drop(columns='redshift')" + ] + }, + { + "cell_type": "code", + "execution_count": 53, "id": "6351c4ce", "metadata": {}, "outputs": [], "source": [ - "labels = \n", - "new_data = " + "labels = cosmos_2020['redshift']\n", + "new_data = cosmos_2020.drop(columns='redshift')" ] }, { @@ -451,12 +1174,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 64, "id": "16bd2cee", "metadata": {}, "outputs": [], "source": [ - "tSNE_map = " + "tSNE = TSNE(\n", + " perplexity = 5, #10,\n", + " n_components=2,\n", + " n_iter=2000,\n", + " n_iter_without_progress=200,\n", + " n_jobs=2,\n", + " random_state=0,\n", + " init = 'pca',\n", + " )\n", + "tSNE_map = tSNE.fit_transform(new_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "c5b1e3c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(499, 2)" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tSNE_map.shape" ] }, { @@ -469,18 +1222,64 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 66, "id": "e9ee41e3", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ - "x, y = \n", - "colormap = ['r', 'b', 'g', 'y', 'm', 'k']\n", + "x, y = tSNE_map[:, 0], tSNE_map[:, 1]\n", + "colormap = ['r', 'b', 'g', 'y', 'm', 'k', 'c']\n", "\n", - "# labels = \n", + "#labels = \n", "\n", - "for i,label in enumerate():\n", - " " + "for i,label in enumerate(labels.unique()):\n", + " indices = np.where(labels==label)\n", + " plt.scatter(x[indices], y[indices], c=colormap[i], label='z={:.2f}'.format(label))\n", + "plt.legend(loc = 'best') " + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "6d5f83aa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.1 , 1. , 2. , 1.5 , 3. , 2.5 , 0.01])" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "labels.unique()" ] }, { @@ -551,7 +1350,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/day1/MLTutorialNoSolutions.ipynb b/day1/MLTutorialNoSolutions.ipynb index 67c16db..9b1af58 100644 --- a/day1/MLTutorialNoSolutions.ipynb +++ b/day1/MLTutorialNoSolutions.ipynb @@ -44,10 +44,19 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 1, "id": "5a1d0a57", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/aizhanakhmetzhanova/opt/anaconda3/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5\n", + " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n" + ] + } + ], "source": [ "import pandas as pd\n", "import numpy as np\n", @@ -57,12 +66,12 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 3, "id": "e543f3b7", "metadata": {}, "outputs": [], "source": [ - "# lsst_data[0:1000].to_csv('session_19_DC2_subset.csv')" + "#lsst_data[0:1000].to_csv('session_19_DC2_subset.csv')" ] }, { @@ -79,18 +88,40 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 57, "id": "94094b3b", "metadata": {}, "outputs": [], "source": [ - "lsst_data = pd.read_csv('') #path to your data\n", + "lsst_data = pd.read_csv('simulated_extragalactic_data.csv') #path to your data\n", "\n", - "# lsst_data_to_classify = \n", - "# random_data = \n", + "lsst_data_to_classify = lsst_data[['id', 'flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z', 'truth_type']]\n", + "lsst_data_to_classify = lsst_data_to_classify[~(lsst_data_to_classify['truth_type'] == 3)]\n", + "#random_data = \n", "\n", - "# train_data = \n", - "# test_data = " + "train_data = lsst_data_to_classify.sample(frac = 0.8)\n", + "test_data = lsst_data_to_classify.drop(train_data.index)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "491088f8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2])" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lsst_data_to_classify['truth_type'].unique()" ] }, { @@ -107,12 +138,20 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 59, "id": "0186b8f1", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.8320802005012531 0.16791979949874686\n" + ] + } + ], "source": [ - "def estimate_class_probabilities():\n", + "def estimate_class_probabilities(x_train):\n", " \"\"\"\n", " Computes unconditional class probabilities. \n", " \n", @@ -122,12 +161,13 @@ " Returns:\n", " ints p1, p2: unconditional probability of an element of the training set belonging to class 1\n", " \"\"\"\n", - " \n", - " p1 = \n", - " p2 = \n", + " len_dset = x_train.shape[0]\n", + " p1 = (x_train['truth_type']==1).sum()/len_dset\n", + " p2 = (x_train['truth_type']==2).sum()/len_dset\n", " return p1, p2\n", "\n", - "p1, p2 = " + "p1, p2 = estimate_class_probabilities(train_data)\n", + "print(p1, p2)" ] }, { @@ -154,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 60, "id": "609b65b7", "metadata": {}, "outputs": [], @@ -170,13 +210,70 @@ " Returns:\n", " means, stdevs (array): MAP estimates of the Gaussian conditional probability distributions for a specific class\n", " \"\"\"\n", + " #x_train_class = train_data.loc[train_data['truth_type'] == label]\n", + " #means = x_train_class.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']].mean()\n", + " #stdevs = x_train_class.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']].std()\n", " \n", - " means = \n", - " stdevs = \n", + " means = np.log(train_data.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]).mean()\n", + " stdevs = np.log(train_data.loc[train_data['truth_type'] == label][['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]).std()\n", " \n", " return means, stdevs\n" ] }, + { + "cell_type": "code", + "execution_count": 61, + "id": "90590520", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 6.971252\n", + "flux_i 8.307006\n", + "flux_r 7.761517\n", + "flux_u 5.278125\n", + "flux_y 8.661954\n", + "flux_z 8.542979\n", + "dtype: float64" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "per_feature_likelihood_parameters(train_data, 2)[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "12289872", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 3.569217\n", + "flux_i 3.220594\n", + "flux_r 3.387434\n", + "flux_u 3.922922\n", + "flux_y 3.135953\n", + "flux_z 3.160724\n", + "dtype: float64" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "per_feature_likelihood_parameters(train_data, 2)[1]" + ] + }, { "cell_type": "markdown", "id": "16dbeb61", @@ -189,7 +286,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 63, "id": "05a17f4d", "metadata": {}, "outputs": [], @@ -210,13 +307,85 @@ " \"\"\"\n", " \n", " # compute probabilities and MAP estimates of the Gaussian distribution's parameters using the methods you wrote above\n", + " p1, p2 = estimate_class_probabilities(x_train)\n", " \n", + " class_1_mean, class_1_std = per_feature_likelihood_parameters(x_train, 1)\n", + " class_2_mean, class_2_std = per_feature_likelihood_parameters(x_train, 2)\n", " return p1, p2, class_1_mean, class_2_mean, class_1_std, class_2_std\n" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 65, + "id": "9d3c7074", + "metadata": {}, + "outputs": [], + "source": [ + " p1, p2, class_1_mean, class_2_mean, class_1_std, class_2_std = fit(train_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "a9015d0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "flux_g 3.175449\n", + "flux_i 3.753061\n", + "flux_r 3.482477\n", + "flux_u 2.768780\n", + "flux_y 4.096621\n", + "flux_z 3.942157\n", + "dtype: float64" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "class_1_mean" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "8c0aec66", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 0.017422\n", + "15 0.033539\n", + "19 0.032811\n", + "22 -0.000089\n", + "23 0.005145\n", + " ... \n", + "988 2.062806\n", + "990 1387.455468\n", + "995 0.133647\n", + "996 -0.005612\n", + "998 0.057714\n", + "Length: 200, dtype: float64" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.product((np.log(test_data[['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']]) - class_1_mean)/class_1_std, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 98, "id": "01867cba", "metadata": {}, "outputs": [], @@ -234,17 +403,40 @@ " Returns:\n", " predict_List (list): class membership predictions\n", " \"\"\"\n", + " x_test = np.log(x_test[['flux_g', 'flux_i', 'flux_r', 'flux_u', 'flux_y', 'flux_z']])\n", + " class_1_mean = class_means[0]\n", + " class_2_mean = class_means[1]\n", + " \n", + " class_1_std = class_dev[0]\n", + " class_2_std = class_dev[1]\n", " \n", " # compute probabilities of an element of the test set belonging to class 1 or 2\n", - " \n", - " for i in range():\n", - " if \n", - " \n", - " if \n", + " likelihood_1 = np.exp(-(x_test - class_1_mean)**2/class_1_std**2)/np.sqrt(2*np.pi)/class_1_std\n", + " posterior_1 = np.array(class_probability[0]*np.product(likelihood_1, axis=1))\n", + " \n", + " likelihood_2 = np.exp(-(x_test - class_2_mean)**2/class_2_std**2)/np.sqrt(2*np.pi)/class_2_std\n", + " posterior_2 = np.array(class_probability[1]*np.product(likelihood_2, axis=1))\n", + " #print(posterior_1 > posterior_2)\n", + " predict_list = []\n", + " for i in range(len(x_test)):\n", + " if posterior_1[i] > posterior_2[i]:\n", + " predict_list.append(1)\n", + " else:\n", + " predict_list.append(2)\n", " \n", " return predict_list" ] }, + { + "cell_type": "code", + "execution_count": 100, + "id": "4e28f694", + "metadata": {}, + "outputs": [], + "source": [ + "predict_list = predict(test_data, [p1, p2], [class_1_mean,class_2_mean] , [class_1_std, class_2_std])" + ] + }, { "cell_type": "markdown", "id": "8067d9e3", @@ -278,6 +470,27 @@ " plt.matshow()\n" ] }, + { + "cell_type": "code", + "execution_count": 110, + "id": "4d98198f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "176" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(np.array(predict_list) == np.array(test_data[['truth_type']]).reshape(200,)).sum()" + ] + }, { "cell_type": "markdown", "id": "cb4c8763", @@ -323,7 +536,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/orientation/.ipynb_checkpoints/TooBriefVisualization-checkpoint.ipynb b/orientation/.ipynb_checkpoints/TooBriefVisualization-checkpoint.ipynb new file mode 100644 index 0000000..ea84e81 --- /dev/null +++ b/orientation/.ipynb_checkpoints/TooBriefVisualization-checkpoint.ipynb @@ -0,0 +1,22897 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Introduction to Visualization:\n", + "Density Estimation and Data Exploration\n", + "========\n", + "\n", + "##### Version 0.2\n", + "\n", + "There are many flavors of data analysis that fall under the \"visualization\" umbrella in astronomy. Today, by way of example, we will focus on 2 basic problems.\n", + "\n", + "***\n", + "By AA Miller (Northwestern/CIERA) \n", + "30 August 2023\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Problem 1) Density Estimation\n", + "\n", + "Starting with 2MASS and SDSS and extending through to the Rubin Observatory, we are firmly entrenched in an era where data and large statistical samples are cheap. With this explosion in data volume comes a problem: we do not know the underlying probability density function (PDF) of the random variables measured via our observations. \n", + "\n", + "Hence - density estimation: an attempt to recover the unknown PDF from observations. In some cases theory can guide us to a parametric form for the PDF, but more often than not such guidance is not available. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "There is a common, simple, and very familiar tool for density estimation: histograms. \n", + "\n", + "But there is also a problem:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "HISTOGRAMS LIE!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "We will \"prove\" this via example. For this exercise, we will load the famous Linnerud data set, which tested 20 middle aged men by measuring the number of chinups, situps, and jumps they could do in order to compare these numbers to their weight, pulse, and waist size. Execute the cell below to load the data (just chinups for now)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/aizhanakhmetzhanova/opt/anaconda3/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5\n", + " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n" + ] + } + ], + "source": [ + "from sklearn.datasets import load_linnerud\n", + "\n", + "linnerud = load_linnerud()\n", + "chinups = linnerud.data[:,0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1a** \n", + "\n", + "Plot the histogram for the number of chinups using the default settings in pyplot." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "fig, ax = plt.subplots()\n", + "ax.hist(chinups, ) # complete\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('N', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Something is wrong here - the choice of bin centers and number of bins suggest that there is a 0% probability that middle aged men can do 10 chinups. This is intuitively incorrect; we will now adjust the bins in the histogram." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "\n", + "**Problem 1b** \n", + "\n", + "Using the same data make 2 new histograms: (i) one with 5 bins (`bins = 5`), and (ii) one with the bars centered on the left bin edges (`align = \"left\"`).\n", + "\n", + "*Hint - if overplotting the results, you may find it helpful to use the `histtype = \"step\"` option*" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "fig, ax = plt.subplots()\n", + "ax.hist(chinups, bins=5, histtype = \"step\") # complete\n", + "ax.hist(chinups, histtype = \"step\", align = \"left\") # complete\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('N', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "These small changes significantly change the estimator for the PDF. With fewer bins we get something closer to a continuous distribution, while shifting the bin centers reduces the probability to zero at 9 chinups. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "What if we instead allow the bin width to vary and require the same number of points in each bin? You can determine the bin edges for bins with 5 sources using the following command:\n", + "\n", + "`bins = np.append(np.sort(chinups)[::5], \n", + " np.max(chinups))`\n", + "\n", + "**Problem 1c** \n", + "\n", + "Plot a histogram with variable width bins, each with the same number of points.\n", + "\n", + "*Hint - setting `density = True` will normalize the bin heights so that the PDF integrates to 1.*" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "bins = np.append(np.sort(chinups)[::5], \n", + " np.max(chinups)) # complete\n", + "fig, ax = plt.subplots()\n", + "ax.hist(chinups, density=True) # complete\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('N', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*Ending the lie* \n", + "\n", + "Histograms lie, tell the \"truth\": show all the data. Viewers can understand the effects of bin choices when all the data are shown (this is cumbersome for very large data, which is essentially all modern data sets). Adding a rug plot, which shows a vertical tick for each source, provides additional clarity." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1d** \n", + "\n", + "Execute the cell below to see an example of a rug plot. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "fig, ax = plt.subplots()\n", + "ax.hist(chinups, histtype = 'step')\n", + "\n", + "# this is the code for the rug plot\n", + "ax.plot(chinups, np.zeros_like(chinups), '|', color='k', ms = 25, mew = 4)\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('N', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Rug plots are also imperfect. What if a measurement is repeated? A (slightly) better solution is to vary the transparency of the rug \"whiskers\" using `alpha = 0.3`. But this too is far from perfect. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "To recap, histograms are not ideal for density estimation: \n", + "\n", + "* They introduce discontinuities that are not present in the data\n", + "* They are strongly sensitive to user choices ($N_\\mathrm{bins}$, bin centering, bin grouping), without any mathematical guidance to what these choices should be\n", + "* They are difficult to visualize in higher dimensions" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Histograms are useful for generating a quick representation of univariate data, but for the reasons listed above they should never be used for analysis. Most especially, functions should not be fit to histograms given how greatly the number of bins and bin centering affects the output histogram." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "There must be a better option!\n", + "\n", + "(sound of slowly building classical music) Enter: [Kernel Density Estimation](https://en.wikipedia.org/wiki/Kernel_density_estimation) (KDE). " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "KDE is a nonparametric form of density estimation whereby a normalized kernel function is convolved with discrete data to obtain a continuous estimate of the underlying PDF. As a rule, the kernel must integrate to 1 over the interval $-\\infty$ to $\\infty$ and be symmetric. There are many possible kernels (gaussian is highly popular, though Epanechnikov, an inverted parabola, produces the minimal mean square error). " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "KDE is not completely free of the problems we illustrated for histograms above (in particular, both a kernel and the width of the kernel need to be selected), but it does manage to correct a number of the ills. We will now demonstrate this via a few examples using the `scikit-learn` implementation of KDE: [`KernelDensity`](http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KernelDensity.html#sklearn.neighbors.KernelDensity), which is part of the [`sklearn.neighbors`](http://scikit-learn.org/stable/modules/classes.html#module-sklearn.neighbors) module. \n", + "\n", + "*Note* There are many implementations of KDE in Python, and Jake VanderPlas has put together [an excellent description of the strengths and weaknesses of each](https://jakevdp.github.io/blog/2013/12/01/kernel-density-estimation/)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "To demonstrate the basic idea behind KDE, we will begin by representing each point in the dataset as a block (i.e. we will adopt the tophat kernel). Borrowing some code from Jake, we can estimate the KDE using the following code:\n", + "\n", + " from sklearn.neighbors import KernelDensity\n", + " def kde_sklearn(data, grid, bandwidth = 1.0, **kwargs):\n", + " kde_skl = KernelDensity(bandwidth = bandwidth, **kwargs)\n", + " kde_skl.fit(data[:, np.newaxis])\n", + " log_pdf = kde_skl.score_samples(grid[:, np.newaxis]) # sklearn returns log(density)\n", + " \n", + " return np.exp(log_pdf)\n", + " \n", + "The two main options to set are the bandwidth and the kernel. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# execute this cell\n", + "from sklearn.neighbors import KernelDensity\n", + "def kde_sklearn(data, grid, bandwidth = 1.0, **kwargs):\n", + " kde_skl = KernelDensity(bandwidth = bandwidth, **kwargs)\n", + " kde_skl.fit(data[:, np.newaxis])\n", + " log_pdf = kde_skl.score_samples(grid[:, np.newaxis]) # sklearn returns log(density)\n", + "\n", + " return np.exp(log_pdf)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1e** \n", + "\n", + "Plot the KDE of the PDF for the number of chinups middle aged men can do using a bandwidth of 0.1 and a tophat kernel.\n", + "\n", + "*Hint - as a general rule, the grid should be smaller than the bandwidth when plotting the PDF (i.e., >200 points in this case)*" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "grid = np.linspace(chinups.min(), chinups.max(), 500) # complete\n", + "PDFtophat = kde_sklearn(chinups, grid, 0.1, kernel='tophat')# complete\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(grid, PDFtophat) # complete\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('PDF', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "In this representation, each \"block\" has a height of 0.25. The bandwidth is too narrow to provide any overlap between the blocks. This choice of kernel and bandwidth produces an estimate that is essentially a histogram with a large number of bins. It gives no sense of continuity for the distribution. Now, we examine the difference (relative to histograms) upon changing the the width (i.e. kernel) of the blocks. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1f** \n", + "\n", + "Plot the KDE of the PDF for the number of chinups middle aged men can do using bandwidths of 1 and 5 and a tophat kernel. \n", + "\n", + "How do the results differ from the histogram plots above? " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "PDFtophat1 = kde_sklearn(chinups, grid, 1, kernel='tophat') # complete\n", + "PDFtophat5 = kde_sklearn(chinups, grid, 5, kernel='tophat') # complete\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(grid, PDFtophat1, label='bandwidth=1') # complete\n", + "ax.plot(grid, PDFtophat5, label='bandwidth=5') # complete\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('PDF', fontsize=14)\n", + "fig.tight_layout()\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "It turns out blocks are not an ideal representation for continuous data (see discussion on histograms above). Now we will explore the resulting PDF from other kernels. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 1g** Plot the KDE of the PDF for the number of chinups middle aged men can do using a gaussian and Epanechnikov kernel. How do the results differ from the histogram plots above? \n", + "\n", + "*Hint - you will need to select the bandwidth. The examples above should provide insight into the useful range for bandwidth selection. You may need to adjust the values to get an answer you \"like.\"*" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "PDFgaussian = kde_sklearn(chinups, grid, 1, kernel='gaussian') # complete\n", + "PDFepanechnikov = kde_sklearn(chinups, grid, 1, kernel='epanechnikov') # complete\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(grid, PDFgaussian, label='Gaussian') # complete\n", + "ax.plot(grid, PDFepanechnikov, label ='Epanechnikov') # complete\n", + "ax.legend(loc = 2)\n", + "ax.set_xlabel('chinups', fontsize=14)\n", + "ax.set_ylabel('PDF', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "So, what is the *optimal* choice of bandwidth and kernel? \n", + "\n", + "Unfortunately, every problem will likely have a different optimization. Typically, bandwidth is far more important than the choice of kernel. If the PDF is likely to be gaussian (or close to gaussian), then [Silverman's rule of thumb](https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator) can be used: \n", + "\n", + "$$h = 1.059 \\sigma n^{-1/5}$$\n", + "\n", + "where $h$ is the bandwidth, $\\sigma$ is the standard deviation of the samples, and $n$ is the total number of samples. Note - in situations with bimodal or more complicated distributions, this rule of thumb can lead to woefully inaccurate PDF estimates. The most general way to estimate the choice of bandwidth is via cross validation (we will cover cross-validation during the session on Machine Learning). " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "*What about multidimensional PDFs?* It is possible using many of the Python implementations of KDE to estimate multidimensional PDFs, though it is very very important to beware the curse of dimensionality in these circumstances." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Problem 2) Data Exploration\n", + "\n", + "Data exploration encompases a large suite of tools to examine large dimensional spaces. There is no single best method for data exploration. \n", + "\n", + "As an example we will start with a basic line plot - and examine tools beyond `matplotlib`." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "x = np.arange(0, 6*np.pi, 0.1)\n", + "y = np.cos(x)\n", + "\n", + "fig, ax=plt.subplots()\n", + "ax.plot(x,y, lw = 2)\n", + "ax.set_xlabel('X')\n", + "ax.set_ylabel('Y')\n", + "ax.set_xlim(0, 6*np.pi)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Seaborn\n", + "\n", + "[`Seaborn`](https://stanford.edu/~mwaskom/software/seaborn/index.html) is a plotting package that enables many useful features for exploration. \n", + "\n", + "Built-in tools in `seaborn` can reproduce everything from **Problem 1** in a single call." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Recreate the above `matplotlib` plot using `Seaborn`. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "import seaborn as sns\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "ax.plot(x,y, lw = 2)\n", + "ax.set_xlabel('X')\n", + "ax.set_ylabel('Y')\n", + "ax.set_xlim(0, 6*np.pi)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "These plots look identical, but it is possible to change the style with `seaborn`. \n", + "\n", + "`seaborn` has 5 style presets: `darkgrid`, `whitegrid`, `dark`, `white`, and `ticks`. You can change the preset using the following: \n", + "\n", + " sns.set_style(\"whitegrid\")\n", + " \n", + "which will change the output for all subsequent plots. Note - if you want to change the style for only a single plot, that can be accomplished with the following: \n", + "\n", + " with sns.axes_style(\"dark\"):\n", + "\n", + "with all ploting commands inside the `with` statement. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Problem 2a** \n", + "\n", + "Re-plot the sine curve using each `seaborn` preset to see which you like best - then adopt this for the remainder of the notebook. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "sns.set_style(\"whitegrid\")# complete\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "ax.plot(x,y, lw = 2)\n", + "ax.set_xlabel('X')\n", + "ax.set_ylabel('Y')\n", + "ax.set_xlim(0, 6*np.pi)\n", + "fig.tight_layout()\n", + "# complete\n", + "# complete\n", + "# complete" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "The `seaborn` devs have thought a lot about color palettes.\n", + "\n", + "A poor choice of colors can easily mask interesting patterns or suggest structure that is not real. To learn more about what is available, see the [`seaborn` color tutorial](http://stanford.edu/~mwaskom/software/seaborn/tutorial/color_palettes.html). \n", + "\n", + "Here we load the default:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "# default color palette\n", + "\n", + "current_palette = sns.color_palette()\n", + "sns.palplot(current_palette)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "which we will now change to `colorblind`, which is clearer to those that are colorblind." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "# set palette to colorblind\n", + "sns.set_palette(\"colorblind\")\n", + "\n", + "current_palette = sns.color_palette()\n", + "sns.palplot(current_palette)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Beyond the basics (we barely scratched the surface), `seaborn` is also powerful for higher dimension data sets. \n", + "\n", + "The famous Iris data set, which measures 4 different features of 3 different types of Iris flowers, will be our focus for the remainder of this notebook. There are 150 different flowers in the data set." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "*Note - for those familiar with `pandas` `seaborn` is designed to integrate easily and directly with `pandas DataFrame` objects. In the example below the Iris data are loaded into a `DataFrame`. `iPython` notebooks also display the `DataFrame` data in a nice readable format.* " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa
..................
1456.73.05.22.3virginica
1466.32.55.01.9virginica
1476.53.05.22.0virginica
1486.23.45.42.3virginica
1495.93.05.11.8virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " sepal_length sepal_width petal_length petal_width species\n", + "0 5.1 3.5 1.4 0.2 setosa\n", + "1 4.9 3.0 1.4 0.2 setosa\n", + "2 4.7 3.2 1.3 0.2 setosa\n", + "3 4.6 3.1 1.5 0.2 setosa\n", + "4 5.0 3.6 1.4 0.2 setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 virginica\n", + "146 6.3 2.5 5.0 1.9 virginica\n", + "147 6.5 3.0 5.2 2.0 virginica\n", + "148 6.2 3.4 5.4 2.3 virginica\n", + "149 5.9 3.0 5.1 1.8 virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iris = sns.load_dataset(\"iris\")\n", + "iris" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "We went to great pains to produce histograms, KDEs, and rug plots in **Problem 1**. `seaborn` handles all of that effortlessly with the [`displot`](https://seaborn.pydata.org/generated/seaborn.displot.html) function.\n", + "\n", + "**Problem 2b** \n", + "\n", + "Plot the distribution of petal lengths for the Iris data set. " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "# note - kde, and rug all set to True, set to False to turn them off \n", + "with sns.axes_style(\"dark\"):\n", + " sns.displot(iris['petal_length'], bins=20, \n", + " kde=True, rug=True)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "The Iris data lives in a 4D space, so plotting more than univariate distributions is important. Fortunately, `seaborn` makes it easy to produce handy summary plots (in a way that is far more comprehensive than `matplotlib`). \n", + "\n", + "**Problem 2c** \n", + "\n", + "Make a matplotlib scatter plot showing the Iris petal length against the Iris petal width." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "fig, ax = plt.subplots()\n", + "ax.scatter(iris['petal_length'], iris['petal_width']) # complete\n", + "ax.set_xlabel(\"petal length (cm)\")\n", + "ax.set_ylabel(\"petal width (cm)\")\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "**Aside**\n", + "\n", + "When there are many many data points, scatter plots become difficult to interpret. \n", + "\n", + "Execute the cell below:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "np.random.seed(2016)\n", + "xexample = np.random.normal(loc = 0.2, scale = 1.1, size = 10000)\n", + "yexample = np.random.normal(loc = -0.2, scale = 0.9, size = 10000)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.scatter(xexample, yexample)\n", + "ax.set_xlabel('X', fontsize=14)\n", + "ax.set_ylabel('Y', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Here, we see that there are many points, clustered about the origin, but we have no sense of the underlying density of the distribution. 2D histograms, such as `plt.hist2d()`, can alleviate this problem. I prefer to use `plt.hexbin()` which is a little easier on the eyes (though note - these histograms are just as subject to the same issues discussed above). " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# hexbin w/ bins = \"log\" returns the log of counts/bin\n", + "# mincnt = 1 displays only hexpix with at least 1 source present\n", + "fig, ax = plt.subplots()\n", + "cax = ax.hexbin(xexample, yexample, bins = \"log\", cmap = \"viridis\", mincnt = 1)\n", + "ax.set_xlabel('X', fontsize=14)\n", + "ax.set_ylabel('Y', fontsize=14)\n", + "fig.tight_layout()\n", + "plt.colorbar(cax)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "While the above plot provides a significant improvement over the scatter plot by providing a better sense of the density near the center of the distribution, the binedge effects are clearly present. Similar to **1g** a density estimate is superior. KDEs are easy in `seaborn` via the `kdeplot` function." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "fig, ax = plt.subplots()\n", + "sns.kdeplot(x=xexample, y=yexample, shade=False)\n", + "ax.set_xlabel('X', fontsize=14)\n", + "ax.set_ylabel('Y', fontsize=14)\n", + "fig.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "This plot is much more appealing (and informative) than the previous two. For the first time we can clearly see that the distribution is not actually centered on the origin. Now we will move back to the Iris data set. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Suppose we want to see univariate distributions in addition to the scatter plot? This is certainly possible with `matplotlib` and you can find examples on the web, however, with `seaborn` this is really easy." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "sns.jointplot(x=iris['petal_length'], y=iris['petal_width'])\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "But! Histograms and scatter plots can be problematic as we have discussed many times before. \n", + "\n", + "**Problem 2d** \n", + "\n", + "Re-create the plot above but set `kind='kde'` to produce density estimates of the distributions." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "sns.jointplot(x=iris['petal_length'], y=iris['petal_width'], kind='kde')# complete\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "That is much nicer than what was presented above. However - we still have a problem in that our data live in 4D, but we are (mostly) limited to 2D projections of that data. One way around this is via the `seaborn` version of a `pairplot`, which plots the distribution of every variable in the data set against each other. (Here is where the integration with `pandas DataFrame`s becomes so powerful.)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ + "sns.pairplot(iris[[\"sepal_length\", \"sepal_width\", \n", + " \"petal_length\", \"petal_width\"]])\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "For data sets where we have classification labels, we can even color the various points using the `hue` option, and produce KDEs along the diagonal with `diag_type = 'kde'`." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sns.pairplot(iris, vars = [\"sepal_length\", \"sepal_width\", \"petal_length\", \"petal_width\"],\n", + " hue = \"species\", diag_kind = 'kde')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Even better - there is an option to create a `PairGrid` which allows fine tuned control of the data as displayed above, below, and along the diagonal. In this way it becomes possible to avoid having symmetric redundancy, which is not all that informative. In the example below, we will show scatter plots and contour plots simultaneously. " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g = sns.PairGrid(iris, vars = [\"sepal_length\", \"sepal_width\", \"petal_length\", \"petal_width\"],\n", + " hue = \"species\", diag_sharey=False)\n", + "g.map_lower(sns.kdeplot)\n", + "g.map_upper(plt.scatter, edgecolor='white')\n", + "g.map_diag(sns.kdeplot, lw=3)\n", + "g.add_legend()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "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.9.7" + }, + "livereveal": { + "scroll": true, + "start_slideshow_at": "selected", + "theme": "solarized" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/orientation/TooBriefVisualization.ipynb b/orientation/TooBriefVisualization.ipynb index 996b372..ea84e81 100644 --- a/orientation/TooBriefVisualization.ipynb +++ b/orientation/TooBriefVisualization.ipynb @@ -89,13 +89,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/aizhanakhmetzhanova/opt/anaconda3/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5\n", + " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n" + ] + } + ], "source": [ "from sklearn.datasets import load_linnerud\n", "\n", @@ -118,16 +127,997 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "fig, ax = plt.subplots()\n", - "ax.hist( # complete\n", + "ax.hist(chinups, ) # complete\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('N', fontsize=14)\n", "fig.tight_layout()" @@ -162,17 +1152,998 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "fig, ax = plt.subplots()\n", - "ax.hist(# complete\n", - "ax.hist(# complete\n", + "ax.hist(chinups, bins=5, histtype = \"step\") # complete\n", + "ax.hist(chinups, histtype = \"step\", align = \"left\") # complete\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('N', fontsize=14)\n", "fig.tight_layout()" @@ -211,17 +2182,999 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "bins = np.append(# complete\n", + "bins = np.append(np.sort(chinups)[::5], \n", + " np.max(chinups)) # complete\n", "fig, ax = plt.subplots()\n", - "ax.hist( # complete\n", + "ax.hist(chinups, density=True) # complete\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('N', fontsize=14)\n", "fig.tight_layout()" @@ -255,13 +3208,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "fig, ax = plt.subplots()\n", "ax.hist(chinups, histtype = 'step')\n", @@ -366,7 +4300,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "slide" @@ -401,19 +4335,1000 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "grid = # complete\n", - "PDFtophat = kde_sklearn( # complete\n", + "grid = np.linspace(chinups.min(), chinups.max(), 500) # complete\n", + "PDFtophat = kde_sklearn(chinups, grid, 0.1, kernel='tophat')# complete\n", "\n", "fig, ax = plt.subplots()\n", - "ax.plot( # complete\n", + "ax.plot(grid, PDFtophat) # complete\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('PDF', fontsize=14)\n", "fig.tight_layout()" @@ -447,20 +5362,1011 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "PDFtophat1 = # complete\n", - "PDFtophat5 = # complete\n", + "PDFtophat1 = kde_sklearn(chinups, grid, 1, kernel='tophat') # complete\n", + "PDFtophat5 = kde_sklearn(chinups, grid, 5, kernel='tophat') # complete\n", "\n", "fig, ax = plt.subplots()\n", - "ax.plot(# complete\n", - "ax.plot(# complete\n", + "ax.plot(grid, PDFtophat1, label='bandwidth=1') # complete\n", + "ax.plot(grid, PDFtophat5, label='bandwidth=5') # complete\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('PDF', fontsize=14)\n", "fig.tight_layout()\n", @@ -493,20 +6399,1001 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "PDFgaussian = # complete\n", - "PDFepanechnikov = # complete\n", + "PDFgaussian = kde_sklearn(chinups, grid, 1, kernel='gaussian') # complete\n", + "PDFepanechnikov = kde_sklearn(chinups, grid, 1, kernel='epanechnikov') # complete\n", "\n", "fig, ax = plt.subplots()\n", - "ax.plot(# complete\n", - "ax.plot(# complete\n", + "ax.plot(grid, PDFgaussian, label='Gaussian') # complete\n", + "ax.plot(grid, PDFepanechnikov, label ='Epanechnikov') # complete\n", "ax.legend(loc = 2)\n", "ax.set_xlabel('chinups', fontsize=14)\n", "ax.set_ylabel('PDF', fontsize=14)\n", @@ -558,13 +7445,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "x = np.arange(0, 6*np.pi, 0.1)\n", "y = np.cos(x)\n", @@ -605,13 +8473,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "import seaborn as sns\n", "\n", @@ -660,16 +9509,1004 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "sns.set_style(# complete\n", + "sns.set_style(\"whitegrid\")# complete\n", + "\n", + "fig, ax = plt.subplots()\n", "\n", + "ax.plot(x,y, lw = 2)\n", + "ax.set_xlabel('X')\n", + "ax.set_ylabel('Y')\n", + "ax.set_xlim(0, 6*np.pi)\n", + "fig.tight_layout()\n", "# complete\n", "# complete\n", "# complete" @@ -692,13 +10529,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "# default color palette\n", "\n", @@ -719,13 +11537,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "# set palette to colorblind\n", "sns.set_palette(\"colorblind\")\n", @@ -760,13 +12559,157 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa
..................
1456.73.05.22.3virginica
1466.32.55.01.9virginica
1476.53.05.22.0virginica
1486.23.45.42.3virginica
1495.93.05.11.8virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " sepal_length sepal_width petal_length petal_width species\n", + "0 5.1 3.5 1.4 0.2 setosa\n", + "1 4.9 3.0 1.4 0.2 setosa\n", + "2 4.7 3.2 1.3 0.2 setosa\n", + "3 4.6 3.1 1.5 0.2 setosa\n", + "4 5.0 3.6 1.4 0.2 setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 virginica\n", + "146 6.3 2.5 5.0 1.9 virginica\n", + "147 6.5 3.0 5.2 2.0 virginica\n", + "148 6.2 3.4 5.4 2.3 virginica\n", + "149 5.9 3.0 5.1 1.8 virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "iris = sns.load_dataset(\"iris\")\n", "iris" @@ -789,13 +12732,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "# note - kde, and rug all set to True, set to False to turn them off \n", "with sns.axes_style(\"dark\"):\n", @@ -821,16 +13745,997 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "fig, ax = plt.subplots()\n", - "ax.scatter( # complete\n", + "ax.scatter(iris['petal_length'], iris['petal_width']) # complete\n", "ax.set_xlabel(\"petal length (cm)\")\n", "ax.set_ylabel(\"petal width (cm)\")\n", "fig.tight_layout()" @@ -853,13 +14758,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "np.random.seed(2016)\n", "xexample = np.random.normal(loc = 0.2, scale = 1.1, size = 10000)\n", @@ -885,13 +15771,1004 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# hexbin w/ bins = \"log\" returns the log of counts/bin\n", "# mincnt = 1 displays only hexpix with at least 1 source present\n", @@ -916,13 +16793,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "fig, ax = plt.subplots()\n", "sns.kdeplot(x=xexample, y=yexample, shade=False)\n", @@ -955,13 +17813,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "sns.jointplot(x=iris['petal_length'], y=iris['petal_width'])\n", "plt.tight_layout()" @@ -984,15 +18823,996 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ - "sns.jointplot(# complete\n", + "sns.jointplot(x=iris['petal_length'], y=iris['petal_width'], kind='kde')# complete\n", "plt.tight_layout()" ] }, @@ -1009,13 +19829,994 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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": [ "sns.pairplot(iris[[\"sepal_length\", \"sepal_width\", \n", " \"petal_length\", \"petal_width\"]])\n", @@ -1035,13 +20836,1004 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "sns.pairplot(iris, vars = [\"sepal_length\", \"sepal_width\", \"petal_length\", \"petal_width\"],\n", " hue = \"species\", diag_kind = 'kde')" @@ -1060,13 +21852,1004 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "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", + " 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 (fig.ws.readyState == 1 && 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", + "\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", + " 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" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "g = sns.PairGrid(iris, vars = [\"sepal_length\", \"sepal_width\", \"petal_length\", \"petal_width\"],\n", " hue = \"species\", diag_sharey=False)\n", @@ -1075,6 +22858,13 @@ "g.map_diag(sns.kdeplot, lw=3)\n", "g.add_legend()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -1094,7 +22884,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.9.7" }, "livereveal": { "scroll": true,