Topology in neuroscience
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2465 lines
244 KiB

2 years ago
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"# Tuning Curves"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"**Import everything**"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"%matplotlib notebook\n",
"import typing\n",
"\n",
"import matplotlib as mpl\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"import ipywidgets as widgets\n",
"import sympy as sp\n",
"sp.init_printing()\n",
"AxOrImg = typing.Union[mpl.axes.Axes, mpl.image.AxesImage]"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"k, x0, y0, phi, theta, sigma_x, sigma_y, sigma, x, y = sp.symbols(r'k x_0 y_0 \\phi \\theta \\sigma_x \\sigma_y \\sigma x y')\n",
"defaults = {\n",
" k: 6,\n",
" sigma: 0.2,\n",
" phi: sp.pi / 2,\n",
" theta: 0,\n",
" sigma: 1,\n",
" x0: 0, y0: 0\n",
"}\n",
"sigma_x = sigma_y = sigma"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"#### Formulas"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/latex": [
"$\\displaystyle \\cos{\\left(\\phi + k \\left(x - x_{0}\\right) \\cos{\\left(\\theta \\right)} + k \\left(y - y_{0}\\right) \\sin{\\left(\\theta \\right)} \\right)}$"
],
"text/plain": [
"cos(\\phi + k⋅(x - x₀)⋅cos(\\theta) + k⋅(y - y₀)⋅sin(\\theta))"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grating_f = sp.cos(k * (x - x0) * sp.cos(theta) + k * (y - y0) * sp.sin(theta) + phi)\n",
"receptive_field = 1 / (2 * sp.pi * sigma * sigma) * sp.exp(-(x ** 2 + y ** 2) / (2 * sigma ** 2)) * sp.cos(k * x * sp.cos(theta) + k * y * sp.sin(theta) + phi)\n",
"receptive_field = receptive_field.subs(theta, 0).subs(phi, 0)\n",
"grating_f"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/latex": [
"$\\displaystyle \\frac{e^{\\frac{- x^{2} - y^{2}}{2 \\sigma^{2}}} \\cos{\\left(k x \\right)}}{2 \\pi \\sigma^{2}}$"
],
"text/plain": [
" 2 2 \n",
" - x - y \n",
" ───────── \n",
" 2 \n",
" 2⋅\\sigma \n",
"ℯ ⋅cos(k⋅x)\n",
"───────────────────\n",
" 2 \n",
" 2⋅π⋅\\sigma "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"receptive_field"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"int1 = sp.Integral(grating_f * receptive_field, (x, -1, 1), (y, -1, 1)).subs(defaults)\n",
"# int1.evalf(2).doit()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"image/png": "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
"text/latex": [
"$\\displaystyle e^{\\frac{k^{2} \\left(\\cos^{2}{\\left(\\theta \\right)} + 1\\right)}{2}} \\cos{\\left(\\phi - k \\left(x_{0} \\cos{\\left(\\theta \\right)} + y_{0} \\sin{\\left(\\theta \\right)}\\right) \\right)} \\cosh{\\left(\\sigma^{2} k^{2} \\cos{\\left(\\theta \\right)} \\right)}$"
],
"text/plain": [
" 2 ⎛ 2 ⎞ \n",
" k ⋅⎝cos (\\theta) + 1⎠ \n",
" ───────────────────── \n",
" 2 ⎛ \n",
"ℯ ⋅cos(\\phi - k⋅(x₀⋅cos(\\theta) + y₀⋅sin(\\theta)))⋅cosh⎝\\s\n",
"\n",
" \n",
" \n",
" \n",
" 2 2 ⎞\n",
"igma ⋅k ⋅cos(\\theta)⎠"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# p = sp.cos(phi) * sp.cos(k*x0*sp.cos(theta) + k*y0*sp.sin(theta)) * sp.exp(k**2 * (sigma_x **2 * (1 + sp.cos(theta))**2 + sigma_y**2 * sp.sin(theta) **2) / 2)\n",
"p = sp.cosh(k**2 * sigma**2 * sp.cos(theta)) * sp.exp(k ** 2 * (1 + sp.cos(theta) ** 2) / 2) * sp.cos(phi - k * (x0 * sp.cos(theta) + y0 * sp.sin(theta)))\n",
"p"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"#### Plot stuff"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def get_orientation_phase_grid(step_phase: float, step_orientation: float) -> np.ndarray:\n",
" \"\"\"\n",
" Returns a grid of x and y values for plotting.\n",
" :param step_phase: step for the phase (phi) - in degrees\n",
" :param step_orientation: step for the orientation (theta) - in degrees\n",
" :return: numpy array of shape (n_orientation, n_phase). Each element is a tuple (theta, phi)\n",
" \"\"\"\n",
" # phase <-> phi\n",
" # orientation <-> theta\n",
" step_phase *= np.pi / 180\n",
" step_orientation *= np.pi / 180\n",
" phi = np.arange(0, 2 * np.pi, step_phase)\n",
" theta = np.arange(0, np.pi, step_orientation)\n",
" return np.array(np.meshgrid(theta, phi)).T.reshape(-1, len(phi), 2)\n",
"\n",
"\n",
"def get_spatial_grid(step_x: float, step_y: float, size: float = 1) -> np.ndarray:\n",
" \"\"\"\n",
" Returns a grid of x and y values for plotting.\n",
" :param step_x: step for the x-coordinate\n",
" :param step_y: step for the y-coordinate\n",
" :param size: size of the grid\n",
" :return: numpy array of shape (2 * size / step_x, 2 * size / step_y). Each element is a tuple (x, y)\n",
" \"\"\"\n",
" x = np.arange(-size, size, step_x)\n",
" y = np.arange(-size, size, step_y)\n",
" return np.array(np.meshgrid(x, y)).T.reshape(-1, len(x), 2)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def eval_func(func: sp.Expr, sub_1: sp.Expr, sub_2: sp.Expr, grid: np.ndarray) -> np.ndarray:\n",
" # return np.array([[float(func.subs(sub_1, x_).subs(sub_2, y_)) for x_, y_ in line] for line in grid])\n",
" func = sp.lambdify([sub_1, sub_2], func, 'numpy')\n",
" return func(grid[:, :, 0], grid[:, :, 1])\n",
"\n",
"def plot_spatial(func: sp.Expr, ax: AxOrImg, step_x: float = 0.05, step_y: float = 0.05, size: float = 1, title: str = None, show: bool = False,\n",
" patch: typing.Optional[typing.Tuple[float, float, float]] = None\n",
" ):\n",
" \"\"\"\n",
" Plots a spatial map of the function.\n",
"\n",
" :param func: function to plot\n",
" :param ax: axes to plot on or the image on axes\n",
" :param step_x: step for the x-coordinate\n",
" :param step_y: step for the y-coordinate\n",
" :param size: size of the grid\n",
" :param title: title of the plot\n",
" :param show: whether to show the plot\n",
" :param patch: optional circle to plot - a tuple (x, y, radius)\n",
" \"\"\"\n",
" grid = get_spatial_grid(step_x, step_y, size)\n",
" image: np.ndarray = eval_func(func, x, y, grid)\n",
" if isinstance(ax, mpl.image.AxesImage):\n",
" ax.set_data(image)\n",
" return ax\n",
" img = ax.imshow(image, extent=[-size, size, -size, size], vmin=-size, vmax=size, cmap='gray')\n",
" ax.invert_yaxis()\n",
" if patch is not None:\n",
" ax.add_patch(plt.Circle(patch[:2], radius=patch[2], color='b', fill=False))\n",
" ax.set_title(title)\n",
" if show:\n",
" plt.show()\n",
" return img\n",
"\n",
"def normalize(img):\n",
" return (img - img.min()) / (img.max() - img.min())\n",
"\n",
"def plot_tuning_curve(func: typing.Union[sp.Expr, typing.Callable], ax: AxOrImg, step_phase: float = 20, step_orientation: float = 15, title: str = None, show: bool = False):\n",
" \"\"\"\n",
" Plots a tuning curve of the function.\n",
"\n",
" :param func: function to plot - sympy or a function of (theta, phi)\n",
" :param ax: axes to plot on or image to update\n",
" :param step_phase: step for the phase (phi) - in degrees\n",
" :param step_orientation: step for the orientation (theta) - in degrees\n",
" :param title: title of the plot\n",
" :param show: whether to show the plot\n",
" \"\"\"\n",
" grid = get_orientation_phase_grid(step_phase, step_orientation)\n",
" if isinstance(func, sp.Expr):\n",
" image: np.ndarray = eval_func(func, theta, phi, grid)\n",
" else:\n",
" image = np.array([[func(theta_val, phi_val) for theta_val, phi_val in line] for line in grid])\n",
" image = normalize(image)\n",
" if isinstance(ax, mpl.image.AxesImage):\n",
" ax.set_data(image)\n",
" return ax\n",
" img = ax.imshow(image, extent=[0, 360, 0, 180], cmap='viridis')\n",
" ax.set_title(title)\n",
" if show:\n",
" plt.show()\n",
" return img"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def plot_gratings(ax: typing.Union[plt.Axes, mpl.image.AxesImage], k_val: float, phi_val: float, theta_val: float, x0_val: float = 0, y0_val: float = 0):\n",
" phi_val *= np.pi / 180\n",
" theta_val *= np.pi / 180\n",
" return plot_spatial(\n",
" # grating_f.evalf(subs={k: k_val, x0: x0_val, y0: y0_val, theta: theta_val, phi: phi_val}),\n",
" grating_f.subs(k, k_val).subs(x0, x0_val).subs(y0, y0_val).subs(theta, theta_val).subs(phi, phi_val),\n",
" ax, step_x=0.05, step_y=0.05, size=1, title='Grating', show=False)\n",
"\n",
"def plot_receptive_field(ax: plt.Axes, k_val: float, phi_val: float, theta_val: float, sigma_val: float = 1):\n",
" phi_val *= np.pi / 180\n",
" theta_val *= np.pi / 180\n",
" return plot_spatial(\n",
" receptive_field.subs(k, k_val).subs(theta, theta_val).subs(phi, phi_val).subs(sigma, sigma_val),\n",
" ax, step_x=0.05, step_y=0.05, size=1, title='Receptive field', show=False)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def get_value(k_val: float = defaults[k], phi_val: float = 90, theta_val: float = 0, x0_val: float = 0, y0_val: float = 0, sigma_val: float = defaults[sigma]):\n",
" phi_val *= np.pi / 180\n",
" theta_val *= np.pi / 180\n",
" grid_size = 0.05\n",
" grid = get_spatial_grid(grid_size, grid_size, 1)\n",
" subs = {\n",
" k: k_val,\n",
" x0: x0_val,\n",
" y0: y0_val,\n",
" theta: theta_val,\n",
" phi: phi_val,\n",
" sigma: sigma_val\n",
" }\n",
" grating_img = eval_func(grating_f.subs(subs), x, y, grid)\n",
" rf_img = eval_func(receptive_field.subs(subs), x, y, grid)\n",
" return np.sum(grating_img * rf_img) * grid_size ** 2"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"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(\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",
" );\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('style', 'box-sizing: content-box;');\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; position: absolute; left: 0; top: 0; 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",
" canvas.setAttribute(\n",
" 'style',\n",
" 'width: ' + width + 'px; height: ' + height + 'px;'\n",
" );\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",
" return function (event) {\n",
" return fig.mouse_event(event, name);\n",
" };\n",
" }\n",
"\n",
" rubberband_canvas.addEventListener(\n",
" 'mousedown',\n",
" on_mouse_event_closure('button_press')\n",
" );\n",
" rubberband_canvas.addEventListener(\n",
" 'mouseup',\n",
" on_mouse_event_closure('button_release')\n",
" );\n",
" rubberband_canvas.addEventListener(\n",
" 'dblclick',\n",
" on_mouse_event_closure('dblclick')\n",
" );\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband_canvas.addEventListener(\n",
" 'mousemove',\n",
" on_mouse_event_closure('motion_notify')\n",
" );\n",
"\n",
" rubberband_canvas.addEventListener(\n",
" 'mouseenter',\n",
" on_mouse_event_closure('figure_enter')\n",
" );\n",
" rubberband_canvas.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",
" this.rubberband_canvas.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.rubberband_canvas.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",
"// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function (e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e) {\n",
" e = window.event;\n",
" }\n",
" if (e.target) {\n",
" targ = e.target;\n",
" } else if (e.srcElement) {\n",
" targ = e.srcElement;\n",
" }\n",
" if (targ.nodeType === 3) {\n",
" // defeat Safari bug\n",
" targ = targ.parentNode;\n",
" }\n",
"\n",
" // pageX,Y are the mouse positions relative to the document\n",
" var boundingRect = targ.getBoundingClientRect();\n",
" var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
" var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
"\n",
" return { x: x, y: y };\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",
" var canvas_pos = mpl.findpos(event);\n",
"\n",
" if (name === 'button_press') {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * this.ratio;\n",
" var y = canvas_pos.y * 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",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\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 icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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(\"<div id='\" + id + \"'></div>\");\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",
" '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\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",
" '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\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 = '<i class=\"fa ' + image + ' fa-lg\"></i>';\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 = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\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": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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S92SSy5ZFH744Yfdeuut57bffnu3++67Bw386Ec/cieeeKI755xz3PLLL99XRuV/9atfuWuuucaNHTvWTZkyxX31q18tvEXyNim9++67brPNNnMvvPCCu/76690HPvABugkCEIDAsBJADA0rbm4GAQhAAAIQaCaBVVdd1c0zzzzu7LPPbqngVlttVSyfu+6664IVl5h56aWXCtFTTSq/yy67uKOPPtqttdZa7oQTTnA//vGPCzsSR2WS12nvvffuJ6aaSYlaQQACuRFADOXWo7QHAhCAAAQgUJPAq6++6lZYYQW37bbb9nltShNHHnmkO/XUU90dd9zh5phjjn6WtfdHS+UWWWSRljztC9ISOXmc5BHaaaed3F133VXYqaY///nPhVjad9993TbbbFOz5hSHAAQgMDQCiKGh8eNqCEAAAhCAwIgn8Oijj7q11167EEISRNV0+umnu8MPP9xdfvnlfcvnYg1+//33i31BjzzySLF3SPuI9P8KynDllVe2XF4KMS2f22+//WKmyYcABCDQUQKIoY7ixBgEIAABCEBg5BG45557iuhvBx98sNt0001bGnDeeecVf9e/J0yYYGpcuY9o4403dt/5zneKa7785S8XnqULL7ywxcZbb73lll56abfRRhu5Qw891GS/LPT22287iamZZprJTTfddLWupTAERiqBf//7307PjZ4nBTghDY0AYmho/LgaAhCAAAQgMOIJaPma9v4ccsghhSiqplIMXXDBBW6ZZZaJtrX0JC2++OLu/PPPd6NGjSquWX311d2HPvQhJzvVVIqhqnCK3uT/Crz44ovuiSeesBanHASyIrDgggu6j3zkI1m1qRuNQQx1gzr3hAAEIAABCDSIgKLGTZw4MbhvpxQ3V111lVtsscUGrfXxxx/vjjvuOKdJmgIxaHlcmRSVTucMXXHFFS02ymVyX/va14pACnWSrn3ssceK+8g7FEoSW9rXNFiZOvek7FQCcE03EmJsy/xFF100uI8vXc3ytIwYyrNfaRUEIAABCEDATOC1114rwmJvt912bq+99mq5LhZAQYW1R+h73/ueO+uss9zHPvax4iyhqhBSGUWWu/vuu92tt97aYn8oARQUuEH7kpZYYgk322yzBdtrKWMGRcE+AnBNNxhibGP56WqWp2XEUJ79SqsgAAEIQAACtQisttpqbr755iuETDUptPZzzz3XL3R2tUwpmMaNG+cmT57sxowZ0+/eOotIe4kUUEH3KVMZWvvcc891yy23XK06WyaFljK1bkrhggBc0w2EGNtYfrqa5WkZMZRnv9IqCEAAAhCAQC0COg/olFNOCR66uuOOO7pdd901aE/nC33zm9902iOkpXGh8Nu68PHHH3drrrlmEa2uXA6nZXMK2KBziq699trah65aJoWWMrVAURgxlHgMxMZsLD9x9bIzjxjKrktpEAQgAAEIQKA+gVdeeaUIry2BouVyWvqm84VmmWUWd8kll7jRo0cXouWWW24p9gQtu+yyxU0UJW7KlClOgmnhhRfud2OVU3mlgw46qAigsOGGG7rx48c77UPSuUM6jFUBFuomy6TQUqbufSmPZyjlGIiN2Vh+yrrlaBsxlGOv0iYIQAACEIBAGwQUmU1nCt12221FyN4VV1yx2E
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "26092ac79aa740f5b1207f63c07ed12a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=6.0, description='k', max=10.0, step=0.2), FloatSlider(value=90.0, des…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(1, 3)\n",
"img_gr = plot_gratings(ax[0], defaults[k], 90, 0, 0, 0)\n",
"img_rf = plot_receptive_field(ax[1], defaults[k], 90, 90, defaults[sigma])\n",
"val = get_value()\n",
"line = ax[2].plot([val, val])[0]\n",
"ax[2].set(ylim=[-0.2, 0.2])\n",
"\n",
"@widgets.interact(\n",
" k_val=widgets.FloatSlider(min=0, max=10, step=0.2, value=defaults[k], description='k'),\n",
" phi_val=widgets.FloatSlider(min=0, max=360, step=10, value=90, description='phi'),\n",
" theta_val=widgets.FloatSlider(min=0, max=180, step=10, value=0, description='theta'),\n",
" x0_val=widgets.FloatSlider(min=-1, max=1, step=0.05, value=0, description='x0'),\n",
" y0_val=widgets.FloatSlider(min=-1, max=1, step=0.05, value=0, description='y0'),\n",
" sigma_val=widgets.FloatSlider(min=0, max=1, step=0.05, value=defaults[sigma], description='sigma'),\n",
")\n",
"def plot_stuff(k_val, phi_val, theta_val, x0_val, y0_val, sigma_val):\n",
" plot_gratings(img_gr, k_val, phi_val, theta_val, x0_val, y0_val)\n",
" plot_receptive_field(img_rf, k_val, phi_val, theta_val, sigma_val)\n",
" val = get_value(k_val, phi_val, theta_val, x0_val, y0_val, sigma_val)\n",
" line.set_ydata([val, val])\n",
" fig.canvas.draw_idle()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"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(\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",
" );\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('style', 'box-sizing: content-box;');\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; position: absolute; left: 0; top: 0; 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",
" canvas.setAttribute(\n",
" 'style',\n",
" 'width: ' + width + 'px; height: ' + height + 'px;'\n",
" );\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",
" return function (event) {\n",
" return fig.mouse_event(event, name);\n",
" };\n",
" }\n",
"\n",
" rubberband_canvas.addEventListener(\n",
" 'mousedown',\n",
" on_mouse_event_closure('button_press')\n",
" );\n",
" rubberband_canvas.addEventListener(\n",
" 'mouseup',\n",
" on_mouse_event_closure('button_release')\n",
" );\n",
" rubberband_canvas.addEventListener(\n",
" 'dblclick',\n",
" on_mouse_event_closure('dblclick')\n",
" );\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband_canvas.addEventListener(\n",
" 'mousemove',\n",
" on_mouse_event_closure('motion_notify')\n",
" );\n",
"\n",
" rubberband_canvas.addEventListener(\n",
" 'mouseenter',\n",
" on_mouse_event_closure('figure_enter')\n",
" );\n",
" rubberband_canvas.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",
" this.rubberband_canvas.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.rubberband_canvas.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",
"// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function (e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e) {\n",
" e = window.event;\n",
" }\n",
" if (e.target) {\n",
" targ = e.target;\n",
" } else if (e.srcElement) {\n",
" targ = e.srcElement;\n",
" }\n",
" if (targ.nodeType === 3) {\n",
" // defeat Safari bug\n",
" targ = targ.parentNode;\n",
" }\n",
"\n",
" // pageX,Y are the mouse positions relative to the document\n",
" var boundingRect = targ.getBoundingClientRect();\n",
" var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
" var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
"\n",
" return { x: x, y: y };\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",
" var canvas_pos = mpl.findpos(event);\n",
"\n",
" if (name === 'button_press') {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * this.ratio;\n",
" var y = canvas_pos.y * 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",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\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 icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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(\"<div id='\" + id + \"'></div>\");\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",
" '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\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",
" '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\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 = '<i class=\"fa ' + image + ' fa-lg\"></i>';\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 = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\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": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABOkAAAKTCAYAAABMyFzvAAAgAElEQVR4XuzdB7xdVZ3w/X96SCcJhBBSpAUQpQqCYgexgKhjBR54VQhjBQRmKKJiwwYqUqLjOIoMDgJiAQRUHFSKqDCoQEJoCS2EkkBIL2/2eZ7LJLS19sk+2Td3f+/7mc87j659ztnf9U9Y8+Oce3qtXPUTfggQIECAAAECBAgQIECAAAECBAgQqE2gl0hXm70nJkCAAAECBAgQIECAAAECBAgQINASEOkMAgECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAAECBAgQIECAAAECBAgQEOnMAAECBAgQIECAAAECBAgQIECAAIGaBUS6mjfA0xMgQIAAAQIECBAgQIAAAQIECBAQ6cwAAQIECBAgQIAAAQIECBAgQIAAgZoFRLqaN8DTEyBAgAABAgQIECBAgAABAgQIEBDpzAABAgQIECBAgAABAgQIECBAgACBmgVEupo3wNMTIECAAA
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "43a5782034fb4bec9f235bff100cb9a5",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.8, description='k', max=10.0, step=0.2), FloatSlider(value=0.8, desc…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(1, 2)\n",
"DEF_K, DEF_SIGMA, DEF_X = 0.8, 0.05, 0.8\n",
"get_tuning_curve_func = lambda k_val, x0_val, y0_val, sigma_val: lambda theta_val, phi_val: get_value(k_val, phi_val * 180 / np.pi, theta_val * 180 / np.pi, x0_val, y0_val, sigma_val)\n",
"left_img = plot_tuning_curve(get_tuning_curve_func(DEF_K, DEF_X, 0, DEF_SIGMA), ax[0], title='Tuning Curve')\n",
"right_img = plot_tuning_curve(p.subs({k: defaults[k], x0: defaults[x0], y0: defaults[y0], sigma: defaults[sigma]}), ax[1], title='Tuning Curve')\n",
"\n",
"@widgets.interact(\n",
" k_val=widgets.FloatSlider(min=0, max=10, step=0.2, value=DEF_K, description='k'),\n",
" x0_val=widgets.FloatSlider(min=-1, max=1, step=0.05, value=DEF_X, description='x0'),\n",
" y0_val=widgets.FloatSlider(min=-1, max=1, step=0.05, value=0, description='y0'),\n",
" sigma_val=widgets.FloatSlider(min=0, max=1, step=0.05, value=DEF_SIGMA, description='sigma'),\n",
")\n",
"def plot_tuning_curves(k_val, x0_val, y0_val, sigma_val):\n",
" plot_tuning_curve(get_tuning_curve_func(k_val, x0_val, y0_val, sigma_val), left_img, title='Tuning Curve - Numeric')\n",
" plot_tuning_curve(p.subs({k: k_val, x0: x0_val, y0: y0_val, sigma: sigma_val}), right_img, title='Tuning Curve - Analytic')\n",
" fig.canvas.draw_idle()"
]
},
{
"cell_type": "code",
"execution_count": null,
"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.10.5"
}
},
"nbformat": 4,
"nbformat_minor": 1
}