replot/docs/Matplotlib_Examples.ipynb

14414 lines
1.0 MiB

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This file contains a Matplotlib implementation of the examples provided in the `Examples.ipynb` notebook, for easy comparison."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Let's go!\n",
"\n",
"First import the required modules."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"source": [
"# Also import numpy as it will be useful…\n",
"import numpy as np\n",
"\n",
"# and add some black magic for easy reloading of the module before executing any cell (just here to ease testing)\n",
"%load_ext autoreload\n",
"%autoreload 2\n",
"\n",
"# ignore matplotlib warnings about too many figures in the notebook\n",
"import matplotlib as mpl\n",
"mpl.rcParams[\"figure.max_open_warning\"] = 50\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Basic plotting\n",
"\n",
"Let's start by doing some basic plotting."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# Let's plot a basic data series\n",
"fig, ax = plt.subplots()\n",
"x = range(10)\n",
"ax.plot(x)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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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dEkjJW0gaRdJ08RZwACAjKivtw8/3P7Sl+ylS1NPU5kIwOI6WyHs6iQ9LemwJs8NUDhTeKFCKF6witchAAEAFeVHP7L797c//DD1JJWLAEQsAhAAUDFGjbJ79bLfeCP1JJWNAEQsAhAAUBHGjbM7dbIffzz1JJWPAEQsAhAAkNyzz9pduti33ZZ6kmwgABGLAAQAJFVba/fpY19+eepJsoMARCwCEACQzLx59sCB9sknc7mXNUEAIhYBCABIYvly+5BD7IMPtpctSz1NthCAiEUAAgDaXalkn3KKvfPO9ty5qafJHgIQsQhAAEC7+8Uv7E03td95J/Uk2UQAIhYBCABoV3feaXfubD/1VOpJsosARCwCEADQbv75z3Ctv7vvTj1JthGAiEUAAgDaxdtv2xtvbP/yl6knyT4CELEIQABAm/voI3unneyqKi73Ug4EIGIRgACANrV0qX3ggfahh4ZLvyAeAYhYBCAAoM2USvaJJ9q77mrPn596mvwgABGLAAQAtJlLL7X79rXffTf1JPlCACIWAQgAaBNjxthdutjPP596kvwhABGLAAQAlN2jj9odO9r33596knwiABGLAAQAlNXUqXbPnvY116SeJL8IQMQiAAEAZTN7tr399vbpp6eeJN8IQMQiAAEAZbFkib3ffvaRR9r19amnyTcCELEIQABAtFLJPv54e8897YULU0+TfwQgYhGAAIBoI0bYW21lz5yZepJiIAARiwAEAET505/sbt3sl15KPUlxEICIRQACANbaI4+Ey708+GDqSYqFAEQsAhAAsFZefdXu0cMePTr1JMVDACIWAQgAWGOzZtn9+tnnnpt6kmIiABGLAAQArJFFi+y99rK/9S27oSH1NMVEACIWAQgAWG0NDfYxx9h7720vXpx6muIiABGLAAQArLazz7a32Sa8BYx0CEDEIgABAKvluuvCSR+vvZZ6EhCAiEUAAgA+1QMPhMu9/P3vqSeBTQAiHgEIAFilyZPtrl3tm25KPQlWIAARiwAEALRqxgx7yy3tCy9MPQmaIgCLaYSkeknzJM1v/O8tTZ4fKGmipAWS3m1cvzUEIACgRQsW2HvsYX/nO3aplHoaNEUAFtMISZNaea6zpBmSLpG0nqQBkmolDW9lfQIQALCS+nr78MPtL37RXrIk9TRojgAsplUF4FBJ70nq0OSxYZKmtrI+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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Or a (X, Y) point series\n",
"fig, ax = plt.subplots()\n",
"x = range(10)\n",
"y = [i**2 for i in x]\n",
"ax.plot(x, y)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 15,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAY6ElEQVR4nO3dX4zlaV3n8c/MUTjAMBAujGHAbJWbOJFhJhoJW5q4aQN7RdhoYjaG7Ew2pC7WwpmUETnZhKABmRgN14Zg9kr43RjupLiQyEQvjBqNeuNOZJGe4a8L9lConDj97MWvhilruhq6v9V96lv1eiVPuuqcX508+fWpOu9+6vmdTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAviniQPJLnfMAzDMIxW44HMr+Nwyx5IMgzDMAzDaDkeCNyG+5OMq1evjmvXrhnFsbe3t/E5XIThPDqX53E4l87jeRpXr159IQDv33BH0NT9Sca1a9cGdfv7+5uewoXgPJ4d5/LsOJdnw3k8G9euXROAlAjAM+QH29lwHs+Oc3l2nMuz4TyeDQFIlQA8QwcHB5uewoXgPJ4d5/LsOJdnw3k8GwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAsCR9Xo9pmkaq9VqTNM01uv1pqd0QwLwcvqBJB9P8uUkX0/yJ0l++tj9Dyf5bJLDJM8k+cBNHksAAsCY429n58pYLrfHYrE7lsvtsbNz5VxGoAC8nH4/c+C9Lsk9SX45yXNJXpvkviRfTPKhJC9L8lCSq0meOOWxBCAAjDGmaRrL5fZIDkcyRnI4lsutMU3Tpqf2EgLwcvqrJL907PNXJbme5C1JHs28MnjvsfsfT/L0KY8lAAFgjLFarcZisXsUf/NYLHbHarXa9NReQgBeTr+Q5DNJfjDJ9yd5X5K/S/LyJB9J8qkTx+8keT7z6uBJAhAAhhVAzr8fSvIHmVf91plX/HaO7vtYkk+cOP7BzAH4+hs8lgAEgHF8D+DW0R7ALXsAOTfuSfL3SX43yWsy/6r3nUn+KfPFH7e1Ari3tzf29/fH/v7+ODg42PTzGgA24jxfBXxwcPCd1+q9vT0BeMm8LvPK3yMnbv+LJO/NjfcAPhF7AAHgwrACeDn9bZKPJnl15hXBdyT5lyRXMq/yPZvkg0mWSd6c5AtxFTAAXBgC8HL64SSfTPKVzL/6/Zsk7z52/0NJnkryrcxvCfP+mzyWAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAE4I5br9djmqaxWq3GNE1jvV5vekqtCUCqBCAAd9R6vR47O1fGcrk9FovdsVxuj52dKyKwQABSJQABuKOmaRrL5fZIDkcyRnI4lsutMU3TpqfWlgCkSgACcEetVquxWOwexd88FovdsVqtNj21tgQgVQIQgDvKCuDZE4BUCUAA7qgX9wBuHe0B3LIHsEgAUiUAAbjjXAV8tgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAF5eO0n+MMlzSb6R5I+P3fdwks8mOUzyTJIP3ORxBCAANCMAL6edzNH3riQvT3Jvkrcc3Xdfki8m+VCSlyV5KMnVJE+c8lgCEACaEYCX01NJfuuU+x5L8uXMUfiCx5M8fcrxAhAAmhGAl88rkvxbkt9M8qdJ/jHJnyX5uaP7P5LkUye+ZifJ85lXB08SgADQjAC8fB5Icj3Jl5L8eOaVvp9N8u0k/ynJx5J84sTXPJg5AF9/g8cTgADQjAC8fO7PHIAfPnH7QZInc5srgHt7e2N/f3/s7++Pg4ODTT+vAYATDg4OvvNavbe3JwAvoadzegA+mpfuAXwi9gACwIVhBfByejzzlb6PJLknyTuT/HOSn8i8yvdskg8mWSZ5c5IvxFXAAHBhCMDL632Zw+5akj9P8o5j9z2U+Urhb2UOxfff5HEEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIEBz6/V6TNM0VqvVmKZprNfrTU+JO0wAUiUAARpbr9djZ+fKWC63x2KxO5bL7bGzc0UEXnACkCoBCNDYNE1judweyeFIxkgOx3K5NaZp2vTUuIMEIFUCEKCx1Wo1Fovdo/ibx2KxO1ar1aanxh0kAKkSgACNWQG8nAQgVQIQoLEX9wBuHe0B3LIH8BIQgFQJQIDmXAV8+QhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjADkk0muJ/mZY7c9nOSzSQ6TPJPkAzf5egEIAM0IwMvt0SQHSZ7PiwF4X5IvJvlQkpcleSjJ1SRPnPIYAhAAmhGAl9cbknz+6M/jK4CPJflyknuPHft4kqdPeRwBCADNCMDL69NJ3n308fEA/EiST504difzKuF9N3gcAQgAzQjAy+kXMwfgC44H4MeSfOLE8Q9mDsDX3+CxBCAANCMAL5/tzHv83njstvIK4N7e3tjf3x/7+/vj4OBg089rAOCEg4OD77xW7+3tCcBL5rEk/5rkq0m+djSuJ/lGkt/JfGHIV/Lv9wA+EXsAAeDCsAJ4+Swz/yr3+Lie5OeTvDbzKt+zST54dOybk3whrgIGgAtDAJL8+7eBSea3fnkqybcy/7r4/Tf5WgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCDATazX6zFN01itVmOaprFerzc9JRCAlAlAgFOs1+uxs3NlLJfbY7HYHcvl9tjZuSIC2TgBSJUABDjFNE1judweyeFIxkgOx3K5NaZp2vTUuOQEIFUCEOAUq9VqLBa7R/E3j8Vid6xWq01PjUtOAFIlAAFOYQWQ80oAUiUAAU7x4h7AraM9gFv2AHIuCECqBCDATbgKmPNIAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAIGNWK/XY5qmsVqtxjRNY71eb3pK0IYApEoAAnfder0eOztXxnK5PRaL3bFcbo+dnSsiEL5HApAqAQjcddM0jeVyeySHIxkjORzL5daYpmnTU4MWBCBVAhC461ar1Vgsdo/ibx6Lxe5YrVabnhq0IACpEoDAXWcFEGoEIFUCELjrXtwDuHW0B3DLHkC4BQKQKgEIbISrgOH2CUCqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAC+nJ5P8dZJrSZ5N8vEkbzhxzMNJPpvkMMkzST5wymMJQABoRgBeTr+R5MeSfF/mv/jfS/KXx+6/L8kXk3woycuSPJTkapInbvBYAhAAmhGAJMkjSZ5P8pqjzx9L8uUk9x475vEkT9/gawUgADQjAEmSX03yuWOffyTJp04cs5M5Eu87cbsABIBmBCBvS/LNJG8/dtvHknzixHEPZg7A15+4XQACQDMC8HJ7R5JvJHnnidutAALABSYAL693ZY6/t93gvkfz0j2AT+QmewD39vbG/v7+2N/fHwcHB5t+XgMAJxwcHHzntXpvb08AXkLvSfL1JD91yv33ZX57mA8mWSZ5c5IvxFXAAHAhWAG8nK4n+XaS547GN4/+PB6EDyV5Ksm3Mr8lzPtPeSwBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgHABrdfrMU3TWK1WY5qmsV6vNz0l4AwJQKoEIFww6/V67OxcGcvl9lgsdsdyuT12dq6IQLhABCBVAhAumGmaxnK5PZLDkYyRHI7lcmtM07TpqQFnRABSJQDhglmtVmOx2D2Kv3ksFrtjtVptemrAGRGAVAlAuGCsAMLFJwCpEoBwwby4B3DraA/glj2AcMEIQKoEIFxArgKGi00AUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAAGgGQFIlQAEgGYEIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJQABoRgBSJQABoBkBSJUABIBmBCBVAhAAmhGAVAlAAGhGAFIlAOEWrdfrMU3TWK1WY5qmsV6vNz0l4JIRgFQJQLgF6/V67OxcGcvl9lgsdsdyuT12dq6IQOCuEoBUCUC4BdM0jeVyeySHIxkjORzL5daYpmnTUwMuEQFIlQCEW7BarcZisXsUf/NYLHbHarXa9NSAS0QAUiUA4RZYAQTOAwFIlQCEW/DiHsCtoz2AW/YAAnedAKRKAMItchUwsGkCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoByLmxXq/HNE1jtVqNaZrGer3e9JQAziUBSJUA5FxYr9djZ+fKWC63x2KxO5bL7bGzc0UEAtyAAKRKAHIuTNM0lsvtkRyOZIzkcCyXW2Oapk1PDeDcEYBUCUDOhdVqNRaL3aP4m8disTtWq9WmpwZw7ghAqgQg54IVQIDvnQCkSgByLry4B3DraA/glj2AAKcQgFQJQM4NVwEDfG8EIFUCEACaEYBUCUAAaEYAUiUAAaAZAUiVAASAZgQgVQIQAJoRgFQJwEvCFbYAF4cA5GZ+PcmzSb6Z5I+SvOkGxwjAS8D/swtwsQhATvPeJP+Q5EeTvDzJh5M8k+SVJ44TgJeA/2UD4GIRgJzmc0nec+zzRZKvJHnXieME4CXg/9kFuFgEIDdyf5LrSd564vZPJ/ntGxwrAIvO+/46K4AAF4sA5EbekDkAf+TE7VOSj564TQAWddhf5//ZBbhYBCA3YgXwLuqyunbeVykB+N4JQE5zoz2AX80pewD39vbG/v7+2N/fHwcHB5t+Xrdifx0Ad8PBwcF3Xqv39vYEIDf0K0k+n/mtX16R5MkkV+Mq4DPXZQUQgIvDCiA382tJvpTkMN4H8I6xvw6Au00AUiUAz4D9dQDcTQKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgADQjACkSgACQDMCkCoBCADNCECqBCAANCMAqRKAANCMAKRKAAJAMwKQKgEIAM0IQKoEIAA0IwCpEoAA0IwApEoAAkAzApAqAQgAzQhAqgQgADQjAKkSgGfo4OBg01O4EJzHs+Ncnh3n8mw4j2dDAFIlAM/Q/v7+pqdwITiPZ8e5PDvO5dlwHs+GAKRKAJ4hP9jOhvN4dpzLs+Ncng3n8WwIQKruTzKuXr06rl27ZhTH3t7exudwEYbz6Fyex+FcOo/naVy9elUAUvJA5ieQYRiGYRj9xgOB23BP5ifP/YZhGIZhtBoPZH4dBwAAAAAAAABIkv+e5I+T/L8kX0vymSQ/udEZ9fHrSZ5N8s0kf5TkTRudTU9PJvnrJNcyn8uPJ3nDRmd0MXwyyfUkP7PpiTS2k+QPkzyX5BuZf05y634g8/f1l5N8PcmfJPnpjc6oh/+W5KnMPxufT3LvifsfTvLZJIdJnknygbs6Oy6E/5nk7UlelWSR5InMP/Bev8lJNfDeJP+Q5EeTvDzJhzN/E75yk5Nq6DeS/FiS78u8ufn3kvzlRmfU36NJDjK/aAjA27OTOfrelfn7+94kb9nojPr6/cyh8rrMFy78cubXmNduclINvD1zBP6PvDQA70vyxSQfSvKyJA8luZr59RtKvpHkv256Eufc55K859jniyRfyfyCwe17JPMPu9dseiJNvSHJ54/+tAJ4+55K8lubnsQF8VdJfunY56/K/NwU1N+b/5yXBuBjmVdUj9/2eJKn7+K8uIDemmSd5D9seB7n2f2Zf4C99cTtn07y23d/OhfKr2aOa27Pp5O8++hjAXh7XpHk35L8ZpI/TfKPSf4syc9tclKN/ULmrUU/mOT7k7wvyf/JvLLKd3ejAPxIkk+dOG7n6Lj77tK8OMf+d+YXgOeP/jw5PnODr3ljkv+beW8bp3thdeVHTtw+Jfno3Z/OhfG2zPsp377piTT1i5kD8AUC8PY8kPncfSnJj2d+4f3ZJN/OS//Rx3f3Q0n+IPM5XWdeudrZ6Ix6uVEAfizJJ04c9+DRcbZvkVdm3nNx2nj1ieP/Y+aVlyfv4hy7sgJ49t6ReevBOzc9kaa2M+8JeuOx2wTg7Xnh+/vDJ24/iJ+Pt+qeJH+f5Hczb+u4N/P3+D9lvoiB784KIHfUw5lfPP7XpifSyI32AH419gDejndljr+3bXoijT2W5F8zPwe/djSuZz6vv7PBeXX1dATgWXhd5ufhIydu/4vMF9Lx3d0oAB/NS/cAPhF7ALlFP5n5LWAe3/REmvmVzJvt35R5z9CTma/CchXwrXlP5reG+KlNT6S5ZeZf/Rwf15P8fFxteTsez/yP4kcyr2K9M8k/J/mJTU6qqb/NvDXm1ZnP5TuS/EuSK5ucVAP3Zt4n+V8yB+Arjz6/J/Mq37NJPpj5e//NSb4QVwFziz6TecPzc5n3X33z6OPVJifVxK9l3id0GO8DeLuuZ95b9VxefA4+F0F4FrwNTM37Mr+oXkvy55nDhVv3w5nfl/IrmX/1+zd58UIlTvdYXtzH//yxj194D8WHMl+t/q3M/1h5/wbmCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwKX0/wEnpr9sEO9WZQAAAABJRU5ErkJggg==\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# Plotting a discrete (X, Y) point series\n",
"fig, ax = plt.subplots()\n",
"x = range(10)\n",
"y = [i**2 for i in x]\n",
"ax.scatter(x, y)\n",
"fig.show()\n",
" \n",
"# or equivalently plotting a discrete (X, Y) point series\n",
"fig2, ax2 = plt.subplots()\n",
"x = range(10)\n",
"y = [i**2 for i in x]\n",
"ax2.scatter(x, y)\n",
"fig2.show()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# Plotting broken lines\n",
"fig, ax = plt.subplots()\n",
"x = [1, 2, 3, 2, 1]\n",
"y = [1, 1, 2, 2, 1]\n",
"ax.plot(x, y)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# Plotting a function\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(-2, 2, 100)\n",
"y = np.sin(x)\n",
"ax.plot(x, y) # Plot sinus on [-2, 2]\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# And we can plot multiples graphs on the same figure\n",
"fig, ax = plt.subplots()\n",
"ax.plot(range(5))\n",
"for i in range(8):\n",
" x = np.linspace(-10, 10, 100)\n",
" y = [np.sin(abscissa + np.pi * i / 4) for abscissa in x]\n",
" ax.plot(x, y)\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Advanced plotting\n",
"\n",
"We can do more elaborated stuff."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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 with a label on the axis, and a title for the figure\n",
"fig, ax = plt.subplots()\n",
"x = range(10)\n",
"ax.plot(x, x, label=\"x\")\n",
"ax.set_xlabel(\"some x label\")\n",
"ax.set_ylabel(\"some y label\")\n",
"ax.set_title(\"A title for the figure\")\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3dd3xUVfrH8efn7toXwbqKouuq2EBXXcG1IQg2sLvuShcsa1QIYMWGWBbEgrq2FXXtuwgWVIJIsSIWFFRAKYqRXkNoCcl8f38cZsWYhCR3Zs4tn/frdV/KMJn5ktzc+8y95zzHDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBEnW9m75pZkZmVm9lmm3h+fTN7zsxWmNkyM3vGzLbLZkAAAABkVmtzRWBXq1kB+IaZvWVmDcxsezMbbWavZDMgAAAAsuN423QB2MjMUmZ28EaPNd3w2O7ZiwYAAIBsqEkBeLqZrank8XVm1jYboQAAAJA9NSkAO5jZ/EoeX2BmF1Ty+P+ZWUMzq8fGxsbGxsYWqa2hufM4Yi4bVwAbmpnY2NjY2NjYIrk1NMTe8VazMYDl9vMxgIdseKyyMYD1zEyFhYUqKipiy+A2bVqR2rYtUoMGRXrkkSKtWOEeX7asSLNnF+nTT4vUrZv7+2HDcpcrLy/P+/eGLfPbxIlFatKkSIccUqSPP/7lz/vjj4vUtKl7zsZ/zxavLVe/3y+95I5d3bq5Y9ns2e7YVlTkjnUPP+z+vl27Ik2f7v/7EsetsLAwXQDWy0yJgTDazMy2MLM25gq5rTf8uarLviPMrMDMdjCzHc3NAn65iufWMzMVFRUJmVFeLj30kFSvntShg7RoUfXPf/ppaZttpH793NdmW35+fvbfBDmTSkkPPOD2oWuvlUpKfv73G/+8S0qka65xz33wQfe1iJds/36Xl0u33OL2oaefrv65CxdK7du7Y+FDD+Xm+JYkRUVFFIAJ0NncLN7yDVv6/48zsz3MrNjMjt7o+fXN7FlzfQCXm9nTVvUOQgGYYT17SnvuKRUU1PxrJk+W9tlHOuUUacmSrEWTRAEYJ2vWSKeeKjVqJI0fX/lzKvt5jx8v7bGH+9o1a7IcEjmVzd/vJUukk092x6opU2r+dQUF7pjYs2fWoiUSBSCCogDMoKFDpe22k2bOrP3XrlghnXGG1KSJtHZt5rOlFdSmMkWoXXaZ1KyZtHx51c+p6ue9fLn72ry8LIWDF9n6/V67Vjr4YHeMWrGi9l8/Y4a7EvjSS5nPllQUgAiKAjBD0ge4YcPq/hqlpdKf/iT17p25XIinV15xHza++67urzF7tttnX301Y7EQU716SUceKa1fX/fXGDbM7W8zZmQuV5JRACIoCsAMWLNGOuQQKRN3X6ZPd+NrqrqlBxQWSttvL73wQvDXev55aYcdpB9/DP5aiKdx49wxafr04K/Vs6d06KEMPcgECkAERQGYAd27S0cd5a7gZcL997sxM/xYUFFZmdSihdS1a+Zes0sX6YQT3GsDG1uxwo0xfeCBzLxeSYnUvLl00UWZeb0kowBEUBSAAf373+4Kyg8/ZO41y8ulE090J2ZgY7fdJu23n1RcnLnXLC6W9t1Xuv32zL0m4qFzZ6l168zO4J0zx13B3tQsYlSPAhBBUQAGMHWquzUycmTmX7uwUKpfX3r55cy/NqLpww+lrbaSPvss86/96afutSdMyPxrI5qGD3fHoGwMD3jzTXfsnDo186+dFBSACIoCMIC2baUrr8ze6z/3nLTTTq6fFpJt1Sppr72kQYOy9x533eXeY/Xq7L0HomHBAmnHHd0Y0Wy58kqpXbvsvX7cUQAiKArAOpowwX2C3VSj5yBSKekvf5HOPTd774FoGDRIOuKI7DbTLS+XDj9cuvvu7L0HouHcc6Xzz8/ueyxc6I6hH32U3feJKwpABEUBWEcnnihdf33232f+fHdr7osvsv9eCKdVq6Sdd5Zefz377zVihHsvrgIm1+efu2PO/PnZf6/rrnNjDFF7FIAIigKwDsaNcz3Yli3Lzftdfrm7EohkSl/9y8XSbakUVwGT7rzzpCuuyM17LV3qegPS9qr2KAARFAVgLaVS0jHHSLfemrv3nDNH2mILBkwnUS6v/qVxFTC5pk51x5pMdjXYlH79pGOPZW3q2qIARFAUgLVUUODavuT6W9a9u9SxY27fE/7l8upfGlcBk6tDh9z36Csqcm1hRo3K7ftGHQUggqIArIVUyp2MBw7M/XvPmuU+mddlnWFEk4+rf2lcBUyemTPdMWbWrNy/94ABbhlMrgLWHAUggqIArIVXXpF22cXfSbFjRzroJ4mPq39pXAVMnu7dpU6d/Lz3qlXu2Mq61DVHAYigKABrqLxcatLELdPmS3p8zpw5/jIgN3xe/UvjKmBypMcZT5vmL8PgwVLTptltdRQnFIAIigKwhl56Sdp9d2ntWr85zjvPzQpGvPm8+pfGVcDkyMvz32lg7Vp3jH3pJb85ooICEEFRANbQCSf4GftX0eTJuevRBT/WrPF/9S8tfRVwzRrfSZAt8+ZJW27pji2+DRwotWzpO0U0UAAiKArAGvjmG3d7JJurftTG6adLvXv7ToFsefpp6YADwjEgPpVyWZ55xncSZEvv3tIZZ/hO4SxcKG2+ufTtt76ThB8FIIKiAKyB3r2lv/7Vd4qfvP++a0TNVZl4OvZY6Z57fKf4yd13S8cd5zsFsmHNGncs+eAD30l+cv75Up8+vlOEHwUggqIA3IS1a13fv3HjfCf5SSol7b+/9OyzvpMg06ZNc1ebFy/2neQnixe7TNOn+06CTHvmmfBcbU4bO1bacUdp3TrfScKNAhBBUQBuwnPPSfvtF64DpCTddZcbl4h46dMnXFeb084/X7rqKt8pkGktWrgJR2GSSkn77is9/7zvJOFGAYigKAA34fjjw3eAlNxYmd/8hsbQcVJSIu20kzRmjO8kv/T22y5bSYnvJMiUmTPdeLuFC30n+aW77nLFKapGAYigKACrEcbbcRs76yypb1/fKZAp//2v9Ic/hLMPWnm5tPfe0tChvpMgU66/Xjr7bN8pKsewg02jAERQFIDVyM+XLrjAd4qqvf661LChVFbmOwkyoXVr6Y47fKeo2u23S23a+E6BTFi/XtptN+mNN3wnqdrf/ib16uU7RXhRACIoCsAqrF3rFih/5x3fSaoWhYM4amb2bHdLf94830mqNm+ey/jdd76TIKgofHgcP94dg3033w8rCkAERQFYhWeecTNtwzb5o6Lrr5fOOcd3CgR1ww3SmWf6TrFpZ5wh3Xij7xQI6uyzwz98JJWSGjem20FVKAARFAVgFcLWi60q6YHcYWlSjdqL0pXc9JWj9et9J0FdpZstz5rlO8mm0YOyahSACIoCsBJff+2WRlq61HeSmmnRgvVao+y119waqGG+HZdWVuYKwBEjfCdBXQ0aFJ0WUkuWuMkgU6f6ThI+FIAIigKwEldf7QYgR8Uzz0gHHhj+29Wo3OmnSzfd5DtFzd14Y3iWDkPtpJf2i9Jt1b/+VbrmGt8pwocCEEFRAFaQSkl77umuykRFejmnCRN8J0FtzZ/vJlZ8/73vJDX3/fcu8/z5vpOgtj78MHrLSL76qrTXXnzArYgCEEFRAFYwYYI7QEZtGaK//13q3t13CtTWgw+6ZuNRc9xx0j//6TsFaqt7d+myy3ynqJ1169wx+aOPfCcJFwpABEUBWEHPnlKXLr5T1N5HH0n167NSQ9REtZCKauGaZFEupDp3dn1Z8RMKQARFAbiR8nI3wH3kSN9Jai+Vkho1isZMUjhz50q//nU0b6XOn++yz53rOwlq6vXX3fCWKN5KffNNd2wO4yo5vlAAIigKwI28+660ww5SaanvJHXTq1c0r14m1eDB0ZmNWZkWLaT77/edAjXVubPUu7fvFHVTWuqaQr/3nu8k4UEBmBz9zGyumRWb2XgzO6ia5443sxIzW7nh+SvN7NIqnksBuJG8POnii32nqLsJE7gNHCVHHy09/LDvFHX30EPSMcf4ToGaKClxx4Yo3v5Nu+gi6fLLfacIDwrAZLjKzOaY2YFmtoWZ3WFmP5rZ1lU8f5y5grEmKAA3WL9e2nlnacwY30nqLpWS9tjD3S5BuBUWuluoCxf6TlJ3Cxa4f8OPP/pOgk154w03RCSKt3/T3n5b2mWXaPTLzAUKwGSYbWaXb/TnX5nZQjNrX8Xzx5nZrTV8bQrADeJycMnPl7p29Z0Cm3LvvVKrVr5TBNeypXTffb5TYFO6dHFDRKIsDh/SM4kCMP7qmVnKzJpVeHyUmQ2q4mvGmdliM1tqZlPN7E4z26aa16cAVHxuL3z4odSgQXTHMSbFUUdJjz7qO0Vwjzwi/fnPvlOgOunbv3HoExr1YTqZRAEYf7ubKwAbV3j8RTN7rIqvaW5m9Tf8fxMzm2RmL1TxXApAxWuAcXm5W1YsijOZk2LOHHfrNA7rNy9a5P4tP/zgOwmq8uabbmhIlG//pkV9ol4mUQDGX12uAFZ0nJmVmhs/WNnrJ74AjFuLgZ49pQsv9J0CVbn7bql1a98pMufEE6V77vGdAlXp2jU+PfSi3Kor0ygAk6GyMYCLrOoxgBWlC8AtK/m7emamvLw85efnKz8/XwUFBb7365yLW5PR9993VzT5lBxOzZpJ//qX7xSZ89hjUvPmvlOgMqWlbkjIBx/4TpI5UW3WnwkFBQX/O1fn5eVRACZAHzP73lzrl63MjekrtMpnAe9sZidt9HcHmdknZja0itdO/BXAKHfHr0r6U3ICa/nQ++47d8t0yRLfSTJn8WL3b4rSesZJMXJkvO5uSNFdrjPTuAKYHLeY2XwzW2U/7wO4h7lef0dv+HMjM5toZsvN9f/71pgEUq24LjR+5ZVSt26+U6Ciu+6STjrJd4rMa9NGGjTIdwpUdOGFUo8evlNkVirlVjR57TXfSfyiAERQiS8Au3SJbnf86rz3HreBw+iII6QhQ3ynyLzHH5f+9CffKbCx9OS299/3nSTzevem3RUFIIJKdAFYVibtuKObWRY35eXSbrtJo0b5ToK09O3fpUt9J8m8pUvdv+2773wnQVpBQfxu/6a98460007R79saBAUggkp0Afjee66lQFwPIldcIXXv7jsF0gYPjkfz56q0bMnawGHSrZsbChJH69e7Y3ccr27WFAUggkp0AXjVVW4GcFy98467whnXAjdqTjzRFYFxdd998WpvE2XpuxvvvOM7SfZ06iRdfbXvFP5QACKoRBeA++0nDR/uO0X2rF8fvxYQUbVihbtFOnu27yTZM2uW9JvfuH8r/Eq3glq/3neS7Bk2TGrc2HcKfygAEVRiC8Dp06UttpCKi30nya727aVrr/WdAi++KB18sO8U2XfQQdJ//uM7Ba65RurQwXeK7Coudsfw6dN9J/GDAhBBJbYAHDBAOu003ymy7z//cSdl+HXBBdL11/tOkX3XXec+dMCvAw+U/vtf3ymy79RTpYEDfafwgwIQQSW2ADz6aOnRR32nyL4VK9xtuVmzfCdJrtJSqX79eDUbr8qECW7YQZxvPYbdzJnudz4Jh/VHHpGOOcZ3Cj8oABFUIgvARYukX/1KmjfPd5LcaNXKDdCHH+PGSbvsEs92HBWVl0s77yyNH+87SXLde6+bcJQEc+e6Y/miRb6T5B4FIIJKZAH4xBPSkUf6TpE7990X7/YjYZefn6xVWS68UOrVy3eK5GrZMt6zzSv605+kJ5/0nSL3KAARVCILwDPPlG67zXeK3GF2pj+plPSHP7glB5PilVfcvzluyytGQRJmm1fUv7901lm+U+QeBSCCSlwBuGaNtPXW0pdf+k6SW8zO9OPrr6Utt5RWr/adJHdWrXL/5qlTfSdJnqTMNt/YlCnumL5mje8kuUUBiKASVwCOGCH9/vfJuzpx7bXxbwsRRv/4h9Sune8Uude2rZtpj9xq397NxE6SVEraay/p9dd9J8ktCkAElbgC8KKLpJ49fafIvQ8+YHamD3/+s/TYY75T5N6jj7qZ9siddOP3Dz/0nST3evSQLr7Yd4rcogBEUIkqAMvLpd/9Tho71neS3Csrc4unx3lpqLBZuDBZs803luTZmb6MH+9mYCdx6ccxY9yxPQkz7dMoABFUogrAjz5yn5BLS30n8aNLF6lPH98pkiNps80rSursTF9695a6dvWdwo90r82JE30nyR0KQASVqAKwb1+3IkNSJX3tzFxL2mzzipI6O9OXuK9tvil/+5s7xicFBSCCSlQB+Mc/Ss895zuFP8XF0uabS9984ztJ/K1d62YmTpniO4k/kydL22zjvhfIrqSsbV6dZ5+VDjvMd4rcoQBEUIkpANNjkpYs8Z3Er5NPlgYN8p0i/kaOlBo1St5s842lUtIee0gFBb6TxN9dd0mnnOI7hV+LFydrzC0FIIJKTAE4ZIh01FG+U/j3z39Kxx/vO0X8XXmldOmlvlP4d8klboYmsuu446SHHvKdwr/mzd3Y2ySgAERQiSkAzznHjUlKuu+/dysFsCpIdu2zj/Taa75T+Pfqq9K++/pOEW/Ll7srX3Pm+E7i3623Suee6ztFblAAIqhEFIClpdJvfyt99pnvJOFw4IHSSy/5ThFf337rxlquWuU7iX/pcafffus7SXwNHepW+oH06adSvXrJ6PRAAYigElEAjhuXvB5R1endW7rwQt8p4uu++6TWrX2nCI8TT5QGD/adIr66dqW9U1p5ubTLLq4nYtxRACKoRBSAV11FwbOxMWOkXXdN9gSFbGrTRrr3Xt8pwuOee6STTvKdIp5SqeQ2t69K167S1Vf7TpF9FIAIKhEF4EEHcctzYyUl0rbbSp9/7jtJ/Kxa5dpx0GrnJ+kWJatX+04SP5MmueEtJSW+k4TH0KHSwQf7TpF9FIAIKvYFIJMeKnfmmdIdd/hOET8jRkh/+ANXVzeWSkl77y29/rrvJPFz++00265oxQp3zI/7pBgKQAQV+wLw4YelFi18pwifxx6TjjnGd4r4+fvfpSuu8J0ifC6/XLrsMt8p4ufoo6V//ct3ivA5/njpkUd8p8guCkAEFfsCsF07aeBA3ynCp7DQtY5Ytsx3kvhIpaQ993RNoPFzb74p7bUXV0YzaelS9ztcWOg7SfgMGCCdfrrvFNlFAYigYl0Appfj+uor30nCqUkT6T//8Z0iPqZOlbbcUlqzxneS8Fmzxn1vpk3znSQ+XnxRatrUd4pw+vJLd+xft853kuyhAERQsS4AR41iOa7qXHON1Lmz7xTxMWiQdOqpvlOE1ymnSHff7TtFfHTqJF17re8U4ZRehvCtt3wnyR4KQAQV6wKwRw+W46rO+PGuZxb9ETOjZUvpwQd9pwivBx6QWrXynSIeysulnXeW3nnHd5LwuuQSqWdP3ymyhwIQQcW6ANx3X5bjqk5pqeua/+mnvpNEX1GR9JvfSLNm+U4SXrNmue/RypW+k0TfJ59I222XjBUv6urVV6X99vOdInsoABFUbAtAluOqGdZIzozhw6X99/edIvwaN5Zeftl3iuhL0pq3dZVehnDGDN9JsoMCEEHFtgAcPJjluGpiyBDpqKN8p4i+iy6SevXynSL88vOliy/2nSL6mjeXnnjCd4rwi/MyhBSACCq2BeBJJ7klqFC9uXNdK4klS3wnia5USmrYUBo92neS8HvrLWn33ZmYFcTixe53dt4830nC7+67pZNP9p0iOygAk6Ofmc01s2IzG29mB1Xz3Ppm9pyZrTCzZWb2jJltV8VzY1kArl7tlp6i5UTNHHqo9PzzvlNE1+TJ0jbbxLvlRKasW+e+V1Om+E4SXc89J/3xj75TREOcWzNRACbDVWY2x8wONLMtzOwOM/vRzLau4vlvmNlbZtbAzLY3s9Fm9koVz41lAUjT2dq5/nqpQwffKaLrH/+If9PZTGrXzjXqRd20by/17es7RTTEuTk7BWAyzDazyzf686/MbKGZta/kuY3MLGVmB2/0WNMNj+1eyfNjWQBecYVbkgs189570o470g6mro4/3i05iJp56CGWZ6yr8nL3u/r++76TRMell0pXXuk7ReZRAMZfPXPFW7MKj48ys0GVPP90M1tTyePrzKxtFa8fuwJwn31o/1Ib69dL9etLH3/sO0n0FBW5hee//953kuj47jv3PYvZYScnJk50v6vr1/tOEh2vvupagsUNBWD87W6uAGxc4fEXzeyxSp7fwczmV/L4AjO7oJLHY1cAzphB+5e6OO88qV8/3ymiZ9gw6YADfKeInv33d61zUDu33CL95S++U0RLuh3MzJm+k2QWBWD85eQKYF5envLz85Wfn6+CggLf+3Ug99/vpv6jdp54wrWWQO107+5am6B2evZ0rXNQO82aSU8+6TtF9LRq5VaiibqCgoL/navz8vIoABOgsjGAi6zqMYDl9vMxgIdseCwRYwBPOcWtyYramTePdjC1lW7/Euf1RrNl1CjawdRWuv3L/Pm+k0TPXXfFb51urgAmQx8z+95c65etzOxOMyu0qmcBjzCzAjPbwcx2NDcL+OUqnhurAnDNGjfl/+uvfSeJJtrB1M6UKdLWW9P+pS7WrnXfuy+/9J0kOmj/UndffSVttZXb7+KCAjA5bjE3tm+V/bwP4B7megMevdFz65vZs+b6AC43s6et6h0kVgXgyJFSo0ZcVair666TOnb0nSI6BgyQ2rb1nSK6TjtNGjjQd4ro6NDBtWxC7aVS0h57SBEf4fQzFIAIKlYF4JVXSpdc4jtFdL37rrTTTrSDqakWLaR//tN3iuh68EHphBN8p4iG8nL3u/nee76TRNfFF0s9evhOkTkUgAgqVgXgvvtKr7ziO0V0rV8vbbed9MknvpOEX7r9y+zZvpNE16xZ0m9+I61c6TtJ+H38Me1fgnr5ZWm//XynyBwKQAQVmwJw5kxOJplw7rnSrbf6ThF+w4dLjRv7ThF9++3nTsyoXr9+rlUT6m7lSvehbdYs30kygwIQQcWmAHzgAW4nZcKQIdJRR/lOEX4XXeRamSCYHj3crTlUr3lz16oJwbRo4YYexAEFIIKKTQF46qkMKM+EuXNdq4mlS30nCa9UyrUwGTXKd5LoKyhwg/OZuFW1JUvc7+S8eb6TRN+AAW7yURxQACKoWBSAa9e6Kf60lMiMQw6RXnjBd4rw+vLL+LWU8CX9u/vVV76ThNfzz7sWTQgu3bopDr+7FIAIKhYFIE1lM+vaa6VOnXynCK+BA+PXVNanU05xjXpRuY4dXYsmBBen5u0UgAgqFgVgjx4sK5VJ77wj7bwz7WCqcsIJ8VhWKizuv19q2dJ3inBKt395913fSeKje/d4jN+lAERQsSgA99mH9i+ZVFoq1asnffqp7yThs3Klm20et4XlfZoxgxn8VfnkE9eaifYvmfPyy65lWNRRACKoyBeA33wjbb65VFzsO0m8nHOO1L+/7xThM3x4vHqJhcW++9IOpjK33upaMyFziovdOePbb30nCYYCEEFFvgC8916pTRvfKeLn8cdpB1OZbt2k/HzfKeKnZ093aw4/d9RRrjUTMqt1a+m++3ynCIYCEEFFvgA88URp8GDfKeIn3Q5m8WLfScIjlZJ23VV6+23fSeJn9Ghpt92YyLWxxYtp/5It993nisAoowBEUJEuANPjsWbM8J0kng47THrmGd8pwuOzz6Tf/lYqKfGdJH5KSqRtt5UmTfKdJDyeflo6/HDfKeLp22+jP3SIAhBBRboAZDxWdt14o3T++b5ThEe/fm5sJLLj7LNZhnBjf/mLdNNNvlPEV9THnVIAIqhIF4DduzMeK5smTnQL0JeW+k4SDkceyXJc2TRkiNSsme8U4VBa6mb/fvyx7yTx1bNntNuHUQAiqMgWgKmUGzPEeKzsKS93/QDHj/edxL+FC6XNNpPmz/edJL7mz3ff40WLfCfxb9w4aZdd6MWZTaNHu6bQUR13SgGIoCJbAE6axHisXOjSRbrqKt8p/HvqKemII3yniL/DD5f+/W/fKfzr00fq2tV3inhLjzv9/HPfSeqGAhBBRbYA7N/fjRlCdr30knTAAb5T+HfeedItt/hOEX833+zGviXd/vtLw4b5ThF/Z50l3Xab7xR1QwGIoCJbADZv7nrVIbuKitxM61mzfCfxJ70yyief+E4Sfx9/7Ma+JXnc6cyZrIySK//6V3T7nVIAIqhIFoD0x8qtVq3ceq1JxXis3Ckvd9/rJI87HTzY9TdF9kW53ykFIIKKZAH4zDOuRx1y4557kr3aSu/ejMfKpS5d3Bi4pGrd2q1whNz44x+lZ5/1naL2KAARVCQLwL/+1fWoQ27EoWlqEPvv78ZCIjeGDk3uuNOVK93vGs3tc+eGG6S//c13itqjAERQkSsA1693vek++sh3kmTZb79oN02tq1mz3HisCP2KRF563Ons2b6T5N7w4VLjxr5TJMuECVKDBu7cEiUUgAgqcgXge+9JO+3EeKxcy893jbeT5v773RhI5FbLltIDD/hOkXvdukm9evlOkSxlZdKOO0rvv+87Se1QACKoyBWAV18tderkO0XyjBkj7bprdJum1tVJJ7kxkMitu++WTj7Zd4rcKi+Xfvc7aexY30mSp2NH6ZprfKeoHQpABBW5ArBxY3ebBLlVUuIab3/2me8kubNqlbTFFtI33/hOkjzTp7vv/apVvpPkzqefunZDSW6B48uwYW6sb5RQACKoSBWAU6dKW26ZrJNCmJx7rtSvn+8UuTNsmBv7iNxLpaR9903Wh71bbnENx5F7q1a5c8u0ab6T1BwFIIKKVAF4xx3S6af7TpFcTz6ZrOXQOnSI3m2hOLn6andrLimOOMItOQg/2rWT7rzTd4qaowBEUJEqAI88UnriCd8pkmvxYunXv5YKC+LIRVkAABehSURBVH0nyb7SUmab+zZhgvsZJOGW6A8/uN+tKDYkjoshQ6RmzXynqDkKQAQVmQLwxx9dx/ZFi3wnSbYWLZIxO/Ott9ykF2ab+1Ne7n4Go0f7TpJ9998vnXCC7xTJtmiRO8fMnes7Sc1QACKoyBSADz0kHXec7xRIyonq7393G/y69FLpsst8p8i+pHywCrtjj5Uefth3ipqhAERQkSkA27ShHUcYJOFWVXm5tNtu7iog/Bo1SmrYMN5XYtNXnpIwtCLs7r7btX6KAgpABBWJAnD5crcywKxZvpNAcmMxhwzxnSJ7PvooOWPPwq6kRNpuO2niRN9Jsufxx6M19izOZs5055oVK3wn2TQKQAQViQLw+eelpk19p0DanXdKbdv6TpE911zjZgAjHNq3l6691neK7DntNOkf//CdAmlNmkgvvOA7xaZRAMbfuWY2zcxWm9nXZnbWJp5/s5mVmdlKMyve8N/nqnl+JArAv/xFuvlm3ymQ9s03bsH6lSt9J8m8VMr1/hs2zHcSpL30UnzXxy0qcr9LNBsPj5tuks4/33eKTaMAjLdmZrbWzM40s1+Z2dlmtsbMDqvma242s3dr8R6hLwDXrpW23Vb6/HPfSbCxgw6SXnzRd4rM+/prmo2HTbpJ79SpvpNk3gsvSAcf7DsFNjZpklv1aN0630mqRwEYb0+Y2bAKjw03s39V8zWxKwDfeEPac8/krUEbdjfe6K7Mxs1tt9FsPIzatZNuv913isw77zx3xQnhkUpJjRpJb77pO0n1KADjbZKZXVPhsevM7NNqvuZmc7d+F5rZd+Zu/+5VzfNDXwBedJHUo4fvFKho0iR3ZXbtWt9JMuvww92KJwiXJ56I3yo0a9ZI22zD3Y0wuvJK6eKLfaeoHgVgND1pZikzK9/w34rb2A3Pm2lml1T42kvN7NtqXvtAM9tjw//vambPbnidrat4fqgLwLIyaeedpXHjfCdBRamUtNde0ogRvpNkzpw5rsXNkiW+k6CixYtdq5QffvCdJHNee036/e+5uxFGY8dKu+wS7vZDFIDRtLWZbV/N9tsNz6vLFcCKNjc3jvDEKv4+1AXgBx9I228vrV/vOwkq06uX1LWr7xSZM3hwMppcR1WLFq4ReVx06SL17u07BSqzfr3UoIH04Ye+k1SNAjDenjCzlyo8tqkxgBWlC8DWVfx9PTNTXl6e8vPzlZ+fr4KCAt/79f/06iV17uw7Bary/vvxKtBPOCFeBUbcDB4stWzpO0VmlJa6350PPvCdBFXp3Nmdg8KkoKDgf+fqvLw8CsAYa2Zu1u8ZZvZrMzvHXDuY6mYBn2dmO2z4/13M7Gkzm21m21Tx/NBeASwrc6sxjBrlOwmqUl7ubpOMGeM7SXCLF7vbv3G6xRg3cbpF//bb0u9+F+5bjElXUODOQWVlvpNUjiuA8XeOuT6Aa8xsqrmWMBv7ysyu3ejPr5qbALLKzArNTQLZu5rXD20BOGaMG/8Xl6tLcXXJJdLll/tOEdzDD0vNm/tOgU1p1kx65BHfKYLLy3PrHCO81q+XdtrJjQcMIwpABBXaArBbN+mKK3ynwKaMGiXtumt4PyXX1NFHSw8+6DsFNuWBB6RjjvGdIpiyMvc7w1rT4Xf55VL37r5TVI4CEEGFsgBct86t/zlhgu8k2JT1691t4CifzGbPdut/LlrkOwk2ZeFC97P67jvfSepu1Ch3+5e7G+H34YduXfAwNoWmAERQoSwAhw+X9t6b9ghRkZ8vdezoO0Xd3XabW48V0XDqqdFuCt2hQ/gmF6ByqZRr1fPyy76T/BIFIIIKZQF47rnSDTf4ToGa+vxz19C2uNh3ktpLpaT994/G4u9wnn9eOuCAaH5ALC6Wtt5a+uIL30lQU337uhVbwoYCEEGFrgAsKpK22CKe637GVSrl1jN9+mnfSWrvs8/ciiarV/tOgppatcp94Jg0yXeS2vv3v6UmTXynQG2k1wcP0WlSEgUgggtdAfjUU9Khh/pOgdoaMEBq3dp3itrLz5c6dfKdArXVsWM0b6OeeKI0cKDvFKitQw5xxXuYUAAiqNAVgK1bc4CMosJC16Nt7lzfSWqurMwNxo/yBJakiuLs8x9/dL8jP/7oOwlqa8AAqU0b3yl+jgIQQYWqAJw/3x0gCwt9J0FdtGol3XWX7xQ199ZbrgCMUhEBJz37fPRo30lqbuBAdwUQ0fPDD+7ctGCB7yQ/oQBEUKEqAAcPlo4/3ncK1NVTT0lNm/pOUXOdOrlbwIimnj2jtVRkkybhu42ImjvuuHAtFUkBiKBCVQAeeaT06KO+U6CuVq50MxwnT/adZNNWr3aTPz77zHcS1NWnn0q//W00JvB88YX73YjiTHk4jzziVqIJCwpABBWaAnDGDNfgdelS30kQRPv2Up8+vlNs2gsvuPYvUWwlAieVkho3ll580XeSTevd2/X/Q3QtWeLOUTNn+k7iUAAiqNAUgDfdJJ1+uu8UCKqgIBqD8087zTWARrT17y+1bes7RfXWr3djTUeN8p0EQbVrJ918s+8UDgUgggpFAVhS4g6Qb7zhNQYyIAonu0WL3Cf52bN9J0FQs2aFfxm/qHwowqa9/rr7WZaW+k5CAYjgQlEAvvCCW/qtvNxrDGRIr17hvt11++1Sy5a+UyBTTjhBuuMO3ymq1r69uwWM6Csrc+eqMAw7oABEUKEoAI8+Wrr7bq8RkEFTpkhbbSUtXuw7yS+VlkoNG0qvvuo7CTLllVfczzQMV2UqWrzY/S58+aXvJMiUQYOkY47xnYICEMF5LwAnTXKz45Yt8xYBWdCqVTjH2KWvNnM7Lj7KyqTf/z4cV2Uq6t+f3n9xs2yZK+o//9xvDgpABOW9AOzWTbr4Ym9vjyx5/XU3FnDdOt9Jfq55c+nee32nQKbdc4901FG+U/zcunWuWTVjm+Pnoouk7t39ZqAARFBeC8AlS9wnqSlTvLw9sqi83LXoCFPj24kTXe+/FSt8J0GmrVjhfrYff+w7yU+eesq1GmJsc/xMnuzOXT7bllEAIiivBeDAgaz8EWcPP+wWUQ9Lr70LLpCuuMJ3CmTL5Ze7CRdhkEq5VXEeecR3EmTLccf5XfqSAhBBeSsAy8qkvfaShg7N+VsjR1avlrbfXho71ncSae5cafPNpW+/9Z0E2fLNN+5nPG+e7yTSmDHSDjtEY5US1M1//+vGnvoaT0wBiKC8FYCvvSbtvrvrG4f4uv76cDTqvfFG6dRTfadAtp1yimsq79tpp0l9+/pOgWxKdxQYMcLP+1MAIihvBWDr1uGcJYrMmjtX2mILd3XGl7VrpZ12CndzamRGQYG0885+Jx9Nn+72+TBciUR29e8vtWnj570pABGUlwJw2jR3gFy4MKdvC086dpT+/nd/7//kk9IBB4RnLCKyJ5VyEy+eespfhksvlTp18vf+yJ0FC9y5bPr03L83BSCC8lIAXnghB8gkmTTJzZhbsiT3751KSYce6iakIBkeekj64x/9FPzpzga+e8Qhdzp2dOe0XKMARFA5LwC/+ELacku3hieSo0ULP8t1jRwpNWggrVqV+/eGH6tWuZ/5yJG5f+/bb3dL0yE5Zs5057TJk3P7vhSACCqnBWAq5brisy5m8owY4cZm5fJic2mpux04eHDu3hPhcN997rZ/LpeHW7HC7eO+JgXAn169cj8WcM4cCkAEk9MC8M03XVsQln1LnlTKXRnJz8/de/ooAhAOPor/nj2lli0Za5pEy5a5c1surzqffTYFIIKpZ2YaNiz7BeD69dKBB3I1Jsm++srdKvnyy+y/16JF0nbbuVmhSKaCAql+fWnx4uy/15Qpbt/++uvsvxfC6b77pIMOyk1rs5EjpXr1KAARTD0z0557FmW9Yekjj0j77iuVlGT3fRBuvXu7DvrZvkpy6aVSu3bZfQ+EX9u22Z+BnkpJxx4r9emT3fdBuJWUSPvsIz36aHbfZ/Vq14D6nnsoABFMPTPT4YcX6brrsrfDrlzpxsYMH56990A0rFwp7bab9Nxz2XuPyZPd1RhW/cA332R/gP6zz7p9euXK7L0HomHYMGmXXbK7L1x7rdS8ubR8OQUggqlnZnr//SJttVX2bs317es+ITM2BpL0/PPS736XnQkh6bGGV12V+ddGNPXp4/aJbBx/iorcvvzCC5l/bURP+mrwDTdk5/W//NK1GZo8mVnACO5/k0Cuuko6+mipvDyzO+wPP0hbby198klmXxfRlUq5tjC9emX+tYcNy/1sY4RbenZuNu5A5Odnr7hENH38sTvnFRZm9nXLy6U//1m6+mr3ZwpABPW/AnDVKmnPPaXHHsvcDltS4mbFdeyYuddEPGRjQsiaNdJee0lDhmTuNREPjz/uxk2tWZO512TiB6rSsaPUqlVmx7w/+qg7R6d7mlIAIqiftYEZMcLNmluwIPjOmkpJnTu7jvzFxcFfD/HTu7f7RLt2bfDXKi11kz6OPTbzV7ERfWVl0jHHSKefnplZmmvXun2XiR+oTHGxO/d16ZKZq8MLFrhz8xtv/PQYBSCC+kUfwHPPdbfnghZt/fpJe+whzZ0b7HUQX8XFUrNm0mmnSevW1f11ysvdJ+4mTegxiaotXSodfLD7YBrkQ8K6ddKpp7p9lw+3qMrcue4ceOutwV6nuNidk8877+ePUwDGW1Mze9PM5ptZysxa1vDr+pnZXDMrNrPxZnZQNc/9RQFYXOxu2zZvXveT6b//7Xqw5aLfG6Jt+XLpiCPc1bu63C5JpVwD3t//Xpo3L/P5EC9z57p9JT+/bldmSkrcvvqnP7mxhUB1pkxx58Knn67b1y9b5s7FrVr98sMGBWC87W9m3czsMDMrt5oVgFeZ2RwzO9DMtjCzO8zsRzPbuornV7oSyNq17lbJIYdICxfWbocdM8YNgB09um47PJJn2TLpsMOkM8+s/aodt93mZmHOnJmdbIifGTNcq47bb6/d15WUSGecIR1+uPvgAtTE6NHunDh2bO2+bsECqWlTt89VNkyGAjA5anoFcLaZXb7Rn39lZgvNrH0Vz69yKbjSUumCC6T99nMzeWti4kQ3TuGJJ2q3oyN3CkK6NMbSpdKhh0rnnFPzIvChh9z+lutF2KMkrD9v3774wu07Dz9cs+eXlkpnn+320aVLs5stCH7e4TRkiNvfJk6s2fPnzHHn3gsuqPp4SAGYHDUpAOtteF6zCo+PMrNB1XxNlWsBl5VJF18sNWokTZhQ+biZVMp9sjn5ZDcjbsCAGv5GwIv8XC7GW0tLlrhPvKecIr31VuUHvrIyNxD6rLOkbbaR3n8/9zmjJMw/b9/ee8/tQ2ed5fapsrJfPqe01O2Lp5zi7ogsWZL7nLXBzzu8Bgxw58iTT5bGjat8CEJ5uTvXNmokXXJJ9WNVKQCj6UlzhVr5hv9W3MZW8jU1KQB33/C8xhUef9HMHqvia6otACW3k/btK227rfsE066dNGiQ6+s3dKgbC9OggWt8mYnZw8iusJ8gFi+WLrtM2nVXt1916iS9/LI0bZp0441Sw4Zu1YW+faXZs32nDb+w/7x9mz3b7Uu77Sbtvrvbx6ZNc/tcx47umLfbblJeXm7WFA6Kn3e4LVjgzpUNGrhz59Ch7lw6aJA7t9av7861fftueowqBWA0bW1m21ez/baSr8nqFcDCwkIVFRVVuy1dWqSxY4vUv3+RTjqpSPXqFalhwyL94x9Fmju3+q9lC8+Wl5fnPUNNtuXLi/T220Xq0aNIe+9dpM02K9JppxXpv/91+6LvfFHZovLz9r0tXVqk//zH7WObbeb2uR493D64fLn/fPy847XNnVukO+9059B69dw5tX9/d46t6fGtsLCQAjAhgowBXGRVjwFsaG4HYmNjY2NjY4ve1tAQS1uY2ZbmCsCTNvz5V9U8v4+ZfW+u9ctWZnanmRVa1bOA/8/czlOPjY2NjY2NLVJbQ3PnccTMnvbTWMGNt5s2es5XZnZtha+7xVzvwFW26T6AAAAAAAAAAAAAAIDIa2qbXmauvpk9Z2YrzGyZmT1jZtvlKiCy7nhzP/uVG7ZiM/vBayJkWm2WhUR03WxmZfbT7/FKc8duxMP5ZvaumRWZGwa2WYW/b2pm75gb9vWjuf0BqFJNlpl7w8zeMrMG5trTjDazV3IVEFl3vLmfPQOI46m2y0Iium42VyAgnlqbKwK72i8LwG3NbJ6Z3WZmm5vZweYmfvbIcUZEVGVXABttePzgjR5ruuGx3XOUC9mVLgCrm1WO6KrtspCILgrAZEgfszcuADub2YIKj11pZjNymAsRVlkBeLqZrankuevMrG3WEyEX0geTOeYOIKPN7DiviZAp9az2TeERXTebu/W70My+M3f7dy+fgZAVlRWA95jZyArPO2rD87bNUS6ExJOWmWXmOpgbH1jRAjO7IFNhkRU13Qd2MbMm5g4m25hZbzNba+5KL6KtLstCIroONLM9Nvz/rmb2rJnNNG73x01lBeDjZvZCheftv+F5u+UoF0IiU8vMcQUwuuqyD6SNNTeWBNHGFcBk29zch7kTfQdBRnEFEBlX1RjAcvv5GMBDNjzGGMD4GmNmt/sOgYyo7bKQiI90AdjadxBkVGUFYCf75RjAHsYYQGzCppaZG2FmBWa2g5ntaG6M2Ms5zojsaWNunND/mVs2sKe5k8ZhHjMhc2q7LCSi6zxzx2kzN7TjaXMfALbxlgiZtJm583MbcwXg1hv+/H/mrvLNNbP+5s7nTcy182IWMKpUk2Xm6psbS7LCzJabO6jUy21MZNEN5iaAFJu7MjTG3CdMxMctxrKQSfCquQkgq8wV+c+Z2d5eEyGTOtvPz9fp/09P2jvY3Czw1eZawtzoISMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhM3/A8t1e6UMJ0k9AAAAAElFTkSuQmCC\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots()\n",
"ax.set_xlabel(\"some x label\")\n",
"ax.set_ylabel(\"some y label\")\n",
"ax.set_title(\"A title for the figure\")\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.sin(x)\n",
"ax.plot(x, y, label=\"sin\")\n",
"ax.legend(\"lower right\") # Not that ax.legend call position matters\n",
"fig.show()"
]
},
{
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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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A8xWWsls//3NunQxW3llsyOPNJs61Xd1ePdds5/+1GzDDc22285s2WXNllnG7NRTzRYt8l0dXnjBrHt3s169zDbayGy55cw6dTK75RazVKq8tdTV1f3vd3VNTQ0BEK2iBRCoYqmUWU2N+4V10UWuFcPMtTZ9+KHZEUeYbbXV4sdRXvPmmZ12mtnyy5sNHGi2YIF7vKnJ7IsvXCg85BCzhga/dVar+nr379Oli9ngwYvDXipl9sEHZmuuaXbuuf5aa2kBRD6dJC0jaT+5ALh8+uul8uxLAAQq1KBBZj16mI0fn//5RYtcCNx2W7MZM8pbG8zOPNNshx3Mxo3L//zMmWY772y2995mc+aUtbSq19hotssuZnvtZTZhQv59xo0z23xzs4MP9vPvQwBEPidLSsmFv+asz/fIsy8BEKhA77zjWpbeeafwfgsXulamHXZIRr+mavH442arrNJ6uMiYM8fsZz8z23VX+gWW07XXunA3f37h/WbONNt9d7NjjilPXdkIgIiKAAhUmMmTXcvfoEHF7b9ggWtlOuOM0tYF55tv3G3FZ58tbv+GBrPNNjO7887S1gXnX/9y3SY++qi4/b/7zv17vvJKaevKRQBEVARAoII0NZn16WN23HHt66D+zTful97IkSUrDeZaXLff3uz889v3uldfdSFjypTS1AVn7lyznj3Nrr++fa+7+243QKStFsM4EQARFQEQqCCPPWa23nruF1l7XXKJC4/lHtlYTa6+2g3u6MjAjiOPNDv55NhLQpZzzzXbbbf2T5PU1OS6UVxxRWnqyocAiKgIgECFaGpytwrvv79jr6+vN1tjDbO//jXeuuDMnOla8d56q2OvnzDBbIUV2u7XiY754gs3Bc9//tOx148c6VrR//3veOtqDQEQUREAgQrxyCNm66/vbjN21AMPuFtZmSlJEJ/rrjPbY49oxxg40I3aZiLv+J10khuZHcWvf+1GDpcDARBREQCBCtDUZLbppi7ART3ONtuY3XRTPHXBmT3brFs315cvigULXEAfMiSeuuCMH+8m3/7662jHmTnTtdL+61/x1FUIARBREQCBCjB0qFtJIo6VI+rqzFZfnVbAON18s9lOO8XTv3LQINffDPE57zyzo4+O71jHHx/PsQohACIqAiAQuMZGN3LxwQfjOV4q5VoThw6N53jVbt4817fyxRfjOd7s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89gpkj4vfyl5EQCRWL16ubU7q93BB/tb/aM1jY1mq6xi9u67vivxb6utzJ54wncVLc2cGc9txtBlvk8/+MB3JS2NHu1WBZk/v+PHIAAm3xxJnXIe65x+PAkIgEisiy82O+UU31X41dDgpn/57DPflSzpuOPiGc0YsqT1L8vWp4/Zvff6rsKvd991/SGT1lKdmZfwlVc6fgwCYPINl7RTzmO9048nAQEQifXGG/FNmhqqYcPM1l47Wf3LMoYONdt2W99V+PXgg2Y77+y7ivwGDjQ74gjfVfg1YIDZMcf4riK/M84w+81vOv56AmAynZa1XS0379/Nks5Nf5ySfjwJCIBIrEWLzLp0MRsxwncl/tTWmp1+uu8q8ps61axTJ7Np03xX4s9RR5lde63vKvL78EM36XBjo+9K/Ond22zwYN9V5Pfkk9H6aRIAk2lcEdtYb9W1RABEov3iF2bXX++7Cn8239zs6ad9V9G6n/7UzWtWjRobzVZe2exf//JdSX5NTe72Z7X205w+3d2e/+4735Xk98MP7g+ojtZHAERUBEAk2h/+UL2L248fn/yR0EkcAVsu77zjJlxOcheFX/0qeSNgy+Xxx+OZcLmUevc2+8tfOvZaAiCiIgAi0caMMVt6abN583xXUn733We2++6+qyhs2DCzddZJZh/FUrvqKjcQJsn+9CezXXf1XYUfp55qdsklvqsoLMr3EAEwDPtKukXSQ5IeztqSgACIREul3LrAdXW+Kym/I480u+4631UUNn++2bLLmn35pe9Kym+HHcwefth3FYVNmOBakavtR3wqZdajh5ukO8neftts9dU71opMAEy+c+Umgv5b1sf5kh7xWVQWAiAS7/TTo42WC1Gm/9Z77/mupG377mv2+9/7rqK8Mv23Jk/2XUnbNt3U7G9/811FeX32mVueb8EC35UUtmiR2UormX38cftfSwBMvi8lHZj+fGb641GS7vFTzhIIgEi8EPryxG3ECDcCOoQRnDff7CarriZPP222xRa+qyjO+eeb1dT4rqK8brvNrScegsMOM7vxxva/jgCYfLOzPp+V/thZbiqYJCAAIvG+/961tkyZ4ruS8rnxRveLIQQjR5qtuKJrzagWffuaXXCB7yqK8/e/m22yie8qyuvAA83uuMN3FcXp6EA3AmDyTZK0UvrzryRtLGkVtQyGPhEAEYTt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NTWZde/u5rQsh2nT3B8E48aV53yhIgCGYWNJG2R93VPSln5KWQIBEFXhr38t39qzb71l1q0bo3/b4447zH72s/Kc6/HHzXr2TMY6xKE4/3yzM88sz7nuuMP/BOEhIAAiKgIgqkJDg1mXLmbvv1/6c51xBrcX22vSJDdae/Lk0p/rgAPMrr++9OepJG+/bbbqqm5pw1JKpdzgqb/8pbTnqQQEQERFAETVOPVUswsuKO05MrcXyxE0K80ee5gNGlTac0ya5G4vTpxY2vNUmuZmN2jm5ZdLe54PPzRbcUWzuXNLe55KQABEVARAVI1hw1xfplLOafbEE9xe7Kh77jHbaafSnuPGG83226+056hU/fu7lXVKqW9f14KOthEAERUBEFWjsdFNalvKVoyf/9zsd78r3fEr2cyZZssvb/bxx6U5firlVv5gbsaOGT/etZ5++21pjp9pPX/33dIcv9IQABEVARBV5aqrzA48sDTHnjLF9WNj9GLHnXOOu1VfCu+/7/qBzp9fmuNXg0MPNbviitIc+5FHXECn9bw4BEBERQBEVZk82S099uWX8R/7llvM+vSJ/7jV5Isv3JyN338f/7H79nXz/6HjXnnFrQyycGH8x/7Zz8xuvjn+41YqAiCiIgCi6px0kgsDcVqwwHWSf+aZeI9bjfbeO/5RuvX13F6MQ3Oz2cYbx38bfdw4d3u5HKPAKwUBEFERAFF1Pv7Y9TWLc+WJBx90t69YWiy6Z581W3fdeFeeGDjQLS3G7cXobr89/mXaamtZOae9CICIigCIqtSnjxsRGoemJjfyd/DgeI5X7ZqazNZf3+zpp+M53ty5bg67urp4jlftZswwW245s08/jed4kye74330UTzHqxYEQERFAERVevZZs3XWiWdi26efdscqRb+oanXzzfGtBnHrrWY77EDrX5xOO83s9NPjOdaFF5oddlg8x6omBEBERQBEVWpqckvDPfZYtOOkUmb/939md94ZT11wfvjB3aZ/551ox5k/3839+Nxz8dQFZ/RoN1jniy+iHee771zrX6mm/qlkBEBERQBE1brnHrNNNnHLxHXUsGHu9iIrF8Tv2mvNttsu2sTdgwaZbbMNrX+lcOGFblLtKNe2X7/STy5dqQiAiIoAiKrV1OQCxoABHXt9c7PZrruaXXNNrGUhraHBtdLee2/HXr9wobs1/+ST8dYFZ8YMs27dzF54oWOvnzTJtSJ+8km8dVULAiCiIgCiqo0Y4W5BjR7d/tfedpvZhhuazZ4df11wnn/ehYzp09v/2t/+1myrrRiZXUp33+0GQHWkL+0555gdcUT8NVULAiCiIgCi6vXrZ7bnnu27lfXZZ66P2j//Wbq64Bx8cPsncH79dffvE9dIVeTX2GjWq1f7+8A+84xblWXMmNLUVQ0IgMi1taSXJE2WlJK0dxv7EwBR9errzXr0MHvooeL2X7DAtSz171/auuB8841rpX3//eL2nzbNbK21On7rGO3zyituku1Ro4rbf/RoF/6YND0aAiBybSbpdEnbSWoWARAoyjPPmK2ySnErRVx0kes7yLQv5XPrrWarrdb2XHHNzW6t5yOPZOBHOV15pRtt/dVXhfebM8e1GF5ySXnqqmQEQBRCCyDQDoMGma2wQusTEC9caHbFFW6fYls7EJ+bb3YtTa3ddm9ocCtKbLCB2cyZ5a2t2qVSLtStvbZrsc1nwQKzo44y22uveFd5qVYEQBRCAATa6e9/N1txRdfilD39yKefuulEttnG9f+DH/fe6/59nn7atSZlvPSS2U9+4lpmP//cX33VLJVyU8Ost54bvJP5tdLU5FbJWX9913Vi6lSfVVYOAmD1GCwX6JrTH3O31/O8hgAIdMCHH7rbWZ07u75k227r+qBdeSW3fZNg6FCz1Vc3k9w0Mb17m628spvXMcqcgYgulXLTIm28sfv/07u3WyN7ww3Nhgzh3ydOBMDqsbykbgW2lfK8pugAWFNTY7W1tVZbW2t1LJgJ2MKFZuPGmb33ntlf/8po0qRJpdwassOGmd13nxv4gWT59ls3sGrwYP5wiktdXd3/flfX1NQQANEqWgABAKhAtAAin2UkLSsXAPdPf925lX0JgAAABIYAiFzra3Ffweztt63sTwAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEBERQAEACAwBEDkOlHSPyX9IOl7Sa9L2qXA/gRAAAACQwBErr6S9pW0gqTOki6QNFtSj1b2JwACABAYAiCKMVPSYa08RwAEACAwBEC0pbekRZI2aOV5AiAAAIEhAFaPwZJSkprTH3O31/O8Zl1J4yRdU+C4BEAAAAJDAKwey0vqVmBbKWf/jSWNlXRDG8ftIslqamqstrbWamtrra6uzvf3NQAAyFFXV/e/39U1NTUEQCxha0nfSepfxL60AAIAEBhaAJFrF7kpYPoVuT8BEACAwBAAket1SU1yU7/MSW+zJV3Wyv4EQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAAAkMARFQEQAAA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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots()\n",
"ax.set_xlabel(\"some x label\")\n",
"ax.set_ylabel(\"some y label\")\n",
"ax.set_title(\"A title for the figure\")\n",
"ax.set_xlim(-20, 10)\n",
"ax.set_ylim(-3, 3)\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.sin(x)\n",
"ax.plot(x, y, label=\"sin\")\n",
"ax.legend(\"lower right\") # Not that ax.legend call position matters\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 31,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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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AIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEACRFAEQAIDIEABR6GBJT0v6RtIUSeMlbV3m9QRAAAAiQwBEoWMkDZfUQ1InSWMkzZI0oMTrCYAAAESGAIhKTJc0ssT3CIAAAESGAIi2bClpgaS1SnyfAAgAQGQIgMuOcZJaJDXn/i1s44v8zOqSPpF0bpnfSwAEACAyBMBlR3dJfcu0FQpeP1jSx5IubuP39pLkRo8e7RoaGlxDQ4NrbGwM/XcNAAAKNDY2/t+xevTo0QRALGUTSV9IOr2C13IGEACAyHAGEIW2lp8C5oQKX08ABAAgMgRAFBovaZH81C+zc22WpFNLvJ4ACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiASIoACABAZAiAKLSnpNclTcu1lyXtU+b1BEAAACJDAEShVXOt1XaS5knauMTrCYApamxsDF1Ch8A4poexTA9jmQ7GMR0EQJRTJ2lb+QD44xKvIQCmqKGhIXQJ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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Passing extra arguments to matplotlib plot command\n",
"fig, ax = plt.subplots()\n",
"ax.set_xlabel(\"some x label\")\n",
"ax.set_ylabel(\"some y label\")\n",
"ax.set_title(\"A title for the figure\")\n",
"ax.set_xlim(-20, 10)\n",
"ax.set_ylim(-3, 3)\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.sin(x)\n",
"ax.plot(x, y, label=\"sin\", linewidth=20)\n",
"ax.legend(\"lower right\") # Not that ax.legend call position matters\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false,
"scrolled": true
},
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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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j8lPASyRcb9KWb4+Q0TG5vCYYiKCM2fO4Nq1a5a9xcXFYd/BU5g6Zxs6+y7Em5+Mw1PV/dCk9VjExMQqz2emW4cOHZRnsMMtOjoG85fuxqcdpqFYpb8hxbtiypytynPx+23PW3R0DMZM3oina/fGgxX+QtXXByLq9EV+vz34dubMGRZACyoqIo/kcnsom8fo9QlgcXH9APHGG2+88cYbb9a7FReyNS1zAC9LznMA7xDXD08x3njjjTfeeOPNUrfi4nodJxu6V0TuE1cBfDPj73flcv/fROSUuJZ+uV9EeonIGcn5KmAiIiIiMpHS8r+5grfe/r7lPgdEpGuWx/mIa+3AeMl7HUAiIiIiIiIiIiKyo2qS9y4jD4vINBGJE5EYEZkiIv8yKiDproG4vvfXM243ROS00kTkbgXZFYisy1tE0uV/v8fXxfXcTfbwkYisF5Fr4joLeGeWf68mIuvEddbvrLh+HohylJ9dRpaIyHIR+be4rk5eISLzjQpIumsgru89JxDbU0F3BSLr8hZXQSB7ekNcJfBL+WcBfFBEzouIn4jcIyJVxDXvv6PBGcmisvsEsFTG16vc8rVqGV8rYVAu0ldmAcztoiKyroLuCkTWxQLoGTKfs28tgG1E5GKWr/0sIscMzEUWll0BfE9EErO5b7KIvKN7IjJC5pNJlLieQFaISH2lichdiknB1wQl6/IW16nfSyISKa7Tv2VUBiJdZFcAB4rI0iz3eyXjfg8alItMIkjcs8vIZ+KaH5jVRRH5xF1hSRf5/Rl4QkSqiuvJ5AER+VVEksT1SS9ZW2F2BSLrek5ESmb8+SkRmSoix4Wn++0muwIYKCLBWe73TMb9/s+gXGQS7tplhJ8AWldhfgYyrRbXXBKyNn4C6NnuEdebucaqg5Bb8RNAcruc5gA65PY5gM9nfI1zAO1rlYj4qw5BblHQXYHIPjIL4Buqg5BbZVcAv5B/zgHsKJwDSHnIa5eRRSISJiKPishj4pojNs/gjKSfJuKaJ3SHuHaN6SSuF40aCjOR+3BXIM/RUlzP0yKuqR2TxfUG4AFlicid7hTX63MTcRXAohl/v0Ncn/KdExFfcb2eVxXXcl68CphylJ9dRh4W11ySOBGJFdeTSjFjY5KOuovrApAb4vpkaJW43mGSffgIdwXyBAvEdQFIvLhK/jQRKas0EblTG7n99Trzz5kX7VUR11XgCeJaEuYvBRmJiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIjII/0/xW0ddLn7uYAAAAAASUVORK5CYII=\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import seaborn.apionly as sns\n",
"# You can also tweak the palette used, either with a seaborn palette\n",
"sns.set_palette(sns.color_palette(\"dark\", 10))\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.sin(x)\n",
"ax.plot(x, y)\n",
"fig.show()\n",
"sns.reset_orig()"
]
},
{
"cell_type": "code",
"execution_count": 37,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# To plot in log scale\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(1, 10, 100)\n",
"y = np.log(x)\n",
"ax.semilogx(x, y)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 34,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"# Same for log-log scale\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(0, 10, 100)\n",
"y = x**2\n",
"ax.loglog(x, y)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": 36,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3de5SdVXn48YdrIIEAwQtXQSpKEU0BRcWlFLxQqVVEqUXBqEC9DAInCBVEhaKiSymyvCIqikBFUEGqHBBoxfy0ShUUsCJICeEuAknAEJLM8/tjJwSHmSRkz+Rkn/l81npXLnMg+105zPmy33fvNwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgTa0TElhEx2eFwOBwOR1PHllE+x+FJ2zIi0uFwOBwOR5PHlgErYXJE5KxZs3L27Nl9dwwMDPR8DM7NuY2Xc+v383NubR79em6zZs1aEoCTe9wRNGpyROTs2bOzH3U6nV4PYcw4tzb187ll9vf5Obc29eu5zZ49WwBSRQA2yrm1qZ/PLbO/z8+5talfz00AUquvA7Db7fZ6CGPGubWpn88ts7/Pz7m1qV/PTQBSq68DEAD6kQCklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQGoJQABojACklgAEgMYIQFbE9yJiMCL2GuZrAhAAGiMAWZ63RUQ3IhaFAASAviAAWZatIuLWxT+aAQSAPiEAWZZLI+LgxT8XgADQJwQgI3lvlABcQgACQJ8QgAxnu4i4MyK2ftzvLTMABwYGstPpZKfTyW632+v3NQAwRLfbfeyzemBgQADyBNMi4pGIuDci/rj4GIyIByLiS0NeawYQABpjBpDhrBcRWww5BiNi/4jYeMhrBSAANEYAsqJsAwMAfUIAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAUksAAkBjBCC1BCAANEYAMpwPR8TNEfFgRNwbEZdExNQRXisAAaAxApDhbB8RGy3++doRMT0i7o6INYZ5rQAEgMYIQJZnQkQcGRGLImLTYb4uAAGgMQKQkewTEQ9ExGBELIyIT43wOgEIAI0RgCzPxhFxRES8cYSvC0AAaIwAZEWsEWVByPOG+ZoABIDGCEBWxNoR8XBE7DfM1yZHRA4MDGSn08lOp5PdbrfX72sAYIhut/vYZ/XAwIAA5AkOj4inLf75UyPiyxFxf0Q8fZjXmgEEgMaYAWQ4F0fEXRExNyLuiIgLI2KXEV4rAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQABojAKklAAGgMQKQWgIQAFZj8+dnzpyZ+bOfZX7nO5mf+1zmUUcJQOoIQADogYULM++4I/PqqzMvuijzi1/MPP74zHe+M/M1r8mcOjXzqU/NjMhcc83MzTfP3GWXzNe+NnPaNAFIHQEIAKNocDDzgQcyr78+89JLM888M/OjH818z3syX//6zBe8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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# To force an orthonormal frame, use orthonormal=True on the plot\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(1, 10, 100)\n",
"y = np.log(x)\n",
"ax.plot(x, y)\n",
"ax.axis(\"equal\")\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using subplots"
]
},
{
"cell_type": "code",
"execution_count": 45,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdebiOVdsG8KWSkJkMEZlJpjKlzGPJnDEqFGVq4y0iMmTKrDILRUmmItucZMhcSco8DyHzvPf5/bHaX2jv7Xmee6113Xt3/o7D8dX23Ne13rzv95ytda+1lCIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIqI4qqFS6nul1DmlVIRS6p67fD6lUmq6UuqsUuqMUupTpVQKmwMkIiIiIrMqKx0CX1GBBcCFSqklSqlUSqnUSqmlSql5NgdIRERERHaUVXcPgI8opSKVUgVu+VnBv3+W2d7QiIiIiMiGQAJgTaXU5Wh+flUpVcPGoIiIiIjInkAC4ItKqWPR/Py4UqpJND9PoJR6WCmVnL/4i7/Efj2s9P8WiYiI/sXGDODDSinwF3/xl/ivhxUREVE0yqrA3gGMULe/A1jo759F9w5gcqUUDh06hHPnzvnu19mz55A58zm0bn0OpUqdQ65cwddo27at+H8OG782bz6HhAnPoUOHc8iQoS1efll+TLZ+BftnOGrUOaRKdQ7t25/Do4+ew5Qp8v8ZYvp16NChqACY3Mz/myAiovjiHqVUIqVUFaWDXJK//z6mJaNvlFLhSqk0Sqm0Su8CnhvDZ5MrpXDu3Dn40YYNQIoUwNWrwIULQMKEwJ49wdUICwuzMzhhw4YBVarov65bNwyZMwORkbJjsiXYP8M6dYD+/fVf9+gBNGhgYVCGnDt3jgGQiIii9ZLSu3gj/v4V9ddllFJZlFIXlFKlb/l8SqXUZ0qfA/iXUmqaivnLxdcB8O23gRdf/Ofvy5QBxo8PrkZ8DYAVKwIjR+q/7tAhDEmTAtu2yY7JlmD+DG/e1P/SsGGD/vutW4GkSYHLly0NziMGQCIikuDbABgZCeTIAcyd+8/P+vQBXnghuDrh4eFmB+YD58/r2dDdu/Xfh4eHo1Yt4P33ZcdlSzB/huvXA6lS6SAIRP/fIz9hACQiIgm+DYDbtv175mbdOiB1aiAiQm5cfjB7NpAnz+0/Gz8eeOopmfH4Sb9+QL16t//srbdun0n2EwZAIiKS4NsAGN27WzduAMmTA5s3y4zJL1q0ADp1uv1nhw8D994LnDolMya/KFcOGDPm9p9t2KD/e3P1qsyYYsMASEREEnwbAAsWBD7//N8/r1ULGDTI/Xj8IiICyJABWL78379XuDDw2Wfux+QXFy8C99//z9J4lMhIIEsWYMkSmXHFhgGQiIgk+DIAXr9++ztutxo9GqhUyf2Y/GLrViBZMuDatX//XvfuQNOm7sfkF4sWAdmyRb8bunZtvXPabxgAiYhIgi8D4O+/A4kS/fMi/61++03/3pUr7sflB1OnAs88E/3vzZunZ07/qzp3Blq1iv73unYFXnvN7XgCwQBIREQSfBkA588HHn88+t+LjNTvc8XXI0/upnt3oGXL6H9vxw4gceL/7iaZSpViPiZoypSYg7MkBkAiIpLgywA4aFDsx70ULQrMmuVuPH7ywgsxvwN59Spwzz3AwYNux+QXWbMCK1dG/3s//gikS+dyNIFhACQiIgm+DIAvvwy8+27Mv9+wITBggLvx+EmhQrGfaZcjB7B0qbvx+MXVq0CCBHo3dHTOngWU8t8uaQZAIiKS4MsAWLIkMH16zL/fo4c+CuW/JiJCL/Hu2BHzZ6pXBz76yN2Y/CKQ5e+MGYE1a9yNKRAMgEREJMF3ATAyEkiZEtiyJebPTJmir4X7rzl4UC/xxnaeXceO+td/TWzvjUYpXx6YONHNeALFAEhERBJ8FwCPH9dLdRcvxvyZNWv0bM5/zbJlQPbssX/m44+BatXcjMdPhg4F6tSJ/TOvvw506eJmPIFiACQiIgm+C4ArVwKPPBL7Z06cuHtIjI8+/lgv8cYmkJAYH7Vpo698i82oUUCNGm7GEygGQCIikuC7ADhmDFClSuyf+a8eBRPI8m4gy8TxUWxHwERZsgTImdPNeALFAEhERBJ8FwADfYetaFHgq6/sj8dPAtngEREBJEkC/PqrmzH5RWxHwESJCsd+OkScAZCIiCT4LgBWrapnAe/mv3gUTI4ceon3bu52VEx8c+WKPgLm0KHYPxcRASRNCvzyi5txBYIBkIiIJPguAAYykwPoo2BiuhEjPrp2LfBDnhs0iPmw6PgomBtQ/HaIOAMgERFJ8FUAvHhRb+44duzun/2vHQUTTMj5r52TOH8+UKBAYJ9t2hTo08fueILBAEhERBJ8FQC3b9dLdJGRd//smjVApkz2x+QX8+YBBQsG9tlp04Cnn7Y7Hj8J5AiYKD176ptm/IIBkIiIJPgqAC5eDOTOHdhn/2tHwQweHPv9yLfy6723tgRyBEyUceOAypXtjicYDIBERCTBVwFw8mSgQoXAPvtfOwrmjTeA//0vsM9GhePLl+2OyS8COQImysKFQP78dscTDAZAIiKS4KsA2KcP0KxZ4J/32wv9NtWuDYwYEdhnIyKAhAmB3bvtjskvsmYFVqwI7LPbtul/cfALBkAiIpLgqwDYujXQtWvgn69bFxg+3N54/KR4ceDLLwP//COPAN9/b288fhERAdx7L7B3b2Cf//NPPTt64YLdcQWKAZCIiCT4KgDWqAGMHh3459u2DXxZNK57+GG98SVQpUoBn39ubzx+EXV3dKCHO0dGAokSATt32h1XoBgAiYhIgq8CYJEiwJw5gX/+/ff1sR7x3c2bepZr377An6lXT++Oje+2bAFSpQrumezZgeXL7YwnWAyAREQkwVcBMF06YMOGwD//ySdA+fLWhuMbR4/qWa5g7vft0AHo1MnemPxi4ULgsceCe+aZZ/RROX7AAEhERBJ8EwCvXtUh58iRwJ8JDwfy5rU3Jr/YtAlImza4ZwYOBBo1sjMeP5kwQe8CDkajRkD//nbGEywGQCIikuCbALhvn17mvHkz8Gd+/tlfOzptmT9f3+8bjGnT/hs3pfTuDTRvHtwzXbro90f9gAGQiIgk+CYArl6tNzoEI2pHZ3w/DHrMGKB69eCeWb4cyJHDznj8pE2b4HaOA3rneO3adsYTLAZAIiKS4JsA+MUXQIkSwT0TGanPu9u1y86Y/KJHD6BVq+Ce+e03fXdwINfqxWU1awIjRwb3zJdfAsWK2RlPsBgAiYhIgm8C4NCh+ly/YGXNCqxaZXw4vtKihb7DNhjnz+vZ0TNn7IzJL558MvjDwNesATJmtDOeYDEAEhGRBN8EwE6dgPbtg3+uZMn4f95d1arA2LHBP/fgg8D27ebH4yfBno8IAAcOAPfcA9y4YWdMwWAAJCIiCb4JgA0a6J2rwapbFxg2zPx4/OTxx4Fvvgn+udy5gSVLzI/HL0I5HxEArl8HEiQADh2yMqygMAASEZEE3wTA0qWBTz8N/rl27fSuzvgsTRpg8+bgnytfXp+VGF8dOxbcLSC3Sp8eWL/e/JiCxQBIREQSfBMAs2UDVq4M/rn33weaNDE+HN+4ckWHnOPHg3+2aVP9zye+2rIFSJ06tGefeAKYPdvseELBAEhERBJ8EQAjIoD77wf++CP4Z+P7bSB79wL33af/GQXrrbeAN94wPya/WLAAKFAgtGdD2T1sAwMgERFJ8EUAPHFCz3JduhT8s4sXA3nymB+TX6xeDWTJEtqzI0b457w7G8aPBypXDu3Z11/XAVkaAyAREUnwRQDcsgVImTK0Z3/+GUiWzOx4/GTmzODPR4zy5ZdA8eJmx+MnvXsDL70U2rP9+uklcmkMgEREJMEXAfCbb0Jfyjt1Ss8eXrhgdkx+MWxYaOcjAvp4lGBvV4lLWrcGunUL7dkpU4By5cyOJxQMgEREJMEXAXDcOKBKldCejYwM/f3BuKBLF73TORSh3K8clzz/PDBqVGjPLlkC5MpldjyhYAAkIiIJvgiAffsCL74Y+vNZswLffWdsOL7SuDEwYEBoz169qmdHjx41Oya/ePJJ4KuvQnt227bQXzswiQGQiIgk+CIAtm+vbwIJValSwIwZ5sbjJ2XLAlOnhv582rTAxo3GhuMrmTIBa9eG9uzRozocX7tmdkzBYgAkIiIJvgiAjRqFPssFAPXq6buE46M8efRO51AVKKCPS4lvom4B2b8/tOevX9cB8MgRs+MKFgMgERFJ8EUArFgRmDgx9OfbtQM6dzY3Hj9JnVrvkg5VfL0NJOoWkKtXQ6+RMqVeCpbEAEhERBJ8EQALFgTmzw/9+fff1+/KxTc3bug7aw8eDL1GgwbABx+YG5NfeLkFJEquXMDSpWbGEyoGQCIikuCLAJghA7BuXejPT5gAVKpkbjx+EXVAdih33UZ54w1/HHhsWng4kDevtxqlSwPTp5sZT6gYAImISIJ4AIyM1Fed7d4deo1584DChc2NyS+2bwcefNBbjV69gFdeMTIcX/nsM+CZZ7zVqF1b35YiiQGQiIgkiAfAM2f0LJeXIfzwA5A5s7kx+cXKlcCjj3qr8eGHQI0aRobjKyNGAHXqeKvx6qtA9+5mxhMqBkAiIpIgHgB//10f5BwZ6a1GokTeaviRiavcvFwl52fduwOvveatxjvveK/hFQMgERFJEA+Aq1d7n707fTp+Xgf30UfAs896q7FiBZA9u5nx+Enr1jrAeTFihF4GlsQASEREEsQD4Jw5QJEi3mpEROgz4fbuNTMmv+jdG3jpJW81fvkFSJ7cyHB8pW5dfU+yF9On640gkhgAiYhIgngA9HIP8K0eegjYsMF7HT9p107fBeyFifPy/KhMGeDTT73VWLIEyJ3bzHhCxQBIREQSxANgv35A06be6+TPDyxc6L2OnzRsCAwa5K1G1I0Xhw+bGZNf5MsHLFrkrcbWrUCqVGbGEyoGQCIikiAeADt2BMLCvNfxemeuH1WoAEye7L1OqlQ67MQn6dIBmzZ5q3HkiA7H16+bGVMoGACJiEiCeABs3Bjo3997nfh4H/DjjwNff+29Tu7cerkzvoiIAO65J/R7gKNcu6YD4NGjZsYVCgZAIiKSIB4AK1XSN3l41aYN0LWr9zp+kjGjtxtSopQuDcyY4b2OX5w6pYPbpUvea6VIAfz0k/c6oWIAJCIiCeIBsFAhfZOHVz16AK1aea/jF5GRQMKE3m5IiVKrFjBypPc6frFzJ5A4sZlaOXMCy5aZqRUKBkAiIpIgHgAzZQLWrvVeZ8QIHXTii7/+8n5DSpRWrXRAji9WrwayZDFT66mngM8/N1MrFAyAREQkQTQARs1y7drlvZYfznQz6Y8/vN+QEqVbN31wcnwxdy5QtKiZWtKzowyAREQkQTQARs1ynT3rvdbixfJnupm0Zo2eHTVh2DB9cHJ8MX68mbMjAfnZUQZAIiKSIBoA//hDzwCamOXasgVIndp7Hb+YN0+/H2nCp58CzzxjppYf9O9v5uxIQH52lAGQiIgkiAbANWuAhx82U+vgQSBBAuDGDTP1pE2cqHdImxAerg9Oji86ddLnR5owfLjs7CgDIBERSRANgHPnAoULm6l1+bJeTj5xwkw9aQMG6DMSTdi0CUib1kwtP2jWTN8gY8JnnwFPP22mVigYAImISIJoABw/Hqhc2Vy9pEmBX381V09Sp05Ahw5mah04oGdHb940U09a9erA2LFmai1eDOTJY6ZWKBgAiYhIgmgAfP99oEkTc/WyZgW++85cPUnNmgF9+pipFTU7evKkmXrSnnwS+OorM7Wk3x1lACQiIgmiAfDNN/UvU0wGA2nVqgFjxpirF59mR7NlA1atMlPr8GEdjqXeHWUAJCIiCaIBsEkTPQtoSrVq5pYGpZkOsyZDk7QHHzQXZqPuAz52zEy9YDEAEhGRBNEAWK0aMG6cuXrNmgF9+5qrJylrVrOBrVix+DE7euWK+eXsZMnkZkcZAImISIJoACxeHJg1y1y9sDBzx4NIS5IE2LHDXL3q1c0uKUs5dMj8hpasWfX1chIYAImISIJoAMyRA1i+3Fy9/v3NbiqRcumS+Vmu5s3NbSqRtGULkCaN2ZpFiuiDtyUwABIRkQTRAJgqFbB1q7l6Jq8Ik3TwoA6AJme5TB6eLGnJEvPHtlSsCEyebLZmoBgAiYhIglgAvHlTL+UdOGCu5pw5ejYnrtu2DUiZ0mzNfv30O5Jx3fTpQOnSZmu+8AIwZIjZmoFiACQiIgliAfD0aT3LdeGCuZqrVwNZspirJ2XlSiB7drM1P/4YqFHDbE0JI0cCtWubrdm6NfDOO2ZrBooBkIiIJIgFwF27gIQJgchIczV37AASJzZXT8rs2cATT5it+fnnwFNPma0poWdPoGVLszW7dQPatDFbM1AMgEREJEEsAP74I5A+vdmax4/rWcWrV83WdW3CBLNX5AH6yrO8ec3WlNCuHfC//5mt+cEHQIMGZmsGigGQiIgkiAXARYuAfPnM1pQ+1NeUQYOAhg3N1ty4EXjoIbM1JTRtCgwYYLbmpElApUpmawaKAZCIiCSIBUAbL/MD8ePKs65dgddfN1tzzx7gvvvMLrlLqF7d/G0vc+cCRYuarRkoBkAiIpIgFgBHjwaef9583SxZ5A71NeW114Du3c3W/Osv85tuJJQoAXz5pdmaq1bpq/IkMAASEZEEsQDYuzfw0kvm6xYsCHz9tfm6LtWvb/5YkogI88fuSMidG1i61GzNX34Bkic3WzNQDIBERCRBLAB27KivbjOtXDlgyhTzdV2qUMHOwcSpU5s9eFtC2rTA5s1max45omdHr183WzcQDIBERCRBLAA2awb07Wu+bp06wPDh5uu6VLiwnavJcuY0e/Wea5GRwL33Anv3mq17+bL5q/cCxQBIREQSxALgc88BH31kvm7LlsC775qv61LWrMD335uvW7w4MGuW+bqunDung9rZs+ZrJ04M7Nxpvu7dMAASEZEEsQBYqpQ+nNi0//1PnxUXlyVLpt9LM61qVWDcOPN1Xdm/X88A2tjJ/PDDwNq15uveDQMgERFJEAuAefLow4lN698faNLEfF1Xrl/Xs1xHjpiv3bgxMHCg+bqubNkCpEljp/bjjwMLFtipHRsGQCIikiAWANOl04cTmzZ2rD4rLq46cUIHwMuXzddu2xZ46y3zdV1ZvhzIlctO7bJlgWnT7NSODQMgERFJEAmAUS/z79ljvvbMmfqsuLhq50579xm/+y7QqpWd2i7MmqXfY7ShTh1gxAg7tWPDAEhERBJEAmDUy/x//WW+9tKl9maJXFi7Vr+PZsPw4UDdunZquzBuHFCtmp3aLVsCPXvaqR0bBkAiIopNb6XUEaXUBaXUd0qpx2L57HdKqWtKqfN/f/68UqpNDJ8VCYD79gH33KMPJzZt0yZ9VlxctWABUKCAndpTpuhzEuOqgQP1e4w2SG0eYgAkIqKY/E8pdUAplV8plUgp1V8pdVgplSSGz69UOjAGQiQAbt5s72X+vXvt7RR1Ydo0oEwZO7W//hooVMhObRfeeku/x2jDgAEym4cYAImIKCZ7lVLtbvn7e5VSJ5RSTWP4/EqlVJ8Aa4sEQJvLtFF33grsazFixAigdm07tX/4Qd+VHFe9+irQo4ed2jaXl2PDAEhERNFJrpSKVEqVuOPni5VSQ2J4ZqVS6k+l1Gml1A6l1AClVNJY6jsPgDY3akRE6OXlffvs1LetVy+gRQs7tXfsAJImtVPbhXr1gGHD7NS2ucEkNgyAREQUncxKB8A8d/z8C6XU+BieKamUSvn3Xz+ulNqilPo8hs+KBMAxY+we1ZImjT4zLi5q3x7o0sVO7ePH9ezo1at26ttWoYK9e56XL9dX5bnGAEhERNEJZQbwTmWUUteVfn8wuvpo27YtwsLCEBYWhvDwcOtfeu+/DzRtaq9+zpzAsmX26tvUtKn+52PDtWs6AB47Zqe+bYULA/Pn26m9dSuQOrWd2ncKDw////+9tW3blgGQiIiiFd07gCdVzO8A3ikqAD4Qze+JzAB27qxnumyJy3feVq+uZ0htSZpULwXHRVmzAqtX26l94ACQIIGdnemx4QwgERHFpItSar/SR78kVvqdvkMq+l3ADymlqt7ye48ppTYqpWbFUFskAL7yin7XzZa4fOdtyZL6HUlbsmTRm0HiomTJgO3b7dS+cEHPjp45Y6d+TBgAiYgoNu8ppY4ppS6q288BzKL0WX+l//77R5RSPyql/lL6/L8/lA83gdSqBYwcaa9+48b6WI+4KHduvUvalkKF9HEwcU3UHclHj9qpHxkJJEwI7N5tp35MGACJiEiCSAB85hng00/t1X/jjbh7523atPowa1vKlbO3kcKmkyd1ALxyxV6P9OmBDRvs1Y8OAyAREUkQCYCPPQYsXGivfo8ecfPO26gjbPbutdejbl17R6nYZPOO5Cj58gEO9kDdhgGQiIgkiATAjBmBdevs1R86VJ8ZF9ecPatnuc6etdejVSvg3Xft1bdl3TogUya7PUqXBmbMsNvjTgyAREQkQSQAJkqkZ3Rs+eQToHx5e/Vt2bfP/jV2Nq9Ts2nhQnt3JEd5/nngww/t9rgTAyAREUlwHgCvXNGzXCdO2Osxf74+My6u2bxZvwNo08CBepNMXPPZZ/buSI7SrBnQr5/dHndiACQiIgnOA+CxYzoAXrtmr8f33wOPPGKvvi0270iOMm6cPiYnrhk1Su8et8nmLSwxYQAkIiIJzgPgb78BSZLY7bF9uz4zLq6ZOdP+fbSzZgHFitntYUPv3vr8SJt69nS/eYgBkIiIJDgPgC5e5j9yRM8yXr9ut49p48YB1arZ7bFsmf1ZRhs6dgQ6dbLbY9gwoH59uz3uxABIREQSnAfAb78F8ue32+PyZR0AT56028e0QYOARo3s9ti0CUiXzm4PG5o3t/9+3uTJQMWKdnvciQGQiIgkOA+AM2YATz1lv88DD9jdaWxDt25AmzZ2e+zerW+8sLnT2IYaNYCPPrLbY84c4Ikn7Pa4EwMgERFJcB4AP/4YeO45+30yZQLWrrXfx6TXXwe6drXb49QpPTt66ZLdPqa5OKNvxQogRw67Pe7EAEhERBKcB8D+/YGmTe33yZ8fWLTIfh+TGjfWx7TYdOOGDoBHjtjtY9pjj9n/89y6FUiTxm6POzEAEhGRBOcB0NVBxE89BXz+uf0+JlWvDowda7/Pgw8Cv/5qv49JDz9s9/YYwM1B3HdiACQiIgnOA+CrrwLdu9vv8+yzwJgx9vuYVLIk8MUX9vtkzgz88IP9PiYlTaqPELLpr7/07Oj583b73IoBkIiIJDgPgC+8AHzwgf0+TZoAAwbY72NS3rxAeLj9PgUKAAsW2O9jyvXrOpgdO2a3T0QEkCABcPCg3T63YgAkIiIJzgNg5crAxIn2+7zxBvD22/b7mJQhA/Djj/b7PPOMvlotrvjzTx0Ar1yx3ytFCuDnn+33icIASEREEpwHwGLFgK++st/nnXeA1q3t9zHpgQeA33+33+f554EPP7Tfx5Rdu4BEidz0yppVXyXoCgMgERFJcB4Ac+XSt1HYNngw0LCh/T6mXLmiZ7lOnLDfq1kz+4cqm7RxI5A+vZtehQsDX3/tphfAAEhERDKcB8C0afVtFLaNHw9UrWq/jynHj+sAePWq/V7t2wNdutjvY8rSpUCePG56lSsHTJ3qphfAAEhERDKcBsDISOC++/RtFLZ9+SVQooT9Pqbs3AkkTuym17vvAq1auellwqxZ7v4sa9cGRo500wtgACQiIhlOA+DFi3qW6/Rp+72WLHE3a2TC+vVAxoxueg0dCtSv76aXCRMmuJvNfflloHdvN70ABkAiIpLhNAAePqwD4I0b9ntt2ODuvTETwsOBfPnc9Jo0CahUyU0vEz74wN37nG++CYSFuekFMAASEZEMpwFw+3YgWTInrfDHH+52jprwxRdAqVJues2eDTz5pJteJnTv7m5Hd+/ewCuvuOkFMAASEZEMpwFw9WogSxYnrXDihLuz40wYO1ZfBefC8uVAzpxuepnQtq2+QtCFkSP1e4CuMAASEZEEpwHwm2+Axx930gpXr7q5PcKUgQOBxo3d9Nq8We/GjiuaNgX693fTa+pUvRPYFQZAIiKS4DQAfvopUKaMk1YA9K5a2/fHmvL228Drr7vptWcPcO+9eld2XPDcc8DHH7vpNX++PgvQFQZAIiKS4DQAjh4N1KzppBUAvat2/Xp3/bxo3Rro1s1Nr9On9ezohQtu+nn19NPAjBlueq1aBWTL5qYXwABIREQynAbAvn2B5s2dtAKgd9WGh7vr50XDhsCgQW563bypA+ChQ276eVWgAPDtt256/fQTkDKlm14AAyAREclwGgA7dQI6dHDSCoDeVfvFF+76eVG1qr69xJXkyYFffnHXz4vMmYG1a930OngQSJAAiIhw048BkIiIJDgNgC1aAL16OWkFQO+qHTvWXT8vSpTQt5e48sgjeld2XPDgg8COHW56nT+vZ0f/+stNPwZAIiKS4DQA1q0LDB/upBUAvat24EB3/bzIk0ffXuJKwYJ6V7bf3bihA9nRo276RUYC99wD7Nvnph8DIBERSXAaACtUAD75xEkrAHpXbdeu7vp5kT69vr3ElTJl9K5svzt1SgfAy5fd9UydGti61U0vBkAiIpLgNAAWLQrMneukFQC9q7ZNG3f9vEiUSN9e4krNmnpXtt/t3g3cf7/bI2uyZwdWrnTTiwGQiIgkOA2Ajz7q7osV0LtqGzVy1y9UV67oWa6TJ931bN5c78r2u1oYPEEAACAASURBVE2bgIcectvziSeAOXPc9GIAJCIiCU4DYKpUwLZtTloBAMaNA6pVc9cvVMeO6QB47Zq7nh06AJ07u+sXqmXLgNy53fasWBGYPNlNLwZAIiKS4CwARkTol+v377fe6v/NnAmULOmuX6h++w1IksRtz549gZYt3fYMxVdfAcWLu+1Zrx4wbJibXgyAREQkwVkAPHdOz3KdPWu91f9bvBjIm9ddv1CtWwdkyuS257BhOuj43cSJQJUqbnu2bKkDsgsMgEREJMFZADxwwO0BuwDw449Ahgzu+oVq0SIgf363PSdP1kudfjdkCNCggduenTu7O7CcAZCIiCQ4C4Dbtrm9YgsAfv8deOABtz1DMWMG8NRTbnvOmaN3Zftdjx7Aa6+57dm3L9CsmZteDIBERCTBWQD87jsgWzbrbW5z4oRedr5yxW3fYH38MfDss257rlihjzvxu3btgLfecttz9Gjg+efd9GIAJCIiCc4C4Pz5QKFC1tvc5upVHQCPH3fbN1j9+wNNm7rtuXWrPvDY7158Uf/zcWnaNH1QtgsMgEREJMFZAJw6FShb1nqbf0mcGNi5033fYLz1FtC2rdue+/bpXdkuD1gORY0aeobUpa+/1lflucAASEREEpwFwFGj9O0TrmXMCKxf775vMF57Deje3W3Pv/7Ss6Pnz7vtG6ynn9bvSLq0ahWQNaubXgyAREQkwVkAdPli/a3y5QPCw933DUaDBsDgwW57RkToAHjwoNu+wSpQAPj2W7c9XW5YYgAkIiIJzgJgly5A+/bW2/xLqVLAF1+47xuMqlX1rSWuJUsG/PKL+77ByJwZWLvWbc/9+/XyuIsjixgAiYhIgrMA2KqVPtLDterVgbFj3fcNRsmS+tYS17JkAX74wX3fYDz4ILBjh9ueUcvjLm5IZAAkIiIJzgLgCy8AH3xgvc2/NG4MDBjgvm8w8uaVWaYuUABYsMB930DduKGD2JEjbvvevOlueZwBkIiIJDgLgFWqABMmWG/zL23aAF27uu8bjIwZ9XVwrpUuDUyf7r5voE6d0kHs0iX3vZMnd7M8zgBIREQSnAXA4sWBL7+03uZf3n4beP11932DkSSJ+2VOQB8+7fqIlWDs2QPcd5/MUTVZsgCrV9vvwwBIREQSnAXAPHmAxYutt/mX/v2BJk3c9w3U9et6luvoUfe9mzTx9/L4li1AmjQyvV0tjzMAEhGRBGcBMEMGmfP4PvoIeO45930D9eefcsucr7+uZ0j9auVKuevqXC2PMwASEZEEZwFQ6kaOzz7Thwn71e7dcsucXbvqdyT9at48oEgRmd7PPedmeZwBkIiIJDgJgNeu6VmuY8estonWggV6Oc+vNm+WW+YcMEDvkvarKVOA8uVlejdp4uYOYgZAIiKS4CQAnjypA+Dly1bbRGv1av1Cv1+tWAHkyCHTe8wYvRHEr0aOBGrXluntanmcAZCIiCQ4CYC7dgH33y+zzPnzz/pID7+aMwcoWlSm94wZwFNPyfQORJ8+wEsvyfTu1s3N8jgDIBERSXASADduBNKls9oiRgcOAAkSuLnWKxSffCK3zLlwIfDYYzK9A9G5M9Chg0zvgQOBRo3s92EAJCIiCU4C4LJlQM6cVlvE6OxZvfx89qxM/7sZMUJumfOHH/Rdu37VqhXw7rsyvceM0dcI2sYASEREEpwEwNmzgSeftNoiRhERegbwwAGZ/nfTu7fcMucvvwDJksn0DsQLLwBDhsj0/vxzN8vjDIBERCTBSQCcNAmoWNFqi1ilSAH89JNc/9iEhQEdO8r0PnRIz47evCnT/24qVwYmTpTp/e23QP789vswABIRkQQnAXDYMKBuXastYvXII8D338v1j02LFkDPnjK9z5/XAfDMGZn+d1O8ODBrlkzvNWuAhx+234cBkIiIJDgJgL16Aa+8YrVFrB5/HPjmG7n+salXDxg6VKZ3ZCRwzz3Avn0y/e8mTx5gyRKZ3tu3Aw8+aL8PAyAREUlwEgDffFMvdUp5+ml9I4gfVaokt8wJAClTAtu2yfWPTYYMwI8/yvQ+fFjPjt64YbcPAyAREUlwEgBffhl47z2rLWJVo4a+E9iPihUDvvpKrn+2bMCqVXL9YyN1fSAAXLigA+Dp03b7MAASEZEEJwGwTh1g+HCrLWLVtCnw/vty/WOTKxewdKlc/0KFgPnz5frHRPL6QEAvj997L7B3r90+DIBERCTBSQCsUEEfeCzljTeAt96S6x+bhx4CNmyQ61+mDDBtmlz/mERdH3jlitwYUqcGtm6124MBkIiIJDgJgEWL6ivPpHTrBrRuLdc/NokSAb//Ltf/+eeB0aPl+sck6vpASY8+CqxcabcHAyAREUlwEgBz5ACWL7faIlaurvUK1pUrepbrxAm5MTRrBvTrJ9c/Jps2yV0fGKVwYWDePLs9GACJiEiCkwCYNq3+Qpcydqyba72Cdfy4DoBXr8qNoV07oEsXuf4xWb5c7vrAKGXLAlOn2u3BAEhERBKsB8DISCBhQmD3bmst7urzz4FSpeT6x+T33/USsKTu3YFXX5UdQ3RmzwaeeEJ2DLVqAaNG2e3BAEhERBKsB8BLl/Qs159/WmtxV66u9QrWhg16E4ikwYOBBg1kxxCdyZP15iFJzZsDffrY7cEASEREEqwHwKNHdQC8ft1ai7tyda1XsJYuBXLnlh3D+PFA1aqyY4jO8OGy1wcCQPv2QOfOdnswABIRkQTrAfC334AkSayVD4ira72CNWuWPgha0syZQIkSsmOIznvvyV4fCADvvgu0amW3BwMgERFJsB4A160DMma0Vj4grq71CtbEifoqOEnh4UDevLJjiE5YmL5CUNKQIUD9+nZ7MAASEZEE6wHQDwHD1bVewRo6FKhXT3YMfgjo0XnlFaBXL9kxTJgAVK5stwcDIBERSbAeAGfOBEqWtFY+IK6u9QpWz55Ay5ayY/DDEn106tYFhg2THcOsWUDx4nZ7MAASEZEE6wFw3Dh/bDJIlcr+tV7B6tAB6NRJdgx+2KQTnYoVgUmTZMewZIn9TToMgEREJMF6APTLMSPZsgHffSc9itu99BLQu7fsGPxwTE90nnxSnwUo6ccfgfTp7fZgACQiIgnWA6BfDhouXBiYP196FLerXRsYMUJ2DJGRwH33yR7UHZ1cuYBly2THsHMn8MADdnswABIRkQTrAdAvV425uNYrWOXLA1OmSI9CX9W3ebP0KG6XLh2wcaPsGI4d07Oj167Z68EASEREEqwHwGbNgL59rZUPWM2a9q/1ClaRIsDcudKjAHLk0Hfv+sn99wN//CE7hsuXdQA8edJeDwZAIiKSYD0A1qwJjB5trXzA/BJEb5U9O7BihfQogKJFgTlzpEfxjytXdPA6cUJ2HJGROoju2mWvBwMgERFJsB4Ay5YFpk2zVj5gflmKvlWaNP5Yei1fHvjkE+lR/OP4cR0Ar16VHoleit60yV59BkAiIpJgPQAWKuSPzRc9evhjM0oUP22+8MNmlFv9/rv9zReBypnT7mYUBkAiIpJgPQD65fiVDz4AXnhBehT/8NPxK344juZWLo5fCdQTT9g9joYBkIiIJFgPgH45gHn8eKBKFelR/MNPBzD74UDqW7k4gDlQFSoAkyfbq88ASEREEqwGQD9dwTZzJlCihPQo/uGnK9j8cCXdrWbNAooVkx6FVqcOMHy4vfoMgEREJMFqALxwQc9ynT5tpXxQwsOBvHmlR/GPdeuAjBmlR6ENHQrUqyc9in9MnAhUqiQ9Cu3ll4H33rNXnwGQiIhi01spdUQpdUEp9Z1S6rFYPptSKTVdKXVWKXVGKfWpUipFDJ+1GgAPH9YB8MYNK+WD4qfABfgrkPopcAH+CqQdOwJhYfbqMwASEVFM/qeUOqCUyq+USqSU6q+UOqyUShLD5xcqpZYopVIppVIrpZYqpebF8FmrAfDXX4GkSa2UDtqOHf5ZcgX8tSTtpyVXQC9Jt2ghPQrN9lgYAImIKCZ7lVLtbvn7e5VSJ5RSTaP57CNKqUilVIFbflbw759ljubzVgPg2rVApkxWSgftyBH/bLoA/LUpxU+bLgD7s27BsD0byQBIRETRSa50eCtxx88XK6WGRPP5mkqpy9H8/KpSqkYM9a0FwEWLgHz5rJQOWtSxK6dOSY9E89OxNH46dgXQ79355Vga28vjDIBERBSdzEoHwDx3/PwLpdT4aD7/olLqWDQ/P66UahLNz60GwC++AEqWtFI6aH46eBnQB1O3aiU9Cm3nTv8cvAz462Bq28vjDIBERBQdJzOAbdu2RVhYGMLCwhAeHm7sy23cOKBqVWPlPPPL1WsA0L490Lmz9Ci0Y8f07Oi1a9Ij0fx0NZ2N5fHw8PD//99b27ZtGQCJiCha0b0DeFLF/A5ghLr9HcBCf//M+TuAgwcDDRpYKR2S7NmBFSukR6E1bw706SM9Cu3yZR0AT56UHolWtCgwZ470KDTby+OcASQioph0UUrtV/rol8RKqQFKqUMq5l3A3yilwpVSaZRSaZXeBTw3hs9aDYDdu/vr/t0iRYC5c6VHodWqBYwcKT0KLTISSJgQ2LVLeiRajhzA8uXSo9BsL48zABIRUWzeU/rdvovq9nMAsyh9NmDpWz6bUin1mdLnAP6llJqmYv5ysRoA27UDunSxUjok5coBU6ZIj0Lz01gAIG1aYNMm6VFofhqL7eVxBkAiIpJgNQA2awb07WuldEj8NOvmp9lIwD+zbn6bjbS9PM4ASEREEqwGwJo1gdGjrZQOiZ/eu/PT+4iAf96789v7iJGRwP332wukDIBERCTBagAsUwaYNs1K6ZD4aeetn3YkA/7Zeeu3HckAkC4dsHGjndoMgEREJMFqACxUCJg/30rpkPjl7L2oMwn37JEeyT/q1PHH2Xt+O5MQAHLmBJYts1ObAZCIiCRYDYDZsgHffWeldEj8cvvGxYv+upUE0LdvvPee9Cj8dysJADzxBDB7tp3aDIBERCTBagBMlQrYutVK6ZBMmOCP+3f9di8x4J/7d5csAfLkkR7F7SpUACZPtlObAZCIiCRYC4CRkcC99wJ79xovHbIvvwSKF5ceBbBjB5AkifQobtezJ9CihfQo/PNndKs6dYDhw+3UZgAkIiIJ1gLghQt6luv0aeOlQ7Z4sT9ml9atAzJmlB7F7YYOBerVkx6FnqWtXFl6FLezuTzOAEhERBKsBcDDh3UAvHHDeOmQrV8PZMggPQogPBzIm1d6FLebOBGoVEl6FMCQIUD9+tKjuJ3N5XEGQCIikmAtAP76K5A0qfGynvz2G5A4sfQogJkzgRIlpEdxu1mzgGLFpEcBvPsu0LKl9ChuZ3N5nAGQiIgkWAuAa9cCmTIZL+vJ0aP+2Hwxfrw/NqPcaskSIHdu6VEAHToAnTpJj+J2NpfHGQCJiEiCtQC4aBGQL5/xsp5cuqQD4J9/yo7DL8fR3Movx6+89BLQu7f0KG5nc3mcAZCIiCRYC4BffAGULGm8rCdRBzDv3i07Dr8cSH0rvxzAXLu2Pw6kvpXN5XEGQCIikmAtAI4bB1StarysZ364gs1PV9JF8csVbH65ku5WNpfHGQCJiEiCtQA4eDDQoIHxsp5lzw6sWCE7hubNgT59ZMdwp8uXdQA8eVJ2HEWLAnPmyI7hTjaXxxkAiYhIgrUA2L078Oqrxst6VqQIMHeu7Bhq1QJGjpQdw50iI4GECYFdu2THkSMHsHy57BjuZHN5nAGQiIgkWAuA7doBXboYL+tZuXLAlCkcQ3TSpgU2beIY7mRzeZwBkIiIJFgLgM2aAX37Gi/rWe3a8rNvRYoA8+bJjiE6OXPKzr5FzUJKb9K5k83lcQZAIiKSYC0A1qwJjB5tvKxnfjhm5NFHgZUrZccQnSeeAGbPluvvl2N67hQZCdx/v53lcQZAIiKSYC0AlikDTJtmvKxnfjhoOHVqYMsW2TFEp0IFYPJkuf5+Oag7OunSARs3mq/LAEhERBKsBcBChYD5842X9Uz6qrHISODee4E9e+TGEJM6dYDhw+X6++WqvujkzAksW2a+LgMgERFJsBYAs2UDvvvOeFnPhgwB6teX63/xop7lOnVKbgwxefll4L335PqvXw9kyCDXPza2lscZAImISIK1AJgqFbBtm/Gynk2YAFSuLNf/yBH/LnN27AiEhcn1X7wYyJNHrn9sKla0szzOAEhERBKsBMDISOCee4B9+4yWNeLLL4HixeX679gBJEki1z82PXsCLVrI9Zf+s4lN3brAsGHm6zIAEhGRBCsB8Px5Pcv1119GyxohPcu0bh2QMaNc/9gMHQrUqyfXX3p2NjYtWgC9epmvywBIREQSrATAgwd1ALx502hZI6TfM1u0CMiXT65/bCZN0kudUqTfz4xNWJheIjeNAZCIiCRYCYC//AIkT260pDHSO02/+AIoVUquf2xmzwaefFKuv/QO7dj07q03yZjGAEhERBKsBMDVq4EsWYyWNCbqrDkb13oFYuxYoFo1md53s2yZPu5Eih/OaIzJiBH6FhnTGACJiEiClQC4YAHw+ONGSxpj81qvQAwaBDRqJNP7bjZt0gceS2neHOjTR65/bKZMAcqXN1+XAZCIiCRYCYCffQY8/bTRksbYvNYrEN26Aa1by/S+m1279F28kZEy/WvVAkaNkul9N3Pn6jucTWMAJCIiCVYC4EcfATVqGC1plK1rvQLxxhvA22/L9L6bP//Us6OXL8v0L1sWmDpVpvfdrFwJZM9uvi4DIBERSbASAN9/H2ja1GhJo3LlsnOtVyCaNAH695fpfTfXr+sAePSoTP/Chf15fSCg725Ondp8XQZAIiKSYCUAvvWWnunyq2LFgK++kun93HPAxx/L9A5EkiR6p7SEbNmAVatket/Nnj36DmfTy+MMgEREJMFKAGzdGnjnHaMljapUCZg4UaZ36dLA9OkyvQORMaM+rFpCypT+vD4QAE6f1rOjFy+arcsASEREEqwEwIYN9W5Xv6pfX996IaFAAWDhQpnegciXDwgPd983IkJfH7h/v/vegbhxQwfAw4fN1mUAJCIiCVYCYLVqwLhxRksa1bKlPnRYQubMwA8/yPQORMmS+rBq186d0wHr7Fn3vQP14IPAr7+arckASEREEqwEQKkQEajOnfWhwxKSJQO2b5fpHQip8H7wIJAggZ4J9KuHHwbWrDFbkwGQiIgkWAmAUsuIgerbVx867NrNm3qW69Ah970DJbV8//PPQIoU7vsG47HHgG+/NVuTAZCIiCRYCYCSGwkCMWoUULOm+75nzugAeOGC+96BktrA8/33QNas7vsG46mngBkzzNZkACQiIglWAqDkUSKBmDZNHzrs2t69do4SMUnqCJ9vvgEKFnTfNxjPPguMGWO2JgMgERFJMB4ApQ8TDsT8+UChQu77bt1q5zBhk/r3lznE+9NPgTJl3PcNRuPGwIABZmsyABIRkQTjATDqOrFLl4yVNG7VKpnlxpUrgUcfdd83GB99pA+rdm30aOD55933DUabNkDXrmZrMgASEZEE4wFw1y4gYUJ/L3P+9JM+dNi1uXOBIkXc9w3G9On6sGrX+vUDmjVz3zcYXbvqEGgSAyAREUkwHgA3bQLSpjVWzor9+2WOHJkyBShXzm3PYC1YoA+rdq1LF6B9e/d9gzFggF4GNokBkIiIJBgPgMuXAzlzGitnxdmzepna8N6XuxoxAqhd223PYP3wgz6s2rVXXwV69HDfNxhjxuiNICYxABIRkQTjAXD2bOCJJ4yVsyIiQs8AHjjgtm/v3sDLL7vtGazt2/Vh1a698AIwZIj7vsGYMUMfBWMSAyAREUkwHgAnTwYqVjRWzpoUKfS7gC6FhQEdO7rtGaxDh/Ts6M2bbvtWrgxMnOi2Z7C+/VYfBm0SAyAREUkwHgCHDQPq1jVWzpqsWfXhwy61aAH06uW2Z7AuXNAB8MwZt32LFwdmzXLbM1hr1ujr4ExiACQiIgnGA2CvXjro+F3BgsDXX7vtWbeuDsh+FhmpD6veu9dt39y5gaVL3fYM1q+/Ag8+aLYmAyAREUkwHgA7dtRLnX5Xpow+fNilihX1ErnfpU6tD612KX16YONGtz2Ddfiwnh29ccNcTQZAIiKSYDwAvvyy3uzgdzVr6sOHXXriCb1Jxu8efVQfWu1SokTAH3+47Rmsixd1ADx92lxNBkAiIpJgPADWrq2PO/G7Zs2Avn3d9syZUx+T43dFigDz5rnrd+WKDlYnT7rrGYqo5fE9e8zVZAAkIiIJxgNg+fLAJ58YK2dN+/b68GGX0qbVB2X7Xbly+tBqV44f1wHw2jV3PUOVOjWwZYu5egyAREQkwXgALFJEX3nmdz16AK1auesXGamvyNu9213PUNWuDYwc6a7fzp1A4sTu+nmRPTuwYoW5egyAREQkwXgANP0FacuQIUD9+u76XbqkZ7n+/NNdz1C99JLb9zjXrwcyZnTXzwvT/4LDAEhERBKMB8A0acwukdkycaI+fNiVo0d1ALx+3V3PUHXsCHTq5K7f4sVA3rzu+nlRvrzZ5XEGQCIikmA0ANp4Sd6WWbOAYsXc9duxA0iSxF0/L3r2dHuW48yZQMmS7vp5YXqTEwMgERFJMBoAo47JOHXKSDmrli7Vhw+7sm4dkCmTu35eDBsG1Kvnrt/48UC1au76efHyy8B775mrxwBIREQSjAbAqHtkTR6Ua8uGDcBDD7nrt2gRkC+fu35eTJrk9j7nwYOBhg3d9fPizTf1L1MYAImISILRAPjLL0CyZEZKWffHH8D997vr98UXQKlS7vp5MXs28OST7vq98w7QurW7fl68956eBTSFAZCIiCQYDYDffw888oiRUtadPKlnK69ccdNv7Ni4s8y5bJk+tNqVtm2Bt99218+LkSOBWrXM1WMAJCIiCUYD4NdfAwULGill3bVrOgAeO+am38CBcWeZc9MmfWi1K02bAv37u+vnxbRpQNmy5uoxABIRkQSjAXDqVLNfjrYlTqwPIXaha1egTRs3vbzavRu47z69q9uFGjWAjz9208sr0/+SwwBIREQSjAbAkSP1MRlxRcaM+hBiF1q3Brp1c9PLq9On9ezohQtu+j39NDBjhpteXq1ebfY1BwZAIiKSYDQAmn5B3ra8eYHwcDe9GjTQu13jgps3dQA8eNBNvwIFgIUL3fTyyvRGJwZAIiKSYDQAvvkmEBZmpJQTJUvq3bkuVK4MTJjgppcJKVIAP//splfmzMCaNW56eXX4sNmjjhgAiYhIgtEA6PoOWa+qVwfGjHHTq1gxfftIXJE1K7BqlZteSZPqm1LiAtOHnTMAEhGRBKMBsGZNYNQoI6WcaNLE3e7TnDn18SpxReHCwLx59vtcv+52N7ZXkZFAwoTArl1m6jEAEhGRBKMBsEwZfUxGXPHGG8D//uemV5o0wObNbnqZUL48MGWK/T4nTrg9j9GEhx4CNm40U4sBkIiIJBgNgI8/DnzzjZFSTnTvDrz6qv0+kZHAvfcCe/bY72VKnTrA8OH2+/z+O/DAA/b7mJQ7N7BkiZlaDIBERCTBaADMkkUfkxFXDBkC1K9vv8/583qW68wZ+71MadEC6NnTfp/16/VxPHFJiRLAl1+aqcUASEREEowGwAcfBLZvN1LKiUmTgIoV7fc5cABIkACIiLDfy5TOnYH27e33WbQIyJ/ffh+TqlYFxo0zU4sBkIiIJBgLgDdu6FmuI0cMfCs6MmcOULSo/T7btgEpU9rvY1K/fkCzZvb7zJgBlC5tv49JjRoBgwaZqcUASEREEowFwD//1AHw0iUD34qOrFwJPPqo/T7ffQdky2a/j0kffqivaLPto4/c9DHp9df11X4mMAASEZEEYwFw1y7g/vvd3R9rgquZublzgSJF7Pcxafp0NzNzrmYaTerWzdy9zgyAREQkwVgA3LBBH48Rl7h6N2/yZKBCBbs9TPv2W+Cxx+z36dwZ6NDBfh+TBg8GGjY0U4sBkIiIJBgLgIsXA3nyGPhGdMjV7txhw4C6de32MG3tWiBTJvt9WrQAevWy38ek8eOBKlXM1GIAJCIiCcYC4MyZ+niMuMTV+Xzvvgu0bGm3h2m//QYkTmy/j6vzBk2aNQsoXtxMLQZAIiKSYCwAjh0LVKtm4BvRMRc3dLRrB3TpYreHaceP69nRq1ft9nF144hJS5cCuXKZqcUASEREEowFwIED9fEYcY2LO3qbNgXef99uD9OuXtUB8Phxu30KFwbmz7fbw7RNm4B06czUYgAkIiIJxgLg22/r4zHimmLF9JKeTc89p487iWsSJ9ZLwTZlzQp8/73dHqbt2QPcd5+ZHe8MgEREJMFYAGzdGnjnHe9fiK5VqaJf6rfpqaf0gcdxTaZMwLp1dnskTw788ovdHqadPq1nRy9e9F6LAZCIiCQYC4ANGujjMeKahg3N3eoQk3z59JVncc1jj+njYGy5eVMHqcOH7fWwIWrchw55r8UASEREEowFwCpVgAkTvH8hutamjblbHWKSMSOwfr3dHjY8/bQ+ENqWU6fi3u0xUUzNXDIAEhGRBGMB0MW7dDZ066aXr2164AFg5067PWyoUcPuu4tx8faYKKbeXWQAJCIiCcYCoIvdtDYMHqyXr225ckXPcp04Ya+HLc2a6avabNmwAUif3l59m0ztXmYAJCIiCcYCYNq0+niMuGb8eKByZXv1jx7VAfDaNXs9bOnQQV/VZktcvD0mSrlywNSp3uswABIRUXTqK6V+U0pdUkr9qpSqc5fP91JK3VRKnVdKXfj7/06P5fNGAqCrGzVsmDVLL1/bsmMHkCSJvfo29eypr2qzZeZMoGRJe/VtqlMHGDHCex0GQCIiulMJpdQVpVRtpdS9Sqm6SqnLSqmisTzTSyn1fRA9jATACxf0LNfp096/EF1btkwvX9uyZg3w8MP26ts0AFBVYwAAHFZJREFUfLjdO4zHjgWqV7dX36ZXXgHee897HQZAIiK602Sl1Ow7fjZHKTUhlmdEAuDBgzoA3rzp/QvRtc2b9XVwtixYABQoYK++TVOm6KvabBkwAGjSxF59mzp1Ajp29F6HAZCIiO60RSn19h0/66aU2hTLM72UXvo9oZTap/Tyb7ZYPm8kAP78M5AihfcvQwl79+rla1s7UT/7DHjmGTu1bZs/X292sOWtt4C2be3Vt6lPH+Cll7zXYQAkIvrv+EQpFamUivj7/975a8Xfn9utlGp9x7NtlFJ/xFI7v1Iqy99/nVEp9dnfdZLE8HkjAXDVKn0sRlz011969tLAPphojR4NPP+8ndq2rVoFZMtmr/6rrwI9etirb9Po0UDNmt7rMAASEf13JFFKpY7lV7K/PxfKDOCd7lf6PcJKMfx+cqUU2rZti7CwMISFhSE8PDzoLzHbM0U2RUQACRIA+/fbqd+nD9C8uZ3attme2a1fHxg61F59m7zM7IaHh////97atm3LAEhERLeZrJT66o6f3e0dwDtFBcDKMfy+kRnATz6x+66YbalSAVu32qkdFmbmXTEJhw7ZfbezYkVg8mQ7tW1buNDMu52cASQiojuVUHrXby2l1H1KqXpKHwcT2y7gF5RSaf7+6/RKqWlKqb1KqaQxfN5IABwyRM/mxFWPPgqsWGGn9iuvAL162altW9Tu7jNn7NQvWhSYM8dObdvWr9dX/HnFAEhERNGpp/Q5gJeVUjuUPhLmVtuVUl1v+fv5Sm8AuaiUOqT0JpDssdQ3EgDfeQd47TXvX4ZSihYFZs+2U7t2bTPnxUmIjATuu8/e+Y6PPgqsXGmntm1//AEkSuR98xADIBERSTASAFu31nfqxlUVKwKTJtmpXbasmRsjpKRLB2zcaKd2qlTAtm12att2+rSeHb140VsdBkAiIpJgJADWr6+XgeMqm+MvUECfBRhX5c2rr2wzLWrzzYED5mu7YGr8DIBERCTBSACsUCHuvswP6ONIune3UztjRmDdOju1XShdGpgxw3zdqON3zp83X9uV1Km9bx5iACQiIglGAmChQvoomLjqrbeAN94wXzcyErj/fv2+WFxVs6Y+88402wdwu5Arl75K0AsGQCIikmAkAGbODPzwg7cvQkkDBwING5qvG7WL9tQp87VdefllM3fe3mnjRv1+YVxWsiQwc6a3GgyAREQkwUgATJIE2LHD2xehpIkTgUqVzNfdv1+/JxYX70iO0rkz0L69+brh4UC+fObruvTss8CYMd5qMAASEZEEzwHwyhU9y3XihLcvQklz5wJFipivu3mzfk8sLuvfH2jSxHzd6dOBp582X9elZs2Afv281WAAJCIiCZ4D4OHDOgBev+7ti1DS998Djzxivu6SJfo9sbhs3DigalXzdUeNAmrVMl/XpY4d9U0vXjAAEhGRBM8B8OefgeTJvX0JSvv1V72Mbdrnn+v3xOKyr74CnnzSfN2ePYEWLczXdalPH+Cll7zVYAAkIiIJngPgypX6Roe47MQJPYt55YrZuh9+CDz3nNmartn6823bVu++jss++gioUcNbDQZAIiKS4DkAfvUV8MQT3r4Epd24oQPg4cNm6/bpAzRvbramaz//DKRIYb5uo0bAoEHm67r0+edAqVLeajAAEhGRBM8BcPx4oEoVb1+CfpAiBfDTT2ZrmnhHTNqRIzoc37hhtm7lynr3dVy2ZAmQJ4+3GgyAREQkwXMAHDAAaNzY25egH2TPDixfbrbmiy963yUq7epVO7u8ixTRu6/jss2bgbRpvdVgACQiIgmeA2CXLvp9rriueHHgyy/N1qxe3fs5cX6QNKn5cx4feQRYvdpsTdf27QPuuUffCxwqBkAiIpLgOQC2aKF3dMZ1NsKajVApwUZYsxEqXTt/Xs+O/vVX6DUYAImISILnAFirFjByZOhfgH5hY7k2Rw7zy8oSihQB5s0zVy8+HB4O6HuMEyYEdu8OvQYDIBERSfAcAJ95Bvj009C/AP2iY0fgzTfN1kyZEti2zWxNCZUqAZMmmasXdXi46Y0lEtKnBzZsCP15BkAiIpLgOQDmzw98+23oX4B+0bevvtrLlKijZQ4dMldTSsOGwODB5ur99JMOx/FB/vzAokWhP88ASEREEjwHwPTpgR9/DP0L0C8+/hh49llz9U6e1AHw0iVzNaW8/jrw9tvm6q1YoZfH44NnngE++yz05xkAiYhIgqcAGPUO1K5doX8B+sXMmUCJEubq/fYb8MAD5upJ6tEDaNXKXL1Zs/QGmfigVi19r3GoGACJiEiCpwAYtQvyzJnQvwD9Ytkys7NSP/wAPPywuXqShg8H6tQxV2/MGL3rOj5o0QLo1Sv05xkAiYhIgqcAaOIcNL/YutXse2nz5wMFC5qrJ2naNKBMGXP1+vXTu67jgy5dgHbtQn+eAZCIiCR4CoCbNwNp0oT+5ecnhw6Z3Zk6eTJQvryZWtIWLgQee8xcvbAw8zuupQwYADRpEvrzDIBERCTBUwBcsgTInTv0Lz8/uXxZB8CTJ83U++ADoH59M7WkrV8PZMhgrl7z5nrXdXwwfjxQtWrozzMAEhGRBE8B8PPPgZIlQ//y85vEic3dTtG1K9C6tZla0nbt0pt9IiPN1Hv2Wb3rOj746ivgySdDf54BkIiIJHgKgB99BDz3XOhffn6TObO5K89efRV45x0ztaSdOaNnR8+fN1OvRAm96zo+WLkSyJ499OcZAImISIKnANinj17Oiy8KFzZ35Vm9esDQoWZqSYuI0Jt99u83Uy9nzvhxRR4A/PwzkCJF6M8zABIRkQRPAdDG9WmSKlY0d+VZuXLAlClmavlB2rR6048JqVLFjyvyAO/X2jEAEhGRBE8B8MUX48/L/ADQoAEwaJCZWo8/DnzzjZlafpAnj97041V8uiIPAK5c0f95jh8P7XkGQCIikuApAFapondBxhevvw689ZaZWpkyAWvXmqnlB089pTf9eBV1Rd7ly95r+UXy5MAvv4T2LAMgERFJ8BQACxUy986cH7z7LtCypfc6kZFAokTA7797r+UXzz8PfPih9zq//QYkSeK9jp/kzKlvkgkFAyAREUnwFAAzZgTWrQvti8+PRowAatf2XufCBT3LdeqU91p+8cor3q48i/LDD0CWLN7r+Enp0sCMGaE9ywBIREQSQg6AERHAvfcCe/aE9sXnR59+Cjz9tPc6u3cD990XP67Ii/L223qJ3Kt58/Ru6/ikTh19X3IoGACJiEhCyAHw1Ck9y3XxYmhffH707bdAvnze66xZo98BjE+GDQPq1vVeZ9Ikvds6PmndGujWLbRnGQCJiEhCyAFwx4749y7Xxo36uBOv5swBihTxXsdPpk/XS51eDRwINGrkvY6f9OwZ+rujDIBERCQh5AC4ciWQLVtoX3p+degQkCABcP26tzpjxgDVqpkZk18sW6Y3O3gVFha/zo4E9OaYGjVCe5YBkIiIJIQcAGfO1Fd6xSfXrull7SNHvNV57z3gpZeMDMk3fvkFSJbMe53GjYEBA7zX8ZNZs4DixUN7lgGQiIgkhBwAR43SR4PEN6lTA1u2eKth8jxBvzB1fl+FCsAnnxgZkm+sWgVkzRraswyAREQkIeQA2KMH0KpVaF96fpYvn94M4kXduvHnHuAoUbu+9+3zVid/fu//fP3mt9+AxIn1+Y/BYgAkIiIJIQfA114D3nkn+C88vytXzvsMVenSwGefGRmOr2TIAKxf761GmjTm7hT2izNn9OzohQvBP8sASEREEkIOgLVqASNHBv+F53eNGnl/Ry1nTmDpUjPj8ZNChYD580N//vp1M+9Y+k1kpD73cffu4J9lACQiIgkhB8BSpczcDes3HTt636WaLBnw889mxuMnlSt7u/v58GEdAL3usvajUO9+ZgAkIiIJIQfAHDmA5cuD/8LzuwED9E7VUF2+rEPOiRPmxuQXL74I9O0b+vObNpk5Z9GPihQJ7V5sBkAiIpIQcgB88EFg+/bgv/D8bvJkoHz50J/fvx+45x7g5k1zY/KLzp2B9u1Df37hQuCxx8yNx0+qVgXGjQv+OQZAIiKSEFIAvHRJz3KdPBn8F57fffut3qkaqh9/BNKnNzcePxk8GGjQIPTn4+M1cFGaNw9tdpQBkIiIJIQUAPft07NcERHBf+H53ebN+izAUH39NVCwoLnx+MnUqUDZsqE/378/0KSJseH4SpcuQLt2wT/HAEhERBJCCoDxeZbryBE9u3ntWmjPT5gAVKpkdkx+ER4O5M0b+vMdOgCdOpkbj5+EOjvKAEhERBJCCoDffAM8/njwX3ZxQdRRJYcOhfZ8v35A06Zmx+QXW7cCqVKF/nzDhsCgQebG4ydTp+ozJIPFAEhERBJCCoATJ8bfWS5AH1a8aVNoz7ZvH39nuY4e9TY7WrYsMGWK0SH5xqJF+haZYDEAEhGRhJACYHx+lwvQO1UXLgzt2QYN4u8s140b3mZH8+bVy8jx0ebN+l8cgsUASEREEkIKgB07AmFhwX/ZxRUVKugdq6GIz7NcgLfZ0ZQp9TJyfBTqIdcMgEREJCGkANi4sffr0vysSRM9yxmKvHn1cmB8lT9/aLOjV6/qgHTsmPkx+cG1a/o/39GjwT3HAEhERBJCCoAVK4Y+QxYXhIXpHauhSJUK2LLF7Hj8pHx5fVh2sA4eBBIk0MvI8VXKlMC2bcE9wwBIREQSQgqABQoACxYE90UXlwwapHesBitqFujIEfNj8otGjUKb/d2wAXjoIfPj8ZM8eYDFi4N7hgGQiIgkhBQA06YFNm4M7osuLpkyJbQDjw8dCu09sLikY0fgzTeDfy4+Hx0UpUwZfRxMMBgAiYhIQtAB8PJlHXKOHw/y2zEOCfXA41B3gsYloe4AnzABqFzZ/Hj8pGlTfQ5kMBgAiYhIQtAB8PffgUSJ4uc1cFFCPfB44UJv9wjHBZMm6V3SwerXD3jxRfPj8ZNu3YDXXgvuGQZAIiKSEHQAXLYMyJEjyG/GOObYMT3LefVqcM+NHQtUrWpnTH6xZAmQK1fwz7Vrp+/Ljc8+/hioXj24ZxgAiYhIQtABcPJkvRM0PrtxQ+9YPXAguOfeeQd49VU7Y/KLnTv1DHBkZHDPvfAC8MEHdsbkFwsW6EPEg8EASEREEoIOgL17A82bB/nNGAdlygSsWRPcM6G8AxbXhPoOaMmS/9fevQdJWZ15HP8BCQKyjSCKKwIbSFSQ4CWJlpisqY23CFFSVsQAGikxSQWikvWCynrJgpsUZBVLk5KQ0shYWKgxQuRiBIRQaKyKiYYYE8wu7qCAcYDmJkZmfvvHmWaYdrr77Zm+vO/091P1ltPdp7ueF2fqPHX6nOexFy0qT0xx8eqrdipV3HtIAAEA1VB0Ajhlin377UXOjAk0erT92GPFvecLX7AffbQ88cTJMceEsi7FOO44+8UXyxNPXOzcGZLjXbuiv2fbNhJAAEDlFZ0AXnCB/dBD7ZgdE+brXy++G8jgwfbateWJJ04++1n7iSeij3///fZ1yUiapia7d2/7j3+M/p7f/pYEEABQeUUngMOH28uWtWN2TJhiT3R++KHdrZu9eXP5YoqLyy6z586NPr4WTo5njBhR3N/H4sUkgACAyisqAWxqso880t64sZ2zY4I89FBY7Yzqrbfsrl07dxHojGJb5a1caZ94YvniiZMLLwynwaOaM4cEEABQeSlJbmiIlgDu2BG+yiuycUgirVgRWntFtW6dPWhQ+eKJk/vusy+9NPr4+fM7fxHojGuvLW6P7LRpJIAAgMpLSfJrr0XL6P7wB7tPn3bOjAnzxht2jx7Ry53U1dnnnFPemOLiF7+wTz89+vhaKI+T8f3v21deGX38V75CAggAqLyUJC9dGi0BXLrUHjmynTNjwmTKnWzdGm387Nnta5GWRL/7nd2vX/TxEyaEf59a8Mgj9he/GH38qFEkgACAyktJ8gMPREsAH3zQvvjids6MCTRgQPTSJd/6lj1jRnnjiYu//z0kx3v2RBs/enRYIa0Fq1bZQ4dGH9+nDwkgAKDyUpJ8003REsAZM0KiUyvOOst+/PFoYy+6yP7JT8obT1w0Ndm9etl/+lO08QMH2uvXlzemuNi0ye7ePdqJ51A3kAQQAFB5KUm+/PJoCeCECZ2/08Xhxo+3f/CDaGNHjLCffba88cTJySfby5cXHnfgQGirt2VL+WOKg0zNwyhbB155hRVAAEB1pCT5zDOjJYC10uki45Zb7G9/u/C4WiqPkxG13MmmTfbHP14bNQAzjj02WqeUp55iDyAAoDpSkjxgQLQEcMgQe82aDs2NifLjH9tf/nLhcQ0NYdVn9+7yxxQX3/xmON1byPPP28OGlT+eOPnMZ+wnnyw8bu5cTgEDAKojJclS2vv355+sDh60P/Yx+29/K80kmQTLloXOJ4W88ordt2/544mTWbPsiRMLj1uwwP7Sl8ofT5x89av2vfcWHjd1KnUAAQDVkZLkHj3S/vOf809WW7aEVa4DB0ozSSbB66/bPXsWrgX49NP2aadVJqa4WLjQ/vznC4+bOdO+5pryxxMn110XuqUUcvHFdAIBAFRHSpJPPDFdsH/pCy/YJ5xQmgkyKfbuDUnvu+/mHzdvnn3JJZWJKS7WrrUHDy487sorQ3HkWjJvnj12bOFxw4fbTzxBAggAqLyUJJ9/ftoPPph/srr/fnvMmNJMkElyzDGFN/RPn25/97uViScuNm+2u3Ur3Pu41g4O2WGf7JAh+cc0NYXV5ZdfJgEEAFReSpKvvTbtG2/MP2FNmWLfemuppsjk+Nzn7MWL848577zaqQGY0dho9+5tv/pq/nGDBoU+ybXkvffCyvGuXbnHbN0axmzbRgIIAKi8lCTPmpX2ZZfln9TOPNNetKi0E2USXHFF/tqHTU12//72Sy9VLqa4OOcc++c/z/363r121672229XLqa4OP54+ze/yf36hg32ccfZ6TQJIACg8lKSvHBh2qefnnuyOniwuM4PncmcOfa4cblfr68PSc6+fZWLKS6mTbNvuCH36+vXhySn0CGazuiii5x3W0VdnX322SSAAIDqSEny73+fdvfuuU/4/vWvob3Vhx+WZ7KMszVr8h9+WbIkdAGpRT/7mX3uublfv/feaIchOqObb87fNvF73wtFxkkAAQDVkJLkXbvS7t/ffvHFtierJ5903hXCziydzt/a6+67o9XD64xCK7PcK3wTJ9p33VXZmOIis8KXy+jR9iOPkAACAKojJcnpdNpjx+YuXnvHHfZVV5VnokyCk06yf/Wrtl8bNy50dKhFH3wQ2rzlKg6e79+ts3vttXBIpq0WeB98YB9xhP3GGySAAIDqOJQAzppljx/f9mRWy0mObU+alHsla8iQ0O6sVp16atttz9Jpu0sXe9u2yscUB/mS45dfDp1jGhtJAAEA1XEoAXz++dy1y4YOtZ97rqzzZazdd1/bNRB37AhfDzc0VD6muLj66tDtI9uaNaEETC0bNSp0icl2//0tPaZJAAEA1XAoAcys2LzzTuvJavfuTL2y8k+YcbV+vT1gwEf3uq1eHa0bRmc2b17byfGcOaEnbi2bNCnsEc02YULL8ySAAIBqOJQA2vbIkR9dsdiwwT722DLPlDGXqWdXX9/6+R/9yL700urEFBfr1oWad9nGj7dnz658PHHywx+6zfqaQ4faK1eGn0kAAQDV0CoBnDLFvuWW1pPVAw+EThe1rq3kON/ewFqROSW9fXvr5w9PcmrV8uX2Jz7ReuV4+/aw0r5zZ3hMAggAyDZK0jJJWyU1Sfq3iO+7W9LbkvZIekHSKXnGtkoAFyxoXdetqck+7bT8BW1rxdVX27fd1vK4sdEeNsx+5pnqxRQXn/qU/dRTLY8bGkJS+N571YspDvbts48+2l61quW5JUvs4cNbHpMAAgCynSzpGklnSGpUtATwJklvSRoh6QhJ90jaIqlXjvGtEsCNG0PHj0zB59Wr7X79kt3lYsWKFSX5nPnz7VNOsf/xj/C4ri7s/8tVPLuSSnWP7TVnjn3GGS0lT37601ACplSqfX8dMXNm6z2St91mT57c8pgEEACQT9QVwP+RNO2wx90kbZc0Mcf4VglgY2OYuG++OUxOY8bYt99ewdmyDKZPn16SzzlwIHT8uOeeUOJj6FD74YdL8tEdVqp7bK/9++2BA+3Fi0PB7KOOKu3KaLXvryO2bg01/15/PdT9y/63IQEEAOQTJQFMNY87K+v5lZLm5nnPoQTQtv/yl1Cj7NZbw8SVfSo4aUqZPLz0kt2zp3399SEZPHiwZB/dIXFIkObPD18FjxtnX3FFaT87DvfXEZMn25dfbn/yk/aMGa1fIwEEgNrxsEKi1tj83+xrdRvviZIAntA87qSs5x+XND/He1KSXF9f31wKJlxLlqTdrVvaEyakWz2fxGvq1Kkl/bzvfCdtKe26uurfW7nusT1XQ0Paw4al3bdv2m++2fnuryPXhg3hd2bMmLR37mz9Wn19PQkgANSIXpL65bn+qY33lGsFcKDC5MPFxVXda6AAAMjSkT2A7yr3HsAuChNPiouLq2rXQIW/RQAAJIWTvD0UEsALmx93yzP+RkmbFUq/9JT0X5LqlfsUMAAAAGJkiFr2Ch5+3XHYmI2SZmS97y6F2oF7VbgOIAAAAAAAAIDOaJQKdxk5StJjknZJ2iFpoaQ+lQqwDM5VuNfdzdceSf9X1Yg6rpiuL0lzp6SDavl/tVvh9zGpxktaJymtsJLfNev1UZLWKqzcb1G4fwAASipKl5FnJT0nqa/C6eRfS/plpQIsg3MV7rWzbLYvtutL0typkDB1FucrJIGT9dEEsLekdyTNktRd0kiFvbvXVzhGAEANaWsFcHDz8yMPe25U83MnVCiuUsskgPkO0SRJsV1fkqazJYAZmd/DwxPAb0jalvXcdZI2VTAuAECNaSsBvETS/jbGHpA0tuwRlUdm4n1LYbL9taR/rWpE7ZdS8TUfk+ZOha9+t0v6X4Wvf/+lmgGVSFsJ4H9LWp417uzmcb0rFBcAIMEeVmm6jExS2B+YbZukCaUKtkSi3vMASZ9WmHiPlPTvkt5XWNlMmvZ0fUmaEZIGNf/8z5LqJL2p5H/F3VYCuEDSoqxxJzePO75CcQEAEqxUXUaStALYnnvOWK2w7yppamEFMFt3hYT9vGoH0kGsAAIAYiHXHsBGtd4DeGrzc0ndA9iWVZJmVzuIdiq260vSZRLA86sdSAe1lQBepY/uAbxe7AEEAJRBoS4jSyWtkHS0pP4Ke+aernCMpXSBwh6yLgpdUm5QSCjOqGJMHdHZu758TeF3Twpf3z+qkPQeWbWIOqarwt/YBQoJYK/mx10UVvnelvSfCn+Tn1YoUcQpYABASUXpMnKUwr6rXZJ2KkzAqcqGWVIzFQ6A7FFYKVulsBqTZHep83Z9eUbhAMhehcT2MUlDqxpRx3xDrf/mMj9nDiKNVDj1vE+hJMx/VCFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi+n8ct6kFrG5etQAAAABJRU5ErkJggg==\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Applying a grid on a figure, one empty subplot\n",
"ax = plt.subplot2grid((1, 2), (0, 0))\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.cos(x)\n",
"ax.plot(x, y)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 46,
"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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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": [
"ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)\n",
"ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)\n",
"ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2)\n",
"ax4 = plt.subplot2grid((3,3), (2, 0))\n",
"ax5 = plt.subplot2grid((3,3), (2, 1))\n",
"x = np.linspace(-10, 10, 100)\n",
"y = np.cos(x)\n",
"ax1.plot(x, y)\n",
"ax2.plot(x, y)\n",
"ax3.plot(x, y)\n",
"ax4.plot(x, y)\n",
"ax5.plot(x, y)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Saving figures"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false,
"scrolled": 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",
" };\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",
" fig.waiting = false;\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",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"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",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\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",
" guiEvent: simpleKeys(event)});\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",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"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\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\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",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var 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-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3deZhU5Z328Tsmyr4IBKOgjmLcxWjczauOCmoGGc1EXHHNRLTdOov7mmhcxphETRSTaOIyRp0YjahtUDFuRIhiXFBQCNgSXIFmp6Hrfv94GkXsahqeqn7qnPp+rquuQFHd/Tvh2P3l1DnPkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAPV0p6RVKDpBmS/ldS/1V8zFOSlkiaK2le8/+OKN+IAAAAKKUrJO0g6UuSuku6S9KEVXzMGEmXlXkuAAAAtJPtJTVJ6tHKa8ZI+lH7jAMAAIByO1vS1FW8ZoykDyV9LGmiwtvIXco8FwAAAMpgf4Vz+gat4nW7SerZ/OvtJL0k6e4yzgUAAIAyGCJptqSha/Cxe0lqlNShhT/7gqR+CucX8uDBgwcPHjyy8+in8HMcOXW0Qvztv4YfvzwAO7bwZ/0kmQcPHjx48OCRyUc/IZdOkzRL0p5tfH1fSQdI6tz8+20kjZd0X5HXd5fk+vp6NzQ05O5RU1OTfAa2jW2rlm3L+/axbdl85HXb6uvrlwdg9zVPDFSygj5d02/Fdf2WB+GGzc8t//1Gkl5QOGI4V9JktX4RSHdJbmhocB7V1tamHqFs2LZsyvO22fnePrYtm/K6bQ0NDQQgohCAGcW2ZVOet83O9/axbdmU120jABEr1wFYV1eXeoSyYduyKc/bZud7+9i2bMrrthGAiJXrAAQAII8IQMQiAAEAyBgCELEIQAAAMoYARCwCEACAjCEAEYsABAAgYwhAxCIAAQDIGAIQsQhAAAAyhgBELAIQAICMIQARiwAEACBjCEDEIgABAMgYAhCxCEAAADKGAEQsAhAAgIwhABGLAAQAIGMIQMQiAAEAyBgCELEIQAAAMoYARCwCEACAjCEAEYsABAAgYwhAxCIAAQDIGAIQsQhAAAAyhgBELAIQAICMIQARiwAEACBjCEDEIgABAMgYAhCxCEAAADKGAEQsAhAAgIwhABGLAAQAIGNee40ARBwCEACACrdwoV1XZ591lr3VVvZaaxGAiEMAAgBQYQoF+8037Z//3D7wQLtjR3ujjezvfte+/377nXcIQMQhAAEAqADz5tkPPmifcoq9ySZ2hw724MH2ddfZr78eonA5zgFELAIQAIAECoUQdtdea++3n73OOvZmm9mnnWY//LC9YEHxjyUAEYsABACgncyfb//5z+Eo38Ybh7d2DzrIvv56+6232v55CEDEIgABACijyZPDuXyDB4ejfAMG2Kefbj/6aLi4Y00QgIhFAAIAUEKLFtmPPWafeWZ4S3eddUL8/exnIQZLgQBELAIQAIBI775rjxxpDx1qd+5s9+9vn3xyuKhj3rzSfz0CELEIQAAAVtOyZfbYsfaFF9pf+5r9xS/ae+5p/+Qn9iuvfPaK3XIgABGLAAQAoA0aGuz77rOPO87+8pftdde1jzzSvvNO+6OP2nsWAhBxCEAAAIqYMiVcwLHffvbaa9tbb22ffbb99NP20qXp5iIAEYsABACg2bJl9jPPhMjbaqsQfYMGhWVapk5NPd2nCEDEIgABAFVt7tzw1u6xx9q9e4fHsceG5yr1xyMBiFgEIACg6kyfbt94Y1ieZe21w9G+c86xn302HAWsdAQgYhGAAIDcKxTsF1+0L7nE3mGHcNXuPvuE++yuzh04KgUBiFgEIAAglxob7dGj7Zoae8MN7a5d7cMOs++4w/7449TTxSEAEYsABADkRkODfc899lFH2T162BtsYI8YEW67tnhx6ulKhwBELAIQAJBpM2eGu3AcdFC47do229jnn2+PG2c3NaWerjwIQMQiAAEAmfPWW/Y119h77PHpXTiuuaZ099qtdAQgYhGAAICKVyjYL71kX3SRve224UjfQQfZt9wSjgBWGwIQsQhAAEBFWrYs3HHjrLPsf/u3cBHHsGH2H/5QuevztRcCELEIQABAxViyxH7sMfu737X79rX79LFPPNEeNcpetCj1dJWDAEQsAhAAkNTChfYDD9jDh9s9e9r9+tmnn26PGZP2fruVjABELAIQANDu5s0Ly7UMG2Z36WJvuqn9wx/aY8fm98rdUiIAEYsABAC0i4YG+6677EMPtTt2DLdfu/BCe8KEcJEH2o4ARCwCEABQNrNn27//vX3wweHK3YED7R/9yH799dSTZRsBiFgEIACgpGbNsm+91f7mN+211w733r3iCnvSpNST5QcBiFgEIAAg2vLoO/DAEH1f/7p91VX222+nniyfCEDEIgABAGtk9mz7d7/79Ejf8uibMiX1ZPlHACIWAQgAaLOGBvuOO+whQ8I5fTvuSPSlQAAiFgEIAGjV/Pn23Xfbhxxid+gQLuS44orque9uJSIAEYsABAB8zqJF9v3324cfbnfuHJZsuewy+403Uk8GmwBEPAIQAGDbbmy0H3nEPvZYu1s3e8AA+/zz7VdeYZ2+SkMAIhYBCABVrKnJfuope8QIu3fvcBu2733PHj+e6KtkBCBiEYAAUGUKBfvFF+3vf9/u39/u08c+5RT7r3/lNmxZQQAiFgEIAFVi0iT70kvtzTe3u3a1hw8Pb/k2NqaeDKuLAEQsAhAAcmzmTPtnP7N32iks23LIIfY999gLFqSeDDEIQMQiAAEgZxoawgLNgwbZX/qSvc8+9q9/He7WgXwgABGLAASAHGhstB96KCzb0qmTvf329jXX2PX1qSdDORCAiEUAAkBGFQr22LF2TU24kGPDDe1zz7VffTX1ZCg3AhCxCEAAyJgpU8KizF/9qt2jh33SSWEpF67grR4EYP5dKekVSQ2SZkj6X0n9V/ExPSXdJWmOpFmS7pDUo8hrCUAAyIDZs+1bbrG/8Q177bXtgw+277033LED1YcAzL8rJO0g6UsKf8l3SZqwio95WNJfJK0rqZek0ZIeKPJaAhAAKlRjoz1qlD1sWLgH784729dfb3/wQerJkBoBWH22l9Sk4kf0NpJUkLTtCs8NbH6upSOHBCAAVJiXX7Zra+2+fcNCzeedZ0+cmHoqVBICsPqcLWlqK38+VNLCFp5fLGlIC88TgABQAd5/377uunD1bufOYZHmxx/nvD60jACsLvtLmidpUCuvOUbSzBaef0/SUS08TwACQCJLltj3328PHRrO69tnH/u22+y5c1NPhkpHAFaPIZJmKxzhaw1HAAGgwk2YYJ9xht27t73JJuGK3n/+M/VUyBICsDocrRB/+7fhtRspnCO44jmAy88bLHoOYE1NjWtra11bW+u6urrU+zUA5M5HH9m/+IX9ta/ZXbrYxx/P0i1YPXV1dZ/8rK6pqSEAc+40haVc9lyNj3lIUp2k3pL6KFwF/Kcir+UIIACUybJl9qOP2ocdFu7D+41v2Lfeas+bl3oyZB1HAPOvIGmJpLnNj3nN/7s8CDdsfm7FQOwp6U6FdQBnS7pdxXcQAhAASmzKFPuCC+x+/ez11w9X8U6alHoq5AkBiFgEIACUwMKF9p132v/+7+GCjkMPDWv4LV2aejLkEQGIWAQgAER4+WX7tNPsnj3tLbe0r73Wfu+91FMh7whAxCIAAWA1NTTYN99s77RTWLPvhBPs556zC4XUk6FaEICIRQACQBsUCvbYsfaJJ4bo22kne+TIEINAeyMAEYsABIBWzJ5t33CDvd12dvfu9qmnhnX8gJQIQMQiAAFgJYWC/fzz9nHH2Z062bvvHu7QMX9+6smAgABELAIQAJrNmfPp0b4ePcLFHa+8knoq4PMIQMQiAAFUvfHj7ZNOCuf27bprONq3YEHqqYDiCEDEIgABVKX58+1f/9r++tftrl3tESM4tw/ZQQAiFgEIoKpMnGiffnq4oGP77cNyLnPnpp4KWD0EIGIRgAByr7HRvucee5997A4d7OHDw0UerNuHrCIAEYsABJBb775rX3yx/ZWv2Jtual9zjf3hh6mnAuIRgIhFAALIlULBHjPG/va37XXWsf/jP+xHHrGbmlJPBpQOAYhYBCCAXJg3z77pJnubbexeveyzz7anTEk9FVAeBCBiEYAAMm3yZPuss8K6fTvsYN96q71wYeqpgPIiABGLAASQOU1Ndl2d/c1vhrd5jzzSfu45LupA9SAAEYsABJAZc+eGO3Vsvrndt2+4wGPGjNRTAe2PAEQsAhBAxZsyJbzN262bvfPO9h132IsXp54KSIcARCwCEEBFKhTsJ5+0hw4Nb/MefnhYuw8AAYh4BCCAirJoUbiQY+DAcDXveefZ9fWppwIqCwGIWAQggIrw3nv2JZeEc/u22soeOdJesCD1VEBlIgARiwAEkNSrr9onnBBu0XbAAfajj3I1L7AqBCBiEYAA2l2hYD/2mD14sN2xo/2d79ivvZZ6KiA7CEDEIgABtJvFi+3bbrO3287u0ye85fv++6mnArKHAEQsAhBA2c2aZV95pb3++vaWW9q33MLdOoAYBCBiEYAAymbatLB+X9eu9t572w89FO7iASAOAYhYBCCAkpswwT7qqLB+37Bh9rhxqScC8oUARCwCEEBJFAr26NH2oEF25872aaeFO3gAKD0CELEIQABRli2z77nH3nFHu3dv+9JL7Q8/TD0VkG8EIGIRgADWyKJF9s032wMG2BtvbF9/vT1/fuqpgOpAACIWAQhgtTQ02FddZa+3nr3ttvYdd9iNjamnAqoLAYhYBCCANvngA/uCC+wePew99rBHjeKOHUAqBCBiEYAAWvXOO/aZZ4YLOw480H766dQTASAAEYsABNCit98Ot2jr0ME+7DD7xRdTTwRgOQIQsQhAAJ/x2mv20UeH8DvuOPuNN1JPBGBlBCBiEYAAbNsvvWR/61t2x472iBH21KmpJwJQDAGIWAQgUOXGjbMPPtju1Cmc6/fuu6knArAqBCBiEYBAlXruuXBRR5cu9g9+YM+cmXoiAG1FACIWAQhUmWeftfff3+7a1T7vvLC8C4BsIQARiwAEqsQzz9j77Wd362ZfeKH98cepJwKwpghAxCIAgZx79lnCD8gbAhCxCEAgp8aOtQcPJvyAPCIAEYsABHJm3Dj7oIPCxR3nnWd/9FHqiQCUGgGIWAQgkBMvv2wPHRpu2fbDH3JxB5BnBCBiEYBAxr3xhj1sWFjA+cwzWc4FqAYEIGIRgEBGTZ0abtXWsaN98sn2O++knghAeyEAEYsABDLmX/+yTz01hN+xx9pTpqSeCEB7IwARiwAEMuKjj+yzzw7n+P3Xf9mvv556IgCpEICIRQACFW7+fPvyy+3u3cOyLuPHp54IQGoEIGIRgECFamy0f/lLe7317F13tZ98MvVEACoFAYhYBCBQYZqa7LvvtgcMsLfayv7Tn+xCIfVUACoJAYhYBCBQQUaPtnfc0e7f3771Vnvp0tQTAahEBCBiEYBABZgwIZzf17Onfc019sKFqScCUMkIQMQiAIGEpk2zjzkmLOny/e9zv14AbUMAIhYBCCQwe3ZY0qVTpxCA06alnghAlhCAiEUAAu1oyRL7F7+we/e2993XfvHF1BMByCICELEIQKAdFAr2/ffbm21mb721/fDDXNkLYM0RgIhFAAJl9ve/23vtZffta48cyZW9AOIRgIhFAAJlUl9vDx8ezvM7/3yb/8wAlAoBiFgEIFBiCxbYl1wS7tl71FFc4AGg9AhAxCIAgRIpFOw77wyLOO+6qz12bOqJAOQVAYhYBCBQAi+8YO+2m92vX4jApqbUEwHIMwIQsQhAIMK//mUfe2x4u/fii+3581NPBKAaEICIRQACa2DxYvvqq+1u3exhw+zp01NPBKCaEICIRQACq2nUKPurX7UHDrTHjEk9DYBqRAAiFgEItNHbb9tDhti9etm/+hXr+QFIhwBELAIQWIUFC+yLLgrr+Z18sv3RR6knAlDtCEDEIgCBIpbfvm3jjcOyLn//e+qJACAgAKvD4ZKeltQgqUnSWqt4/VOSlkiaK2le8/+OKPJaAhBowVtv2QceaH/5y/att7KsC4DKQgBWh0EKEXiC2haAYyRd1sbPTQACK1i4MCzn0qmTfcop9qxZqScCgM8jAKvL3mp7AP6ojZ+TAASaPfywvemm9s472+PHp54GAIojAKvL6gTgh5I+ljRR0pWSuhR5LQGIqldfb3/rW3bPnvZNN9nLlqWeCABaRwBWl7YG4G6Sejb/ejtJL0m6u8hrCUBUraVL7Z//PCzmPHy4/f77qScCgLYhAKtLWwNwZXtJapTUoYU/IwBRlcaNs3fYwd58c/uJJ1JPAwCrhwCsLrEB2LGFP+suyTU1Na6trXVtba3r6upS79dA2cyda59xRrjI47LLwi3dACAL6urqPvlZXVNTQwBWgbUUjt4NVgjAzs2//0ILr+0r6YDm10jSNpLGS7qvyOfmCCCqxoMP2v372/vsY0+alHoaAFhzHAGsDsdJKijEX9MKv95L0oYKa/3t2fzajSS9IGm2wvp/k8VFIKhyM2aEizzWXTes6VcopJ4IAOIQgIhFACK3mprsm2+2u3e3jzqKizwA5AcBiFgEIHJp0iR7r73sjTayH3009TQAUFoEIGIRgMiVxkb7yivtzp3t008PF30AQN4QgIhFACI3JkwIS7tstZX9/POppwGA8iEAEYsAROYtWWJfdFFY2uXCC1naBUD+EYCIRQAi08aPt7fd1v7a18IRQACoBgQgYhGAyKRFi+xzzglH/X7843DuHwBUCwIQsQhAZM64ceE8v512sl99NfU0AND+CEDEIgCRGYsX2xdcEI76XX65vXRp6okAIA0CELEIQGTCSy/Z220XzvX7xz9STwMAaRGAiEUAoqItXRrO8evUyb744nDFLwBUOwIQsQhAVKxJk+xddw3n+40fn3oaAKgcBCBiEYCoOIWCfeONdpcudm2tvXBh6okAoLIQgIhFAKKivPuuPXhwuIfvk0+mngYAKhMBiFgEICrGfffZ665rH3usPWdO6mkAoHIRgIhFACK5hgb7+OND/N17b+ppAKDyEYCIRQAiqeeeszfZxN5vv/D2LwBg1QhAxCIAkcTSpfall9qdO9vXXWc3NaWeCACygwBELAIQ7W7aNHvPPcPyLi+/nHoaAMgeAhCxCEC0q3vusXv0sE8+2V6wIPU0AJBNBCBiEYBoF/Pn2yeeGC70+OMfU08DANlGACIWAYiy+8c/7C23tPfay37nndTTAED2EYCIRQCibAoF+6abwoUel1xiL1uWeiIAyAcCELEIQJTF7Nn2t79tr7++PWZM6mkAIF8IQMQiAFFy48aFtf0OOsj+4IPU0wBA/hCAiEUAomQKBfuGG8Jbvldfzdp+AFAuBCBiEYAoiYYG+7DD7A02sJ95JvU0AJBvBCBiEYCINmGCvdlm9uDBvOULAO2BAEQsAhBRfvOb8Jbvj3/MW74A0F4IQMQiALFGFi4MCzt/+cv244+nngYAqgsBiFgEIFbblCn2DjvYu+1m19enngYAqg8BiFgEIFbLqFHhdm6nnWYvWZJ6GgCoTgQgYhGAaJOmJvvSS+2uXe0770w9DQBUNwIQsQhArNKcOfbBB9ubbmq/8krqaQAABCBiEYBo1cSJ9uab2wceaM+alXoaAIBNACIeAYii7r/f7tbNPv98e9my1NMAAJYjABGLAMTnNDXZF18c4u+Pf0w9DQBgZQQgYhGA+Ix58+xDD7UHDLBfey31NACAlhCAiEUA4hNTptjbbmvvt5/98ceppwEAFEMAIhYBCNv2k0/avXrZZ5xhL12aehoAQGsIQMQiAOGbbgr38/3Nb1JPAgBoCwIQsQjAKrZ0qX366XafPvYzz6SeBgDQVgQgYhGAVWrOHPuAA+yttw7n/gEAsoMARCwCsApNmWJvtVVY3HnOnNTTAABWFwGIWARglXn2Wbt3by72AIAsIwARiwCsInffHS72+OUvU08CAIhBACIWAVgFCgX7iivCnT0efjj1NACAWAQgYhGAOdfYaJ90kr3BBvaECamnAQCUAgGIWARgjs2ZYw8aZG+/vV1fn3oaAECpEICIRQDm1Lvv2gMHhit9585NPQ0AoJQIQMQiAHPo9dftDTe0TzghvAUMAMgXAhCxCMCcefppu2dP+6KLwsUfAID8IQARiwDMkfvuC8u8jByZehIAQDkRgIhFAObEDTfYXbrYf/5z6kkAAOVGACIWAZhxhYJ98cX2uuvazz+fehoAQHsgABGLAMywZcvsESPsfv3s115LPQ0AoL0QgIhFAGbU4sX2YYfZW2xhT5+eehoAQHsiABGLAMyguXPt/fazd97Z/vDD1NMAANobAYhYBGDGfPyxvcsu9v77s8AzAFQrAhCxCMAMmTnT3m47+5BDwlvAAIDqRAAiFgGYEdOm2ZttZg8fbi9dmnoaAEBKBCBiEYAZ8Oab4dZup55qNzWlngYAkBoBiFgEYIX7xz/svn3tc8/l1m4AgIAARCwCsIK9+KLdq5d9xRWpJwEAVBICELEIwAr1t7/ZPXvaP/1p6kkAAJWGAEQsArACPfOM3b17uL8vAAArIwARiwCsMGPG2N262SNHpp4EAFCpCEDEIgAryOjRdteu9m23pZ4EAFDJCMDqcLikpyU1SGqStNYqXt9T0l2S5kiaJekOST2KvJYArBCjR9tduth33JF6EgBApSMAq8MghQg8QW0LwIcl/UXSupJ6SRot6YEiryUAK8DjjxN/AIC2IwCry95adQBuJKkgadsVnhvY/Fz/Fl5PACb2xBPhbd/bb089CQAgKwjA6tKWABwqaWELzy+WNKSF5wnAhJ58MsTf736XehIAQJYQgNWlLQF4jKSZLTz/nqSjWnieAEzkqae44AMAsGYIwOpStiOANTU1rq2tdW1trevq6lLv17n3/PNhqZff/Cb1JACArKirq/vkZ3VNTQ0BWEXaeg5gkz57DuD2zc9xDmAFePFFu0cP+8YbU08CAMgqjgBWh7UkdZA0WCHkOjf//gtFXv+QpDpJvSX1UbgK+E9FXksAtqNXX7V797b/539STwIAyDICsDocp3AVb1PzY/mv95K0oaR5kvZc4fU9Jd2psA7gbEm3q/gOQgC2k0mT7PXWsy+7LPUkAICsIwARiwBsB1On2v362eeeaxcKqacBAGQdAYhYBGCZzZxpDxhgn3468QcAKA0CELEIwDKaNcseONAePtxuako9DQAgLwhAxCIAy2T+fHuPPeyhQ+3GxtTTAADyhABELAKwDJYssQ84wN5nH3vRotTTAADyhgBELAKwxJYts4cNs7/+dZv/WwEA5UAAIhYBWEKFgn3qqfaWW9offJB6GgBAXhGAiEUAltDll9sbbGBPn556EgBAnhGAiEUAlshvfxtu8fbKK6knAQDkHQGIWARgCYwaZXfpYj/1VOpJAADVgABELAIw0t/+Znftat93X+pJAADVggBELAIwwqRJdu/e9vXXp54EAFBNCEDEIgDX0AcfhFu8nXNO6kkAANWGAEQsAnANLFxo7767ffjh3OINAND+CEDEIgBXU1OTfdhh4TZv3OUDAJACAYhYBOBqOvtse7PN7A8/TD0JAKBaEYCIRQCuhpEj7V697MmTU08CAKhmBCBiEYBtVFcX1vp75pnUkwAAqh0BiFgEYBtMnBju8nHnnaknAQCAAEQ8AnAVPvooLPdy/vmpJwEAICAAEYsAbEVjo73vvvahh7LcCwCgchCAiEUAFlEo2CNG2Ntvb8+bl3oaAAA+RQAiFgFYxA032H372tOnp54EAIDPIgARiwBswejRdufO9vPPp54EAIDPIwARiwBcydSpYa2/225LPQkAAC0jABGLAFzB/Pn2wIH26aenngQAgOIIQMQiAJsVCvYRR9h77RWu/gUAoFIRgIhFADa79lq7f3/7vfdSTwIAQOsIQMQiAP3pRR/jxqWeBACAVSMAEavqA/Cf/wwXfdx6a+pJAABoGwIQsao6ABctsnfc0T7llNSTAADQdgQgYlV1AJ58sr3LLvbixaknAQCg7QhAxKraALz99vDW77RpqScBAGD1EICIVZUB+Oqrdpcu9iOPpJ4EAIDVRwAiVtUF4Ny59hZb2BdemHoSAADWDAGIWFUVgIWCPWyYvd9+9rJlqacBAGDNEICIVVUBeMMN9gYb2O+/n3oSAADWHAGIWFUTgBMmhMWe//rX1JMAABCHAESsqgjAefPCeX+XXZZ6EgAA4hGAiFUVAXj88fbee3PeHwAgHwhAxMp9AN5xh927t/3uu6knAQCgNAhAxMp1AE6ebHfrZo8alXoSAABKhwBErNwG4OLF4T6/tbWpJwEAoLQIQMTKbQB+//shALnPLwAgbwhAxMplAD7xRLjV25tvpp4EAIDSIwARK3cBOGuW3b+//atfpZ4EAIDyIAARK3cBeMQR9je/GW77BgBAHhGAiJWrALzrLrtPH3vmzNSTAABQPgQgYuUmAKdPt3v0sB94IPUkAACUFwGIWLkIwKYme5997O98J/UkAACUHwGIWLkIwGuvtQcMCPf8BQAg7whAxMp8AL7xht25s/3ss6knAQCgfRCAiJXpAFy2zN5tN/t730s9CQAA7YcARKxMB+A119ibb24vXJh6EgAA2g8BiFiZDcCJE8Nbv889l3oSAADaFwGIWJkMwKVL7V12sX/wg9STAADQ/ghAxMpkAF51lb3FFrz1CwCoTgQgYmUuAF9/Pbz1O3Zs6kkAAEiDAESsTAVgU5O9++689QsAqG4EIGJlKgBvvNHeZBN7wYLUkwAAkA4BiFiZCcD6ertbN/svf0k9CQAAaRGAiJWJACwU7P/8T36K7qwAAA4HSURBVHv48NSTAACQHgGIWJkIwP/7P7t3b/vDD1NPAgBAegQgYlV8AM6eba+/vn377aknAQCgMhCAiFXxAXjyyfagQeFtYAAAQAAiXkUH4DPP2F262FOmpJ4EAIDKQQAiVsUGYGOjve229tVXp54EAIDKQgAiVsUG4E9/am+1lb1kSepJAACoLARg9bhM0gxJ8yQ9JWmbVl77lKQlkuY2v36upBFFXluRAThjRljz78knU08CAEDlIQCrww8lTZe0taQOkn4i6V1JnYu8foxCMLZFRQbgEUfYRx6ZegoAACoTAVgdpko6bYXff1HS+5KOLvL6MZJ+1MbPXXEB+MQT4ejfjBmpJwEAoDIRgPnXXVJB0q4rPf+YpGuLfMwYSR9K+ljSRElXSurSyuevmABcssTeckv7uutSTwIAQOUiAPOvv0IAbrHS83+QdEuRj9lNUs/mX28n6SVJdxd5bUUF4FVXhSt/GxtTTwIAQOUiAPNvTY4ArmwvSY0K5w+29PldU1Pj2tpa19bWuq6uLsnO/M47Yc2/p59O8uUBAKhodXV1n/ysrqmpIQCrQEvnAH6g4ucArmx5AHZs4c8q5gjg4YfbxxyTegoAACofRwCrww8kTVNY+qWTwjl99Wr5KuC+kg5Y4c+2kTRe0n1FPndFBOCzz4ajf1z4AQDAqhGA1eNSSTMlzddn1wHcUGGtvz2bf7+RpBckzVZY/2+yKvwikKYme6ed7B//ONkIAABkCgGIWMkD8Pe/tzfc0F64MNkIAABkCgGIWEkDcN48e4MN7LvvTvLlAQDIJAIQsZIG4EUX2bvvbhcKSb48AACZRAAiVrIAnD7d7tzZfuGFdv/SAABkGgGIWMkC8Mgj7eHD2/3LAgCQeQQgYiUJwOefD8u+1Ne365cFACAXCEDEavcALBTsPfawL7mk3b4kAAC5QgAiVrsH4IMP2n372nPnttuXBAAgVwhAxGrXAFy61N56a/vGG9vlywEAkEsEIGK1awD+9rf2gAH2kiXt8uUAAMglAhCx2i0AFy60+/Vj0WcAAGIRgIjVbgF4zTX2jjuGe/8CAIA1RwAiVrsE4KxZds+e9ujRZf0yAABUBQIQsdolAM8+2x40qKxfAgCAqkEAIlbZA7C+3u7UyX7xxbJ9CQAAqgoBiFhlD8Dvftc+4oiyfXoAAKoOAYhYZQ3AqVPtDh3sN98sy6cHAKAqEYCIVdYAPOkke/jwsnxqAACqFgGIWGULwLffDkf/Jk8u+acGAKCqEYCIVbYAPP54+7jjSv5pAQCoegQgYpUlACdPDkf/3n67pJ8WAACYAES8sgTg8OH2iSeW9FMCAIBmBCBilTwA33wzHP2bOrVknxIAAKyAAESskgfgUUfZ//3fJft0AABgJQQgYpU0ACdOtDt2tKdNK8mnAwAALSAAEaukAXj00eHOHwAAoHwIQMQqWQBOmRLO/ZsypQR7NgAAKIoARKySBeCIEeH8PwAAUF4EIGKVJABnzgzn/r3ySon2bAAAUBQBiFglCcCzz7aHDCnRXg0AAFpFACJWdADOnm1362Y//3wJ92wAAFAUAYhY0QF4+eX23nuXbqcGAACtIwARKyoAFyyw+/Sx6+pKvGcDAICiCEDEigrA66+3d9jBLhRKvGcDAICiCEDEWuMAbGy0N9rIvvfeMuzZAACgKAIQsdY4AH/3O3vzze1ly8qwZwMAgKIIQMRaowAsFOzttrNHjizTng0AAIoiABFrjQLw8cft3r3thQvLtGcDAICiCEDEWqMAHDLEvuCCMu3VAACgVQQgYq12AE6aZK+zjj1jRhn3bAAAUBQBiFirHYCnnmofc0wZ92oAANAqAhCxVisAZ82yO3e2//73Mu/ZAACgKAIQsVYrAK++2v5//6/MezUAAGgVAYhYbQ7Axka7f3/7/vvbYc8GAABFEYCI1eYA/MMf7E02YeFnAABSIwARq80BuOuu9s9+1g57NQAAaBUBiFhtCsCxY+1u3ew1uGMcAAAoMQIQsdoUgEceaZ91Vjvt1QAAoFUEIGKtMgDffz8s/Pzmm+24ZwMAgKIIQMRaZQBefbW9777tuFcDAIBWEYCI1WoANjXZm25q33tvO+/ZAACgKAIQsVoNwLo6+ytfCWsAAgCAykAAIlarAXjIIfYFF7TzXg0AAFpFACJW0QCsr7fXXtueNi3Bng0AAIoiABGraABecok9ZEj779QAAKB1BCBitRiAS5faG2xgjxqVaM8GAABFEYCI1WIA3n+/vfHG3PcXAIBKRAAiVosBOHiwfcUVifZqAADQKgIQsT4XgG+/He78MXNmwj0bAAAURQAi1ucC8Jxz7G9/O+FeDQAAWkUAItZnAnDpUnv99cMC0AAAoDIRgIj1mQB85JFw9S8XfwAAULkIQMT6TAAOG2afe27ivRoAALSKAESsTwJw1iy7Qwf7jTdS79YAAKA1BCBifRKAv/qVvdtuqXdpAACwKgQgYn0SgLvsYt98c+pdGgAArAoBiFjdJfmFFxrcsaM9e3bqXRoAAKwKAYhY3SX5zDMbfMQRqXdnAADQFgRg9bhM0gxJ8yQ9JWmbVl7bU9JdkuZImiXpDkk9iry2uySvt14Da/8BAJARBGB1+KGk6ZK2ltRB0k8kvSupc5HXPyzpL5LWldRL0mhJDxR5bXdJ/spXGnK59l9djquWbcumPG+bne/tY9uyKa/bRgBWh6mSTlvh91+U9L6ko1t47UaSCpK2XeG5gc3P9W/h9d0luba2YdV7WwbV1tamHqFs2LZsyvO22fnePrYtm/K6bQRg/nVXiLddV3r+MUnXtvD6oZIWtvD8YklDinx+jx9PAGYN25ZNed42O9/bx7ZlU163jQDMv/4KAbjFSs//QdItLbz+GEkzW3j+PUlHtfB8d0mur693Q0ND7h41NTXJZ2Db2LZq2ba8bx/bls1HXretvr6eAMy5ch8B7KewA/HgwYMHDx48svfoJ+RWS+cAfqDi5wA26bPnAG7f/FxL5wB+QWHn6c6DBw8ePHjwyNSjn8LPceTUDyRNU1j6pZOkKyXVq/hVwA9JqpPUW1IfhauA/1T2KQEAAFBSlyqc2zdfn10HcEOFtQH3XOG1PSXdqbAO4GxJtyv8SwEAAAAAAABAtThc0tOSGhTOD1wr7TgldaWkVxS2bYak/1XL5z9m0cWS3lY4uvuBpEcVzvHMoz8pXAC1b+pBSuASScskzVU4Yj9X4W49ebK7pCcUtm22pGfTjlMyryls0/LHAoX98j9TDlUifRW+P76ncNeo5yTtlXSi0uopaaTCjRPmKlw8ufKKGlmwqp/XAyX9VeEdwncVvt8ARQ1S2KlOUP4C8ApJO0j6ksJb33dJmpB0otL5qj69rd+XJH1P4Zt33k4CPlbhPNYm5ScAn049RBntrhB9RyvcrWgtSTsnnah8Tlf4x9c6qQcpgT8qhEMvhe8h31MIpZ4phyqhBxX+kbyuwt/XzyS9o3AufZa09vO6q6R/SbpcYRu3VbhG4Mx2nhEZtLfyF4ArW34VdLH7IWdVB0lnKWxb78SzlFJ/hYuelq+BSQBWvqcl/U/qIdrJRIXbcebBywpBu1wXhf/m8hDvnRWOuu+ywnMdJC2VdGSSieK19PP6OIWDACs+d4akt9pxLmRUNQTg2QpL6eTFNxWOthQUvsHl7QfvY5JOav51ngJwnsItHP+pcFT631IOVEKdFPbDqyW9IOkjSeMlfSvlUGWyr0JAbJx6kBI5UtKTkr4iaW1J50iarBBKWddZ4WfbimvoLt9Xs/o9s6Wf19cpHOVc0e7Nr+vaTnMho/IegPsr/OAdlHqQMuipcJj/v1IPUkKnKgTgcnkJwK0VrtiXpPUVrtJ/W8WXcsqSfgp/TzMl7ajwveRQSUv0+QXss+4+hWW28mIjSY8o/P01KhxJ2j3pRKX1WPOjr8LRzRsUAnBkyqEitPTz+jeS7l7pdVs2v26DdpoLGZXnAByicKRsaOpByugLCheEbJd6kBLYVOFclg1XeC4vAbiydSQtUvgHStZ1V/h7Wvlt0TqFC7LyYn2FSDow9SAl8gVJUyT9VuH0mLUUvlfOUbioIA/6SLpN4Zy4GQrLqb2ucJ54FnEEECWV1wA8WiH+8vADtjVfUrgqMQ9vtx2ncMvCDyR92PwoKPw93pxwrnJYHoB5OTL9lvIfgJcqHLXNi14K/32tvIrAi5J+2P7jtIsvK9wq9d9TD7KGWvp5faw+fw7gmeIcQLRiLYXzPAYr7FCdm3+fh6tJT1NY0mDPVb0wg85QeDtDCt/MblHY1vWSTVQ6HRXesljxUZB0mLJ/VeJh+vRCnfUUFmefqvC2VB6coXD0dnuF7yFDFX7Q7pRyqBL6osLyGj9IPUiJvabwPaSbwt/bEIV/mGQ1kFa2ucL3SUnaTNJfJP053ThrrLWf110Vjm7+WOF76HYKVzpzFTCKOk7hh2tT82P5r/OwBlRB4fyj5et2LV93LQ9B+JDCuVbzFP6jf0DhvKu8yssyMA8qXAAyX+HtqLsU3vLOk3MUfvA0SPq7QkzkxbcUgrZX6kFKbIDCepvvK7z1+6o+vQArD05Q+O9tvqTpCkeks7h8z6p+Xm+rcCX+AoV/iF2UYEYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpf8PhXZ5v1TCv8wAAAAASUVORK5CYII=\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Save a figure to a file\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(1, 10, 100)\n",
"y = np.log(x)\n",
"ax.plot(x, y)\n",
"fig.savefig(\"/tmp/out.png\")"
]
}
],
"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.2"
}
},
"nbformat": 4,
"nbformat_minor": 0
}