Skip to content

Instantly share code, notes, and snippets.

@tritemio
Last active December 23, 2015 00:04
Show Gist options
  • Save tritemio/da1d2951670ae37e0eee to your computer and use it in GitHub Desktop.
Save tritemio/da1d2951670ae37e0eee to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Best practice for introductory class\n",
"\n",
"The first code cell always import commonly used libraries and set up the notebook for plotting. This are my suggested imports:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from __future__ import division # only needed in python2.x, NO-OP on python 3.x\n",
"%matplotlib notebook\n",
"from pylab import *"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simple calculator\n",
"\n",
"Algebraic operations are intuitive:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3 + 2 - 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The equal sign (`=`) assigns variables:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"x = 7"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3.5"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x / 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A double equal (`==`) is a comparison:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x == 7"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To elevating to the power `**` is used:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"9"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3**2"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"49"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x**2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Define an array\n",
"\n",
"Syntax to define a numpy's array. Here students can type-in the experimental data:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"a = array([1, 3, 8, 7])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"b = array([-1, -3, -7, 8])"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"c = array([[1, 2, 3, 4],\n",
" [5, 6, 7, 8]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Arrays from a range of numbers can be generated with `arange()`, a function that takes *start*, *stop* and *step* arguments:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"arange(0, 20, 2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **NOTE**: by convention *stop* is not included!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If *step* is not specified it defaults to 1:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"arange(0, 10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Array operations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Array to array operations, they are like scalars:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 0, 1, 15])"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a + b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Broadcasting: array + scalar = array"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([11, 13, 18, 17])"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a + 10"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Arrays have built-in methods for common operations:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4.75"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.mean()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2.8613807855648994"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.std()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"19"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.sum()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Array indexing\n",
"\n",
"In python array index start at 0.\n",
"\n",
"Take the first element:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Take the last element:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"7"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[-1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Take a slice between index *start* and *stop* (not included!):"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([3, 8, 7])"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[1:4]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Math functions\n",
"\n",
"All the common functions are predefined (`sin`, `cos`, `tan`, `log`, `exp`). They take both scalar and arrays as inputs:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0.1353352832366127"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"exp(-2)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 1.00000000e+00, 8.18730753e-01, 6.70320046e-01,\n",
" 5.48811636e-01, 4.49328964e-01, 3.67879441e-01,\n",
" 3.01194212e-01, 2.46596964e-01, 2.01896518e-01,\n",
" 1.65298888e-01, 1.35335283e-01, 1.10803158e-01,\n",
" 9.07179533e-02, 7.42735782e-02, 6.08100626e-02,\n",
" 4.97870684e-02, 4.07622040e-02, 3.33732700e-02,\n",
" 2.73237224e-02, 2.23707719e-02, 1.83156389e-02,\n",
" 1.49955768e-02, 1.22773399e-02, 1.00518357e-02,\n",
" 8.22974705e-03, 6.73794700e-03, 5.51656442e-03,\n",
" 4.51658094e-03, 3.69786372e-03, 3.02755475e-03,\n",
" 2.47875218e-03, 2.02943064e-03, 1.66155727e-03,\n",
" 1.36036804e-03, 1.11377515e-03, 9.11881966e-04,\n",
" 7.46585808e-04, 6.11252761e-04, 5.00451433e-04,\n",
" 4.09734979e-04, 3.35462628e-04, 2.74653570e-04,\n",
" 2.24867324e-04, 1.84105794e-04, 1.50733075e-04,\n",
" 1.23409804e-04, 1.01039402e-04, 8.27240656e-05,\n",
" 6.77287365e-05, 5.54515994e-05])"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = arange(0, 10, 0.2)\n",
"y = exp(-x)\n",
"y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Plotting\n",
"\n",
"> It is worth spending some time on getting familiar on how to use the mouse to zoom and pan the plot. Hint: the pan tool allows both panning and zooming (using the right click).\n",
"\n",
"## Procedural interface (MATLAB-like)\n",
"\n",
"A simple plot:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\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('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",
"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 = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(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",
" 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",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.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 = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\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",
"\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",
"\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]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\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, 0, fig.canvas.width, fig.canvas.height);\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",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = 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.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",
" /* 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",
" evt.data.type = \"image/png\";\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",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\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(\"No handler for the '\" + msg_type + \"' message type: \", msg);\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(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://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",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\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",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\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",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value});\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",
"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\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";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.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",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['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 = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\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.get(0);\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",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\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).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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 () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('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",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\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('matplotlib', mpl.mpl_figure_comm);\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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot(x, y);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Typying a second plot will resule the prefious figure, unless the figure is closed by cliccing on the red \"x\"."
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x6ef1390>]"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot(y, x, '-o')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Closing a plot results in a static image to be enbedded in the notebook."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#close('all')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Object-oriented interface\n",
"\n",
"This requires slight more typing but will manage many plots better:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\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('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",
"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 = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(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",
" 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",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.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 = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\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",
"\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",
"\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]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\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, 0, fig.canvas.width, fig.canvas.height);\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",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = 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.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",
" /* 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",
" evt.data.type = \"image/png\";\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",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\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(\"No handler for the '\" + msg_type + \"' message type: \", msg);\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(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://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",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\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",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\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",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value});\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",
"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\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";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.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",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['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 = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\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.get(0);\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",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\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).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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 () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('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",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\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('matplotlib', mpl.mpl_figure_comm);\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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = subplots()\n",
"ax.plot(x, y, '-sg');"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\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('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",
"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 = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(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",
" 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",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.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 = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\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",
"\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",
"\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]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\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, 0, fig.canvas.width, fig.canvas.height);\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",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = 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.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",
" /* 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",
" evt.data.type = \"image/png\";\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",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\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(\"No handler for the '\" + msg_type + \"' message type: \", msg);\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(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://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",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\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",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\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",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value});\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",
"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\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";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.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",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['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 = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\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.get(0);\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",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\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).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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 () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('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",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\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('matplotlib', mpl.mpl_figure_comm);\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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = subplots()\n",
"ax.plot(x, y, '-hr');"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\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('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",
"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 = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(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",
" 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",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.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 = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\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",
"\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",
"\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]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\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, 0, fig.canvas.width, fig.canvas.height);\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",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = 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.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",
" /* 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",
" evt.data.type = \"image/png\";\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",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\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(\"No handler for the '\" + msg_type + \"' message type: \", msg);\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(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://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",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\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",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\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",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value});\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",
"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\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";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.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",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['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 = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\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.get(0);\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",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\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).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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 () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('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",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\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('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA3AAAAFoCAYAAAAW8BkIAAAgAElEQVR4nOzdeVwV1fsH8GcA2UQQVHJBQXMvFVMTywW3Mkv9mVjmkktlKfbV+9XKUsMl69uuZuaSuWSmpZXlggtu5b602oJ7rpmluCICn98fh4vcFbjM3DNz53m/XvMSxmHmgeGew3PnnOcQMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjHnN/4joJyLKIKLTRLSYiGIK+ZrNRHSDiC4X2J7RLkTGGGNF1IuIviXRpucSkV8hx0cS0SdEdJGILhDRIiKK0DJAxhhjjJXMq0TUmIgCSHTanxDR94V8zSYimqhxXIwxxorvPiJ6lIgGUtESuFVEtI6IooioHBGtJ6KvtAyQMcYYY+qKJ9Hpu3sHdhMRTfJOOIwxxjyQSIUncLF5xzQosK9h3r7CRmIwxhhjTCeeJ6IjhRyziYjOE9G/RPQbEb1GRKU1josxxljRJVLhCVw3IrruZH8mET2kQUyMMcYYU1kHIrpCYgiOOy2IqGzexw2JaD8RLXFynEJEVYgonDfeeOPNh7YqJNo3PUukwhO4fkR01sn+s0TU224ft+e88cabL25GaM8Zc+khEhPYu3nwta2J6CYRBdntr0JE4I033njzwa0K6VsiqfsEjttz3njjzVc3vbfnjDnVh0QFsg4efr01gQu22x9ORDhx4gQyMjJMtSUnJ0uPgb9v/r75+1Z/O3HihLXDD/e4xfWORPJsDlwjcj4HLpyIQHQCRBlo2nSo9Hthtt/zJk2GgijDYdPqXujl+5Z5v5s2df4zj4xshaZNhzps3boZ93Wh9/vt6l6U5PffQO05Yw6GkZjLdm8Rj48mok4k5rwpRHQHEe0lomVOjg0nImRkZMBsLBaL7BCk4O/bXMz4fWdkZOi9w/cj8WbafSQSsdC8z10NEVpJRGtJVKAsT0QbyHkVyrwELgNEQEKCee69Hn7PL10CypWzgAgOm1b3Qg/ftwwFv++EBOc/84CA7l69F96g9/vt6l40b+553AZozxlzKZcc13S7TLcSumpOPt9F4ondZSI6SGItOWdFTDiBMxn+vs3FjN+3ATr8ASTa9VwiyinwcWtybM+JbNeBu0hEH5Pz7y2ciBAePhSVKlmQlGSee+/t3/OkJAsSEm5tDRtaEBxs8XrSYMbXN8AJnF4lJVkQFWVBpUriddGsmXhd3HEHJ3CMqc20CVxqaqrsEKTg79tczPh9m7jDDycibN2agZAQ4Ngx2XfCe7z9e+4qaYiKamuT1CmK+CNWq2TajK9vwPb7dnUvSpf2vQRO7/f72DEgMBA4evTWvv37gdBQYNs2z85p4vacMbdMm8AxxnyTiTv8/Pa8b1+gXz/Zd8J3uUoa7JODBg2Ajz+WFKRJJCVZEBtrQUSE7VPRqCjfS+D0btQooEcPx/3vvgvExgIXLhT/nCZuzxlzixM4xphPMXGHn9+eHzsGhIQA338v+274pqImcK++CnTuLClIE2nTBnj/fdt9Rb1HTB2XLwMREcB33zn+X24ucNttFpQrZ0Hz5raJdmFPp03cnjPmFidwjDGfYuIO36Y9HzUKuO8+yTfDgHJzc1WrtvfjjxkICMjA0aPyKwT66nbsWAb8/TPwyy+2+7t1u1V5snbtoQgIGIomTYxdhVLP2xtvZKBx4wxcvOj8/+Pj3b9mcnNznb4eMzJM254z5hYncIwxn2LiDt+mPe/a1QJ/fwvq1i3eO95mV+D3hzfeePPS5urvUBO354y5xQkcY8ynmLjDt2nPeQiZZ6y/P2ZcH5U33ry9Wdd5y8jgBI6x4uAEjjHmU0zc4XMCpwLr7w/3i4xpr7DXm4nbc8bc4gSOMeZTTNzhcwKnAk7gGPMeTuAY8wwncIwxn2LiDp8TOBVwAseY93ACx5hnOIFjjPkUE3f4nMCpgBM4xryHEzjGPMMJHDOFefPmQVGU/M3f3x9VqlTBI488gj/++CP/uJSUFCiKIjHSWzHk5OS4PW7Tpk1QFAVbtmzxUmTe99dfYn2h4jBxh2/Tnicl3ao8GRZmwe23cxXKovDFBM6+/StTpgwaNWqE6dOnIzs7W7XrxMbGYuDAgaqeb8CAAfmfW7+P48ePl/jcZ86cQZcuXRAVFQVFUTBlyhRVz+9MSkoKNm7cqMm5C/ryyy/xzjvvOOzXY5/BCRxjnuEEjpmCtWNevnw5du3ahe3bt2PhwoWoVasWYmJi8l8DKSkp8PPzkxqrNYbCErhLly5h165duHTpkpci01ZmJrBjBzBlCtCrF1C9OqAowNdfF+88Ju7wXbbnw4YBI0aodKN8nC8ncNb2b/369XjqqaegKApefvll1a7zww8/4MiRI6qdLy4uziYh/Pvvv7Fr1y7cuHGjxOceMmQIIiIi8NVXX2HXrl04e/as5gmcoigYN26cJucuqH///oiJiXHYr8c+gxM4xjzDCRwzBWvHfPjwYZv9GzZsgKIoSE1NBWCsJ3C+ZNcuIDAQKFcO6NwZmDgRWLcOuHCh+OcycYfvsj2fOxdo06bk98kMfDmBs2//2rVrh4iIiBKfX42Eyhn7BE5NiYmJaGP3ovBGAjd27FhNzl2QqwROjziBY8wznMCxEsnJycGCqVOxYOpUVRMOtc/r6g+YXbt2QVEUfPPNNwCcJ3A3b97Eq6++ijp16iAoKAiVK1fGyJEjkZmZaXPcyy+/jMaNGyM8PBzly5dHu3btsHPnTodYzp07hyFDhiAmJgZBQUGoWrUq+vXrl/9HkDWGgwcPonPnzggLC0NsbCwmTpyI3Nzc/PM4Gw7Tpk0btGzZEuvXr0fjxo0RGhqKO++8E19++aVDHIsXL0adOnUQHByMBg0aYMWKFWjTpg0SExOL+dMt3I0bwM6dwD//OP//a9eA9HSgwLfnMRN3+C7b8/37gfBwwETvCXjMTAncc889B0VR8PfffwMQT9C6dOmCyMhIhISE4N5778W3335r8zXW5GD79u1o0aIFQkJCMCLv8a79kEdAtLHt27dHWFgYSpcujfbt22P37t0OMU6ZMgWxsbEIDg5G06ZNsXXrVocEzlWCNXv2bDRu3BghISGIjIxEmzZtsH37dqc/i6NHj9oMJ7Vux44dc3p+RVEwfvx4p+eYP3++zf7NmzejQ4cOiIiIQOnSpdGoUSPMnTs3/zz224QJEwDAZbtr//P8+++/MXjwYNSuXRuhoaGoWrUqevfujVOnTuUf079/f4frVK9eHYDrIZTvvPMOateujcDAQFSqVAnDhg1zeEpnTT6nTp2KuLg4lClTBm3atMGBAwdsjktNTUWLFi0QERGBsLAw1KlTBxMnTnR6LwBO4BjzFCdwzGM7tmzBgCZNkBoSgtSQEAxo0gQ7VBhbr8V5rR3zH3/8gZs3byIzMxO//vor2rdvj4oVK+Jy3kQrZwnco48+itKlS2PSpElIS0vDe++9h7Jly6JHjx42xz3xxBNYsGABNm/ejFWrVqFXr14IDAzEzz//nH/Mv//+i5o1a6J8+fKYMmUKNm7ciE8//RSPPfYYrly5YhPDnXfeiXfeeQdpaWkYPnw4FEXBvHnz8s/lrDNOTExEpUqVcMcdd+CTTz5BamoqOnbsiICAABw6dCj/uHXr1kFRFHTv3h1r1qzBggULUKNGDVSuXBlt27Yt0c8aAM6dA776Cnj+eaBlSyAoCIiKArww/cPMHb7L9vzGDaBUKaDArwBzoSgJXMH5hQU3NeYXanFuVwlcjx49UKpUKVy/fh379u1DaGgoWrVqheXLl2P16tXo2rUrgoKCsG/fvvyv6d+/P8qUKYPY2FhMnz4dW7ZsyU/I7BOuH3/8MT8hW758OZYvX45mzZohJCQEP/74Y/5xH374IRRFwaBBg7B27VpMnz4dMTExiIiIKDSBGzlyJBRFwVNPPYWVK1di9erVGDduHJYuXer0Z3Hjxg3s3LkTjRo1QpMmTbBr1678YZmuEjhromVlTeAWLFiQv++rr76Cv78/EhMTsXTpUqSlpWHq1KlISUkBAOzcuTP/e7Re05p4tWnTxmm7a//z/OOPP/Dss8/i888/x9atW7F06VI0a9YMcXFx+W8oHj58GA8++CCio6Pzr/PDDz8AcN5nvPjii1AUBc8++yzWrVuHd999F2FhYWjVqpXNG4aKoiAuLg6dOnXCN998g2XLlqF69eqoWbNm/jzKw4cPIzAwEH379sXatWuxadMmzJo1C6NHj3Z6LwBO4BjzFCdwzCPp6elIjo5GVoHydllESI6ORnp6uu7Oaz+J37pVqVIFe/bsyT/OPoHbunUrFEXBokWLbM73ySefQFGU/I7RXnZ2Nm7evIk6depg+PDh+fvHjRsHf39/l19XMAb7d3cbNGiA++67L/9zV0/gAgMDbZK1c+fOwd/fH6+++mr+vhYtWqBBgwY259+3bx8URSlxArdtm5i7Vq8e8OSTwEcfAb//rs7TtaIwcYfvtj2Pjwc+/9w798DIipLAaVnhU4tz27+B9e+//2LmzJnw9/dH9+7dAYjhlPXr18fNmzfzvy4nJwf16tXD//3f/+Xvsz7h+drJ5FT7hKNHjx6IjIy0+VleunQJUVFRePjhh/OvERMTgwceeMDmXEuXLoWiKG4TuIMHD8LPzw8jR44s9s/k3nvvdWjrPE3gcnNzERsbi2bNmrm9pqs5cEVN4OxlZ2fjzz//hKIoNqMsXA2htO8z/vnnHwQGBjpcY9GiRQ73WFEU1K5d26bozbJly6AoCnbs2AEA+Pzzz6EoSv4bokXBCRxjnuEEjnnkwIEDmBMZ6fBXxpyyZXFg1y4gI8Oj7cCuXZhTtqzjeSMjHYZqFIe1Y16xYgX27duHvXv3YsWKFejYsSMqVKiA3377DYBjAvfSSy8hKCgI165dw82bN/O3c+fOQVEUTJs2Lf/Y9evXIzExEeXKlbNJEgv+YdK8eXO0aNHCbazWGKzDmqx69eqFunXr5n/uKoG74447HM5ZqVIlDBkyBIDo9AMDAx2GBQFAjRo1Ck3gsrLEcMjz553//40brodKeoOJO3y37fnAgcBLL3n5ZhhQSRK4Zs0snjZ9+VuzZtolcPaVePv3748LFy7g2rVrCAgIQEpKik07d/PmTQwbNgxRUVH55+rfvz+CgoJsns5Y2SccFSpUQL9+/RyOGzBgAMqVKwcAOH78uMPoAkAMXS9VqpTbBO6DDz7IT0yLS80E7rfffoOiKJg1a5bba6qRwM2YMQMNGzZEWFiYzf18/fXX848pagK3atUqKIqCtLQ0m+OsP/tRo0bZxJ6cnGxz3O+//w5FUfKfdh46dAiBgYHo3Lkzli1bhr/++svtzwPgBI4xT3ECxzziMoEjwgFnf30UcTuQdw6tEjj7IUTXr19H+fLl8eijjwJwTOCefPJJp0/uFEWBn59ffhK0b98+lCpVCl27dsWKFSuwe/du7N27F/Hx8TYdc82aNdGzZ0+3sboqYtK/f3/ExcXlf+4qgWvVqpXDOQv+IXD27FkoioIZM2Y4HJeQkODwh8SVK8CGDcDLLwPt2gGhoUBkpNinRybu8N2259OmAXYPOZgTJUngiFztL86mXQJnfQMrPT3dpvDIyZMnXbZz1rbOyl2BDPuEIyAgAM8//7zDcS+88EL+Oa1DC1evXu1wXMWKFd0mcK+88goURcHVq1eL+RNRN4H77rvvoCgKVq1a5faaxU3g7JdlmDZtGhRFwahRo7B+/Xrs3bs3fx53wRiLmsB9/PHHUBQFv/76q8OxFStWxKBBg9zG7mwo6aZNm9CpUyeEhITAz88PCQkJbpct4ASOMc9wAsc8kp6ejqFOhjoOLV8e6fv3e/z2c/r+/RhavrzjeVUaQmmfwAFAs2bNUL9+fQCOCdwLL7yAkJAQ7Nu3z+l25swZAOJJXenSpR3WVKpWrZpNx9yiRYsiP4HTKoFz9wSuevXqNvHu3QsEBAAxMUDv3sAHHwC//KLvYhgm7vDdtufffQdUrOjlm2FAvvwEzln7BwBXrlyBv78/hg8f7rKtsypOAhcdHe30CVz//v1Rvnx5AO6fwAUEBLhN4GbOnKn5E7jg4GCMGTPG5ri9e/faJC7WJ1GePoG7//77cc899zjsL1OmjM33f88996Bjx442xxw5csTjBK64T+CKksBZZWVlYePGjWjZsiXCwsJw3sWQDU7gGPMMJ3DMYwWLjawJCcHAJk2w065imV7O6+oPmKtXryIqKiq/nLR9Ard582anHZy9ESNGoEyZMjYJXFpamsOcspSUFPj7+9tM4LfnLoGzVhMDPE/gAPGHwJ133glADHe8fPnWHyUF483MBI4e9d78NTWYuMN3255fvizmJua958Bc8OU5cK4SOOBWWX1nQyML6t+/P6pWrer0/+zbmZ49e6JcuXI2c6Ksc+CSkpIAiDlw1apVQ6dOnWzOtWTJkkLnwB0+fBj+/v6azoGrU6cOunbtanPchAkTHObAVa9evdA5cEFBQTZJkdXTTz+N8uXLIysrK3/fli1bHL7/xo0bO8wVHDdunEMCN3jw4PwhqgU5mwMXFBSEp556yuY46xy4lStX5u8rbgJntWLFCiiKgr179zr9f07gGPMMJ3CsRHJycrBw2jQsnDZN9WUE1DyvtWNetmwZduzYge3bt2P58uVo27Yt/Pz8sGzZMgDOq1D27t0bkZGRmDRpElJTU7Fu3TrMnj0b3bt3z38quHbtWiiKgr59+2LDhg2YMWMGKleujJiYGJvy0BcvXkStWrVQoUIFTJ06FWlpaVi6dCn69OnjUAnT0ydwLVu2dPj+Cw7F+ecfYPz49SBSEB7+fyBaheRkUYWyUqVKaN++fUl+1NKZuMMvtD2vXRtwMlKNFWCmKpQF7d+/H2FhYejYsSOWLFmCzZs3Y9myZXjppZdsqgi6ewJnP+Tvp59+QkhICO6+++78KpR33303QkND8dNPP+UfN3fu3PxkJTU1FdOnT0fVqlURERFhU0bfWYI1atQo+Pn5YfDgwfjmm2+wevVqjB8/3mUVSqt7773XoXS/s/Nb33SbPHkyNmzYgJSUFNSpU8chcVmxYgX8/f3Rtm3b/CqU06dPz69CCYgErG7duli/fj327NmD06dPA7jVlvft2xfr16/H7NmzUa9ePZQtW9bm+3/xxRfh5+eHV199FevXr8eLL76I2rVrOyRwU6dOhaIo+OCDD7B79+78n7WzPuOll16CoigYMWIE1q5diylTpqBMmTJo3bq1zc+mKAncBx98gN69e2PRokX5vz9NmjRBTEyMw7I7VpzAMeYZTuCYKcyfP99hXkd0dDTat2+PdevW5R83fvx4m/kegHh3derUqWjUqBGCg4MRERGBRo0a4YUXXrB57bz33nuoXr16/h8saWlpSExMdHiX99y5cxg8eDAqVaqEwMBAVK1aFQMGDMifk2KNwT6BGzBggMMTOD8/P4dlBFw9gUtKGoj4eMDPT1SI7NhxMSpXFmvb3Xnnnfjqq6/QuHHj/OpwRmXiDr/Q9vzRR4HJk714MwzIV9eB8/Pzc5vAAaIYR69evRAdHY2goCDExMSgW7duWLNmTf4xAwYMKPITOECsA9ehQ4f8deA6dOhgU/nXaurUqfnrwDVr1gzbtm1zug6cn5+fwzpwM2fORMOGDREUFISoqCi0bdvW6RqcBbVs2dLpEzj782dmZmL48OGoVKkSypQpg169emH37t1Onzxt3LgRbdu2RVhYGMLCwhAfH29TTXjbtm1o0qQJgoODHZKuWbNmoVatWvnr7+3bt8/h+79+/TqGDBmCChUqoEyZMujSpUt+ElXwXFevXsVjjz2GyMhIKIrtOnD2fQYAvPvuu6hTpw4CAwNRuXJlDBs2zKGSZFESuB07dqBbt26oWrUqgoKCUKlSJTzyyCNupz9wAseYZziBY8wkrl8HliwBzp51/v8nTpxAcHAwXnnlFe8GpjITd/iFtuf/+x9gt3whs+OLCRxjesUJHPNl/yOin4gog4hOE9FiIoop5GsiiegTIrpIRBeIaBERRTg5jhM4xgwuKwvYvh2YNAlITAQWLiz8a65fv45nnnkGy5Ytw+bNm/HRRx+hbt26KFeuHM66yvAMwsQdfqHt+dq1QI0aXrwZBsQJHGPewwkc82WvElFjIgogkYR9QkTfF/I1q4hoHRFFEVE5IlpPRF85OY4TOMYM6MoVURa+a1egTBmgXDmgZ09g5kzgxInCvz4rKwvdu3fPH8YZGRmJbt26lWipBr0wcYdfaHt+7pwoiHHxohdviMFwAseY93ACx8wknohyyfkTNSKi2Lz/b1BgX8O8ffZP7jiBY8yAMjOBBx8E3ngD2LdP32X9vc3EHX6R2vMqVYDNm710MwyIEzjGvIcTOGYmzxPRETf/342IrjvZn0lED9nt4wSOMR26cQPYuBFwMtefFcLEHX6R2vMuXYB33/XSzTAgTuAY8x5O4JhZdCCiK0R0n5tj+hHRWSf7zxJRb7t9nMAxphOHDgHTpwMPPQSULi0WXZ4xQ3ZUxmPiDr9I7fnLLwOPP+6lm2FAnMAx5j2cwDEzeIhEQZJuhRxX7CdwycnJsFgssFgsSE1N9fLLlzFzy80FGjYESpUC2rcXwyJ//NFYi2fLlpqamt+GJScnm7XDL1IC9+WXQIMGXroxBsQJHGPeY329HTrECRzzTX1IVJTsUIRjnc2Ba0Q8B44x3dqxA7Bbdod5yMQdfpHa82PHAH9/sawEc8QJHGPeY329ffYZJ3DM9wwjon+J6N5ifM1KIlpLogJleSLaQFyFkjGvu3ED2LABsFiAF16QHY05mLjDL1J7npsLREYCu3d76YYYDCdwjHmP9fU2ejQncMz35BLRDSK6bLdZE7pqdp8T2a4Dd5GIPibnv/ycwDGmsnPngPnzxYLJYWFA5crAk08Ca9bIjswcTNzhF7k9b9cOmDXLCzfDgKy/PydOnEBGRgZvvPGm4XbixAkQETp25ASOseLgBI4xlXXuDDRrBkycCOzfz3PZvM3EHX6R2/ORI4FnnvHCzTCgAr8/vPHGm5c2f/+haN7cgoQEsSUlWexfj2ZrzxlzixM4ZkpPPvkkFEWBxWIp8tfMmzcPiqLg+PHjbpOyrCwVAiwgJycHw4cPR8WKFeHn54fu3bure4FiSElJwcaNGx329+/fH3FxcRIicmTiDr/I7fmiRUDz5l64GQaUm5tr84TgpZcy8Oij6j95OHw4A0QZOHlS/lMQI2zly2cgLU398z79dAaGDJH//Rlh++9/M9Cvn7rnbNp0KIgyQJQLIuRvCQmcwDHmDidwzHSuXbuG8PBwhIaG4rbbbkN2dnaRvm7mTJHAPfzwcdSpAxTxy0ps6dKlUBQF7777Lnbu3ImDBw9658JOKIqCcePGOew/fPgwfvjhBwkROTJxh1/k9vzXX4GQEO/9DhvZ448DEyZoc+7y5YFdu7Q5ty/55x/xR/2FC+qf+733gAcfVP+8vujBB4GpU9U9Z0KCxSZx4wSOsaLhBI6ZzuLFi6EoCt577z0oioKVK1e6PPb8eWDePKBrVyAgYB6IFAwZchzbtwM5Od6Jd/z48VAUBbk6GIupKArGjh0rOwy3TNzhF7k9z84GQkOBAwe8cEMM7p57gE8+0ebcrVuL9oW5t327WBdTC2vXArVqaXNuX1O1KrBpk7rn5ASOMc9wAsdM5/7770f9+vWRm5uLKlWqoGfPni6PnTIFaNoUmDwZmDz51hBKq6ysLIwZMwaxsbEIDAxEXFwcxo4di5s3b9qc5/Dhw3jggQcQGhqK6OhojBw5ErNmzXI4n73Y2FgoimKzLViwAJs2bYKiKNiyZYvN8QWHeRY8R9++ffHpp5+ibt26KF26NJo2bYrvvvvO4XqbN29Ghw4dEBERgdKlS6NRo0aYO3cuADjEoSgKJuQ9mnA2hPL06dPo168fypcvj6CgIDRs2BCLFi1yGu/OnTvRu3dvhIeHo3LlyvjPf/6DzMxMlz8Xd0zc4RerPU9IEEMpmXvR0cDOndqce8gQ4LnntDm3L/noIyAxUZtzHzkCBASoP/Td11y4IBKr8+fVPS8ncIx5hhM4ZiqnTp1CQEBAfuJhsVgQHByMCy7G5hR86OUsOXrssccQEBCAlJQUrF+/HuPHj0epUqXQu3fv/GNu3LiBGjVqoGrVqli4cCFWr16Nhx9+GNWqVYOfn5/bBO7777/HwIEDoSgKdu3ahV27duHvv/8uVgIXFxeH2NhY3H333Vi+fDlWrlyJxo0bo2zZsrh48WL+cV999RX8/f2RmJiIpUuXIi0tDVOnTkVKSgoAYOfOnVAUBYMGDcqP5dSpUwBEAle9evX8c125cgW1atVCdHQ05syZg9TUVPTp0weKomD27NkO8daqVQspKSlIS0vDpEmT4O/vn3/d4jJxh1+k9jwpSRQJuO02CypVciwawG7JyNDmj1YrHr5XNM8/r13RnexsIDAQSE/X5vy+YutWoEoV9c/LCRxjnuEEjpnK66+/DkVR8Mcff+DoUWDYsF0gUjB69MxCv9Y+Ofr5559tnkJZvfLKK1AUBT/99BMA5D9p27Nnj81xjRo1KjSBA4AxY8ZAURSbfcV9AhcVFWWTrO3duxeKomDx4sUAROGG2NhYNGvWzG0srubA2T+Bsw5PtY+vQ2d6tDsAACAASURBVIcOiI6Ozh8Oao13/PjxNsc99NBDqF27tttYXDFxh1+k9rywP5jYLfv3A2XLaldJNi0NKPC+B3Oha1cxGkIr9eoBq1Zpd35fMH068MAD6p/X+oaS/cZVKBlzjxM4porMTPFutbPNVaGE7GzXX+Ph6LlC1apVH5Urx+Puu4FSpYD77wcqVKiBZs1aFPq19snR+++/D0VRcPjwYZvjjh07BkVRMH36dADAwIEDnVZonDBhQqFDKAF1ErgH7d7mz8zMhKIoeP311wEAv/32GxRFwaxCFgcragLXs2dPVK1a1eE4a3y//PKLzef2ye3o0aMRHBzsNhZXTNzhcwKnss8+E0OotXLmjPjZX7mi3TV8Qe3aQGqqdufv1g14913tzu8LBg8WT0K9zcTtOWNucQLHVJGS4vgHoXXL+1vdwS+/uP4aD0fPufX113tApKB69bGYOvUCDh++gAsXLmD48OFQFAXphYyhsU+OJk2aBEVRcO3aNZvjrl+/DkVRMHHiRABAp06dcPfddzucb+bMmV5J4OLi4tCvXz+H8xZ8evjdd99BURSsKuRt6KImcO3bt3f6Pa9ZswaKomDr1q028donwSkpKQ7fc1GZuMPnBE5lr74K9Oql3flzc4GoKGDvXu2uYXQ3bgD+/sCxY9pdY9QoYOhQ7c7vC2TNmTVxe86YW5zAMVUY4QncsGHDnBbisG6FVVcs6hO4o0ePOjyBi42NdThfSZ7A7dixA4qiYP369Tb733rrLY8SuN9//13qEzhO4FTBCZzKBg0CtC662rIlsHChttcwMuuSF1pW/Z09G+jYUbvzG11ODlC6NJA3K8CrTNyeM+YWJ3DMZ1y9CixZAnz+ueP/3bhxA+XKlUOLFi2wZcsWm23z5s1o3Lix0ySrIPsE7pdffoGiKJg8ebLNcdY5cNYkZfbs2VAUBbt3784/Jjc3Fw0bNvR4Dtzp06ehKAreeecdm/1t27Z1OGdRErjc3FxUr1690DlwQUFBGDVqlMN++yIm1uR227ZtNsd17NgRFStWdJgDxwmcKjiBU1nr1sD8+dpeY/BgYPRoba9hZF98AcTHa3uNTZuAQpp/U7LOT4uPt4DIgubNvV/wyMTtOWNucQLHDC07G1i/Xiy2GxYG1K0LzJnjeNwXX3wBRVGw0MVb3dbhjJvcLHLjbHhi7969UapUKUyYMAHr1q3DhAkTUKpUKfTp0yf/mKysLNx+++2IiYnBggULsGrVKnTv3h3VqlWDoig4ceKE2+/RWQIHAImJiahQoQIWLlyINWvWoE+fPoiLi3M6B66wBA4AVqxYAX9/f7Rt2za/CuX06dNtqkE2btwYdevWxfr167Fnzx6cPn0agOMTuKtXr6J27dq47bbb8OGHH2LNmjXo27cvFEXBnAI3iBM4VRWrCmVCggVRURZUq8ZVKF2pUgVwstqGqqZMEUU6mHNaD2MFgFOnAEUBrl/X9jpGo4c3e0zcnjPmFidwzLDefFP8gXXbbcCIEcC+fa6rxf3f//0fIiIicN1FD52RkYHQ0FAMHDjQ5fXmzZvn8HQrKysLY8eORWxsLEqVKoW4uDiMGzcO2XbjRg8fPozOnTsjJCQE0dHRGDFiRH5FzEuXLrn9PseOHQs/Pz+H/SdPnkSXLl1QtmxZVKxYEWPGjMGHH37o0RM4q40bN6Jt27YICwtDWFgY4uPjMb/AI4ht27ahSZMmCA4Otvn6AQMG2DyBA4AzZ87YrAPXqFEjfGK3IrL1Z2qfwI0fP97p91wUJu7wi92e89wf165eFX+snj2r7XXWrwduv13baxjZ448DdkVqVZebK4YIupqvbVacwDGmX5zAMcNasgRYswawWzPbMB588EHUrFlTdhg+x8QdfrHb8/ff16Y0uC/4+WfxVF+rJQSsrE9/7GohsTx33y3aeq3FxwNffqn9dYyEEzjG9IsTOKZrrgqgGM3bb7+NWbNmYePGjVixYkX+cMLCioaw4jNxh1/s9nz1ajHsmDn68kugUSPtr5ObC0REAN9/r/21jCY3FwgPB374Qftr9ewJ5K2qwvJwAseYfnECx3Tpxx+B4cOB6GigkBofhvD++++jXr16KF26NIKDgxEfH4+PPvpIdlg+ycQdfrHb899+A4KDtX/KZERvvgn06OGda7VoAdiNLmYATp8WTyevXtX+WmPGAE8+qf11jIQTOMb0ixM4phsZGcCsWUCzZqJs9OOPi+pgWpaPZr7HIB3+BCI6RURXiGgLEd3h5tiGRLSOiM4T0d9E9AURVXNyXLHb8+vXxR9kebVoWAFPPw288IJ3rvXEEyKBYLY2bgQK1EbS1Pz5ouoouyUpSVSeJLLgrrtuFT/iKpSMyccJHNOFAweA0FCgaVPggw+AixdlR8SMygAd/nNE9CeJpC2YiF4lopNEVNrJsQoRnSCid4moFBGFEdFSItrm5FiP2vNKlQC71R4YgPbtnVe0VVtSkgWxsRZERt76A5mrggozZgCdOnnnWtu2idcCs3XoEFCqlLzpDAZozxmTghM4pgs5Od6Z58B8nwE6/KNE9GyBz/2J6C8i6uvk2PJElEtEDQrse4iIrjk51qP2/J57gEWLNLoZBhYbK0YAaE0Pw9T06j//ERWGveHvv8XPvZCiwKazYYPcKqkGaM8Zk4ITOOY1ubn8ZI1pT+cdfgSJhKy53f61RPS2i6/ZSkTvEVEIEZUlomVE9LGT4zxqz/v0ASZN0uhmGFRmpph7VcgSjargBM61++4DZs70zrVyc4GyZYH9+71zPaP48EPxNFoWnbfnjEnDCRzT3JUrYm5bfDyXLGfa03mHX5VEAlfHbv8SIprt4mtqEVE6EWUTUQ4R7SWiaCfHedSejx0LDBqk0c0wKGtxF2/Mv+UEzrVq1YDNm713PW8tWWAkY8eKOZqy6Lw9Z0waTuCYZg4eBCwWUSI7Pl7MJ7l8WXZUzNfpvMN39QRuHRG95eT4iiQKlzxDYg5cKIkCKIfyPi7Io/Z87lygbVuNboZBffMNcMcd3rkWJ3DOXbninYXUC+Kn0Y769pX7M9F5e86YNJzAMU288QYQGAg89piYHM5lypm3GKDDP0K2c+ACiOgcEfVxcmwSEV202xdOIgls5mQ/kpOTYbFYYLFYkJqaWujPy5uV/oxiyhSgWzfvXIsTOOf27xdDGr3Zd0yYAPTr573rGUHLlsDHH3v3mqmpqfltWHJyst7bc8bc6kVE3xJRBomO26+Q4zcT0Q0iulxge8bJcZzAMU0cPcqlyZkcBkjgRhHRcRJVKEOI6DUSlSbtn6gREdUkoiwieopEohdMRCkk+oIIu2M9as+PHgX8/YGbN7W5H0Y0bBgwcqR3rpWUJKpORkdbULkyV6G0/jxq1rSgdGnv/jwWLwYSEjS/jKHExADffivv+gZozxlz6z4iepSIBlLRErhNRDSxCOflBI4x5lMM0uFPIKIzRHSVxBtu1nXgqpF4w+3eAsd2JaLdRHSBiP7NO76Vk3N61J7fvCkSuCNHNLohBtSpkyhh702vvQb06uXda+qRzCeSe/cCUVGaX8YwbtzwXjEfVwzSnjNWqEQqegI3qQjn4wSOFVturnhH7uGHgY8+kh0NY7ZM3OF73J5Xrw6kpWlwMwyqZk1g3TrvXnPxYqBFC+9eU49kJnAZGeJa589rfilDkL0GHGDq9pz5mEQqegJ3nsS7tb+RGKLjbJFYTuBYkWVnA8uXiyEm4eHAqFHA8eOyo2LMlok7fI/b83btRLlwBmRlAQEB3n8iuW0bULmyd6+pR7LnBN52G7Bjh1cupXuy14ADTN2eMx+TSEVL4FqQWC+IiKghEe0nUabaHidwrEgWLABq1RLj4d9+W7xTyZgembjD97g9f+IJYMwYDW6GAVmfOnh7TuDJk2K42o0b3r2u3shO4Fq2BBYu9MqldG/uXLlrwAGmbs+Zj0mkoiVw9loT0U0iCrLb71HVMmY+b78tOrWsLNmRMOaIq5YRUQkSuEmTRAl1BqSmArVre/+6OTkicTx82PvX1hPZCdygQWLtMwaMGyd3DTiAEzjmOxKpZAlcsN1+fgLHGPMpJu7wPW7PFy0C7rlHg5thQNOnA507y7l29epiWQczS0qyoFEjCxTFgubNvV+V87XXgEcf9cqldK9fP/nr4pm4PWc+wo9E8nUfiQQuNO9zxcmx0UTUicScN4VEdbO9RLTMybGcwLF8f/4JXLwoOwrGSsbEHb7H7fm2bUClShrcDAMaMQL4z3/kXDsxEZg3T8619WTtWjlPQQExz7txYznX1ptWrby/Bpw9E7fnzEcMIJG45RJRToGPW5Nj2elqRLSLxOKvl4noIBH9j7iICXPh0CExTCIoCPj8c9nRMFYyJu7wPW7PT58Ww9SuXdPghhjMQw8B06bJuXb//sD48XKurSdz5gAdOnj/uklJFjRsaIGfn5ynf3pTtarcNeAAU7fnjLnFCZyJHT4MDBwoErfHHwd++012RIyVnIk7fI/b89xcIDiY2wAAqFsXWL1azrVfflm0yWY3bpyYi+Ztsuff6cmNG4Cfn9w14ABTt+eMucUJnEk9/7xI3Pr1A9LTZUfDmHpM3OGXqD2XmbjoRXY2EBgor02cO1cs6WB2sp5EcgJ3y+HD8teAA0zdnjPmFidwJvXNN8Dvv8uOgjH1mbjDL1F7/sADwPvvq3wzDOb4cfHUQVYpfz2su6UHbdvKmQvICdwtaWn6+F00cXvOmFucwDHGfIqJO/wStedDhwKjRql8MwwmLU1UgpTl4EHxBDAnR14MelCjhrgX3sYJ3C16WAMOMHV7zphbnMD5sIwM4Px52VEw5l0m7vBL1J6/+SbQo4fKN8NgZs0COnaUd/3r10XCcPq0vBhks66Hd/Cg96/NCdwtelgDDjB1e86YW5zA+aDr18XC2+XKAW+8ITsaxrzLxB1+idrzZcuAu+5S+WYYzHPPAUOGyI2hYkVgxw65MchkrYh6/br3r52UJKpOVq9uQUSEuatQ9usHTJwoOwpTt+eMucUJnA/JyREL8larBjRqJAoS5ObKjoox7zJxh1+i9nzfPiAyUuWbYRDWP9wjIy2IjZX7h3vz5sCSJV6/rG7s3AncdpvcGNasEUV9zKxVK2DhQtlRmLo9Z8wtTuB8xPbtQNOmQEyMaHTNPoeCmZeJO/wStef//iuefFy8qPINMQA9DZ175BHg9de9flnd+Owz4O675cZw4ABQurS53wCtWhXYulV2FKZuzxlzixM4H/HZZ8DkybwQL2Mm7vBL3J5HRADff6/izTAIPSVwzz0nCsqY1ZtvAklJcmO4dEnc/3/+kRuHLNY14P78U3Ykpm7PGXOLEzjGmE8xcYdf4vY8Ph744gsVb4ZB6CmBmz4dePBBr19WN559Fvjvf2VHId7M+OEH2VHIcfgwEBAgfw04wNTtOWNucQLHGPMpJu7wS9yed+8uCiCZjZ4SuG++Ae680+uX1Y1u3YApU2RHATRoIO6FGaWliaUc9MDE7TljbnECZyA7dwJjxsiOgjF9M3GHX+L2/L//BYYNU/FmGISeErgffwTKlDHv/KvGjfXxFLhzZ/MubD93LtCunewoBBO350wDHYhoBhHtIaLDef/OIKKOMoPyECdwBnD2LDBwIBAaCkyYwAVKGHPHxB1+idvz994z5/C9pCQL4uJsS8fLqkJ58aJIHi9c8PqldaFcOWDvXtlRAM88A4weLTsKOcaNAwYNkh2FYOL2nKmoDRH9SESniGgBEY0ioqfy/l1ARCfz/j9RUnye4AROx7KzxTuAERFigd1jx2RHxJj+mbjDL3F7vnIlUL++ijfDQEaPBgYPlh2FYNb5V1euiOT1779lRyKKgvXuLTsKOfSyBhxg6vacqeh7IupKRP4u/t8/7//3ey2ikuMETqcyMsR6QDVqAGvXyo6GMeMwcYdf4vb8wAHxpN+Mw/f69gUmTZIdhdCwIbBihewovO/XX4GQEH38/i1cKNZCMyO9rAEHmLo9ZyryU/k4PeAETqdyc4EFC3hZAMaKy8Qdfonb86tXxROQs2dVvCEG0aYNMH++7CiELl2AadNkR+F9qalAnTqyoxA2bwbi4mRHIYde1oADTN2eM+YWJ3CMMZ9i4g5flfb8ttuAHTtUuhkGUqOGqL6nB8OGASNHyo7C+2bPBjp2lB2FoKdS+t6kpzXgAFO358zLHpMdQDFxAscY8ykm7vBVac8TEoDFi1W6GQaRkwMEBgJ//CE7EkEPi1nLMHYs8MQTsqMQMjPF0+hTp2RH4l16S1xN3J4zL7ssO4Bi4gROsi++EIUDGGPqMHGHr0p73quXKOBgJmfPij/Wr16VHYmwdCnQrJnsKLzv8cdFpWW9qFjRfE+j9bQGHGDq9pwxtziBk+Tvv4HHHgMiI4Fly2RHw5jvMHGHr0p7/uKLwJNPqnQzDGLPHlG+Xi927gSio2VH4X16mocIiCT6s89kR+FdeloDDjB1e86YW5zASfDFF6Jz7toVOH1adjSM+RYTd/iqtOezZwPt26t0Mwziiy+A+HjZUdxy5ox4Imi2IlbVqwMbN8qO4pYePYC335YdhXfpaQ04wNTtOVPZJCKaaLeNI6LeRFRWYlye4gTOiy5eBPr0EU/dFi3SR6lkxnyNiTv8ErfnSUkW1KtnQVCQ/AWtvWnqVFH5US9ycoCgIP3MyfOG7GygVCng0CHZkdwyYgQwfLjsKLxLT2vAAaZuz5nKNhPRJrvtOyI6nbfVlxaZZziB86KTJ4FHH+WnboxpycQdfonb84QEC4jgsCUk+HYCN2oUMHSo7Chs1aoFrFsnOwrvOXVK/K5lZsqO5Ja33wYeflh2FN6lpzXgAFO358xL/IjoNSJaodH5exHRt0SUQUS5VPhac5FE9AkRXSSiC0S0iIginBzHCRxjzKeYuMPnBM5Djz4KvPaa7ChsdegAzJkjOwrv2bFDFA3Rk88/N18xGT2tAQeYuj1nXlSGiM5odO77iOhRIhpIRUvgVhHROiKKIqJyRLSeiL5yclw4EeHChQuyX6OMMaYKE3f4nMB56J57xLB2PRk0SJTVN4ulS4HmzWVHYWvnTrEuolnobQ04wNTtOfOiABJPu7SUSIUncLF5xzQosK9h3r4Yu2PDiQi94+OxY8sW2a9Tn3LzpuwIGDMnE3f4nMB5qGpVQG9d4IQJYj6SWbzxBtCzp+wobJ0+rb9hnVrS2xpwgKnbc+ZF7Ylov8bXSKTCE7huRHTdyf5MInrIbl84EeE8EZKjo5Geni77tWp416+LEtzPPCM7EsbMycQdPidwHsjOBvz9gSNHZEdia/58oHVr2VF4z7BhwMiRsqOwlZOjv8IqWtLbGnCAqdtzprIniGiQ3fY0Eb1N4unb4xpfP5EKT+D6EdFZJ/vPkqiWWZDo8IkwJzISBw4ckP1aNbRDh0Qp6oQEfQ1BYMxMTNzhq1KFMiHBgooVxWaGKpQnTwKKIoaP6cmmTUBsrOwovKdrV1ENVG/i4sS9MAO9rQEHmLo9Zyo7RkRH7bZ0Ikoloke8cP1E0uAJXDIROgQF4fHHH0dqaqrs16shffklEBEhSg7r7Q8BxnxdamoqLBYLLBYLkpOTzdrhq1aU6q23xBpYZqDH4hmAeCLo76+v4Wxaio8X/ajetG6tr6qMWrC+cVOligUVKujrjRtO4JivSCTP5sA1Ijdz4M4TYSgPofRIdrYoQR0eDnz2mexoGGMm7vBVS+CWLNFfQQmtfPaZPisNZmXpr6CElqKigH37ZEfhqE8f4JVXZEehLT0PnTZxe858hB8RBZOoRplLRKF5nysujl9JRGtJVKAsT0QbyE0Vyj7+/ti5dq3s16kh5eYCzz1nrgVXGdMzE3f4qiVw27YBVaqocDMMQM9rfcXEAN9+KzsK7V2+LBKG8+dlR+LoxReBp5+WHYW2OIFjjGi0RucdQCJxyyWinAIftyaiakR0mYjuLXB8wXXgLhLRx+T8l18sI9C8OZCSIvt1yhhjJWbiDl+1BO74cfH0xwzVdEeMAP7zH9lROKfH5Q20cOAAEBoq3hDVmxkzgAcekB2FtjiBY4zoF9kBFJPo8NeuBcLCgL/+kv1aZYyxEjFxh69aApeVJQp7mGH4Xo8ewJtvyo7CucceAyZPlh2F9tasAerWlR2Fc998A9x5p+wotMUJHGPGc6vD79IFePZZ2a9VxhgrERN3+KolcABQqRKwfbsqp9K1u+8Wc/70aPRoYPBg2VFob9Ys4L77ZEfh3I8/igJlvowTOGZmCokKj6tkB1JMtzr8n38GgoPFSo7MwdWrYp2aM2dkR8IYc8fEHb6qCVyzZuYozFSpkpjzp0cffADcf7/sKLQ3ZoxYP1WP/v1XJDMqvax0KSnJggYNLPD3v1WBkqtQMl9XnsS8t6Mk5qZ9KTecYrPt8Pv3B/r2lfpi1aPTp4EmTYBWrYBz52RHwxhzx8QdvqoJXPfuwDvvqHIq3bpxQ99DRVev1u/QQjX16wdMmiQ7Cudyc8UMk19+kR2Jtr7+GmjYUHYUjkzcnjON3EuiSEgmiQW8bxBRc6kReca2wz92DDlBQVjwwgtYMHUqcnJy5L5ydeD338Viqv378/pujBmBiTt8VRO4Z58F/vtfVU6lW0eP6rtYi56Le6ipdWtgwQLZUbhWr56Yp+fLZswAOneWHYUjE7fnTGVPE9EPRJRNRGuIqBeJcv5niChaYlyesunwd2zZggHR0Uj180NqSAgGNGmCHVu2SH75yrNjB1CuHPDSS77fgTLmK0zc4auawL3xBvDII6qcSre2bhWl+vUoKcmCZs0sILKgSRN9DWtTW1wcsGmT7Chcu+8+MU/Pl730kj7nW5q4PWcqyyWivURUy26/4RO49PR0JEdHI6vADNYsIiSbdIHvEyfEsIn33pMdCWOsOEzc4auawC1eDLRoocqpdOuTT/T7Peq5sISasrOBgAB9T79/8klg7FjZUWjr8ceBiRNlR+HIxO05U9kEIjpNRBlENJfEOmxEPpDAHThwAHMiIx16izmRkThw4IDs17AUv/4qOwLGWHFp3OGHEVEzImpnt+mBqgnc1q1A1aqqnEq3/vc//T5lNEsCd/KkmIeYmSk7EtcmTBAJji9r1w746CPZUTjiBI6pKYCIehLRJhJP5A4T0TUiqiczKA9xAscY8ykadvj/R+LNu1wnmx6omsAdOQL4+4snJL5q2DBg5EjZUThnlgRu+3ZRCVTP5s0D2raVHYW2atcG1q2THYUjTuCYVuoR0TQiukiioMksueEUm80QyqFOhlAOjYoy5RBKxpgxadjhHyIiCxGVVvm8alE1gcvMFF3BqVOqnE6XunUDpkyRHYVzZkngPv0USEiQHYV7GzYANWvKjkI7ubmiWI4eRx1xAse0VpqIBhPRftmBFJNjEZMmTZAaEoI1ISEYWKECdjZqBHA1SsaYQWjY4V9S8VwTiOgUEV0hoi1EdEchxw8gop/zjv+LiKY6OUbVBA4AoqOBXbtUO53u3HUXsHy57CicM0sC9/rr+h3GavXHH0BQkO8WM7OudXfpkuxIHHECx5hzDh1+Tk4OFk6bhoXTpiEnI0PU0J8xQ96rV2M5OcCoUcDevbIjYYypQcMOfxURxatwnueI6E8SSVswEb1KRCfJ9ZO9kUR0hMTyNX5EFEJEjZ0cp3oC16SJfhMcNVSoAOzeLTsK55KSRNXJ22+3oEwZ361CmZws+mA9u3ZNJDh//SU7Em389BMQHi47Cuc4gWNqGEVEpQo5JjDvOKMovMNfuxYoUwY4ftx7r1gvyckBnnoKqFEDOHZMdjSMMTVo2OGPI6JjRDSWiAbZbcVxlIieLfC5P4mnan2dHBtORJeJ6MEinFf1BK5bN2DqVNVOpyvXr4s/ys+ckR2Jexs3ij7K11gT1LJlLYiN1X+CWr48sGeP7Ci0sXo1UL++7Cic4wSOqWE2iSEv/yOitkRUgUTCViHv8//l/f9sWQF6oGgd/sCByLn/fiyYOtVnFvjOzgYGDhTj2k+ckB0NY0wtGnb4x/K2o062ooogUfSkud3+tUT0tpPjO+Ud/18iSieR6KUSUUMnx6qewBnh6YinDh4ESpXS/wyB9HQgMND3hu8ZbYjoXXcBX3whOwptzJ4t1rrTI07gmFriiWgBEV0g2wpkF4loIakzvMabitTh71i5EgMCApBaqpRPLPCdnS1KAteu7dsT9BkzI513+FVJ9Bl17PYvIedv/vXNO34LEVUiMeTyfySWs7H//lRP4F57DejVS7XT6crGjWIBab27elUkNufOyY5EXUZL4Hz5afTLLwODBsmOwjmdt+fMgPyJqC4R3ZP3r7/ccDxWaIfviwt8P/kkUK8ecPq07EgYY2rzUodf3sOvc/UEbh0RveXk+K55x99fYJ8fEV2120eU154nJyfDYrHAYrEgNTW1RD/Ljz8GWrZU6cbozIIFQKtWsqMomshIYP9+2VGoy2gJnJ6XnCipQYNEEqcXqamp+W1YcnIyJ3CMOVFoAueL68OtWcPJG2O+SsMELpCI3iWRPOXm/Tslb39xHCHbOXABRHSOiPo4Odb6xK5gsuZPbhI4NZ/AbdpkjKdUnnjlFaB3b9lRFE2DBsDXX8uOQl1GS+DeeEP/1TI9dd99YhilHvETOMacM2UCxxjzXRp2+K8R0S8kFvRukPfvzySGNBbHKCI6TqIKZUjeeU8QUaiL478gMYQymoiCSFStPEFEYXbHqZ7AGWWemCeefhp44QXZURTNAw8AH3wgOwp1GS2B+/RToEUL2VFoo359UchEjziBY8y5Ig2hdLrAd9myhh1CyRjzXRp2+EeIqKbdvttJFDYprglEdIbEk7TNdGsduGokqk7eW+DYMkQ0l4j+JaLzRLSaiOo7OafqCZy1UuPZs6qdUjc6dwamT5cdRdE89RQwZozsKNSVlOS4RIKeq1Bu2wZU75JG8wAAIABJREFUqSI7Cm2Eh4ulBPSIEzjGnCtaERP7Bb6rVcPOiAjgzz+99BJmjLGi0bDD/5fEcMeCAkkUtdID1RM4QJRP98V1Mhs0AFaskB1F0YwfD/TvLzsK9U2ebJxhrH/+Cfj5AVlZsiNR16VL4k2af/+VHYlznMAx5lyRO3ybBb6tC6g1bSreotUxlf+WYYzpnIYd/rdE9B+7fcPy9uuBJglcfDzw5ZeqnlIXjFQY5MMPgfbtZUehvqFDgeeflx1F0dy8KRI4X1sz9rffgNBQ/S5TwQkc00INIhpDRO/nfV6LiOrJC8cjnnf4mZlA8+bAgAHIyc7W5Rpxe/YA5cr5XoPLGHNNww6/BYkhj/uI6PO8f6+QqEasB5okcA89BLz3nqqnlO7KFfHU4e+/ZUdSNKmpQN26sqNQX9euxijNb110PDDQgjvu0P9wz+JYvx6oVUt2FK5xAsfU1o5Ex72OxHwFIqLWRLRKWkSeKVmHf/IkdkRGYkDVqkgNCdHVGnHHjwPR0cBbb8mOhDHmTRp3+NWI6EUimkFEo/M+1wtNErhnnjFOsY+i+u03IDhYv08d7P3yC1C6tHHiLaq77gKWL5cdReGMVnClOObNA9q2lR2Fa5zAMbXtJVGBjOjW/IcQIjqr4TUnENEpEonjFro16d2ZzUR0g0Ryad2ecXJciTr89PR0JEdG6m6NuCtXxLCfwYN9r8NjjLln4g5fkwTulVeAPn1UPaV069bp+6mDvQsXRBd78aLsSNQVHQ3s2iU7isL5cgI3aRLQr5/sKFwzcXvONHKxwMfWBE6x26+m54joTxJJWzCJMtIniai0i+M3EdHEIpy3RB2+HpcYyM0FevYEWrcGbtyQEgJjTCKVO/x+BT5+gogGudj0QJMEbv58oE0bVU8p3dy5QLt2sqMoutxc8QTul19kR6KeGzfEnwynTsmOpHC+nMA9/TTw4ouyo3CNEzimtl9JzHkjupXA1SWxJpAWjpLtwq/+RPQXEfV1cfwmIppUhPP6XAL36qtAbCxw7pyUyzPGJFO5w/+lwMfHSLTFzjY90CSBS0sDbr9d1VNKZ8SqjnXqiLlwvuLoUcDfH8jOlh1J4Xw5gXvwQeD992VH4RoncExtI4loPxF1JKIMImpJRDvIsUKZGiKIKJeImtvtX0tEb7v4mk0k1gv6l4h+I7FQrLOndSUeQul0jbjy5aUNofzpJ/2uZ8IY056JO3xNErg//gCCgnxrOPoTTwBjx8qOonjatxdPDn3Ft98CMTGyoygaX07gGjXS93IaJm7PmUb8iGg8iSGTuUR0jYjeyduvtqp516hjt38JEc128TUtiKhs3scNSSSbS5wcV+IO32GNuHLlsLNaNeDsWeTk5OiyOiVjzHdp2OGPdrH/eZWv4ylNEjhrxUZfGtVw333AzJmyoyie/v2BCRNkR6GeTz8FEhJkR1E01iqUd9xhQUCAb1WhLFcO2LdPdhSucQLHtHQbEQVpeH5XT+DWEdFbRTxHayK6SY5xhhMRkpOTYbFYYLFYkOrBGA2bNeKysoC+fbEjLg4DGjbUXXVKxpjvSU1NzW/DkpOTterwL7vY79MLeQPGWjPNFesf4QkJFgQHW1CnjrH+CH/pJbH8qq946y0gKUl2FMVz8iSgKL4zv/7aNfHmzF9/yY7ENU7gmNoak2P56GpE1Eij6x0h2zlwAUR0joj6FPHrrQlcsN1+TTr89F9/RXJQkO6qUzLGfJ8GHb4fiXnHl/M+LrjVJzEfWQ80S+AaNAC+/lr103qV0YfBzZgBPPCA7CjUM2IEMHy47CiKJztbzNvzlbVlDx4EAgMBPQ+Q4gSOqe17cly0uz6JhV21MIqIjpOoQhlCYk7bCSIKdXJsNBF1IjHnTcn7mr1EtMzJsZp0+HosbsIYMwcNOvzcQrapKl2npDRL4B54QCQQRmb0BO7rr4GGDWVHoZ6kJODNN2VHUXwxMcC2bbKjUMemTUD16rKjcI8TOKa2DCf7FBf71TKBiM4Q0VUS67xZ14GrRuKd4XsLfL6LxPy8y0R0kIj+RxoUMXHFWwncpk3Gm4jOGNOWBh1+Yt52nYjaFPi8NRHVVukaatAsgXvqKTGEz8iMnsDt3w9ERcmOQj0JCWIenNEkJABLl8qOQh0ffwy0aiU7Cvc4gWNqO0FEUXb7yhHRaQmxlIQ2QyhdVacsWxbp6emqFDc5fx6oUkXf5W8ZY96nYYdvP2xebzRL4CZOBB5/XPXTepXRE7hz50S8V6/KjkQdVauKSpRG06MH8PbbsqNQx2uvAY89JjsK9ziBY2r7hIjmElGpvM9LEdEcIvpUWkSe0azDd6hOWa0adgYFYcfo0fn7PS1ukpsLdOsmNl8qbc0YKzmNO/xSJEY/tCWidgU2PdCsPf/oI2MtfO2M0RO43FwxX8kXppFb55IdOSI7kuIbPhywGONXplDJycBzz8mOwj1O4JjaYogoncRaa3vz/j1IouS/kWjW4QN21SlzcpA+fz6SFaXExU1mzBBP386f1yRsxpiBadjhNyKxmLf9HLgcla/jKc3a83XrgFq1VD+tV1mrUFapYkH58sYsBV+9upg6YHSnTok/ATIzZUdSfG++CTzyiOwo1NGtGzB1quwo3OMEjmkhhIiSiOg5IupJjhUejUDTBM7egQMHMCc8vERz437+GQgN9Y1OjDGmPg07/DQimkVEkSSWDogkoo9I9AN6oFl7/uuvQEiIb4x4MOIi3latWol5S0a3ezcQHS07Cs98+ilwzz2yo1BHkybA8uWyo3CPEzjGnPN+AlfC4iYDBhi382WMaU/DDv9fulUMylqwKoqIflf5Op7SrD2/dEk01//8o/qpve7++423iLfVY4+JeUtG98UXQOPGsqPwzNatQLVqsqNQx223Abt2yY7CPU7gmNr8iWgAEc0gooV528d5/xqJVxM4l8VNQkORfuBAkYqbZGUBN296JVzGmAFp2OGfJ7EGJxHRSSKKILEW3BWVr+MpTdvz8HDgxx81ObVX3XEHsHKl7Cg889xzYt6S0U2bBnTpIjsKzxw5AgQEiHl8Rnbjhvgz7NQp2ZG4xwkcU9tMIvqHiD4jovlENK/Av0bi1QQOcFLcpH597IyLw47atTGgfv0SFTdhjDENO/ztRJSQ9/E3RPQOieVdflX5Op7StD2/4w5g1SpNTu1VZcsCP/wgOwrPTJki5i0Z3fPPA0OGyI7CM5mZIvE5fVp2JCVz9KgoJKP3RJQTOKa2f4ioluwgVOD1BA5wUtzk55+RHBpa4uImjDGmYYefSET35H3ckIj+ILE25wMqX8dTmrbn998PzJqlyam95vJl0cUYtQDWsmVA06ayoyi5Pn2AyZNlR+G56Ghgzx7ZUZTMt9+KRcn1jhM4prbTdGsojZFJSeDsFTY3To114xhj5mDiDl/T9vyJJ4Bx4zQ5tdf8/jsQHGzcYiw7dwIVK8qOouTatAHmz5cdhefuugv48kvZUZTMp5+KRcn1zsTtOdPIy0T0X9lBqEDfCVxgID6dMqXE68YxxsxDww5/Hon13+zNUPk6ntK0PU9JEUWkjGzDBqBmTdlReO7kSUBRxPwlI7v9dnEvjKpLF+C992RHUTJvvgkkJcmOonCcwDG1fUtEWUR0KO9j67ZVZlAe0EUC56q4Sa+AINSm+fidqvPQSsZYkWjY4eeQqD5pv2zAZZWv4ylN2/M5c4AOHTQ5tdfMnw8kJsqOwnPWBbCPHZMdiedyc4GgIPE01KiGDAFeeEF2FCUzfDgwYoTsKArHCRxT23gXW4qccDymiwQOcFLcpEkT9O+7CxWUw7hGwS6XHeDhlYyxgjTs8C8TUTsSa8ANtduvB5q252vWAHXranJqr3nlFaBvX9lRlEyVKsC2bbKj8Nz586Irv3xZdiSemzxZzOMzsqQk4K23ZEdROE7gGHNONwkcYFvc5PjxHJQunQ1L2P85Dq0MCcGBPXtskj4eXskYAzRP4IiI7iJRvGSC3X7ZNG3Pf/4ZKF3auPPHAOCZZ4DRo2VHUTLNmwNLl8qOwnM//ABERMiOomQWLDD2k1xAzH9bskR2FIXjBI5pIYKI+hDR83mfV8zbjERXCVxB3bsDXbtmOF83LiAA68LC3Fau5CdzjJmTFxI4IqLbSQyhn0UmWAcuKcmCpk0tIBL/JiSILSnJovq1tPTQQ8D06bKjKJkePYC335YdhedWrhRLUhhZWpqx51ICogLld9/JjqJwnMAxtcUT0V9ElE63Ou8HiGiZtIg8o8sE7quvgKgo4Nw550Mrd27digNz52JOQIDTypWfLljAT+YYMykvJXBE4g2774koV+XreEqz9jwhwWLf1IJI7DeS+HjjVw8cPhywGOvHbmPmTLEkhZEZvZrpzZvGmUvJCRxT2xYiSs77+ELev2WI6JSccDymuwQuOxuoUQP46KNb++zXjQNcV658JSgIT0dG8pM5xkxKww6/nJN9ZUisD6cHnMAVonx546/f9eabQM+esqPw3LhxYkkKIzP6eoJGqmbKCRxT279E5Jf38YUC+y9JiKUkdJfAAcDBg4W/s+W6cmUAZjr5S4OfzDFmDibu8DmBc+P6dRHzmTOyIymZxYuBe+6RHYXnBg4EXn5ZdhQlV7asmM9nREZaT9DE7TnTyCEiqpz3sTWBq0ZEf8gJx2O6TOCKytnwyk8XLsSc8HDHJ3MhIfxkjjETULnD/73AxydcbH+qcB01cALnxuHDQEAAYPTmfetWoFo12VF4rmNHYPZs2VGU3J13AqtWyY7CM8uWAU2byo6iaDiBY2p7lYjWEVFtEglcDBF9TbyMgNfZD690+WTOz8+jJ3Oc2DFmLCp3+H0KfDzAxdZfheuogRM4N7ZsAWJjZUdRckeOiEQ0O1t2JJ6pXx9YvVp2FCXXqRP+v737jq+iSv8H/oFQAqGDhY5iQbEhLZZVBHRdG5Ys2LCgrl+JglfsawHsrgVXXQsqWMD6U3EtAVGx765rRVlWkSoWUOnSknx+f5ybJST33twyM2fmns/79ZoXyTB3zhNInifPnZlz+MADtqPIzoQJ5LHH2o4iPWrgxGuFACbDPLxetT0f3x8lkW/gEsnoylzDhjy3qCjhlblnpkxJeculmjuR8PGp4DcEMAzhzvG+zkJZXBzjDjvE2LJlNGehnDKFPOAA21HkbsMGU6q+/952JNlp0YL8/HPbUeTurLPM83xRdPHF5Pnn244iPWrgxC9tAfQH0NV2IFnKywaOzODKXGEh769fv3ZjV1TEc9u0SXrLZao16NTYidjjU8Gvh/AsF5CM7/n81VfJ3Xbz7fS+uuUWctgw21F4Y9ttozkZy6pVppz+8ovtSHJ37bXmeb4oqXojpm3bGDt3jsYbMWrgxGudUHtGsrbY8lxcVISigfv+e/OAud+SXplLMJvlOCDxLZetWvHVV19laYJmsK6rdskaOzV8It7xseB/AKCHx+f0ku/5/IsvyObNfTu9ry64gBwzxnYU3ujVK5rLIcyZQzZpEt3p96ubONE8zxclUbwVWg2ceO1DAL1r7OsD4H0LseQiFA3cEUcENytV2lfm2rTh/c2a1W7gAE7r0IETGzasfdWuRYukV+2SNXbZXslT0yeSmI8F/0IAcwCcA2AwgIHVtjDwPZ+vWGFS28qVvg3hm+OOI++803YU3jj6aPLuu21HkbnXXyd33tl2FN547TXzPF+UqIETAVbC3FJTXQG2XlLAa+Ng1plbC7MOXc8Ux7YGMAUmzhUAngDQMsFx1hu4t98298QvX24thIRX5p6ZOjVhYzeybVu+On48JzZpkviqXUFB2rdjntKmTcYNX814c73Kl81VQV1JlDDzseBXptjCwPd8XllJFhWRX37p2xC+6duXfPZZ21F447zzyMsusx1F5iZNIgcMsB2FN774wvzuEiVq4ESAHwA0q7GvGYDlPo13CcxU1T1hHqK/EcB3AIqSHP8KzCyZbWBu7XwdwIsJjrPawFVWmvVsrrvOyvBbSbRYeKLG7h/vvpv8ql2LFrw/WWOXIGuOa9iQ9zdunNGVvBkzZmR8+2ayhi/T/TX/TXK9khhE86ix3RqbdLrgB5LPe/QwVx+ipn178sMPbUfhjRtuIE85xXYUmbvuOvLUU21H4Y1ffzUlOEpTCKiBEzFLBlxfY994mMbJDwsAXFDt8wIAPwE4NcGxXWHeEd6z2r694vs61TjWagP30kvmYew1a6wMn5ZEjR2Z2VW7E9u04f3Nmydu4Bo0SP/5u8aNOW3YsIRX/64vKuK5rVqlfZUv0/2pmsdsriQG0TzabFw1tp03C0inC34g+XzwYPP8T5Rs2kTWq0cuWWI7Em88+mg0r2Sdey55+eW2o/BGZSXZtKl5ri8q1MCJALsB+BnAFwCeA/A5gF+Q+rbGbLWEab7619g/HcDtCY4fAmB9gv0bABxVY5+1Bq683CyEGcX7+Kuke9UuWWN3cpLG58SWLXl/UVHiBm7QoITP3yW9ygfw/nr1EjePic7TuHHCq4ITmzXjtLFjOTHBc4HjiooSPi94ffPm1ppHm42rxrbzZsHXX39N0veCvzuA82FuaR9fbQuDQPL5mWcG98yyVxYtIuvXJzdvth2JN2bOJHfayXYUmTvqKPKee2xH4Z1ddjHP9UVFSUmMu+wSY9OmW2ag1CyU4qLtAFwM4N74n9v6NE5nmAZu1xr7nwLwYILjhwP4McH+HwGcXGOftQbus89MA7dxY+BD+y6T2zEzev4u/ott0qt8Cda5G9e0Ke9v2jRxo9aoUe39DRokvCo4saCA0zp25MREzSBSNI+Z7k9w/on163Naly6cmOD5wnH16yd87nBcQUHy/Ymueib7uhs25LQDD0zcNCe7gpqsOc5w/8RGjTjt97/nxET/T9mMkew8CfZPbNyY0446ihMTNPOZniuIsSe2bs2vvvqKpK8FvwTAJgCfAdhc7c+3PB4nW4Hk86uvJkeM8HUIz73/Ptmxo+0ovDN3LllYGL3ZHPfZJ5qzZyYzcKB5ri9KJkwghwyxHUX61MBJlCW7AjcDwG0Jjs/4ClxpaSljsRhjsRjLysoC+8EsLw9sqFBIdjtmJg1fsr/L9CpfpvtTNY9JryS2apX41tGiooRXGJM1mxObNeO0q69OfPWvsDDxc4eFhby/sLD2/iRXGJNeeWzShNPOOCPxpDXJztWoUfL9iRqZJPsnNm7MaSUl9pqoY4+1N/aQIRmNPbpZM5522mmMxWIsLS31q+B/DmBE/OOqCasuAHCdx+NkK5AG7sEHozd9+tNPk/362Y7CO2vWmG/9n3+2HUlm2rWL5vp1yQwfHo5n+DMxZgxZWmo7ivSpgROvnQ+gV/zjfQEsgXlOrebSAl6Zj62fgWsAYBmAUxIc2xW1n4HbGyF8Bk5SS9bwJfu7TK7yZbM/0zG8aiqzaR5tNq4aO/ixRwZzC+VqmOePAWBV/M9GMLMDh0Eg+TyKi3nfcQd5/PG2o/BWq1bk55/bjiJ969ebH9kffrAdiXeuuMI81xclQ4eSN99sO4r0qYETry3AllsmX4V5Fm08/LuV5mIAi2CesWsC4CaYprFpkuNfhnlGri2AdgBmIoSzUIr3MrnKl83+TF9jq3m02bhqbDtjV/Gx4P9YLefOh3lDrCmANR6Pk61A8vns2WSzZtG6fe+ii8hRo2xH4Y2SEvPcUpMmMe66azSeYyLJb78lGzQg82mFmXvvJY880nYUmdlvP3LKFNtRpE8NnHhtdfzPhjBrrTWFuSr2q49jjoNZvmAdgFnYMmFKF5hfIA6odmz1deBWAngcib/51cCJ72w1jxrbvbFJXwv+ywCOjX88EcA7AMpg1uUMg0DyeRQX8x46lLz1VttReCOKMwmSZs3XLl1sR+GtadPMc31R0rkz+c47tqNInxo48doPMGus/Q7AP+L7GiE878SmSw2ciOQVHwt+ewAd4x+3BvAAgCcBdPd4nGwFks8rK80VuNmzfR3GU/vvT06dajsKb0S1gZsyxfw/5JOPPzbP9UVFeTlZUEAuWGA7kvSpgROv/Q3AJwC+BjAmvq8PgNnWIspOoA3c2rXRe+haRKLF4YIfWD6P2mLeXbpE66pDKlFt4G65xVwJzSc//mj+7devtx1JepYsMeshbtpkO5L0OZzPxSeNAJwD4DQA9eP7DgEwzFpE2Qm0gZswgTzooECGEhFHeVzwB6a5hUFg+fzQQ81slFFQXm6evZo/33Yk3ohqAzdqlHkWMZ9UVJANG5Lz5tmOJD0ffEC2b287isyogRNJLLCCX15Odu+eP7exiEg4eVzwK9PcMjUOZvbKtTDP0PVMfTgA8/UsjI9XP8nfB5LPo7SY9/ffmwZnwwbbkXgjqg3c8ceTt99uOwrvdetGzpplO4r0PP002bev7SgyowZOvFYA4EoA32DLhCa/h7kqFyWBFfyXXiI7dIjWpXsRiZ4IFPxLACyGadoKAdwI4DsARXW87hGYSVMqYLmBu+Ya08RFwb/+RW67re0ovFM1C+Xee8dYr16M/ftHYxbKfv1MA5FvDjwwOrM63nZb9JbTiEA+l4gZD+AzmHXYqtYD2gnAp9Yiyk5gBX/QIPL6630fRkQcF4GCvwBbr+tZAOAnAKemeM3RAP4JYBBCcAUuSot5P/88ue++tqPw3rp15srbsmW2I0muqtksLo6xYcMYe/aMRrOZiRNPNM/3RcHo0WaLkgjkc4mYhTDT9wPAivifBdU+jorA1g0qLAx3oRGR/OBjwa8HYDSA/8As5zIHwIVI3Ewl0xKmAetfY/90mPVEE2kLU3N2BzAAIWjgXnvNTGQSBX/9K3nMMbaj8EfbtmYmxLCK6u2emRgzhrzgAttRpOeEE8xVuChRAyde+xlbCmhV09YIwDI74WQtkII/ejR51lm+DiEiQtLXgj8G5rm1C2GuiF0Ic+vjJRmcozNMA7Zrjf1PAXgwyWuegbllHwhJAzd7NllUFI3FvC+9lBw50nYU/thnH/KFF2xHkZwLDdydd5LHHWc7ivRE8TZWNXDitVkAhsY/rmrgSmDeRY2SQAr+hg1aPkBEguFjwf8vgH1r7OsF8yx0upJdgZsB4LYEx58I4N8wd3gAWxq4ggTHBtbArVwZncW8Tz6ZvPFG21H445hjzBXGsHKhgXv22ehMDNK+vZmJMkrUwInX+sMs2j0VwHoAD8M8C9fPZlBZ0ELeIpJXfCz4K1H7ylcBtjwHna752PoZuAYwd2+ckuDYSTAzVS6PbythGrjlAIbXOLYFAJaWljIWizEWi7GsrMyXf+MoLeZ98MHkY4/ZjsIfpaXkxRfbjiI5Fxq4Dz80E7SF3caNZg24xYttR1K3srKy/+Ww0tJSNXDiuV0B/BXAazCzg/WxG05W1MCJSF7xsYH7GOZOi+qOj+/PxMUAFsHMQtkEwE0AlgBomuDYVgA6VNtKYBq4zgmODzSf77ZbNBbz7t6dfOMN21H445ZbyGHDbEeRnAsNXFQWx16wgKxfn9y82XYkmdEVOPFSYwCvwEz/HHVq4EQkr/hY8I8EsBHA/wNwK4Dn458fncW5xgH4AWYylFnYsg5cF5i7Ow5I8roBCMEyAmQ0FvOurCQbNyb/+1/bkfhj6lRyv/1sR5Fc1SyU220XY/v2W2akzKdZKDdvNo1R2K9svfMO2amT7SgypwZOvLYMiZ9BiBo1cCKSV3wq+AcDiAE4CMADMG/i3Y9w3TYfaD4fMSL8i3kvX26u+KxdazsSf7z3XjR+KT/mGPKuu2xH4Z8OHcL/bNmUKeFu9pNRAyde+xuAM2wH4QE1cCKSV3wo+COw5bmzctR+9iwsAs3nUVjM+9NPydatbUfhn0WLonFbXNhny8xVv37kM8/YjiK1W24hhw61HUXm1MCJ154GsAnA+wCeAPB4fHvMZlBZ8K3gf/QROXy456cVEUnJh4I/G1smGBkO4COPzuu1QBu4iRPDv5j33/9O7rmn7Sj8U3X73qJFtiNJrU0b8pNPbEfhvapbRFu3jrFr13DfInr++WbNuqhRAydem5xkm2QnnKz5VvDHjCFPO83z04qIpORDwV8Fs4g3YGaMXO7Reb0WaAMXhcW877uP/MMfbEfhr06dyHfftR1FcmvWmNtY83EpoShN0jJkCDlhgu0oMqcGTiQxXwp+ZSXZuTP58suenlZEpE4+FPw1NT5fkfAo+wJt4L78MvyLef/5z+Q559iOwl/7728mMwmrOXPIpk3D/X2SrSg1cPvuSz73nO0oMqcGTvxQH+YB9pL4n/VSHx5KvhT8Dz4gW7Uy646IiATJh4K/EcD4+HYdzNqf1T8f79E4uQq0gatazHvFikCGy8rpp5PjxtmOwl/DhpE332w7iuSicKU2W1Fq4LbZhvznP21HkTk1cOK19jDPQVQA+Dn+579h1umJEl8K/oUXhv/hdhHJTz4U/FkA3qq2zUrwcRgEPilV8+bhXsx70CDy4YdtR+GvSy4xC3qH1QMPkIcdZjsKf0SlgVu/3sT1/fe2I8mcGjjx2lMwE5m0iX/eBsCT8X1R4nnBr6ggO3aMxgKvIpJ/HC74gTdwu+1GvvpqYMNlbNddyenTbUfhr7/+lTz6aNtRJPfnP5Nnn207Cn9EpYH75huyYUPz+1nUOJzPxSc/AmhZY19LAD9ZiCUXnhf8X381s09u2uTZKUVE0uZwwQ+8gTvssPAu5l1ZaZ7R++or25H468UXzTT9YTV8ODl+vO0o/FE1C2X//jECMe6zTzhnoXzrLbJbN9tRZMfhfC4++RFA8xr7mkMNnIiIVQ4X/MDz+YgR5NVXBzZcWqp+qe7Tx/xS3bdvOH+p9srHH5tp+sPq4IPJyZNtR+G/HXYg33zTdhSJPfYY+bvf2Y4iOw7nc/HJMwCmYMtVuFYw68E9ay2i7KiBE5G84nDBDzyfX3tt+J53jsptbV5Zvtx8fevW2Y4ksTA3Nl6aJZsRAAAgAElEQVQaMICcNMl2FIndcAN50km2o8iOw/lcfNIRwKcwk5csB1AO4DMAnXwarwTAXAC/AZgD4Lg6jh8bj21NtW1KguPUwIlIXnG44AeezydOJAcPDmy4tLjWwFVWkoWF5Ny5tiOprbzcPHs1b57tSPx3+unk2LG2o0js//6PvPRS21Fkx+F8Lj4qALAfgKHxP+v7NE5/mGmrj4uPeTxMI9c7xWvGAngnjXOrgRORvOJwwQ88n5eVhW+KeNcaOJLcZRdyxgzbUdS2dKn5t9+wwXYk/rvmmvBdja5y5JHk3XfbjiI7DudzyQOTAPy/GvueB/BQiteMBfBuGudWAyciecXhgh94Pg/jYt4uNnBhXS7hww/J7be3HUUwHn6YHDjQdhSJ7bWXmewmihzO5+KTxwE8Vu3P6pvXPgFwWY19VwL4OMVrrgWwFsAyAAthbp/sluA4zwr+zz+btUZERGxyuOAH3sCtWhW+xbxdbODOOMM8jxg2Tz9N9utnO4pgzJxJdu9uO4rE2rQxk91EkcP5XHwyGebK2KT4xzNgbnN8IsNzVKbY3owfNw/AuTVeex6Ab1KcuyeAzvGPO8TjmgegqMZxnhX8884jR43y4KdVRCQHDhd8K3dUNG9OfvFFoEOmVDULZbNmMe60k/k4n2ehJM3teyNG2I6itr/8hSwpsR1FML75hmzUKHxrra1bZ97AWLbMdiTZcTifS4D+COCeDI4vglkAPNlWtUzBJwAur/Hauq7A1dQIpsEcXGN/CwAsLS1lLBZjLBZjWVlZxj9gFRXkttuatUZERIJWVlb2vxxWWlrqasG30sDtvns4F/Pu2JF87z3bUQQjjJPJkOQFF5BjxtiOIhgbNphGaelS25Fsbe5csnHjcN3mnAk1cBKEAgC/+HDeR1D7GbgXAEzM4BxVDdyhNfZ7UvC//JJs2lSLd4uIfQ4XfCsN3GGHkQ88EOiQddq4kaxXj/zuO9uRBGP6dHLXXW1HUduQIeRdd9mOIjjt25MffGA7iq29/np4b+1Mh8P5XAJ0APxZyLtqFspjATQEcALqnoVyKIC28Y+3g3k2bz58uoXyvvvC+/CuiLjF4YJvpYE766zwLeY9b56Zvj5st7P5Zc4cskmT8F1l6dWLfOEF21EEp7iYfPJJ21Fs7ZFHzBp1UeVwPhefvFtj+wTAZgDjfBqvBMB/YBq5ROvAfYmtb7OcBjOByToA38FMYrJjgvN6UvBPOimcD1CLiHscLvhWGrhrrzWTaITJzJnkTjvZjiI4a9aY2/d+/tl2JFtr2za6k2dkY9gw8uabbUextXHjyOHDbUeRPYfzufhkbI1tDICDrEWTvZwLfmUl2amTKZgiIrY5XPCtNHAPPRS+56/CGJPfWrcmP/nEdhRbrF1rmsrly21HEpxLLzUTuoXJ2WeTV15pO4rsOZzPRVLKueBXVJCTJ5tkLSJim8MF30oDV1YWvuevrrrK3Nrpkr33JqdNsx3FFmG9rdNP995LHnGE7Si2dvjh5jGXqHI4n4uHdkxzixIt5C0iecXhgm8ln3/1VfgW8z71VPK662xHEayjjiLvvtt2FFuEsbH328svkz172o5iaz17mriiyuF8Lh5KtWZb1VZhLbrsqIETkbzicMG3ks+rFvP+9ddAh03pwAPJxx+3HUWwRo40t/CFxYMPkoceajuKYM2eTTZrFq43M1q0ID/7zHYU2XM4n4uHuqW5RYkaOBHJKw4XfGv5vEWLcC3m3bkz+e67tqMI1k03kSeeaDuKLVy8jXX1avNmxi+/2I7EqHpzJSzxZMPhfC6Skho4EckrDhf8wPN5SUmMxcUxFhbGuOuu5uPi4hhLSmKBxVDTxo1k/frkkiXWQrBiyhTygANsR7HFaaeZGRBdE6bJZKrW6A3TFcFMOZzPxWOzanx+io0gPKQGTkTyisMFP/B8XlwcI8BaW3GxvQbu22/JBg3I8nJrIVjxzjvmymNYDBhATppkO4rg7bNPeNa+e+216D+H6HA+F4+tqfH5CitReCengj9vHrluncc/rSIiOXC44KuBI/nGG+SOO1ob3pqFC8mCAnLzZtuRGDvuaP4vXDNkCDlhgu0ojAcfjP5yGg7nc/GYGrhq+vQhp071+KdVRCQHDhd8NXAkH36YHDjQ2vDWbNpE1qtHLl5sOxKzvFDDhuQ339iOJHijRpExe9/+W7nmGvLMM21HkRuH87l4TA1c3OrV5t0+154zEJFwc7jgq4EjefXV5IgR1oa3qmNH8v33bUdBfv+9+T5Yv952JMG7/Xby+ONtR2GceaZp4qLM4XwuHtsIYHx8uw7A+hqfj7cXWlayLvjTp5Pduvnw0yoikgOHC74aOJrJM8aPtza8VcXF5JNP2o6C/Mc/yO22sx2FHc89R/bubTsKY/BgcxtllDmcz8VjswC8VW2bleDjKMm64F91FTl8uA8/rSIiOXC44FubhbJ37xiBGPv2tT8L5UEHkY89Zm14q4YOJW+91XYU5DPPkP362Y7Cjo8+Itu1szd+1c9k1eywPXrY/5nMhcP5XCSlrAv+wQdH/50dEck/Dhd8a7MKV1aaBYxnzw586Fq6dCHfftt2FHaMGUOef77tKMjbbiNLSmxHYceyZeYq9Nq1dsYP41XxXDicz0VSyqrgb9hANm5M/uc/Pv3EiohkyeGCb3VZmL32IqdNszL0/2zaZNaAW7TIbhy23HWXmQXRtlGjyIsush2FHZWVZJMm5Jw5dsZXAyfihqwK/vr1ZtHQKC8OKSL5yeGCb7WBO+448s47rQz9P/PnmzXgwjKVftCef57s1ct2FOSxx4ZnKn0bevQwa7DZoAZOxA1ayFtE8orDBd9qPg/D7XtvvknusIPdGGz697/tPn9VZd99TTPpqt//nrz/fjtjq4ETcYMaOBHJKw4XfKv5/N57ySOOsDL0/0yaRB5yiN0YbPrpJ/PL+rp1duNo29Y0k67605/IK66wM7YaOBE3qIETkbzicMG3ms/LysytYzZdey15xhl2Y7CpstI8n/7f/9qLYe1a0zAsW2YvBttuuIE8+WQ7Y1fNQrnNNjF26LBlRkrNQimSX9TAiUhecbjgW83nX39tmoeKCivDkyRPP50cO9be+GGw007k66/bG/8//yELC91+Rv6JJ8gDDrAbwyGHkA8/bDcGLzicz0VSUgMnInnF4YJvNZ9v3EjWq0cuWWJleJJmeZvJk+2NHwaHHEI+8oi98adPJ3fZxd74YfDuu2SnTnZj6Nw5P5bTcDifi6SUccGfPdv+/fUiIsk4XPCtvyFnew22rl3JWbPsjW9T1a1z7drF2LGjvVvnJk4kBw8OdMjQWbzYLGexaZOd8devN2+mLF1qZ3wvOZzPRVLKqOBXVpLt2+fHuzoikp8cLvjWGzibV382byYLCsiFC+2Mb1tYJq+4+mpyxIhAhwyd8nKznMX8+XbGnzPHrEWXD7exOpzPRVLKqODPn082bGje3RERCSOHC771Bu6ss8irrrIz9sKFpoFzdQ24sDRweg7R6NaNfOstO2O/9BK5xx52xvaaw/lcIm5vAK8B+AFAJYBBab5uHIClANYCeBtAzyTHZVTwX3vN/ixjIiKpOFzwrTdwNmffmzXL3ELpqrA0cLafwQsLm89j3nGHWUw9HziczyXiegA4C0BvmAZuYBqvuQTAYpimrRDAjQC+A1CU4NiMCv7dd5NHHeXzT6uISA4cLvjWG7inniL797cz9uTJ5pdmV4WlgevenZw5M9AhQ+m008hx4+yMXVpKjhljZ2yvOZzPJY+k28AtAHBBtc8LAPwE4NQEx2ZU8EePJi+80OefVhGRHDhc8K03cP/6F7nNNnbGHjvW3L7nqjA0cBUVZKNG5DffBDZkaNl8FvD3vyfvu8/O2F5zOJ9LHkmngWsZP65/jf3TAdye4PiMCv5RR5H33OPzT6uISA4cLvjWG7iffzZNw+rVwY99xhlmIW9XVc1CWVwcY5MmMe6yS3CzUFaN3bt3jECM/fpFe/FoLzz0EDlokJ2xu3e3uxaglxzO5xJSk2EarWTbmwlek04D1zl+3K419j8F4MEEx2dU8F9+2SzWKiISVg4XfOsNXGUl2bIl+fnnwY89YAA5aVLw44ZRSQl5663BjReGq39h8/rrZlH1oG3aZHcGTK85nM8lpIoAtEmxNU/wmlyuwM0AcFuC41sAYGlpKWOxGGOxGMvKymz/vIqIZKSsrOx/Oay0tNTVgm+9gSPJXr3I558PftwddiDffDP4ccPoyivJc84Jbjw1cLV9/bW5nbSiIthx580zs4Xny2ysauAkH6T7DNx8bP0MXAMAywCckuDYUBR8ERGvRKTgpztT8DYAHoXJ62tgnnG+EUCjBMeGIp+fcAJ5223Bjrl5c35ddchV0BO6qIGrbf1682/w/ffBjjt9OrnzzsGO6aeI5HORhAoBNIFp4A6Pf16Q4viLASyC+YWgCYCbACwB0DTBsaEo+CIiXolAwc9kpuAdAFwR/xMAugP4HMCdCY4NRT6/9FJy5Mhgx1y0iKxf39w+JuT775Pt2wc3nhq4xLbfnvzww2DHvPde8g9/CHZMP0Ugn4sk1A1bnourqPbxNdWO+RLA5TVeNw5m7bh1AGbBo3XgRETCLgIFP5OZghMZDeCzBPtDkc/vv9/Mghekt98mu3QJdswwW7482Mlk1MAl1r+/WVojSLEYecEFwY7ppwjkcxErQlHwRUS8EvKCn+lMwYm8CuCRBPtDkc9nzAj+Fq5HHyUPOijYMcOsspJs3Zr8+ONgxispibF//xjr149xzz23zIbp8iyUJDl0KHnLLcGOecwx5IQJwY7pp5DncxFr0i74GzYE8JMqIpKjkBf8TGcKrulqmGfnOiT4u1A0cFWTKJSXBzfmuHHk8OHBjRcFQV/9+f57c9Vt3brgxgy7Sy4J/nbi3Xc3M4bni5DncxFr0i74e+xBvvJKAD+tIiI5CHnBz3Sm4Oqug3m+eeckfx+KWYU3bSILCsiFC4Mbc8QIs3CybDF8ODl+fHDjvfUW2bVrcOOFWdW6eN26xdiqVXBXJCsqyMaNyblzfR3Gd5pVWKRuaTVwlZVkkybkV18F9NMrIpKlkDdwQGYzBQNAPQD3AvgaQJcU5w3FFTgy+Cn9Bw4kH344uPGiYPx48tRTgxvvvvuCf/YxrGw9E7hkCVmvXn7dMRWBfC5iRVoFf+lSkxTWrw/oJ1ZEJEsRKPiZzBTcAMAUmMmqtq/jvKFp4AYNIh96KLjxdtyRfOON4MaLgqeeIvv1C2680aPJUaOCGy/MbDVw+XgVNAL5XMSKtAr+22+TnTsH9NMqIpKDiBT8ZDMFd4FZ7+2A+OcHw9xy+Vt8f9W2OsE5Q9PA/elP5BVXBDNWeblZA+7bb4MZLyo++YRs1crcQROEww8n//a3YMYKO1sN3MSJ5s2TfBKRfC4SuLQK/sMPk4ccEtBPq4hIDhwu+KFp4G6+mRw2LJixFi82d4hs3BjMeFGxZo1pGpYvD2a8bt10FbSKrQbu8svNmyf5xOF8LpJSWgX/yivJs88O6KdVRCQHDhf80DRwzzxD9u3r7xhVE0XsvnuMDRtq6vpE2rc3i3r77bffTBO9dKn/Y0WBrQaupIS89VZfhwicw/lcJKW0Cv4TT5DPPx/QT6uISA4cLvihaeA+/phs29bfMbR4dN0OPpicNMn/cT7/nGzePLjbNcOu6s2F4uIYO3aMcZttgnlzoVev/PtdzeF8LpJSaAq+iIgXHC74ocnnK1aYZmrlSv/GUANXt3POCeZZxKefJvv08X+cKJoyhSwu9n+cykrTRH/+uf9jBcnhfC6SUmgKvoiIFxwu+KHK561bm4k0/KIGrm5/+Yu5rc5vQS9ZECWffUa2aOH/1cmffjLf/2vX+jtO0BzO5yIphargi4jkyuGCH6p83qcP+dxz/p1fDVzdpk0j99rL/3FOPpm8/nr/x4mi9evJ+vXNGm1++uAD88xjvnE4n4ukFKqCLyKSK4cLfqjy+dCh5C23+Hd+NXB1mzOHbNKErKjwd5x99yWffdbfMaJs553JsjJ/x3jsMfLAA/0dwwaH87lISqEq+CIiuXK44Icqn19+OXnuuf6dv6Qkxr32irFevRj799cslIls2GCu/ixe7N8YlZVkURE5e7Z/Y0TdsceSt9/u7xjXXEOecYa/Y9jgcD4XSSlUBV9EJFcOF/xQ5fOJE8lDD/V3jCef9H+5gqjbcUd/12dbssQsIbB+vX9jRN2VV5JnneXvGKeckp+3sTqcz0VSqrPgjxljLs2LiESBwwU/VA3cG2+Y5sFPV15Jjhjh7xhRd/jh5H33+Xf+mTP9/3+OuiBmouzf37yhkW8czuciKdVZ8IuLyalTA/xpFRHJgcMFP1QN3IIFZEEBuXmzf2McfTQ5YYJ/588Ho0aRMR/vKr3nHvKII/w7fz4IYibKtm3Jjz7y7/y2OJzPRVKqs+C3a0f+618B/rSKiOTA4YIfqgZu82ayQQNy/nz/xuja1d/bA/PB3XeTRx7p3/nPP9/fBjEf+D0TZdW6i7/+6s/5bXI4n4uklLLgr1yZv0lBRPKTwwU/VA0cSe60k7nFzg+rVpn6tGyZP+fPF9Onm1kQ/XLooeQDD/h3/nzh50yU//432aaNP+e2zeF8LpJSyoL/8cdmMVYRkahwuOCHpoErKTEzQrZsGeMOO/gzQ+T775Pbb+/Z6fLWggXmSuimTf6cv3Nn8u23/Tl3PvFzJsqnnyb79fPn3LY5nM9FUkpZ8J9+WjN8iUi0OFzwQ9PABbFG2333+T/LZT4oLycbNya//tr7c69da/5ff/zR+3PnGz9norzhBrOYej5yOJ+LpJSy4E+dSl50UcA/rSIiOXC44DvVwI0cqfqUrt13J19+2fvzfvIJ2aqVv5Nz5As/Z6I880zy6qv9ObdtDudzkZRCU/BFRLzgcMEPTT4PooH73e/IyZM9O11eO/ZY8o47vD/v1Klm+nqpm58zUR50EPnoo96fNwwczueSB/YG8BqAHwBUAhiUxmvGAqgAsKbaNiXBcaEp+CIiXnC44Icmn/vdwFVWki1bmue0pW6XXkr+3/95f95rryVPP9378+YjP2ei7NDBPBOajxzO55IHegA4C0BvmAZuYBqvGQvgnTSOC03BFxHxgsMFPzT53O8GbvFi88vwb795crq899BD5KBB3p932DDyppu8P2++8nImyqqJgvr1ixGIsXdv7ycKCgOH87nkmUwauHfTOC40BV9ExAsOF/zQ5POqXy6Li2Ns0ybGLl28/eXylVfIHj08OZUT3nnHzBbptb33Jp9/3vvz5qshQ7ybiTKI25TDwOF8Lnkm3QbuWgBrASwDsBDm9sluCY4LTcEXEfGCwwU/lPn8llvIE07w9pw33UT+8Y/enjOf/fCD+eV+3TrvzllRQTZpQs6Z4905852XM1GqgROxZzJMQ5ZsezPBa9Jt4HoC6Bz/uAOAJwDMA1BU47hQFnwRkWw5XPBDmc/ffNP7qz8nn0yOH+/tOfNZZSXZvDn5+efenXPhQrKggNy40btz5jsvZ6JUAydiTxGANim25glek24DV1MjAOsBDK6xvwUAlpaWMhaLMRaLsSx+g/aLL+bvrEYikl/Kysr+l8NKS0tdLfihbOBWrSLr1TNXgbyy556mRkn6evcmn3vOu/OVlZlnuiR9n37q3UyUauBEoiXXBu7QGvuTFvxzzyUvv9zCT6uISA4cLvihbOBIsw7ZSy95c66NG8kGDchvv/XmfK446STyxhu9O99dd5FHH+3d+Vzg5UyUauBEoqEQQBOYBu7w+OcFKY4fCqBt/OPtADwGYD4yuIVy0CAzc5WISJQ4XPBD28CdcQZ51VXenOuLL8iiIvMMltStakKZjh1jbNduy+QyuU4oc9555MUXexSkQ7yaibKkJMY99oixoCDG/v29+38NG4fzueSBbtjyXFxFtY+vqXbMlwAur/b5NJgJTNYB+A5mEpMdE5w7acHv2pV8663Af1ZFRHLicMEPbQP3t7+Rhx3mzbm8fI7IBX5dqRk4UG/yZsPLmSgnTCCPOMKbc4WVw/lcJKWEBX/DBv8WnBQR8ZPDBT+0DdxHH5GtWnnz7M9ll5HnnJP7eVzhVwPXoQP53nseBekQL2ei/OMfyRtu8OZcYeVwPhdJKWHBnzuXLCzULSoiEj0OF/zQNnAbN5KNGpFff537uY44gvzrX3M/jyv8aOBWrTLnWL7cw0Ad4dUV5MpK00Tn+51SDudzkZQSFvyyMrJnT0s/rSIiOXC44Ie2gSPJ/v3JJ57I/TydO5OzZuV+Hld42cBVPU9X9exVvj535SevZqJcsMBM5uPl2n5h5HA+F0kpacHfsMHCT6qISI4cLvihbuAuuIAcPTq3c/z6q2k+fvnFm5hc4GUD58rMh3767TdvHlGZMoXs29ebmMLM4XwuklKoC76ISKYcLvihzuePP07ut19u53jnHXPbmKSv6qpZ9Stn/ftnd9VMDZw3dtop95koR47M/Q2RKHA4n4ukFOqCLyKSKYcLfqjz+dy5ZOPG5KZN2Z/j3nvJww/3LibXlJebyWT++c/sXq8GzhtezES5997kM894E0+YOZzPRVIKdcEXEcmUwwU/1Pm8ooJs2ZL8+OPsz3HuueQll3gXk4uOOy77Bb3VwHkj15koV60yt2EuXepdTGHlcD4XSSnUBV9EJFMOF/zQ5/PBg8n77sv+9fvvTz72mHfxuOjee8lBg7J7rRq43JWUxNi9e4xFRVtubc10IpgZM8xavS5wOJ+LpBT6gi8ikgmHC37o8/mVV5Jnnpndaysrzex9n33mbUyuqbqV9bffMn9tSUmMbdrE2KlT9s2H67xogq+9ljz5ZP9iDBOH87lISqEv+CIimXC44Ic+n7/4IrnHHtm9duFCsqBAMyTnqrKS7NiRnDkz89du3Eg2b57bbbCu86KBGzzYXEl1gcP5XCSl0Bd8EZFMOFzwQ5/Ply4l69UjV69O/zVVsyjuumuMhYW66uOF008nr7gi89fNnGlmAc11DTOX5drAlZeTzZq5cyXa4XwuklLoC76ISCYcLviRyOcdO2a2ELeeu/LeY49lt4ZYLEaefbb38bgk1+/nTz81V0HLy30ONCQczuciKUWi4IuIpMvhgh+JfH7cceStt6Z/vBo47y1damYxXLEis9ftvLO5DVayl+v38z33kIce6nOQIeJwPhdJKRIFX0QkXQ4X/Ejk85tuIktK0j9eDZw/dtuNfOGF9I//73/N5Cdr1vgXkwuqL6zeunWMHTtmdkvwySeTY8f6HGSIOJzPRVKKRMEXEUmXwwU/Evn8jTfILl3SP14NnD/OP99s6brjDi2i7rXnnyd33DGzZwq7djXLCLjC4XwuklIkCr6ISLocLviRyOcrV5qJTH78Mb3j+/dXA+eHF14ge/RI//iBA8m77/YvHhdt2EC2akV+8EF6x3/3nbn1NZNJgKLO4XwuklIkCr6ISLocLviRyec9epB//3t6xw4YEGNBQYx9+2rtMS+tWGGage++q/vYlSvJBg3I+fP9j8s155xDlpamd+zTT5P77ONvPGHjcD4XSSkyBV9EJB0OF/zQ5/Oq53/atdvy7E9dzdiwYeRFFwUYpEP69TMzUtbl2WfJnj39j8dFs2aR7dqRmzbVfezo0eTIkf7HFCYO53ORlEJf8EVEMuFwwQ99Ps/0ebalS8lGjch58wIO1BFXXEGedlrdx51+Onnppb6H46SKCrJzZ/Lll+s+tk8fcsoU/2MKE4fzuUhKoS/4IiKZcLjghz6fZ9rAXXMNeeSRAQfpkJkzzbp8qSbRKC8nt9mGfOed4OJyzWWXkSeemPjvqq5a9+0bIxBjr15u3ULscD4XSSn0BV9EJBMOF/zQ5/NMGriNG8nttiNfe81CoI5Yv54sLCTnzk1+zIcfkq1bk5s3BxeXa2bPJps0STw5ieuzsDqcz0VSCn3BFxHJhMMFP/T5PJNfRp94wiwcXVFhIVBHlJTE2KJFjN26JZ8g5qqryJNOshikI/bai3z00dr71cA5m89FUgp9wRcRyYTDBT/0+TzZL6M9etT+ZbS4mJwwwUKQDkmnOdhnH/eeu7Lh1lvJww6rvd/1ZTQczucScacBeA/ALwB+BvAWgP3TeN04AEsBrAXwNoCeSY4LfcEXEclERAp+ujkaAFoDmAJgJYAVAJ4A0DLBcaHP51XP81TfunePsVGjGBct2nLcRx+RRUVm+nrxT7IGrk2bQ1hcHOO++5rnrvr0ceu5KxuWLDFLNfzww5Z9q1eTrVqpgUP487lILSMBHAqgCEABgNEAVgPomOI1lwBYDPMLQSGAGwF8Fz9HTaEv+H4pKyuzHYIV+rrd4uLXHYGCn0mOBoBXAMwA0AZAWwCvA3gxwXGRzefnnEP272+eeyPNrIfnnZf+6138Pidz/7qTNXCFhceFumnIx//vqttZu3Y1zXKvXjE2bRpjgwbV/y/KQvd/4bcI5HORtK0AMCTF3y8AcEG1zwsA/ATg1ATHRrbg5yoWcyP51aSv2y0uft0RKPiZ5OiuACoB7Flt317xfZ1qHBvZfL5+PdmyZYzbbRdj794x1qsX4957p3/Vx8XvczL3rztZA1evXrgbuHz8/67ramhxcYzbb7+vcwvZRyCfi6SlP4DNALol+fuWMIW9f4390wHcnuD4yBb8XOVjAUiHvm63uPh1h7zgZ5qjhwBYn2D/BgBH1dgX6Xy+zz7Z3yrm4vc56V8DV1SkBi5o6TyPmI9fd11Cns/FQZNhiniy7c0Er+kMYCGA8SnO2zn++l1r7H8KwIMJjm8BgEuWLOGqVauc2kpLS63HoK9bX7e+bu+3JUuWhLngZ5qjhwP4McH+HwGcXGNfpPN5nz4jCayqtfXpM1Lf5z593UOGjGSfPrW31q2Pyvr/Igpfd+drakEAAAcoSURBVBi3dL7/8/HrrmsLeT4XBxXBPM+QbGte4/idYG67ubmO8yZ7d3cGgNsSHN8R5gdDmzZt2vJtS/WssC2Z5uhMrsApn2vTpi1ftzDmc5GU9gLwPYA/p3n8fGz9fEUDAMsAnJLg2HowPxQttGnTpi2Pto4w+S2MMsnRXVH7Gbi9kfgZOOVzbdq05eMW5nwuktD+AH4FMCqD11wMYBHMDGdNANwEYAmApp5HJyIimco0R78M84xcWwDtAMxE4lkoRUREJATeBFAOYE2N7fJqx3xZ43PArDH0A4B1AGYh9RpDIiISrGQ5ugtMjj+g2rHV14FbCeBxmHelRURERERERERERCSsxgFYCmAtgLeR/1fqbgbwBYBVMM8VTkXt50jy3Qswz88Msh1IgPaDuZq9GmYdxfeR//fTtwEwCeYqzwoAHwA4yGpE3jsRwLswP8+VAOrX+Pu9ALwDk9+WArg20OiCp3yufO4C5XPlcxfyuUhSlwBYDFPkCwHcCOA7mBky89WNAHrBTBrQEua2pE+tRhSs0wCUwSTHgZZjCcp+MAXvVJjv8/oA+lqNKBhPwPwS3xbma74I5hee1jaD8thhAIYBOBO1C35zmF92bgDQGMAeMM+ZXRhwjEFRPlc+d4HyufK5C/lcJKUF2HomtAIAP8EkRlfsA5MoWtoOJACdYCZOqFqHypWC/y6Av9gOwoLZ2PrnuxnM/3s+/rIzALUL/ukw+az6vlEA5gUXVqCUz5XPXaB8biif53c+F0kq2VpE0wHcHnw41lwKM6V3vqsHs87U2fHPXSn4TWEmAboFwD8B/Azg3wCOtxlUQMYDeA/A9gAaArgMwNcw717mmwGoXfDvBPBajeP2jx/XLJiwAqN8biif5zflc+Xz6vI1n4ukVPWu3a419j8F4MHgw7FiMMy91IfZDiQAI2F+maviSsHvBPO1/gCgN0xBOA7ARgDFFuMKQhNsub1qM4AfYQpePhqA2gX/YZh8Vt1u8eM6BBNWYJTPlc+Vz/Ob8rk7+VwkpWTv2M4AcFvw4QTuKJj76IfYDiQA3WEe8O9SbZ8rD71XfZ/fVGN/GcwECPnsXZii1wqmEB4DMwX93jaD8skA1C74d8D8P1eXr+/YKp8rnyuf5zflc3fyuUid5mPre6obAFgG4BQ74QTmFJjEN9h2IAE5A+YdyuXVtkqYf4P77YUVmG9Qu+BPT7Avn7SD+T+uWdw/hpnsIt8MQO2CfxrMMxMF1faNhvl+yEfK5244A8rnyueG8nn+5nORlC6GeQi6J8zl+ZtgZvVpajMon50P4FdsvUhuvmsCc4tB1dYRJjkOhXk3L9+NgrnlZm9seedyPfLz4e/qFgCYCDN7V32YqxQbkF+3WtWHmYnuMJjv6abxz+vBvCv7PYDr4/v2hJmlMV9nLVM+d4PyufK58nn+53OROo2DSYbrAMxC/q8bVAnz7uWaGptLvwAA7jwzUeVymGS/Guah96PthhOIngBegXmHfhXMLGZnp3xF9JwB871cCaCi2sdV6yPtCbNu0DqYPHdN8CEGSvlc+dwFyufK5y7kcxEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREUnkSwDDLYzbCsACAB3TOPYEAG/6G46ISOQpn4uIiETcWgBr4ttGAOXVPl8D4AB7oeGO+JaujwEc71MsIiJhp3wuIiLimOsQnnc9WwBYDaBHBq85D8B7/oQjIhIpyuciIiIOuB7AWwn2LwRwVvzjbgAqAZwJ4HOYd3zfhrktJhY/dgWA+wDUr3aOjgCmAvgOwE/xj9uliKUEwOIa+7oAeBXALwBWApgN4MBqf79jPLZtU5xXRMQFyuciIiIOSFbwFwAYEf+4G0xRLYMp2EUA3gUwD8BNABoC6A5T9E+Mv6YxgLkAbgXQJP6axwDMSBHLzQBeqbFvCoAHADSKf75zPJ7q1gA4IsV5RURcoHwuIiLigEwKfvVnKUbDvHNbr9q+l7DleYfjYd6pra5j/DwdksTyIIAna+x7JH7e3WuMVd13AE5N8nciIq5QPhcREXFAJgV/x2p/f3b8mOqehCnaAHAZgM0w7+JW334DUJwklptgbq+prg3MLxFzYW7beQS1b6/RO7YiIsrnIiIiTvCr4J8Gc0tOJkoALErx9x1gHtB/otq+HaBnJkREAOVzERERJ3hZ8J8CMDH+cTOY4j0eQMv4vm0BDEsRS0uYd1+rz1p2IszzGPVhZjV7DcCkan9/HoD3U5xTRMQVyuciIiIOSDbtdM2CX4GtC/5ZAObXeE31d2wB8w7rZJjCvwrANwDuriOeO+NblRthZkVbC2AZzMxnbav9vdYNEhExlM9FREQkcK1gCnynNI49HuFZ80hERLamfC4iIiIiIiIiIiIiIiIiInnu/wMF4LFN2WpbtQAAAABJRU5ErkJggg==\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\laser2002j\\Anaconda\\envs\\py3\\lib\\site-packages\\IPython\\kernel\\__main__.py:3: RuntimeWarning: divide by zero encountered in log\n",
" app.launch_new_instance()\n"
]
}
],
"source": [
"fig, ax = subplots(1, 2, figsize=(11, 4.5))\n",
"ax[0].plot(x, exp(-x), '-hr', label='Bleaching')\n",
"ax[0].plot(x, log(x), '--', label='A log function')\n",
"ax[1].plot(x, cos(x)**2, '-sb', label='Periodic fluctuations')\n",
"\n",
"ax[0].set_xlabel('Time (s)')\n",
"ax[1].set_xlabel('Time (s)')\n",
"ax[0].set_ylabel('Fluorescence (A.U.)')\n",
"ax[1].set_ylabel('Polarization')\n",
"ax[0].legend(frameon=False)\n",
"ax[1].legend();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Define a function\n",
"\n",
"Let's define a gaussian function, as an example (in principle the normalized Gaussian function ia already defined as `normpdf()`):"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def gaussian(x, mu=0, sigma=1, amplitude=1):\n",
" return amplitude*exp(-((x - mu)**2)/(2*sigma**2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that arguments can have default values used when the argument is not specified. To call the function we can both input the argument in the proper order (for example `gaussian(x, 0, 1, 10)`) or specify the arguments by name (like in the below example), in which case the order of the arguments does not matter:"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\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('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",
"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 = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(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",
" 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",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.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 = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\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",
"\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",
"\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]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\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, 0, fig.canvas.width, fig.canvas.height);\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",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = 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.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",
" /* 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",
" evt.data.type = \"image/png\";\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",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\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(\"No handler for the '\" + msg_type + \"' message type: \", msg);\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(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://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",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\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",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\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",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value});\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",
"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\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";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.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",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['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 = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\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.get(0);\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",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\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).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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 () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\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) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('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",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\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('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdd3gU1f4G8G96ISREIHQIXUFaFsnaEVCEq1jYH1wFNCCiEgSDohThEkEQBaQIUiyANBERFCR0QqgKiEBEQ29SRHpCyu68vz8CSCSBJDOzZ3fzfp5nnkc2s+e8yx5u3ruzMyNCREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREbuy/IpIkIhdERBMR79vsHy4is0TkvIicE5GZIhJmZkAiIiIiMtZjItJeRDpL/grgEhFZLiJ3iEhJEVkhIgvNDEhERERE5mgqty+AVa7uU++Gx+pffayiacmIiIiIyBRN5fYF8CkRuZLL4+ki8oQJmYiIiIjIRE3l9gWwk4iczOXxkyLy/L8e8xKRCiISyo0bN27cuHFzq62CZP8epyKgqRj7CWAFEQE3bty4cePGzS23CkJFQlMp3HcAG0ju3wEMFREcFEFXX19sX7oUFy5ccIttxPwRkCiBvC2Qvle3twXBTYKxddtW5fkaN26c6z/WGjVqoF27dihWrBiqVauGcuXK5bpfaGgofHx8cM899+CDDz5AgwYNct2vcePGyl+rJ26xsbHKM3Dj++GKG98L19iOHj167fdAaOErBbkDbxEJlOyzgTURCb7657w++l0sIssk+wzgUiKyUnI/CzhURNChQQNsbtUKKF0aWLkSrizDnoE3lr6BsOFhGDprKCytLAiKCUJQTBDqPFoH5d4oh9azWuPvtL+V5rRarbkWNn9/f/Tp0wfbtm2Dpml57me1WnH69GlMmjQJTZs2zfP//VmtVqWv01PFxcWpjkA34PvhOvheuIYLFy6wABYRMZJd/DQRcdzw3w+JSGURuSQi99+w/43XATwvIl9J7oskVERw7ty57BX1+edAsWLAkCGAw6F2defi6IWjuPeze9Fw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olzvNELrIEGssyg34rSv9RhvAtFGzfeoufUeLxblxinyr1JRykZLUQrIHaIsMdZLy1BBZoA0LICLRPk7URuPANI1NWZ3EfKtUaJ8Mx2idZAglyfKEaYfaw2nKL83z2sXK2j9RxoWwM0uHiPfShLl70H9sveJKDcTkn8MkIYF8H5RrgEMq/XYI6L83SFyq7G7i5BvPCQip6TuQt6kDaMop01qRjtRvuGOFOXIB/nXw6KcAu4lV486XRLeeKCFgyJSJMpdp6GinLG4LLw8wh9CRbkLfpgo34+iqz8OEeUo33ci8lT1Yz1EWd2DdwHTNbnbXYT8xynKUaeyeoOFMDDwGkBtTRXlB9o5UW4CuV3bOEGru4i8LcpR8bOi3BU89iefQd6SJ8r3IaeIOGr9f806jD1EWQfwgig/z//s/4hEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQUnP4/VEPWboTy3r8AAAAASUVORK5CYII=\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = subplots()\n",
"ax.plot(x, gaussian(x), '-hr')\n",
"ax.plot(x, gaussian(x, mu=1), '-hg')\n",
"ax.plot(x, gaussian(x, mu=2, sigma=1.5), '-sk')\n",
"ax.plot(x, gaussian(x, amplitude=0.6), '--');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Fitting\n",
"\n",
"What do you want to achieve here?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment