Skip to content

Instantly share code, notes, and snippets.

@SoTaInverSpinel
Last active December 21, 2019 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SoTaInverSpinel/9b871c991c36dd064c1bfdfca9b39374 to your computer and use it in GitHub Desktop.
Save SoTaInverSpinel/9b871c991c36dd064c1bfdfca9b39374 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"fig, ax = plt.subplots()\n",
"ax.plot(1, 1) # a figure with a 1x1 grid of Axes\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"# Figureを作成\n",
"fig = plt.figure()\n",
"\n",
"# Axes(サブプロット)を追加。1行1列の1番目のグラフ\n",
"ax = fig.add_subplot(111)\n",
"#ax.plot(1, 1) # a figure with a 1x1 grid of Axes\n",
"\n",
"p = pat.Polygon(xy = [(0,4), (0,0), (6,0), (6,4)],fc = \"pink\", ec = \"black\")\n",
"\n",
"# Axesに多角形を追加\n",
"ax.add_patch(p)\n",
"ax.set_xlim(-1,7)\n",
"ax.set_ylim(-1,5)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"# Figureを作成\n",
"fig = plt.figure()\n",
"\n",
"# Axes(サブプロット)を追加。1行1列の1番目のグラフ\n",
"ax = fig.add_subplot(111)\n",
"#ax.plot(1, 1) # a figure with a 1x1 grid of Axes\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"P=(3,1)\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"S = pat.Polygon(xy = [A,P,D],\n",
" edgecolor='black',\n",
" facecolor='lightgray',\n",
" linewidth=1.6)\n",
"\n",
"# Axesに多角形を追加\n",
"ax.add_patch(p)\n",
"ax.add_patch(S)\n",
"ax.set_xlim(-4,4)\n",
"ax.set_ylim(-3,3)\n",
"\n",
"scale=1.1\n",
"ax.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"\n",
"scale=1.2\n",
"ax.plot(P[0],P[1],marker='o',color='black')\n",
"ax.text(P[0]*scale,P[1]*scale,\"P\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [],
"source": [
"ax.text?"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib nbagg\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"from matplotlib.animation import PillowWriter,FuncAnimation\n",
"\n",
"fig = plt.figure()\n",
"\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"scale=1.1\n",
"scaleP=1.2\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"# Axesに多角形を追加\n",
"\n",
"def initialize():\n",
" ax1.set_xlim(-4,4)\n",
" ax1.set_ylim(-3,3)\n",
" ax1.add_patch(p)\n",
"\n",
"\n",
" ax1.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
" ax1.text(-3.5,0.0,\"4cm\",horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(0.0,-2.5,\"6cm\",horizontalalignment='center',verticalalignment='center')\n",
"\n",
" \n",
"\n",
"def moveP(x):\n",
" if 0<= x <4:\n",
" return A+np.array([0,-1])*x*velocity\n",
" elif 4<=x <10:\n",
" return B+np.array([1,0])*(x-4)*velocity\n",
" elif 10<= x <14:\n",
" return C+np.array([0,1])*(x-10)*velocity\n",
" else:\n",
" return D\n",
" \n",
"\n",
"velocity=1.0\n",
"\n",
"def animate(t):\n",
" plt.cla()\n",
" initialize()\n",
" \n",
" x=0.1*t\n",
" P=moveP(x)\n",
" \n",
" ax1.plot(P[0],P[1],marker='o',color='black')\n",
" ax1.text(P[0]*scaleP,P[1]*scaleP,\"P\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" \n",
" S = pat.Polygon(xy = [A,P,D],\n",
" edgecolor='black',\n",
" facecolor='lightgray',\n",
" linewidth=1.6)\n",
"\n",
" ax1.add_patch(S)\n",
" \n",
" plt.axis('off')\n",
" plt.title('x=' + '{:.1f}'.format(x)+'sec')\n",
" \n",
"anim = FuncAnimation(fig,animate,frames=140,repeat=True,interval=100)\n",
"#anim.save(\"ugokutenP.gif\", writer='pillow',fps=10)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3.1.1\n"
]
}
],
"source": [
"import matplotlib\n",
"print(matplotlib.__version__)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3de+zVdf0H8Jc4/TlWpP7UVcil3FxcZhOaCATS1h/ZZUC1LB2IOstLxawty7zAEkgowdW4r4GUyijtsuVqtkkGbm1t1AKh/HnJCf/9kp+uCUv57f3ZznfKJc73++LL+3DO42xuv36c1/d7zuP9/PJ6cm7f0w4dOnQoXAgQIECAAAECBHpG4DQFsGfO2h0lQIAAAQIECDQCCqAgECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekxAAeyxA3d3CRAgQIAAAQIKoAwQIECAAAECBHpMQAHssQN3dwkQIECAAAECCqAMECBAgAABAgR6TEAB7LEDd3cJECBAgAABAgqgDBAgQIAAAQIEekygawrg73//+1i2bFn86U9/in379sVjjz0Ws2bN+o/HuXXr1vja174WO3fujPe+973xjW98I2666aYei4C7S4AAAQIECPSaQNcUwMcffzy2bdsWEyZMiM985jPHLYDPP/98jB8/Pm688cb40pe+1Mzecsst8fDDDzfzLgQIECBAgACBbhXomgL41gM67bTTjlsAb7/99vjlL38ZzzzzTN9oefTvz3/+czz99NPdet7uFwECBAgQIEAgerYATp8+PS699NJ44IEH+mJQnjb+3Oc+F//617/ijDPOEA8CBAgQIECAQFcK9GwBvPjii2PevHlxxx139B3s9u3bY+rUqbF37954z3vec8SBHzhwIMp/rcubb74Z//u//xv//d//HeVRRxcCBAgQIECg8wUOHToUr776avP6/yFDhnT+DR6EW9jTBfC6666Lb33rW32s5XWAH/7wh5s3kbz73e8+gnvBggWxcOHCQTgGX5IAAQIECBA42QIvvfRSXHjhhSf723bE9+vZAjiQp4APfwRw//79MXLkyCgBGjZsWEccqBtBgAABAgQI/GeB//u//4sRI0bEK6+8Eu9617t6kqtnC2B5E8ivfvWr2LVrV9/B33zzzbFjx4623wRSAlSCU4qgAtiTPz/uNAECBAicggL2d3TPm0Bee+21ePbZZ5sYljd33H///fGRj3wkzj333OZRuvJU78svvxwPPvhgc53Wx8CUj4ApHwVT3vlb3gXcn4+BEaBT8KfeTSZAgACBnhewv7uoAD755JNN4Tv8cu2118aGDRuaN3y88MILUa7XupQPgr7tttv6Pgi6PCrYnw+CFqCe/zsEAAECBAicggL2dxcVwBr5E6Aa6r4nAQIECBDICdjfCmAqQQKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfCmAqeAKU4jNMgAABAgSqCNjfXVYAV65cGcuWLYt9+/bFuHHjYsWKFTFt2rRjhqv8+apVq+If//hHnHfeefHZz342lixZEmeddVZbgRSgtphciQABAgQIdJSA/d1FBXDz5s0xZ86cKCVw6tSpsWbNmli/fn3s2rUrRo4ceUTwfvKTn8QNN9wQP/rRj2LKlCnxt7/9LebNmxdXXXVVLF++vK2gClBbTK5EgAABAgQ6SsD+7qICOGnSpJgwYULziF7rMmbMmJg1a1bzqN7hly9/+cvxzDPPxO9+97u+P/r6178ef/zjH+Opp55qK6gC1BaTKxEgQIAAgY4SsL+7pAAePHgwhg4dGlu2bInZs2f3hWz+/PmxY8eO2Lp16xHBe+SRR+Kmm26K3/72t3HZZZfFc889F5/4xCfi2muvjW9+85ttBVWA2mJyJQIECBAg0FEC9neXFMC9e/fG8OHDY9u2bc3Tua3L4sWLY+PGjbFnz56jBu8HP/hBlEf9Dh06FP/+97/j5ptvbp5CPtblwIEDUf5rXUqARowYEfv3749hw4Z1VLjdGAIECBAgQODoAgpglxXA7du3x+TJk/tOe9GiRbFp06bYvXv3EQl48skn4/Of/3zce++9UZ4+fvbZZ6M8YnjjjTfGXXfdddTELFiwIBYuXHjEnymA/oohQIAAAQKnjoAC2CUFcCBPAZd3B19++eXNu4Zblx//+MfxxS9+MV577bUYMmTIEUn2COCp88PtlhIgQIAAgWMJKIBdUgDLAZdH8SZOnPi2p3DHjh0bM2fOPOqbQMp1P/rRj8Z9993Xl4+HH344rr/++qYAnn766cf9yRGg4xK5AgECBAgQ6DgB+7uLCmDrY2BWr17dPA28du3aWLduXezcuTNGjRoVc+fObV4n2HpHcHk69/7772+u13oKuLwGsBTD8rXauQhQO0quQ4AAAQIEOkvA/u6iAliiVd7AsXTp0uaDoMePH998nt/06dOb1M2YMSNGjx4dGzZsaP53edNH6zWCL7/8cpx//vnxqU99qvn/nX322W0lVYDaYnIlAgQIECDQUQL2d5cVwJOdLgE62eK+HwECBAgQyAvY3wpgKkUClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY3wpgKngClOIzTIAAAQIEqgjY311WAFeuXBnLli2Lffv2xbhx42LFihUxbdq0Y4brlVdeiW9/+9vx6KOPxj//+c943/veF9///vfj4x//eFuBFKC2mFyJAAECBAh0lID93UUFcPPmzTFnzpwoJXDq1KmxZs2aWL9+fezatStGjhx5RPAOHjzYXO+CCy6IO+64Iy688MJ46aWX4p3vfGd88IMfbCuoAtQWkysRIECAAIGOErC/u6gATpo0KSZMmBCrVq3qC9mYMWNi1qxZsWTJkiOCt3r16ubRwt27d8cZZ5wxoGAK0IDYDBEgQIAAgaoC9neXFMDyaN7QoUNjy5YtMXv27L5QzZ8/P3bs2BFbt249Imjlad5zzz23mfvFL34R559/flx99dVx++23x+mnn37UYB44cCDKf61LCdCIESNi//79MWzYsKph9s0JECBAgACB9gQUwC4pgHv37o3hw4fHtm3bYsqUKX2nv3jx4ti4cWPs2bPniER84AMfiBdeeCGuueaauOWWW+Lvf/973HrrrVFK4913333UBC1YsCAWLlx4xJ8pgO39wLkWAQIECBDoBAEFsMsK4Pbt22Py5Ml92Vq0aFFs2rSpeZr38MvFF18cr7/+ejz//PN9j/jdf//9fW8iOVpAPQLYCT+2bgMBAgQIEMgJKIBdUgAH8hTwFVdc0bz274knnuhL0eOPP968A7gUvTPPPPO46RKg4xK5AgECBAgQ6DgB+7tLCmBJVnkTyMSJE5t3AbcuY8eOjZkzZx71TSDlnb8PPfRQPPfcczFkyJBm5IEHHoj77rsvylPK7VwEqB0l1yFAgAABAp0lYH93UQFsfQxMeXdveRp47dq1sW7duti5c2eMGjUq5s6d27xOsPWO4PKRL6Ugzps3L77yla80rwG8/vrr46tf/Wrz2YDtXASoHSXXIUCAAAECnSVgf3dRASzRKo/+LV26tPkg6PHjx8fy5ctj+vTpTepmzJgRo0ePjg0bNvSl8Omnn47bbruteadwKYc33HDDf3wX8OHxFaDO+oF2awgQIECAQDsC9neXFcB2Dv1EXkeATqSmr0WAAAECBE6OgP2tAKaSJkApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP3dZQVw5cqVsWzZsti3b1+MGzcuVqxYEdOmTTtuuB555JH4whe+EDNnzoyf//znx71+6woC1DaVKxIgQIAAgY4RsL+7qABu3rw55syZE6UETp06NdasWRPr16+PXbt2xciRI48ZuhdffLG5/vvf//4499xzFcCO+fF0QwgQIECAwOAIKIBdVAAnTZoUEyZMiFWrVvWlZcyYMTFr1qxYsmTJURP0xhtvxBVXXBHXXXddPPXUU/HKK68ogIPzs+arEiBAgACBjhFQALukAB48eDCGDh0aW7ZsidmzZ/cFbP78+bFjx47YunXrUUN3zz33xF/+8pd47LHHYt68ecctgAcOHIjy31ufAh4xYkTs378/hg0b1jHBdkMIECBAgACBYwsogF1SAPfu3RvDhw+Pbdu2xZQpU/pOfPHixbFx48bYs2fPESko173qqquagnjeeee1VQAXLFgQCxcuPOJrKYD+miFAgAABAqeOgALYZQVw+/btMXny5L4ELlq0KDZt2hS7d+9+WypfffXVuOSSS5rXC1555ZXNn3kE8NT5wXVLCRAgQIBARkAB7JIC2N+ngMujfpdeemmcfvrpffl58803m/97yJAhzSOGF1100XGzJUDHJXIFAgQIECDQcQL2d5cUwJKs8iaQiRMnNo/qtS5jx45tPtrl8DeBvP766/Hss8++LZB33nlnlEcGH3jggbj44ovjzDPPPG5gBei4RK5AgAABAgQ6TsD+7qIC2PoYmNWrVzdPA69duzbWrVsXO3fujFGjRsXcuXOb1wke6x3B7TwFfHiCBajjfqbdIAIECBAgcFwB+7uLCmA57fLo39KlS5sPgh4/fnwsX748pk+f3gRhxowZMXr06NiwYcNRg6EAHvfnxRUIECBAgEBXCCiAXVYAT3YqBehki/t+BAgQIEAgL2B/K4CpFAlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQis8wAQIECBCoImB/K4Cp4AlQ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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"from matplotlib.animation import PillowWriter,FuncAnimation\n",
"\n",
"# Figureを作成\n",
"fig = plt.figure()\n",
"\n",
"# Axes(サブプロット)を追加。1行1列の1番目のグラフ\n",
"ax1 = fig.add_subplot(111)\n",
"#ax.plot(1, 1) # a figure with a 1x1 grid of Axes\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3dXaxkVZk/4NWgiEoaByYGkG5wxDgCcUZAEVSUiPHjQjAmE81IwKgXaoxmYkJGjHbHQcRW8cKIKEZQQySMoiiRTKJ8ewEamSAEM2CQFppRArRfsQnO+WfX0Pzb5qOrWW/POqd+TyXnRmsvaj/7t973PftUVa9aWlpaah4ECBAgQIAAAQIxAqsMgDHX2okSIECAAAECBGYCBkBBIECAAAECBAiECRgAwy640yVAgAABAgQIGABlgAABAgQIECAQJmAADLvgTpcAAQIECBAgYACUAQIECBAgQIBAmIABMOyCO10CBAgQIECAgAFQBggQIECAAAECYQIGwLAL7nQJECBAgAABAgZAGSBAgAABAgQIhAkYAMMuuNMlQIAAAQIECBgAZYAAAQIECBAgECZgAAy74E6XAAECBAgQIGAAlAECBAgQIECAQJiAATDsgjtdAgQIECBAgIABUAYIECBAgAABAmECBsCwC+50CRAgQIAAAQIGQBkgQIAAAQIECIQJGADDLrjTJUCAAAECBAgYAGWAAAECBAgQIBAmYAAMu+BOlwABAgQIECBgAJQBAgQIECBAgECYgAEw7II7XQIECBAgQICAAVAGCBAgQIAAAQJhAgbAsAvudAkQIECAAAECBkAZIECAAAECBAiECRgAwy640yVAgAABAgQIGABlgAABAgQIECAQJmAADLvgTpcAAQIECBAgYACUAQIECBAgQIBAmIABMOyCO10CBAgQIECAgAFQBggQIECAAAECYQIGwLAL7nQJECBAgAABAgZAGSBAgAABAgQIhAkYAMMuuNMlQIAAAQIECBgAZYAAAQIECBAgECZgAAy74E6XAAECBAgQIGAAlAECBAgQIECAQJiAATDsgjtdAgQIECBAgIABUAYIECBAgAABAmECBsCwC+50CRAgQIAAAQIGQBkgQIAAAQIECIQJGADDLrjTJUCAAAECBAgYAGWAAAECBAgQIBAmYAAMu+BOlwABAgQIECBgAJQBAgQIECBAgECYgAEw7II7XQIECBAgQICAAVAGCBAgQIAAAQJhAgbAsAvudAkQIECAAAECBkAZIECAAAECBAiECRgAwy640yVAgAABAgQIGABlgAABAgQIECAQJhA9AJ5zzjlt+rnjjjtml/2www5rH/3oR9sb3vCGsBg4XQIECBAgQCBJIHoA/N73vtd23333dsghh8yu+QUXXNA2bNjQfvazn82GQQ8CBAgQIECAwCIKRA+Aj3VB99lnn9kQ+M53vnMRr7dzIkCAAAECBAg0A+DDIfjLX/7SLr744nbKKafM7gAeeuih4kGAAAECBAgQWEiB+AHwpptuasccc0z785//3Pbaa6924YUXtje+8Y2PebG3bNnSpp+tj//5n/9p9913X9t3333bqlWrFjIgTooAAQIECCyawNLSUvv973/fDjjggLbbbrst2unNdT7xA+CDDz7Y7rzzzvbAAw+0b33rW+28885rV1111WPeAVy3bl1bv379XLCeRIAAAQIECCxvgY0bN7YDDzxweb/IXfTq4gfA7V1POOGE9rznPa+de+65jyLf/g7g5s2b29q1a9sUoNWrV++iS2RZAgQIECBAoFLgd7/7XVuzZs3s5s/ee+9dufSKWcsAuN2les1rXjMLxfnnn7/DizgFaArONAgaAHfI5QkECBAgQGBZCOjfLftDIB/+8Idn3/k3DXzTewG++c1vtk9+8pPt8ssvb6997Wt3GFIB2iGRJxAgQIAAgWUnoH+HD4DTV7388Ic/bJs2bZrdyXvRi17UTjvttLmGvynNArTs9rQXRIAAAQIEdiigf4cPgDtMyA6eIEC9go4nQIAAAQL/9wL6twGwK3UC1MXnYAIECBAgMERA/zYAdgVPgLr4HEyAAAECBIYI6N8GwK7gCVAXn4MJECBAgMAQAf3bANgVPAHq4nMwAQIECBAYIqB/GwC7gidAXXwOJkCAAAECQwT0bwNgV/AEqIvPwQQIECBAYIiA/m0A7AqeAHXxOZgAAQIECAwR0L8NgF3BE6AuPgcTIECAAIEhAvq3AbAreALUxedgAgQIECAwRED/NgB2BU+AuvgcTIAAAQIEhgjo3wbAruAJUBefgwkQIECAwBAB/dsA2BU8AericzABAgQIEBgioH8bALuCJ0BdfA4mQIAAAQJDBPRvA2BX8ASoi8/BBAgQIEBgiID+bQDsCp4AdfE5mAABAgQIDBHQvw2AXcEToC4+BxMgQIAAgSEC+rcBsCt4AtTF52ACBAgQIDBEQP82AHYFT4C6+BxMgAABAgSGCOjfBsCu4AlQF5+DCRAgQIDAEAH92wDYFTwB6uJzMAECBAgQGCKgfxsAu4InQF18DiZAgAABAkME9G8DYFfwBKiLz8EECBAgQGCIgP5tAOwKngB18TmYAAECBAgMEdC/DYBdwROgLj4HEyBAgACBIQL6twGwK3gC1MXnYAIECBAgMERA/zYAdgVPgLr4HEyAAAECBIYI6N8GwK7gCVAXn4MJECBAgMAQAf3bANgVPAHq4nMwAQIECBAYIqB/GwC7gidAXXwOJkCAAAECQwT0bwNgV/AEqIvPwQQIECBAYIiA/m0A7AqeAHXxOZgAAQIECAwR0L8NgF3BE6AuPgcTIECAAIEhAvq3AbAreALUxedgAgQIECAwRED/NgB2BU+AuvgcTIAAAQIEhgjo3wbAruAJUBefgwkQIECAwBAB/dsA2BU8AericzABAgQIEBgioH8bALuCJ0BdfA4mQIAAAQJDBPRvA2BX8ASoi8/BBAgQIEBgiID+bQDsCp4AdfE5mAABAgQIDBHQvw2AXcEToC4+BxMgQIAAgSEC+rcBsCt4AtTF52ACBAgQIDBEQP82AHYFT4C6+BxMgAABAgSGCOjfBsCu4AlQF5+DCRAgQIDAEAH92wDYFTwB6uJzMAECBAgQGCKgfxsAu4InQF18DiZAgAABAkME9G8DYFfwBKiLz8EECBAgQGCIgP5tAOwKngB18TmYAAECBAgMEdC/DYBdwROgLj4HEyBAgACBIQL6twGwK3gC1MXnYAIECBAgMERA/zYAdgVPgLr4HEyAAAECBIYI6N8GwK7gCVAXn4MJECBAgMAQAf07fAA888wz27e//e126623tqc//ent2GOPbWeddVZ7wQteMFcgBWguJk8iQIAAAQLLSkD/Dh8AX//617e3vvWt7SUveUl76KGH2umnn95uuummdsstt7RnPvOZOwyrAO2QyBMIECBAgMCyE9C/wwfA7RP529/+tj372c9uV111VTvuuON2GNjEAE2D8j333LNDG08gQIAAgZUjsN9++7WnPOUpK+cFd77SxP69PdmqpaWlpU7HhTn8tttua89//vNndwEPP/zwR53Xli1b2vSz9TEFaM2aNW3z5s1t9erVC+PwRCfy61//enbOHgQIECCwOAIbN25sBx544OKc0A7OxADoDuAjEZnm4BNPPLHdf//97ZprrnnM6Kxbt66tX7/+Uf+fATCmZjhRAgQILKSAAXAhL+sTnpQ7gA/z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xAAlF4y5QuFJBAgQWCECyfU8sX8bAAs3ZmKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgfK1gqgAABYdSURBVOECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3XGKAkgtGYXQsRYAAgeECyfU8sX8bAAu3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uvgcTIAAAQIEhgjo3wbAruAJUBefgwkQIECAwBAB/dsA2BU8AericzABAgQIEBgioH8bALuCJ0BdfA4mQIAAAQJDBPRvA2BX8ASoi8/BBAgQIEBgiID+bQDsCp4AdfE5mAABAgQIDBHQv4MHwDe96U3txhtvbL/5zW/a3/zN37QTTjihnXXWWe2AAw6YO4wCNDeVJxIgQIAAgWUjoH8HD4Bnn312O+aYY9r+++/f7rrrrvahD31oFswf//jHcwdUgOam8kQCBAgQILBsBPTv4AFw+xReeuml7aSTTmpbtmxpT33qU+cKqQDNxeRJBAgQIEBgWQno3wbAWSDvu+++9p73vGd2J/Daa6993JBOw+H0s/WxefPmtnbt2rZx48a2evXqZRVuL4YAAQIECBB4bIFpAFyzZk174IEH2t577x3JtGppaWkp8sxba6eddlr7/Oc/3/70pz+1l73sZe373/9+23fffR+XY926dW39+vWpXM6bAAECBAgslMDtt9/e/u7v/m6hzmnek1moAXCeAe2GG25oRx111Mzn3nvvnd39+9WvfjUb7KbfAqYhcNWqVY/pt/0dwOk3h4MOOqjdeeedUb9BbP3NKe3Op/POutPterve8zbSlfy81Jxv/Qve/fff3571rGet5Ev4pF/7Qg2A00A3/TzR4+CDD2577rnno57y61//enY7ePoQyPThkHkeqe8hcN6bo/7k73q73vPUw5X+HDmX85We4Z19/Qs1AO7syW/7/Olu1vR+viuuuKK9+tWvnmspBUPBmCsoK/xJci7nKzzCc718OZfzuYKyQE+KHACvv/76Nv284hWvmH0H4C9/+cv20Y9+tG3atKndfPPN7WlPe9pcl1jBUDDmCsoKf5Kcy/kKj/BcL1/O5XyuoCzQkyIHwJtuuql94AMfaP/5n//Z/vjHP86+C/D1r399+8hHPtKe85znzH15p/cEnnnmme1f//Vf5x4a5158GT/RebveyzieZS9NzuW8LEzLeCE5z8r5tlGMHACX8V700ggQIECAAAECu1zAALjLif0HCBAgQIAAAQLLS8AAuLyuh1dDgAABAgQIENjlAgbAXU7sP0CAAAECBAgQWF4CBsDldT28GgIECBAgQIDALhcwABYTT5+oOvroo2efMP7Zz37W/vEf/7H4v7C8lnvTm97Ubrzxxvab3/xm9pU6J5xwQjvrrLPaAQccsLxeaOGrueOOO9rHP/7x9qMf/ajdc889s3N9+9vf3k4//fS2xx57FP6Xlt9SZ5xxRrvssstm13w61+lfw1nExxe+8IW2YcOG2VdDHXbYYe1zn/tce+UrX7mIp/rIOV199dWzc/7pT386O+9LLrmknXTSSQt9ztPJTd/k8O1vf7vdeuut7elPf3o79thjZzXsBS94wUKf+znnnNOmn6meTY8p59PXob3hDW9Y6PPe9uSma//hD3949q0g0x5PexgAi6/4FKT/+q//aj/4wQ8iBsCzzz579i+nTF+lc9ddd7UPfehDM9HpX1RZ1Mfll1/eLrroova2t72tHXLIIe3nP/95e/e7391OPvnk9ulPf3pRT3t2Xh/72Mdm/2zS9C/nfOUrX1nIAXC6ttO1nIbAl7/85e3cc89t5513XrvllltmXxa/qI+pZl133XXtiCOOaG95y1tiBsDpK8De+ta3tpe85CXtoYcemv0iN31V2HS9n/nMZy7q5W7f+9732u677z6rYdPjggsumP0CMN24mIbBRX9M/yzsP/3TP83+Vafjjz/eALjoF3xXn99UQP/lX/6lfetb35ptoIQ7gNubXnrppbO7BtOd0Kc+9am7mnzZrD8Vzum36elLxRMe559/fvvgBz+4kAPgdAd/GoKm67n18cIXvnCW6+mOQcJj+vfQU+4Abn89f/vb37ZnP/vZ7aqrrmrHHXdcwuV+5Bz32Wef2RD4zne+c6HP+w9/+MNsj0+/5P3bv/3b7C917gAu9CXftSf33//93+3II49s3/nOd9rf/u3ftuc+97lxA+B9993X3vOe98zuBF577bW7FnyZrT59ifh0Z/AnP/nJMntlu+blLOoA+OCDD7ZnPOMZ7eKLL25vfvObH8Gb7uxPf/aehoKER/IAeNttt7XnP//5s7uAhx9+eMLlbn/5y19mmT/llFNmfevQQw9d6POeznMadqe/YE3/9KsBcKEv9649uaWlpfbGN75x9ueiaRCY3lORNACedtpp7fOf/3z705/+1F72spe173//+23ffffdtejLaPXbb7999tvkZz7zmfaud71rGb2yXfdSFnUAvPvuu2f/GtD0p9DpvWBbH5/4xCdmfyL7xS9+setQl9HKqQPgVMtPPPHEdv/997drrrlmGV2RXfNSpiF3egvPn//857bXXnu1Cy+8cNbLFvnxzW9+c3bXb/plfc899zQALvLF7jm3devWtfXr1z/hEtP7CKb3u03vG5reRD29p2KlD4DznvdRRx01s7n33nvbdPfvV7/61cxr7733ng2BUxNZSY+dPe/p3KaB4VWvetXsZ3qf2Ep8PJnzXvQBcNrTU2Pc+pg+/PL1r3999kGBhEfqAPi+971v9iGn6S8YBx544MJf6umO95133jl7K8f01qWphk13uRf1DuDGjRvb1Lf+4z/+o/3DP/zD7Pq6A7jwMX9yJzgNNtPPEz0OPvjg2RuIpzfUbjvwTLfUp2Hwn//5n2d3DlbSY97znn572v4xfThgzZo1s6F42wa6Es5/Z897Gv6mNw9P7xmbBqLddtttJZzmo17jzp73tMCiDoD+BPy/8UgcAN///vfP3sIz/SI//QUn8TF9i8Pznve82QefFvExXd/prR1Tb976mHr1lPepfk/vXd/2/1tEg23PyaeAC67w9BvU7373u0dWmgaD173ude3f//3fZ8NBwm+SW09++g1r+qTkFVdcMfvNalEf0/scp+Fvet/nN77xjaiiscgD4HRu056druv0BvGtj+mOyPSnQR8CWbwdPf3Zdxr+pg+9XHnllbP3/6U+XvOa18x+gZ9+wVvEx+9///vZX6q2fbzjHe9of//3f9+mtzKlvOdz6/kbAHdBylf6n4DnJbn++uvb9POKV7xi9h2A0ydgp++Rmr5D7Oabb25Pe9rT5l1qRT1v6599p0H3a1/72l8Nf/vtt9+KOpedfbHTLzvTn/unT3tPnxbc+j6p6askpvcQLcJj69fAfPGLX5zdxf7Sl77UvvzlL88yfdBBBy3CKT7mOUyfjJw+ADE9XvziF7fPfvazs19ypjfLL/LX37z3ve+dvfftu9/97l9999/0VpbpewEX9TF9/930nX/TwDcNRtN74z75yU/OPsz22te+dlFP+1Hn5U/AMZf6/+ZEUwbA6Q3E06cjpy+9/uMf/zj7LsDpO7WmD8JMb6Rf1Mf02/H0W+NjPaa7CYv8OPXUUx/zLQ2Ldsd3uvv3qU99avbLzHRXYPq04KJ/Jch092sa+LZ/TJ+YXNQ7QtO5Pt57lb/61a+2Ke+L+pi+6uWHP/zhLOPTsPuiF71odhcsafibrq0BcFET7rwIECBAgAABAgQeJeBPwEJBgAABAgQIEAgTMACGXXCnS4AAAQIECBAwAMoAAQIECBAgQCBMwAAYdsGdLgECBAgQIEDAACgDBAgQIECAAIEwAQNg2AV3ugQIECBAgAABA6AMECBAgAABAgTCBAyAYRfc6RIgQIAAAQIEDIAyQIAAAQIECBAIEzAAhl1wp0uAAAECBAgQMADKAAECBAgQIEAgTMAAGHbBnS4BAgQIECBAwAAoAwQIECBAgACBMAEDYNgFd7oECBAgQIAAAQOgDBAgQIAAAQIEwgQMgGEX3OkSIECAAAECBAyAMkCAAAECBAgQCBMwAIZdcKdLgAABAgQIEDAAygABAgQIECBAIEzAABh2wZ0uAQIECBAgQMAAKAMECBAgQIAAgTABA2DYBXe6BAgQIECAAAEDoAwQIECAAAECBMIEDIBhF9zpEiBAgAABAgQMgDJAgAABAgQIEAgTMACGXXCnS4AAAQIECBAwAMoAAQIECBAgQCBMwAAYdsGdLgECBAgQIEDAACgDBAgQIECAAIEwAQNg2AV3ugQIECBAgAABA6AMECBAgAABAgTCBP4ftJEQ5libZokAAAAASUVORK5CYII=\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np #追加\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat #追加\n",
"\n",
"fig = plt.figure()\n",
"\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"ax1.set_xlim(-4,4)\n",
"ax1.set_ylim(-3,3)\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"ax1.add_patch(p)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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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bNCgQfFI33rrrfihkFatWtkbb7xhbdu2TRBgVwQQQAABRYFSG8AJEybYqaeeGl9xCq88FWUr+vrdHE40gAnKRQ7QwoULbeedd7ZPf/rTtnTp0tjw1W1f+cpX7KGHHrJbb73Vhg4dmiDArggggAACigKlNoDXX3+9nXbaaTZw4ED77W9/WxiqIq/fzYVEA5ggXeQAXXTRRfH9FuEvr/Hjx3/sKCdPnhwvxw8YMMAeffTRBAF2RQABBBBQFCi1Aaxbi4r2tqMir9/NlScawATpIgdot912izfj/NznPmfbbLPNx45y9erVNnv2bGvRooW9+uqr8c7tbAgggAACCJQqUGoD+PWvf93uueceC+8FDPcGLMpW5PW7uYxoABOkixqg8Cnf8GnfUrZx48bZD3/4w1IeymMQQAABBBCIAqU0gPVvA/P0009bnz59CqNX1PW7OYFoABO0ixqgs846y6655ho799xz7fLLL9/gEf7ud7+zL3/5y/Hu7M8++2yCArsigAACCKgJlNIA1t0I+gtf+EK8/ViRtqKu381pRAOYoF3EAH344YfxU77h077hzuvhDuwb2j766KP4uDfffNOee+4522uvvRIk2BUBBBBAQElgUw3gyy+/bOedd178Krgtt9zS/vjHP9rnP//5QvEUcf1ubiAawATxIgbogQcesKOPPtp23XVXmz9//iaP7owzzrDrrrvORo4caWPGjEmQYFcEEEAAASWBugZw2LBh8bDXrFljYU188cUX49oTvoAgvAc93PuvV69ehaMp4vrd3Eg0gAniRQzQkCFD7K677rLRo0dbdXX1Jo/uqaeesoMPPtg6depkixYtih8KYUMAAQQQQKAhgboGsO5xm222mbVr1y6+stSzZ894ISL8hH8v4lbE9bu5nWgAE8QJUAIeuyKAAAIIIJBJgPXbjAYwIXwEKAGPXRFAAAEEEMgkwPot3gBeeumldu+998b3K3zqU5+yAw880C677LL4/rlSNgJUihKPQQABBBBAoFgCrN/iDWD4bsJvfetbFj6iHj49e/7558dPxM6bNy9+cqmhjQA1JMT/RwABBBBAoHgCrN/iDeC6kQy3TgnfmjFt2jTr27dvg4lVDFBolF9//fUGbXgAAggggED5CGy33XaF/cBGUygqrt/rOvIewHoiL730UvzY+sbuixe+Qi381G0hQJ07d7Zwt/Pw6SeFLXx1XDhmNgQQQACByhFYvHhxvCOEykYDyBXAtVkP9yw65phj7J133rHp06dvcA6E26rU1NSs9/9oAFVKBseJAAIIVKYADWBlntdNHRVXAP+nE26K/NBDD1m4N97G/griCqBZ/SuA4at9tt9+e71ZwxEjgAACFSCwdOlS23///eOR0ABWwAlt5CHQAJpZ+O7cKVOm2JNPPmk77bRTyYSKl5DrN4BqBaPkYPBABBBAoAwElOu54vq9biSlG8Dwsm9o/u677z574okn4vv/GrMpBki5YDQmGzwWAQQQKLqAcj1XXL9pAOsJnH766fF7Cu+///6P3fuvffv28b6ADW2KAVIuGA3lgf+PAAIIlJOAcj1XXL9pAOsJrPtdhnX/6+abb7bhw4c3OI8VA6RcMBoMBA9AAAEEykhAuZ4rrt80gI6TUzFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQApFwzH6DAUAgggkF1AuZ4rrt80gI5TTjFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQApFwzH6DAUAgggkF1AuZ4rrt80gI5TTjFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQApFwzH6DAUAgggkF1AuZ4rrt80gI5TTjFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQApFwzH6DAUAgggkF1AuZ4rrt80gI5TTjFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQApFwzH6DAUAgggkF1AuZ4rrt80gI5TTjFAygXDMToMhQACCGQXUK7nius3DaDjlFMMkHLBcIwOQyGAAALZBZTrueL6TQPoOOUUA6RcMByjw1AIIIBAdgHleq64ftMAOk45xQAp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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"fig = plt.figure()\n",
"\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"ax1.set_xlim(-4,4)\n",
"ax1.set_ylim(-3,3)\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"ax1.add_patch(p)\n",
"\n",
"ax1.text(-3.5,0.0,\"4cm\",horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(0.0,-2.5,\"6cm\",horizontalalignment='center',verticalalignment='center')\n",
"\n",
"scale=1.1\n",
"ax1.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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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+CP95JNP/IdCmjVrZh999JG1atUqQIBdEUAAAQQUBfJtACdOnGjnnXeef8XJvfKUlS3r63djONEABihnOUDLli2zPffc07bffntbtWqVb/hy20knnWRPP/203XvvvTZkyJAAAXZFAAEEEFAUyLcBvOOOO+z888+3fv362X/+539mhirL63djIdEABkhnOUBjxozx77dwf3lNmDDhG0c5depUfzm+b9++9txzzwUIsCsCCCCAgKJAvg1gbi3K2tuOsrx+N1aeaAADpLMcoH322cffjPM73/mO7bTTTt84yg0bNti8efOsSZMm9v777/s7t7MhgAACCCCQr0C+DeD3v/99e+yxx8y9F9DdGzArW5bX78YyogEMkM5qgNynfN2nffPZxo8fbz/72c/yeSiPQQABBBBAwAvk0wBWvQ3Mq6++aj179syMXlbX78YEogEM0M5qgC6++GK79dZb7fLLL7cbbrihxiN8/vnn7Xvf+56/O/sbb7wRoMCuCCCAAAJqAvk0gLkbQX/3u9/1tx/L0pbV9bsxjWgAA7SzGKCvv/7af8rXfdrX3Xnd3YG9pm3jxo3+cR9//LG9+eabdsABBwRIsCsCCCCAgJJAbQ3g0qVL7YorrvBfBbfddtvZa6+9ZgceeGCmeLK4fjc2EA1ggHgWAzRjxgw75ZRTbO+997bFixfXenQXXnih3X777TZy5EgbO3ZsgAS7IoAAAggoCeQawKFDh/rD3rRpk7k18e233/Zrj/sCAvcedHfvv+7du2eOJovrd2Mj0QAGiGcxQIMGDbJHHnnERo8ebeXl5bUe3SuvvGJHH320tW/f3pYvX+4/FMKGAAIIIIBAXQK5BjD3uG222cZat27tX1nq1q2bvxDhftx/z+KWxfW7sZ1oAAPECVAAHrsigAACCCCQSID124wGMCB8BCgAj10RQAABBBBIJMD6Ld4AXnfddfb444/79yt861vfsiOOOMKuv/56//65fDYClI8Sj0EAAQQQQCBbAqzf4g2g+27CM844w9xH1N2nZ6+88kr/idhFixb5Ty7VtRGguoT4dwQQQAABBLInwPot3gBWj6S7dYr71oyZM2dar1696kysYoBco/zhhx/WacMDEEAAAQSKR2CXXXbJ7Ac2CqGouH5Xd+Q9gFVE3nnnHf+x9a3dF899hZr7yW0uQB06dDB3t3P36SeFzX11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wIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFNOMUDKBSNidBgKAQQQSC6gXM8V128awIhTTjFAygUjYnQYCgEEEEguoFzPFddvGsCIU04xQMoFI2J0GAoBBBBILqBczxXXbxrAiFOuUAG67rrrbNSoUfaTn/zEbrnllojPOHwo5YIRrscICCCAQHYElOt5odbv7Jzdup9JWWVlZWXdD+MRNQkUIkBz5861QYMGWevWra137940gEQPAQQQQKAgAjSAbWzdunV+vVXc5BvA22+/3caNG2erVq2y/fff3zdcRx99dF5ZiN0AfvHFF9a1a1dzz2nMmDF2yCGHbG4A165daz//+c/tySef9IHt0qWLjR071k466SSbPHmyjRgxwu6//3772c9+ZitWrLD+/fvblClT7NFHH7XRo0f7fc466yw/XtOmTfM6vpoepFwwGozGjggggEAGBZTreez1O4Ont86nJN0APvTQQzZkyBDfcB155JE2ceJEmzRpki1atMg6duxYJ17sAA0dOtR22GEHu/nmm+3YY4/d3ABu2rTJP7/PP//c/1vnzp39c3SNXL9+/XwD+OMf/9jvc/311/vHnX766datWzdr27atbwCXLl1qAwcOtHvvvdd++MMf1nlsW3uAcsFoMBo7IoAAAhkUUK7nsdfvDJ7eOp+SdAN4+OGH+ytuEyZM2Ay177772oABA8y9D6+uLWaApk6d6q/6zZs3z1q0aPGNBvC5557zjd6f/vQn22uvvbZ4Wq4BPPvss+2dd97xzaHbzjvvPLvvvvvso48+slatWvn/dsIJJ1inTp3sjjvuqOvQtvrvygWjwWjsiAACCGRQQLmex1y/M3hq83pKsg3gV199ZS1btrRHHnnETjvttM1Y7oMXCxYssJkzZ24BuGHDBnM/uc0FqEOHDsHvIXAv2Xbv3t1co3fwwQf74ateAbzhhhvstttus+XLl9d4Ul0DeOGFF9r69es3/7u76ude/l24cOHm/+auMLqrg48//nhe4ajpQcoFo8Fo7IgAAghkUEC5ntMAmsk2gB988IHttttuNnv2bDviiCM2T81rr73Wv3furbfe2mK6lpeXW0VFxRb/PfRNpNOmTfNNaNX35m3cuNHKysqsSZMmduONN9pNN91UawPo3gPo3ieY29xz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xYoV1r59++w8uQI/E8X1mwawhlAtWbLEunbtajfeeKOdc845W43dhg0bzP3kNhegDh062Lp166x169YFjms2hq/aAGbjGfEsEEAAAQRCBWgAQwWLb/+yysrKyuJ72jU/4/LycquoqKj1cObOnWvdu3ff/JgPPvjAjjnmGP8zadKkWvfd2vg0gKWSII4DAQQQ0BSgAdQ77yXVAK5evdrcT21bp06drEWLFv4hrvnr3bu3HX744TZ58mRr0qRJrftyBdDs66+/9p+cZkMAAQQQKB2BXXbZxbbZZpvSOaA6joSXgM1KqgGsT3JXrlzpm79u3brZ/fffb02bNq3P7v6xWQ5QWVnZFsez7bbb2s4772y9evWyX/ziF3bggQfW+5jZAQEEEEAAgZzA+vXr7c4777Tp06fbokWL7LPPPrPtttvO9tlnH+vbt69/W1XHjh0zB5bl9buxsCQbwNzLvi6U99577zeaP/dXUL5blgOUawCHDh26+XDcS9Xz58/3b/Z19zt0H3pxTTAbAggggAAC9RX4/e9/b6effrq5D5O0bNnSevTo4S8yuLXGvd3qk08+sebNm9tTTz1lffr0qe/wBX18ltfvgh54lcElG0D3cu/ZZ59do3F93hKZ5QDlGsDqx/P3v//dhg8fbvfdd5+/Avi///u/jZU1fg8CCCCAQIkIuLXDNXx/+9vfbOTIkXb11Vf7K3+5bdOmTTZt2jT7+c9/bu4uG8OGDcvUkWd5/W4sKMkGMBZulgO0tQbQHbu712Hnzp09g7tc37Zt21gkjIMAAgggUOIC7sLCwQcfbG+++aa5D0eOHj16q0fsrga6V50OOOCATKlkef1uLCgawADpLAeotgbQvWejVatW/sjdJfpvf/vbAQrsigACCCCgJODePtSvXz9/38B33323KD88kuX1u7GyRAMYIJ3lANXWAL788sv+tjeu8XMNIBsCCCCAAAL5Clx88cV266232k9/+lO76aab8t0tU4/L8vrdWFA0gAHSWQ5QTQ2guxTvvr3joosusrfffttPXDeB2RBAAAEEEMhX4KijjrLZs2f795KfddZZ+e6Wqcdlef1uLCgawADpLAeoptvA5A51p512sltuucUGDx4ccPTsigACCCCgKLDvvvva4sWL/Z0kjj/++KIkyPL63VigNIAB0lkOUE23gXE3sl6+fLm9/vrr1q5d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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"fig = plt.figure()\n",
"\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"ax1.set_xlim(-4,4)\n",
"ax1.set_ylim(-3,3)\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"ax1.add_patch(p)\n",
"\n",
"ax1.text(-3.5,0.0,\"4cm\",horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(0.0,-2.5,\"6cm\",horizontalalignment='center',verticalalignment='center')\n",
"\n",
"scale=1.1\n",
"ax1.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"P=np.array([-3.0,1.0])\n",
"\n",
"scale_P=1.2\n",
"ax1.plot(P[0],P[1],marker='o',color='black')\n",
"ax1.text(P[0]*scale_P,P[1]*scale_P,\"P\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3dC7BdVX0/8JUHAZIAASUPAnlCElSKCqVQrUoLyrMtoFhfjRbqQEGKD+RRGahDLXVQaRV8VMeotFBKLQVbLbRTW6u8lakDIhVCCDEPCJCEAOER/rP2vydzuTf35u6bs/ddZ63PmXGQcPZea31+yx9f9z77nDEvvfTSS8GLAAECBAgQIECgGIExAmAxtbZQAgQIECBAgEAlIADaCAQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWFjBLZcAAQIECBAgIADaAwQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWFjBLZcAAQIECBAgIADaAwQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWFjBLZcAAQIECBAgIADaAwQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWFjBLZcAAQIECBAgIADaAwQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWFjBLZcAAQIECBAgIADaAwQIECBAgACBwgQEwMIKbrkECBAgQIAAAQHQHiBAgAABAgQIFCYgABZWcMslQIAAAQIECAiA9gABAgQIECBAoDABAbCwglsuAQIECBAgQEAAtAcIECBAgAABAoUJCICFFdxyCRAgQIAAAQICoD1AgAABAgQIEChMQAAsrOCWS4AAAQIECBAQAO0BAgQIECBAgEBhAgJgYQW3XAIECBAgQICAAGgPECBAgAABAgQKExAACyu45RIgQIAAAQIEBEB7gAABAgQIECBQmIAAWEDBb7vttnDooYdWK/3Upz4Vzj///AJWbYkECBAg0JTAmDFjXnbq8ePHh9122y3MmDEjHHTQQeH4448Pv/M7vxPin3ulKSAAplmXrs7qzDPPDFdccUV1zv333z/ce++9XT2/kxEgQIBAWQKdALh48eJq4Zs3bw7r1q0L999/f/j5z38eXnrppbDvvvuGv/mbvwmHHHJIWTg9sloBsEcKNdJpPv/882GvvfYKa9euDdOmTQurVq0Kd911V3j9618/0lM6jgABAgQKF+gEwBj0+r8eeOCBcMEFF4Rrr702TJw4Mfzwhz8Mr33tawsXS2/5AmB6NenqjG644YbqMvyb3/zm6j+f/OQnw9lnnx0+97nPdXUcJyNAgACBcgSGCoAdhVNPPTV87WtfC6973evCj3/843JwemSlAmCPFGqk03zHO94RrrvuuvDXf/3XVQBcsGBBdSVwxYoVYdy4cSM9reMIECBAoGCB4QTAeEt45syZYePGjeEHP/hBeOMb31iwWHpLFwDTq0nXZhT/xzd9+vTqsxjx1u+UKVPCr/3ar4Xbb789fPe73w1HHXVU18ZyIgIECBAoR2A4ATBqdC5CxLtPF154YTlAPbBSAbAHijTSKcarfh/84AfDSSedVF0FjK/Pf/7z4ayzzgrvec97wlVXXTXSUzuOAAECBAoWGG4A/LM/+7PwiU98IrzrXe8Kf/u3f1uwWHpLFwDTq0nXZvSmN72puuz+j//4j+F3f/d3q/M++uij1UMhEyZMCKtXrw6TJ0/u2nhORIAAAQJlCAw3AH75y18Op512WnXHKd558kpHQABMpxZdnclDDz0U5s2bF3bfffewcuXKKvB1Xscdd1z453/+5/DNb34zvO997+vquE5GgAABAvkLDDcAfulLXwqnn356OProo8O//Mu/5A/TQysUAHuoWHWmeskll1Sft4j/z+uLX/ziyw695pprqsvxRx55ZLjpppvqnNZ7CRAgQIBAGG4A7Py7yMeO0ts0AmB6NenKjBYtWlR9Ged+++0Xpk6d+rJzbtq0Kdx5551h7Nix4ZFHHqm+ud2LAAECBAgMV2C4AfDtb397+Id/+IcQPwsYvxvQKx0BATCdWnRtJvEp3/i073Bel112WfjoRz86nLd6DwECBAgQqASGEwD7fg3Mj370o3DYYYfRS0hAAEyoGN2ayoc+9KHwhS98IZxzzjnh05/+9FZPe/PNN4e3vvWt1bez/+QnP+nW0M5DgAABAgUIDCcAdr4I+ld/9Verrx/zSktAAEyrHts9mxdeeKF6yjc+7Ru/eT1+A/vWXi+++GL1vjVr1oSf/vSn4TWvec12j+0EBAgQIFCGwFAB8MEHHwznn39+9VNwkyZNCrfccks44IADyoDpoVUKgD1UrOFM9cYbbwy//du/HRYuXBjuu+++IQ8544wzwpVXXhnOPffccOmllw7n9N5DgAABAgS23AJevHhxpbF58+awfv36cP/991f/7ok/QBA/gx6/++/ggw8mlqCAAJhgUbZnSieffHL4+7//+3DRRReFiy++eMhT/fd//3f4jd/4jbD33nuHZcuWVQ+FeBEgQIAAgW0JdK4Adt43fvz4sOuuu1Z3lg466KDqQkT8T/xzrzQFBMA062JWBAgQIECAAIHGBATAxmidmAABAgQIECCQpoAAmGZdzIoAAQIECBAg0JiAANgYrRMTIECAAAECBNIUEADTrEuys4pfM7Nq1apk52diBAgQIFBfYPr06R7YqM/W00cIgD1dvvYnH39CLn6ppxcBAgQI5COwfPny6hshvMoREADLqXVXVnrHHXeEQw45pCvnchICBAgQSENAAEyjDm3OQgBsUzuDsfoGwPg9g1OmTMlgVZZAgACB3hN49tlnw9KlS0P85Y1f/OIX4eGHHw7xV5629dpzzz3DggULqu/si98bG18C4LbU8vvnAmB+NW10RX0DYPw94fi5ES8CBAgQaE7g6aefroLeAw888LL/rFixovrFjcFeM2bMCK9+9avDq171quo/8b/vv//+4RWveEV1yCOPPBL22WcfAbC50iV9ZgEw6fKkNzkBML2amBEBAnkIxKDXuZrX968x6A31mjlz5paA1wl78a+77777kMcJgHnsm5GuQgAcqVyhxwmAhRbesgkQ6JrAU089VQW9/lf0Vq5cOeQY8SGNzhW9zl/jFb2RfhRHAOxaSXvyRAJgT5Zt9CYtAI6evZEJEOgtgQ0bNlQhr+/VvPj32/oqrVmzZr3sil7n1m38rd1uvgTAbmr23rkEwN6r2ajOWAAcVX6DEyCQoMD69eu3hLy+V/XWrFkz5GznzJkz4NZtvKK3yy67tLJKAbAV5mQHEQCTLU2aExMA06yLWREg0LzAunXrqit68YnbvrdwH3300SEHnzt37oBbt4sWLQqTJ09uftJDjCAAjir/qA8uAI56CXprAgJgb9XLbAkQqC/w5JNPbgl5fcPeY489NujJxowZE+bNmzfg1u3ChQvDpEmT6k+ihSMEwBaQEx5CAEy4OClOTQBMsSrmRIDASAQef/zxAQ9ixCt88c8He40dOzbMnz9/wK3beEVv5513Hsk0Ru0YAXDU6JMYWABMogy9MwkBsHdqZaYECITqe/LWrl271adun3jiiSGD3r777jvg1m38AuVeC3qDLVIALPt/IQJg2fWvvXoBsDaZAwgQaEGgE/TiLdu+D2LEz+rFW7qDvcaNGxf222+/AbduY9DbcccdW5j56A0hAI6efQojC4ApVKGH5iAA9lCxTJVAhgIx6MWHLvp/h178+/g07mCv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rLPCHXfcUV31u/baa8O73/3u6uGQHXbYYdAAGG8N77nnntU///rXvx7OPPPMsHHjxi3vv+iii6rfRP3xj3/clXk7CQECBJoSEACbknVeAgSSEZg9e3Y48sgjw1e/+tUtc/riF78YLrnkkuqzezG0xdu32wqA8WGSKVOmVOdYsmRJdRXxySef3HLOiy++OFx//fXh7rvvTmbtJkKAAIGtCQiA9gUBAtkLxKt7y5cvf9lDIB/+8IfDbbfdVl0VjLdt423cm266achbwAJg9lvFAgkUIyAAFlNqCyVQrkC81fvrv/7r4U//9E+rhzfiZwDjAyBf+cpXwnve854K5gMf+ED493//9/BXf/VX1UMgy5Ytq54Gju/vfAZQACx3D1k5gdwEBMDcKmo9BAhsVeA73/lO9dDG//7v/4a5c+dWD4T0fQr42WefDRdccEH11S5r166tvgYm/n0MhgKgTUWAQG4CAmBuFbUeAgQIECBAgMA2BARAW4QAAQIECBAgUJiAAFhYwS2XAAECBAgQICAA2gMECBAgQIAAgcIEBMDCCm65BAgQIECAAAEB0B4gQIAAAQIECBQmIAAWVnDLJUCAAAECBAgIgPYAAQIECBAgQKAwAQGwsIJbLgECBAgQIEBAALQHCBAgQIAAAQKFCQiAhRXccgkQIECAAAECAqA9QIAAAQIECBAoTEAALKzglkuAAAECBAgQEADtAQIECBAgQIBAYQICYGEFt1wCBAgQIECAgABoDxAgQIAAAQIEChMQAAsruOUSIECAAAECBARAe4AAAQIECBAgUJiAAFhYwS2XAAECBAgQICAA2gMECBAgQIAAgcIEBMDCCm65BAgQIECAAAEB0B4gQIAAAQIECBQmIAAWVnDLJUCAAAECBAgIgPYAAQIECBAgQKAwAQGwsIJbLgECBAgQIEBAALQHCBAgQIAAAQKFCQiAhRXccgkQIECAAAECAqA9QIAAAQIECBAoTEAALKzglkuAAAECBAgQEADtAQIECBAgQIBAYQICYGEFt1wCBAgQIECAgABoDxAgQIAAAQIEChMQAAsruOUSIECAAAECBARAe4AAAQIECBAgUJiAAFhYwS2XAAECBAgQICAA2gMECBAgQIAAgcIEBMDCCm65BAgQIECAAAEB0B4gQIAAAQIECBQmIAAWVnDLJUCAAAECBAgIgPYAAQIECBAgQKAwAQGwsIJbLgECBAgQIEBAALQHCBAgQIAAAQKFCQiAhRXccgkQIECAAAECAqA9QIAAAQIECBAoTEAALKzglkuAAAECBAgQEADtAQIECBAgQIBAYQICYGEFt1wCBAgQIECAgABoDxAgQIAAAQIEChMQAAsruOUSIECAAAECBARAe4AAAQIECBAgUJiAAFhYwS2XAAECBAgQICAA2gMECBAgQIAAgcIEBMDCCm65BAgQIECAAAEB0B4gQIAAAQIECBQmIAAWVnDLJUCAAAECBAgIgPYAAQIECBAgQKAwAQGwsIJbLgECBAgQIEBAALQHCBAgQIAAAQKFCQiAhRXccgkQIECAAAECAqA9QIAAAQIECBAoTEAALKzglkuAAAECBAgQEADtAQIECBAgQIBAYQICYGEFt1wCBAgQIECAgABoDxAgQIAAAQIEChMQAAsruOUSIECAAAECBARAe4AAAQIECBAgUJiAAFhYwS2XAAECBAgQICAA2gMECBAgQIAAgcIEBMDCCm65BAgQIECAAAEB0B4gQIAAAQIECBQmIAAWVnDLJUCAAAECBAgIgPYAAQIECBAgQKAwAQGwsIJbLgECBAgQIEBAALQHCBAgQIAAAQKFCQiAhRXccgkQIECAAAECAqA9QIAAAQIECBAoTEAALKzglkuAAAECBAgQEADtAQIECBAgQIBAYQICYGEFt1wCBAgQIECAgABoDxAgQIAAAQIEChP4f0UkyRT0M34VAAAAAElFTkSuQmCC\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib nbagg\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"\n",
"fig = plt.figure()\n",
"\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"ax1.set_xlim(-4,4)\n",
"ax1.set_ylim(-3,3)\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"pol = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"ax1.add_patch(pol)\n",
"\n",
"ax1.text(-3.5,0.0,\"4cm\",horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(0.0,-2.5,\"6cm\",horizontalalignment='center',verticalalignment='center')\n",
"\n",
"scale=1.1\n",
"ax1.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"ax1.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"P=np.array([-3.0,1.0])\n",
"\n",
"scale_P=1.2\n",
"ax1.plot(P[0],P[1],marker='o',color='black')\n",
"ax1.text(P[0]*scale_P,P[1]*scale_P,\"P\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
"#△APDを追加\n",
"S = pat.Polygon(xy = [A,P,D],\n",
" edgecolor='black',\n",
" facecolor='lightgray',\n",
" linewidth=1.6)\n",
"\n",
"ax1.add_patch(S)\n",
"\n",
"#枠を消す\n",
"plt.axis('off')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\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",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" fig.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\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 backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\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 * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\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 overridden (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",
" var width = fig.canvas.width/mpl.ratio\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 + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3dCdhNVfv48dtMhlCGKKKQBgqFUKkMhQbJVKHCq5A8PMZklhAyRShD5ggVhd6oqEdR6aUo4i+JDJln/te9fr/HT72Gc85z9jlr7/Vd1/VeV2+dvfe6P2t3d9t77bVSnTlz5ozQEEAAAQQQQAABBJwRSEUB6MxYEygCCCCAAAIIIGAEKAC5ERBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRQABBBBAAAEEKAC5BxBAAAEEEEAAAccEKAAdG3DCRcA1gR49ekjPnj3/K+wMGTLI0aNHQ+JYsmSJdOvWTb7//nu57LLLpGbNmjJgwADJnTt3SMfzIwQQQMA2AQpA20aE/iCAQFQFkgvAjz76SC6//PKz506dOrXccccdl7zWsmXL5P7775caNWpIy5YtZefOndKxY0fJkSOHfPPNN6KFJA0BBBDwmwAFoN9GjP4igEBYAskF4J9//ilXXnllWMfqj7VIPHTokHn6lzZtWnP8ihUrpEKFCjJq1Ch57rnnwj4nByCAAALxFqAAjPcIcH0EHBfQ17Dly5eXAwcOyKpVq84+pfvjjz/k1ltvlRtuuEE++eQTSZMmTURSKSkAt23bJldffbW88sor0qlTp79dv1ixYlKwYEFZtGiR+fuHDx+Wl19+WWbPni3bt283r4oLFy4s7dq1kwYNGpw9Vp8a9urVS7744gtzTPHixaVz585St27dv51fr62vrhcuXCg7duwwxeudd94pI0eOlDx58kRkwUEIIIBAsgAFIPcCAgjEXeDnn3+W0qVLS5UqVUwBdfr0afPX//nPf+S7776Tq666Ss6cOSOnTp0Kqa/JT+r0x8kFYN68ec3rWy2kqlWrJn369JECBQpc9Hwff/yxVK9eXT788EN58MEH//bbxx9/XJYvXy6///67+fstWrSQyZMnm/Pedttt5qmh9j9z5szSqlUr85tPP/3UnK9s2bLm7+kr6enTp8uECRPk7bffliZNmpjfafF3++23y4kTJ6RLly5SokQJ2b17t2h/EhMTTVFMQwABBFIiQAGYEj2ORQCBqAnMnDlT6tWrJ0OHDpU9e/aYQkrn7WkhqE2LpKeffjqk62mxmNy0KNu6daspyjJmzCgrV640H3CkS5fOPHHMnz//Bc85depUeeKJJ+TLL7+UcuXK/e13//rXv0yfjh07Zv7+LbfcItdff7289957FzyfPu3LlCmT6cO5RWqtWrVMX3777TfRuYnPPvusKSb1tbMeQ0MAAQSiLUABGG1RzocAAhELPP/88zJu3DjzpE+ffPXu3fvsufQJ2K+//hrSucuUKXPR32kBpq+d9Snc66+/fskC8KuvvjJP7c5tWgBOnDjx7JfEWrRNmTJFXnzxxbNP+bTYS26//PKLFClSRAYNGiRt2rT527nGjh0rGvu6detMwZcvXz5TUOoTPxoCCCDghQAFoBeqnBMBBCIS0Plx+uozffr05mlYrly5zp4n0lfAF+qIFlrZsmWTpKSkC/Y1nFfA+spXnyzOmDFD1q9fb5426qvmgQMHmsJPXxdXrFjxoi6fffaZVKpUyTydbNSokYwfPz4iRw5CAAEELiVAAXgpIf45AgjEREALKH1yp/P/9KOHu+++W+bNm3f22pG+Ar5Q53UenS7loq93L9SSPwLp37+/Wfrl3KbH6xzC5I9Azv1n2n/9eEM/HMmePbv89NNPpijUY/SDj9q1a5/3kvphSdasWXkCGJM7josg4LYABaDb40/0CFgj8NRTT8mcOXPM/DgtmOrUqSODBw+Wtm3bmj5G8xWwvtLVZVxeeOEFGTJkyEUN9NWvfq2rH6Mkf4msx+sr5DfeeMN8/HGhpn3XOY1a3OpXwUWLFjVPA/Wjkou15DmAP/zwg2hRSEMAAQSiLUABGG1RzocAAmEL6Ly/Zs2a/e1L2NatW8uYMWPMcimhLNh8oYuWLFlSnnzySTO3LvkjEH0tqwWZvnLWL4yTm36YoU8eddmZ5LZ06VLzIYp+qKHz9PRLYn2yp1/wnrsQtBaKukOIfrGrTxZ//PFH6dq1qyn6dN1AbfoV8AMPPGCuoV/86gco+sGL/nb16tUya9Ys87vkr4CT50LqfMC//vrLfBSTkJDAV8Bh32EcgAAC/xSgAOSeQACBuAroUy4tnnQdPH3Nm9z061p9SqdP/r799lvzKjWSpmvwaaGma/MdP37cvF7VIkzX7Du3+NNzp0qVyhRnWvSd2xYvXmx+r08Bk7eC0yLy3K3g9NWubhm3ceNG88RQi7uHH37YFIFXXHHF2dOtWbNG+vbta66xd+9e889uvPFGE79+WJLcdA5k9+7dZcGCBcZA50PqHMLhw4ezBV0kNwLHIIDA3wQoALkhEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoALkHEEAAAQQQQAABxwQoAB0bcMJFAAEEEEAAAQQoAB24B5KSkqRcuXIm0n79+knnzp0diJoQEUAAAQS8EkiVKtXfTp02bVq5/PLL5aqrrpLSpUtLrVq15OGHHxb9+zQ7BSgA7RyXqPaqVatWMnLkSHPO4sWLy7p166J6fk6GAAIIIOCWQHIB2LhxYxP46dOnZd++fbJhwwZZv369nDlzRq6//nqZMmWK3HHHHW7h+CRaCkCfDFSk3Txx4oTky5dPdu/eLXny5JE//vhDVq1aJaVKlYr0lByHAAIIIOC4QHIBqIXeP9vGjRulS5cuMnPmTLnssstk+fLlcuuttzouZl/4FID2jUlUezR//nzzGP7uu+82/+vVq5e8+OKLMmTIkKheh5MhgAACCLgjcLECMFmhadOmMn78eLnttttk9erV7uD4JFIKQJ8MVKTdfPzxx+Xdd9+VsWPHmgKwaNGi5kngtm3bJE2aNJGeluMQQAABBBwWCKUA1FfC+fPnl0OHDsnnn38uFStWdFjMvtApAO0bk6j1SP/ly5s3r5mLoa9+s2fPLmXLlpWVK1fKwoULpXr16lG7FidCAAEEEHBHIJQCUDWSH0Lo26du3bq5A+SDSCkAfTBIkXZRn/o1b95cHnvsMfMUUNvw4cPlhRdekCeeeELeeeedSE/NcQgggAACDguEWgD27dtXXnrpJWnQoIFMnTrVYTH7QqcAtG9Motaju+66yzx2f++99+SRRx4x5/3zzz/NRyHp06eXHTt2SJYsWaJ2PU6EAAIIIOCGQKgF4JgxY6RFixbmjZO+eaLZI0ABaM9YRLUnmzdvlsKFC0uOHDlk+/btpuBLbjVr1pQPP/xQJk2aJE899VRUr8vJEEAAAQSCLxBqATh69Gh57rnn5IEHHpAFCxYEH8ZHEVIA+miwwulqnz59zHwL/ZPXG2+88bdDp0+fbh7HV6lSRRYtWhTOafktAggggAACEmoBmPzfIqYd2XfTUADaNyZR6dENN9xgFuMsUqSI5M6d+2/nPHbsmHzzzTeSOnVq+e2338zK7TQEEEAAAQRCFQi1AKxTp47Mnj1bdC6grg1Is0eAAtCesYhaT/QrX/3aN5Q2aNAgadeuXSg/5TcIIIAAAggYgVAKwHOXgVmxYoWUL18ePYsEKAAtGoxodaV169YyYsQISUxMlAEDBpz3tIsXL5aqVaua1dm//fbbaF2a8yCAAAIIOCAQSgGYvBD07bffbpYfo9klQAFo13ikuDcnT540X/nq17668rquwH6+durUKfO7nTt3yg8//CA333xziq/NCRBAAAEE3BC4WAG4adMm6dy5s9kKLnPmzPLll1/KLbfc4gaMj6KkAPTRYIXS1ffff18eeughKVasmPz0008XPaRly5YyatQo6dixo/Tv3z+U0/MbBBBAAAEEzr4Cbty4sdE4ffq07N+/XzZs2GD+26MbEOgcdF37r0yZMohZKEABaOGgpKRLdevWlVmzZkn37t2lR48eFz3VF198IZUqVZKrr75atmzZYj4KoSGAAAIIIHApgeQngMm/S5s2rWTLls28WSpdurR5EKH/079Ps1OAAtDOcaFXCCCAAAIIIICAZwIUgJ7RcmIEEEAAAQQQQMBOAQpAO8eFXiGAAAIIIIAAAp4JUAB6RsuJEUAAAQQQQAABOwUoAO0cF2t7pcvM/PHHH9b2j44hgAACCIQvkDdvXj7YCJ/N10dQAPp6+GLf+cmTJ0ujRo1if2GuiAACCCDgmcDWrVvNihA0dwQoAN0Z66hEumbNGilZsmRUzsVJEEAAAQTsEKAAtGMcYtkLCsBYagfgWr/99ptcc801JpIqVapIjRo1AhAVISCAAALuCEybNk2SkpL+FjAFoDvjnxwpBaB7Y56iiM8tAO+8804ZM2ZMis7HwQgggAACsRE4cuSI2SBgwYIF5oK6F/x3331n/poCMDZjYNNVKABtGg0f9OXcAjBTpkyyfPlySZcunQ96ThcRQAABdwU0d7/44ouyfv16g9C0aVPp1KmTXH/99RSAjt4WFICODnykYZ9bAOo59KMQ/VMkDQEEEEDAToEVK1ZIhw4dZN++feYP7CNGjJDmzZvLufmcJ4B2jp2XvaIA9FI3gOf+ZwH4wgsvSLNmzQIYKSEhgAAC/hY4c+aMvPXWWzJs2DA5ffq0XHXVVTJ79mwpX768CYwC0N/jm9LeUwCmVNCx4/9ZAJYrV07Gjh3rmALhIoAAAnYLHD58WF566SVZvHix6WiFChVk1qxZpghMbhSAdo+h172jAPRaOGDn/2cBmDFjRtHXC8wDDNhAEw4CCPhWYMuWLWa+3y+//GJiaNmypQwePFjSp0//t5goAH07xFHpOAVgVBjdOcm5CSNVqlSirxgmTpwopUqVcgeBSBFAAAFLBT777DPzcceBAwckQ4YMMnr0aGnSpMl5e0sBaOkgxqhbFIAxgg7KZc5NGDfddJOsXbtWWrVqJf/617+CEiJxIIAAAr4T0Dl+uizXG2+8Yf5gruu1zpkzR8qUKXPBWCgAfTfMUe0wBWBUOYN/snMTxrPPPivjx4+XsmXLyrhx44IfPBEigAACFgro074uXbrI0qVLTe/uuecemTlzpuTKleuivaUAtHAwY9glCsAYYgfhUucmDC3+tAjU1ww6D/Cf80uCEC8xIIAAAjYLbNq0Sdq0aSObN2823UxISJBXX31V0qZNe8luUwBekijQP6AADPTwRj+4cxPGDz/8ICVKlDCvGyZMmCClS5eO/gU5IwIIIIDAeQWWLFkiXbt2Ff3iVxfm1zcxDRs2DFmLAjBkqkD+kAIwkMPqXVD/TBgPP/ywrF69Wp5//nl57rnnvLswZ0YAAQQQMAKnTp2SkSNHnl2Cq1ChQvLee+9JyZIlwxKiAAyLK3A/pgAM3JB6G9A/E8aQIUPM8gJ33HGHmQ9IQwABBBDwTkB38+jYsaPZhlNb1apVZdq0aZIzZ86wL0oBGDZZoA6gAAzUcHofzD8TxrfffisPPfSQmf+n8wB1PiANAQQQQCD6ArqPr67vp3lYmy730qdPH0mTJk1EF6MAjIgtMAdRAAZmKGMTyD8TRpYsWeSKK64w2wzplkO33357bDrCVRBAAAGHBD766CN5+eWX5ciRI5I5c2Yz77pOnTopEqAATBGf7w+mAPT9EMY2gPMlDF1natWqVcwDjO1QcDUEEHBA4OTJk/L666+bgk9bkSJFzHw/XYc1pY0CMKWC/j6eAtDf4xfz3p8vYSQmJsqgQYPMgqNvv/12zPvEBRFAAIEgCuzdu1c0vyYlJZnwatSoIe+8845kz549KuFSAEaF0bcnoQD07dDFp+PnSxgffvih1KxZk3mA8RkSrooAAgEUWLdunbRt21Z+//13E52+/u3evbukTp06atFSAEaN0pcnogD05bDFr9PnSxj6VZp+gabzAPVLYP0imIYAAgggEJnA+++/Lz179pRjx45J1qxZzVM//dgu2o0CMNqi/jofBaC/xivuvb1QwtCi7+uvv5YWLVpIy5Yt495POoAAAgj4TeDEiRPy2muvyZQpU0zXb7jhBpk7d64UK1bMk1AoAD1h9c1JKQB9M1R2dPRCCaNDhw4ycOBAsxtI8mRlO3pMLxBAAAH7BXbt2iXt27c3H9Rpq127tsml+gTQq0YB6JWsP85LAeiPcbKmlxdKGAsXLpQHH3xQ0qVLZ9YDzJgxozV9piMIIICAzQJr1qwx8/127twpqVKlkr59+5o1/vSvvWwUgF7q2n9uCkD7x8iqHl4oYRw4cEBy5MhhtijS/SjLli1rVb/pDAIIIGCjwOzZs03Bp69/9ete3dWjevXqMekqBWBMmK29CAWgtUNjZ8culjDKlStnlito3ry5tG7d2s4A6BUCCCBggcDx48fllVdekXfffdf05pZbbjHr+1133XUx6x0FYMyorbwQBaCVw2Jvpy6WMPSVxauvviqlSpWSiRMn2hsEPUMAAQTiKKCvevWVr7761Va/fn3z5kR3+IhlowCMpbZ916IAtG9MrO7RxRKGblX0wAMPSNq0ac08wEyZMlkdC51DAAEEYi2wevVqSUhIkN27d5s1/QYMGGD+v9fz/c4XJwVgrEffrutRANo1Htb35mIJ4+DBg2YOi84DfPPNN6V8+fLWx0MHEUAAgVgInDlzRmbMmGHekuj2brqHuv7/++67LxaXP+81KADjRm/FhSkArRgG/3TiUglDi76vvvpKmjVrJi+88IJ/AqOnCCCAgEcCuqBz7969Zd68eeYKt912m5nvV7BgQY+uGNppL5XPQzsLv/KrAAWgX0cuTv2+VMLo0qWLmdh86623yuTJk+PUSy6LAAII2CGwfft2M99v7dq1pkONGjWS0aNHWzFF5lL53A5BeuGVAAWgV7IBPe+lEsaiRYukWrVqZh7g8uXL5bLLLguoBGEhgAACFxdYuXKlWdx57969JicOHjxYWrVqFZf5fufr6aXyOeMbbAEKwGCPb9Sju1TC0HmAuh6gznEZM2aM3HnnnVHvAydEAAEEbBbQ+X76BkQLPp0TnTt3bpk1a5bcddddVnX7Uvncqs7SmagLUABGnTTYJwwlYVSoUMF8Bdy0aVNp06ZNsEGIDgEEEDhH4MiRI9KjRw9ZsGCB+bu6T7ou9nz11Vdb5xRKPreu03QoagIUgFGjdONEoSSMrl27Sr9+/aRkyZLyzjvvuAFDlAgg4LzA1q1bzXy/9evXGwv9Q/CIESMkQ4YMVtqEks+t7DidiooABWBUGN05SSgJY8mSJVKlShXmAbpzWxApAs4L6FuPxMRE2b9/v9kTXQs/3RXJ5hZKPre5//QtZQIUgCnzc+7oUBLG4cOHzXqAurelfu2mr4RpCCCAQBAFdL7f+PHjZdiwYaJ/nS9fPrO9mx/WQQ0lnwdxzIjpfwQoALkTwhIINWFUqlRJvvjiC3nmmWfMKxEaAgggEDSBQ4cOSbdu3WTx4sUmtIoVK5qPPfLmzeuLUEPN574Ihk6GLUABGDaZ2weEmjA0Kfbp00dKlCghU6ZMcRuN6BFAIHACW7ZsMR+5bdy40cTWsmVL89Vv+vTpfRNrqPncNwHR0bAEKADD4uLHoSaMTz75RO6//35JkyaNWQ8w1pucM1IIIICAVwLLli2Tzp07y4EDB8wHHjrVpUmTJl5dzrPzhprPPesAJ46rAAVgXPn9d/FQE4bOA9T1AI8fPy6jRo0SfSVMQwABBPwscPr0abO+qeY0bddcc43MmTNHypQp48uwQs3nvgyOTl9SgALwkkT84FyBcBKGLnr6+eefy9NPPy0JCQlAIoAAAr4V0Kd9utXl0qVLTQz33HOPzJw5U3LlyuXbmMLJ574Nko5fUIACkJsjLIFwEkb37t2lV69ecvPNN8u0adPCug4/RgABBGwR2LRpk5nvt3nzZtMl/QPtq6++apa68nMLJ5/7OU76fn4BCkDujLAEwkkYn376qdx7772SOnVqMw8wS5YsYV2LHyOAAALxFtB1TXVxe53WkilTJhk3bpw0bNgw3t2KyvXDyedRuSAnsUqAAtCq4bC/M+EkDN0SSdcD1HmAI0eOtG4fTPu16SECCMRLQPfw1bw1duxY04VChQrJe++9Z3Y4CkoLJ58HJWbi+D8BCkDuhrAEwk0YOk9Gv5jTL+TatWsX1rX4MQIIIBAPgX379knHjh3NmwttVatWNdNYcubMGY/ueHbNcPO5Zx3hxHERoACMC7t/LxpuwtBN0Xv27Ck33XSTTJ8+3b+B03MEEHBCQPfxffHFF0VznbZOnTqZNU11SaugtXDzedDidz0eCkDX74Aw4w83YejTP30KqPMAdWeQrFmzhnlFfo4AAgjERmDhwoWiH6/p9BVdu3TChAlSp06d2Fw8DlcJN5/HoYtc0kMBCkAPcYN46nATxtGjR808wGPHjpnN0e++++4gshATAgj4WODkyZMydOhQmThxoomiSJEiZr6fvrkIcgs3nwfZwsXYKABdHPUUxBxJwtAvgfWL4EaNGkliYmIKrs6hCCCAQHQF9u7da/JSUlKSOXHNmjVl8uTJ5g+uQW+R5POgm7gUHwWgS6MdhVgjSRi6FqC+VilevLhZOJWGAAII2CCwbt06M99v+/btpjuap15++WUzZcWFFkk+d8HFlRgpAF0Z6SjFGUnC+Oyzz8yr31SpUpl5gNmyZYtSbzgNAgggEJnA/PnzzUL1Oj1Fc5I+9XvooYciO5lPj4okn/s0VLp9HgEKQG6LsAQiSRiaYPV1is4HHDZsmFSuXDmsa/JjBBBAIFoCJ06ckEGDBsnUqVPNKfXNhM73K1asWLQu4ZvzRJLPfRMcHb2kAAXgJYn4wbkCkSaM++67T/7973/LU089JR06dAAVAQQQiLnArl27zHqkq1evNteuXbu2+dLX1dUJIs3nMR84LuiJAAWgJ6zBPWmkCUPX0erWrZvccMMNMmvWrOACERkCCFgpsGbNGmnbtq3s3LnTTEfp27evWeNP/9rVFmk+d9UraHFTAAZtRD2OJ9KEoXP/KlWqZJLt559/LpdffrnHPeX0CCCAwP8IzJ492xR8+vpXp6Porh7Vq1d3nifSfO48XEAAKAADMpCxCiPShKHzAHPkyGEWWNX1tvSVMA0BBBDwUkD3IX/llVfk3XffNZe55ZZbzHy/6667zsvL+ubckeZz3wRIRy8qQAHIDRKWQEoSRpUqVWTJkiXy5JNPmn02aQgggIBXAvqqV1/56qtfbfXr15dx48aZHT5o/yOQknyOof8FKAD9P4YxjSAlCUNfwbz00kvma7vkP5HHtPNcDAEEnBDQjzwSEhJk9+7dZk2/AQMGmP/v8ny/8w18SvK5EzdSwIOkAAz4AEc7vJQkjBUrVkiFChVMl3QeoAsr7Ufbn/MhgMCFBc6cOSMzZsyQV199VXR7tyuuuML8f6acnN8sJfmc+9D/AhSA/h/DmEaQkoSh83F0HuDhw4eZBxjTUeNiCARfQNcZ1dUG5s2bZ4K97bbbzGEB0PoAACAASURBVHy/ggULBj/4CCNMST6P8JIcZpEABaBFg+GHrqQ0YVSrVk0WLVokDRs2lM6dO/shZPqIAAKWC+hWbrqlm27tpk33HR89erRkypTJ8p7Ht3spzefx7T1XT6kABWBKBR07PqUJQ7/I69KlixQpUkTmzJnjmB7hIoBAtAVWrlwp7du3l71790ratGll8ODB0qpVK+b7hQCd0nwewiX4icUCFIAWD46NXUtpwvjyyy/lzjvvNKHpHsH6SpiGAAIIhCug8/0mTZokQ4YMkVOnTknu3LnNx2W63igtNIGU5vPQrsKvbBWgALR1ZCztV0oThi7EqkXfoUOHzJ/UdWkYGgIIIBCOgK4n2r17d1m4cKE5rGzZsmax5/z584dzGud/m9J87jygzwEoAH0+gLHufjQShq7A//HHH0uDBg3M62AaAgggEKrA1q1bzXy/DRs2mEOaNWsmw4cPlwwZMoR6Cn73vwLRyOdg+leAAtC/YxeXnkcjYegSDboH5/XXX2++0qMhgAACoQjoUlKJiYmyf/9+SZcunYwYMUKaN28eyqH85jwC0cjnwPpXgALQv2MXl55HI2EkJSVJuXLlTP+XLl1q1uqiIYAAAhcS0Pl+48ePl2HDhon+db58+cx8v/Lly4OWAoFo5PMUXJ5D4yxAARjnAfDb5aORMHQeYM6cOeXgwYMyaNAg0aVhaAgggMD5BHS+cLdu3WTx4sXmH1esWFFmzZolefPmBSyFAtHI5ynsAofHUYACMI74frx0tBLGgw8+aCZw16tXz2wPR0MAAQT+KbBlyxZp06aNbNy40fyjli1bmo/H0qdPD1YUBKKVz6PQFU4RBwEKwDig+/mS0UoYujdnx44d5brrrpO5c+f6mYS+I4CABwLLli0zi8UfOHDAfOChCzs3adLEgyu5e8po5XN3Bf0dOQWgv8cv5r2PVsL4+uuv5Y477jD9//TTT+XKK6+MeSxcEAEE7BM4ffq0jBkzRkaNGmU6d80115hF48uUKWNfZ33eo2jlc58zONt9CkBnhz6ywKOVMHSjdp0HqH+6HzhwoOjSMDQEEHBbQPOBLg2lH4dpu+eee2TmzJmSK1cut2E8ij5a+dyj7nFajwUoAD0GDtrpo5kwatasKR9++KHUrVvXTPKmIYCAuwI6z0/X99u8ebNBSEhIEF0ySrd3o3kjEM187k0POauXAhSAXuoG8NzRTBj6BbCu6VWoUCGZP39+ALUICQEEQhFYsmSJdO3aVQ4fPiyZMmWScePGScOGDUM5lN+kQCCa+TwF3eDQOAlQAMYJ3q+XjWbC+Oabb+T22283FMwD9OsdQb8RiFxA9/DVxZy14NOmfxjUxeFLliwZ+Uk5MmSBaObzkC/KD60RoAC0Zij80ZFoJgxN/joPUFf116+CH3jgAX8g0EsEEEixwL59+8xKAMuXLzfnqlq1qkybNs3kBFpsBKKZz2PTY64STQEKwGhqOnCuaCeMWrVqyQcffCCPP/64vPzyyw4IEiICCKxfv97M99N8ok2Xe+ndu7ekSZMGnBgKRDufx7DrXCoKAhSAUUB06RTRThi6qGu7du3k2muvlffff98lSmJFwEkBXQC+e/fucuTIEcmcObNMnDhRHnvsMSct4h10tPN5vOPh+uEJUACG5+X8r6OdMFavXi2lS5c2rp988onkzp3beWMAEAiigC79NHToUFPwaStSpIiZ73fTTTcFMVxfxBTtfO6LoOnkWQEKQG6GsASinTB0HqAuAv3XX3+ZJR90izgaAggES2Dv3r3mi/+kpCQTmC4BNXnyZMmePXuwAvVZNNHO5z4L3/nuUgA6fwuEB+BFwnj44YfNMjD6GqhHjx7hdYhfI4CA1QLr1q0z8/22b99u+qmvf3W+b+rUqa3utwud8yKfu+AWlBgpAIMykjGKw4uEMWTIELPoa8GCBc0HITQEEAiGgP7BrlevXnLs2DHJli2beer30EMPBSO4AEThRT4PAIszIVAAOjPU0QnUi4Tx3XffyW233WY6qAvC5smTJzqd5SwIIBAXgRMnTogu9D516lRz/eLFi5v5fsWKFYtLf7jo+QW8yOdY+0eAAtA/Y2VFT71IGLr5u84D1HlCr7zyipkfREMAAX8K7Nq1y3zZrx94aatdu7ZMmDBBsmbN6s+AAtxrL/J5gLkCFxoFYOCG1NuAvEoYjz76qMydO9f8x6Jnz57eBsHZEUDAE4Hvv//eTOfYuXOnpEqVSvr27SudOnUyf02zT8CrfG5fpPTofAIUgNwXYQl4lTBef/11M1H8mmuukQULFoTVJ36MAALxF3j33XelX79+oq9/9ete3dWjevXq8e8YPbiggFf5HHJ/CFAA+mOcrOmlVwlDnxzceuutJs7FixdL3rx5rYmZjiCAwIUFjh8/bqZuaAGo7ZZbbjHz/a677jrYLBfwKp9bHjbd+18BCkBuhbAEvEoYOg8wV65csmfPHvMUQbeIoyGAgN0CO3bsMK9816xZYzpav359GTdunNnhg2a/gFf53P7I6aEKUAByH4Ql4GXC0Pl/+uRA5wPq0hE0BBCwV0A/8tDib/fu3WZNv4EDB0rbtm2Z72fvkP1Xz7zM5z5icLarFIDODn1kgXuZMIYPHy4vvPCC5M+fXz766KPIOshRCCDgqcCZM2dk+vTpMmDAANHt3fQL/hkzZsi9997r6XU5efQFvMzn0e8tZ4y2AAVgtEUDfj4vE8YPP/wgJUqUMIIff/yx5MuXL+CahIeAvwSOHj0qvXv3Njv3aCtVqpTMmTPHLOJO85+Al/ncfxru9ZgC0L0xT1HEXiYMnQeYO3du80pJl49gx4AUDRUHIxBVAd3KTb/U163dtDVq1EhGjx4tmTJliup1OFnsBLzM57GLgitFKkABGKmco8d5nTDq1Kkjs2fPFt0fuE+fPo4qEzYCdgmsXLlS2rdvbxZrT5s2rej2jS1btmS+n13DFHZvvM7nYXeIA2IqQAEYU27/X8zrhDFixAhp3bo18wD9f6sQQQAEdL7fpEmTTMF36tQp84Rel3upVKlSAKIjBK/zOcJ2C1AA2j0+1vXO64Sxdu1aufnmm03c+iGIfhBCQwCB2AscOXJEunfvLgsXLjQXL1u2rHk6z7+TsR8Lr67odT73qt+cNzoCFIDRcXTmLF4nDH3ikCdPHvnzzz/NZPNHHnnEGVsCRcAWga1bt5r5fhs2bDBdatasmehX+hkyZLCli/QjCgJe5/ModJFTeChAAeghbhBPHYuEUbduXZk1a5b5CEQ/BqEhgEDsBFasWCGJiYmyf/9+SZcunei0jObNm8euA1wpZgKxyOcxC4YLhS1AARg2mdsHxCJhjBo1ykwwv+qqq8xyMGwk7/Y9R/SxEdCn7+PHj5dhw4aJ/rUuw6Tz/cqXLx+bDnCVmAvEIp/HPCguGLIABWDIVPxQBWKRMHSZiZtuusmA6/yjq6++GnwEEPBQ4NChQ9KtWzezD7e2ihUrmqfw7MntIboFp45FPrcgTLpwAQEKQG6NsARikTD06YP+h2fnzp1mSzjdGo6GAALeCGzevNnM99u4caO5gD59Hzx4sKRPn96bC3JWawRikc+tCZaO/JcABSA3RVgCsUoY9erVk5kzZ0qtWrWkX79+YfWRHyOAQGgCy5Ytk06dOsnBgwfNBx5jxoyRxo0bh3Ywv/K9QKzyue+hAhoABWBAB9arsGKVMHSHgeeee858EayvpZgH6NWIcl4XBXTXHS32dL6ttgIFCpgt3UqXLu0ih7MxxyqfOwtseeAUgJYPkG3di1XC+Omnn6R48eIm/AULFsg111xjGwX9QcCXAgcOHJAuXbrI0qVLTf8rV64sM2bMkFy5cvkyHjoduUCs8nnkPeRILwUoAL3UDeC5Y5Uwkr9C/OOPP6Rnz55Su3btAGoSEgKxFdB5fjrfT+f9aWvXrp3079/fbO9Gc08gVvncPVl/REwB6I9xsqaXsUwYDRo0kOnTp0uNGjXMf6RoCCAQucCSJUuka9eucvjwYcmUKZNZ8kX/HaO5KxDLfO6usr2RUwDaOzZW9iyWCUPnKLVo0cLsP6r/8WIeoJW3BJ2yXED38NXFnMeNG2d6WqhQIXnvvfekZMmSlvec7nktEMt87nUsnD98AQrA8M2cPiKWCUO3oSpWrJjx/uCDD6RgwYJO2xM8AuEK7Nu3Tzp27CjLly83h1atWlWmTZsmOXPmDPdU/D6AArHM5wHk831IFIC+H8LYBhDLhKHzAHXj+e3bt5tN6evUqRPbYLkaAj4WWL9+vZnvp//OauvcubPZXztNmjQ+joquR1Mglvk8mv3mXNERoACMjqMzZ4l1wnjiiSdk6tSp8uCDD8qrr77qjDOBIpASAd1BR//QdOTIEcmcObNMnDhRHnvssZSckmMDKBDrfB5AQl+HRAHo6+GLfedjnTDGjh1rNqLXJSo++eQT5gHGfsi5oo8ETp48KUOHDjUFn7YiRYqY+X7JWyv6KBS6GgOBWOfzGITEJcIQoAAMA4ufxmYv4HOdf/75ZylatKj5W++//75ce+21DAMCCJxHYM+ePdKhQwdJSkoy/7RmzZoyefJkyZ49O14InFeAAtDtG4MC0O3xDzv6WCcMnQeoi0Bv27bNbFZft27dsPvMAQgEXWDt2rXStm1bM19Wm77+ffnllyV16tRBD534UiAQ63yegq5yqAcCFIAeoAb5lPFIGE8++aRMmTJFHnjgARkwYECQeYkNgbAF5s2bJ7169ZLjx49LtmzZzFO/hx56KOzzcIB7AvHI5+4p2xsxBaC9Y2Nlz+KRMHTB2qZNm8oVV1whn376KfMArbwz6FSsBU6cOCEDBw40y7po060Tdb5f8tJJse4P1/OfQDzyuf+UgttjCsDgjq0nkcUjYej2Vddff72JR592FC5c2JPYOCkCfhHYtWuX2cZt9erVpsu6VeKECRMka9asfgmBflogEI98bkHYdOF/BSgAuRXCEohHwtB5gAUKFDDrmTEPMKzh4scBFPj+++8lISFBdu7caZ6G9+3bVzp16sST8QCOtdchxSOfex0T5w9dgAIwdKuY/fKVV16RLl26SJs2bcySDja1eCWMRo0amblN1apVk0GDBtlEQl8QiJnAu+++K/369RN9/ZsjRw6zRmb16tVjdn0uFCyBeOXzYCn6NxoKQMvG7uuvvzZfuupk7sqVK1MA/u/4vPXWW/Lss8+aLayWLl3K0w7L7lu6462AfuChfzDUAlBbiRIlzHw/pkN46x70s1MABn2ELx4fBaBF43/w4EEpVaqUjBo1Svr06SO33nrr2QLwr7/+Mmt86Rw43d9T58T179/frPWlc390y6d33nnHzAvaunWr2TlDF4PV/2DokhB6jH5Nq08UU7IVVLwSxq+//nr2P3Zz586V6667zqKRoysIeCewY8cO88p3zZo15iL169eXcePGmR0+aAikRCBe+TwlfebY6AlQAEbPMsVnaty4sXnCNWTIELnnnnvOFoCnT5+WChUqyIEDB8w/0+Jn3bp1ppDTpVG0ANTdMvQY3S5Nf6eTwkuXLm0WgdUCcNOmTWYrqEmTJkm9evUi7mu8EobOA9RFoP/f//t/0rVrV/MfQRoCQRfQjzy0+Nu9e7dZ00+/+tX1/nTuHw2BlArEK5+ntN8cHx0BCsDoOKb4LNOnTzdP/b755hvJmDHj3wrARYsWmULvxx9/PLsrxrkX1ALw6aefll9++eXsk7EWLVqYOXP69CBLlizm5zpXSIuo0aNHR9zfeCaMJk2amKeaVatWlddeey3iGDgQAdsF9A88mhN03Uvd3u3KK6+UGTNmyL333mt71+mfjwTimc99xBTYrlIAWjC0+sq2TJkyooVeyZIlTY/OfQKo/xEYOXKkbNmy5by91QKwZcuWcujQobP/XJ/66etf3SEguekTRn06OGfOnIijjmfCSC50mQcY8fBxoA8Ejh49Kr1795b58+eb3uq0EP13tmDBgj7oPV30k0A887mfnILaVwpAC0ZW57Q9+uijf5ubd+rUKfOaR1/76NOuwYMHX7QA1DmAOk8wufXo0UP0vN99993Zv6dP0PQ3+vcjbfFMGJs3b5ZChQqZrusE+OS1ASONheMQsE1At3LTf5d1ioc2/fpdn9hnypTJtq7SnwAIxDOfB4DP9yFQAFowhPpU7p9P9/SV7g033CAdO3Y083/01c/FXgG7UADqUGkBqIVg586dpWHDhhaMHl1AIDoCSUlJkpiYKHv37pW0adOa+b76ZJ/5ftHx5Sz/LUAB6PZdQQFo6fif+wpYu6hLwujq//okUJ98/fTTT+Y/DDqvL/kr4KA/AVQHLYw13ipVqhgLGgJ+F9D5fvpxlt7P+sFX7ty5zfSNSpUq+T00+m+5AAWg5QPkcfcoAD0GjvT0/ywA9+zZI+3btzfzgnSuX/IyMDVq1HCqANT/UOpcRv26edmyZeYVOQ0BvwocPnxYdLrGwoULTQhly5aV2bNnS/78+f0aEv32kQAFoI8Gy4OuUgB6gBrkU8Y7Yeircv2SWZv+h7Jo0aJB5ia2AAvox186dWPDhg0mymbNmsnw4cMlQ4YMAY6a0GwSiHc+t8nCxb5QALo46imI2YaEobsf6MLQuv/pE088kYJoOBSB+AgsX77cLOy+f/9+SZ8+vYwYMcIUgDQEYilgQz6PZbxc6+8CFIDcEWEJ2JAwdEs43Rruvvvus26rvLAw+bFzAjrfb/z48TJs2DDRv86XL595kl2uXDnnLAg4/gI25PP4K7jbAwpAd8c+oshtSBi6wLUuj3H55ZfLZ599xjzAiEaSg2ItoHN3u3XrJosXLzaXrlixosyaNUvy5s0b665wPQSMgA35nKGInwAFYPzsfXllGxKGzp0qUKCA8dOvJYsVK+ZLSzrtjoAuXaTz/TZu3GiCbtWqlVnfU1//0hCIl4AN+TxesXNdEQpA7oKwBGxJGPoVtP7HVNdJfPLJJ8OKgR8jEEsB/Vpd56sePHjQfOAxZswY8yU7DYF4C9iSz+Pt4Or1KQBdHfkI47YlYeiE+XHjxpkFsl9//fUIo+EwBLwT0DX9tNgbNWqUuYg+tdYt3UqXLu3dRTkzAmEI2JLPw+gyP42iAAVgFDFdOJUtCWPKlCnmyV+2bNnk888/Zx6gCzefj2LU3X26dOkiS5cuNb3WhdxnzJghuXLl8lEUdDXoArbk86A72xofBaCtI2Npv2xJGNu2bZOrr77aKOlEet02j4aADQI6NUHn++m8P23t2rWT/v37m+3daAjYJGBLPrfJxKW+UAC6NNpRiNWmhKGLQP/8889m/1T9KpiGQLwFlixZIl27dhXd4SNTpkxmyZcGDRrEu1tcH4HzCtiUzxmi2AtQAMbe3NdXtClhNG/eXMaOHSu6bZ7uoEBDIF4Cp06dMos567xUbYUKFZL33ntPSpYsGa8ucV0ELilgUz6/ZGf5QdQFKACjThrsE9qUMKZNmyYNGzaUrFmzmnmAadKkCTY+0VkpsG/fPvM1uu7uoa1q1aqi92bOnDmt7C+dQiBZwKZ8zqjEXoACMPbmvr6iTQnj999/l/z58xtPnWB/4403+tqWzvtPYP369dKmTRvROanaOnfuLL179+YPI/4bSid7bFM+d3IA4hw0BWCcB8Bvl7ctYegi0Bs2bJD27duztprfbiaf93fBggXSvXt3OXr0qGTOnFkmTpwojz32mM+jovsuCdiWz12ytyFWCkAbRsFHfbAtYbRo0cKstXb33XebOVg0BLwWOHnypAwZMkQmTZpkLlWkSBGZO3cuT6C9huf8URewLZ9HPUBOeFEBCkBukLAEbEsY06dPN19ZZsmSRb744gtevYU1mvw4XIE9e/ZIhw4dJCkpyRxaq1Yt0b2pdV9qGgJ+E7Atn/vNz+/9pQD0+wjGuP+2JYw//vhDrrrqKqOgxeBNN90UYxEu54rA2rVrpW3btrJ9+3YTco8ePaRbt24sQu7KDRDAOG3L5wEktjokCkCrh8e+ztmYMIoXLy4//fSTWXC3SZMm9qHRI98LzJs3T3r16iXHjx83u8+888475ukfDQE/C9iYz/3s6be+UwD6bcTi3F8bE8bzzz8vb7zxhtx1110ycuTIOAtx+SAJnDhxQgYOHGiWddGmf9jQ+X66CDkNAb8L2JjP/W7qp/5TAPpptCzoq40JY+bMmVKvXj3zJabOA2TLLQtulAB0YdeuXeap8urVq000tWvXlgkTJph1J2kIBEHAxnweBFe/xEAB6JeRsqSfNiaMHTt2SN68eY2QPqm5+eabLdGiG34V+P777yUhIUF27twpqVKlkr59+0qnTp3MX9MQCIqAjfk8KLZ+iIMC0A+jZFEfbU0Y+vHHunXrzCT9Z555xiIxuuI3gXfffVf69esn+vo3R44cMnXqVKlevbrfwqC/CFxSwNZ8fsmO84OoCFAARoXRnZPYmjBatmwpo0aNkooVK5r5gDQEwhXQDzy08Js9e7Y5tESJEmY/38KFC4d7Kn6PgC8EbM3nvsALQCcpAAMwiLEMwdaEoU9tHn/8cbnsssvMnqzMA4zlXeH/a+k0An3lu2bNGhNM/fr1Zdy4cWZeKQ2BoArYms+D6m1bXBSAto2I5f2xNWH8+eefkjt3bqM3ZcoU8/SGhkAoAqtWrTIfe+zevdus6adf/epUAub7haLHb/wsYGs+97Opn/pOAein0bKgrzYnjFtuuUX+85//yIsvvijPPvusBVp0wWaBM2fOmI+GtODT7d2uvPJKmTFjhtx77702d5u+IRA1AZvzedSC5EQXFKAA5OYIS8DmhNG6dWuzH3CFChVk9OjRYcXFj90SOHr0qPTu3Vvmz59vAi9VqpTMmTNHChYs6BYE0TotYHM+d3pgYhQ8BWCMoINyGZsThk7er1OnjmTKlMnMA0yXLl1Q2IkjigK///67eUr8448/mrM2btzYfDik9w0NAZcEbM7nLo1DvGKlAIyXvE+va3PC0IV7c+XKZWQnT54st956q0+V6bZXAklJSZKYmCh79+41HwoNHTpUdCcZ5vt5Jc55bRawOZ/b7BaUvlEABmUkYxSH7QlDP/744YcfpE2bNtK0adMYqXAZ2wV0vt+kSZNk8ODBcvr0acmTJ4/MmjVLKlWqZHvX6R8CngnYns89C5wTGwEKQG6EsARsTxha+A0bNkzuvPNOGTNmTFix8eNgChw+fFh69OghCxcuNAGWLVvWrPWXP3/+YAZMVAiEKGB7Pg8xDH4WoQAFYIRwrh5me8LQhXt1z1bmAbp6h/497q1bt5r5fhs2bDD/oHnz5uYPCBkyZAAIAecFbM/nzg+QxwAUgB4DB+30ticMXctN5wHqKz/mAQbt7gsvHv0QqEOHDrJ//35Jnz69+UK8WbNm4Z2EXyMQYAHb83mA6a0IjQLQimHwTyf8kDD044/vv/9edFkYfeJDc0tAi//x48ebJ3361/ny5TOvfMuVK+cWBNEicAkBP+RzBtE7AQpA72wDeWY/JAx95ff666+b/+CPHTs2kONAUOcXOHTokHTr1k0WL15sfqB7Q+vHHnnz5oUMAQT+IeCHfM6geSdAAeidbSDP7IeEMW/ePHnkkUckY8aMsmLFCtYDDOSd+N9Bbd682cz327hxo/mHrVq1ktdee828/qUhgMB/C/ghnzNu3glQAHpnG8gz+yFh6BpvV1xxhXn9N3HiRLPLAy3YAkuXLpXOnTvLwYMHzQce+gW4LvBMQwCBCwv4IZ8zft4JUAB6ZxvIM/slYWjR9+2335qnQP/6178CORYEJWZNP932T3fy0FagQAGzpVvp0qXhQQCBSwj4JZ8zkN4IUAB64xrYs/olYSQkJMiQIUPMmm/jxo0L7Hi4HNiBAwfMU79ly5YZhsqVK8uMGTPO7gbjsg2xIxCKgF/yeSix8JvwBSgAwzdz+gi/JIz58+fLww8/bF4H6jxA5oEF67bVeX666PeWLVtMYO3atZP+/fub7d1oCCAQmoBf8nlo0fCrcAUoAMMVc/z3fkkYf/31l+TMmdPMA3z77belTJkyjo9ccMLXL3xfeukl0R0+dMFvXfKlQYMGwQmQSBCIkYBf8nmMOJy7DAWgc0OesoD9lDB0Htjq1avl+eefl+eeey5lgXN03AVOnTplFnNOfqVfuHBh0Z1fdP9nGgIIhC/gp3wefnQccSkBCsBLCfHP/ybgp4TRvn17swzIHXfcYZ4S0fwrsG/fPunYsaPo7h7aqlWrJlOnTjVPeWkIIBCZgJ/yeWQRctTFBCgAuT/CEvBTwvjggw+kVq1aZv6fzgNk/9ewhtqaH69fv97M99u2bZvpU5cuXaRXr16SJk0aa/pIRxDwo4Cf8rkffW3vMwWg7SNkWf/8lDD0qZE+IdKlQt566y25/fbbLdOkO5cSWLBggXTv3l2OHj0qWbJkMes61q5d+1KH8c8RQCAEAT/l8xDC4SdhClAAhgnm+s/9ljC06Pvmm2/MHECdC0jzh8DJkyfNMj6TJk0yHS5SpIjMnTtXbrzxRn8EQC8R8IGA3/K5D0h91UUKQF8NV/w767eEkZiYKIMGDTJfAevXwDT7Bfbs2SMdOnSQpKQk01l9jT958mS5/PLL7e88PUTARwJ+y+c+ovVFVykAfTFM9nTSbwlDXyHWqFGDeYD23EIX7cnatWulbdu2sn37dvO7Hj16SLdu3SR16tQ+iYBuIuAfAb/lc//I+qOnFID+GCdreum3hLF//34zD1CXENEvgfWLYJqdAvPmzTMfdxw/flyyZcsm77zzjnn6R0MAAW8E/JbPvVFw96wUgO6OfUSR+zFh6HZwK1eulBYtWkjLli0jipuDvBM4ceKEDBgwQKZPn24uUrx4cTPfr2jRot5dlDMjgID4MZ8zbNEToACMnqUTZ/JjwtD147TAKFWqlPmKlGaPwK5du8w2brpgtzb9wnfChAmS8be4cQAAHzNJREFUNWtWezpJTxAIqIAf83lAhyIuYVEAxoXdvxf1Y8JYuHChPPjgg5IuXTqzkLBuH0aLv8D3338vCQkJsnPnTkmVKpX07dtXOnXqZP6ahgAC3gv4MZ97r+LOFSgA3RnrqETqx4Rx4MAByZEjh5kHqNuI6SthWnwFZs2aJf369RNd7kXHRnf1qF69enw7xdURcEzAj/ncsSHyNFwKQE95g3dyvyaMcuXKmWVFmjdvLq1btw7ewPgkIv3AQwu/2bNnmx7rPr66n6/u60tDAIHYCvg1n8dWKbhXowAM7th6EplfE0bnzp2lf//+zAP05K4I7aQ7duwwr3zXrFljDmjQoIGMHTtWMmfOHNoJ+BUCCERVwK/5PKoIDp+MAtDhwY8kdL8mjI8//ti8YkybNq3ZF5h5gJGMfuTHrFq1ynzssXv3brOH78CBA+XFF19kvl/kpByJQIoF/JrPUxw4JzACFIDcCGEJ+DVhHDx40Mw10zlnb775ppQvXz6suPlxZAJnzpyRadOmmYJP7a+88kqZOXOmVK5cObITchQCCERNwK/5PGoAjp+IAtDxGyDc8P2cMO6880758ssvpVmzZvLCCy+EGzq/D1Pg6NGj0rt3b5k/f745snTp0jJnzhwpUKBAmGfi5wgg4IWAn/O5Fx6unZMC0LURT2G8fk4YXbp0kVdeeUVuvfVWs7cszTuB33//3bzi/fHHH81FGjduLG+88Qav3r0j58wIhC3g53wedrAc8F8CFIDcFGEJ+DlhLF68WKpWrWrmAep6gJdddllYsfPj0AT0a+vExETZu3evsR46dKg8//zzzPcLjY9fIRAzAT/n85ghBfhCFIABHlwvQvNzwjh06JCZB6hbj40ZM0b0lTAtegI632/SpEkyePBgOX36tOTJk0d0vb9KlSpF7yKcCQEEoibg53weNQSHT0QB6PDgRxK63xNGxYoVzdO/pk2bSps2bSIh4JjzCBw+fFh69OghuuuKNl1sW9f6y58/P14IIGCpgN/zuaWsvukWBaBvhsqOjvo9Ybz00ktmyzFdgHjKlCl2oPq8F1u3bjXF9M8//2wi0cW2hw0bJhkyZPB5ZHQfgWAL+D2fB3t0vI+OAtB740Bdwe8JY8mSJVKlShWzFp2uB8g8wJTdnl988YV06NBBdLu99OnTy4gRI8xX1jQEELBfwO/53H5hu3tIAWj3+FjXO78nDH1VmT17djMPcPTo0VKhQgXrjP3QIZ3vp/sqDx8+XPSv8+XLZ1756pZ7NAQQ8IeA3/O5P5Tt7SUFoL1jY2XPgpAw9KMEfXL1zDPPSNu2ba10trlT+jGNvkrXp6nadF6lfuyRN29em7tN3xBA4B8CQcjnDGrkAhSAkds5eWQQEsbLL79sFihmHmD4t/Cvv/5q1vfbtGmTObhVq1by2muvmde/NAQQ8JdAEPK5v8Tt6i0FoF3jYX1vgpAw/v3vf8t9991n5gHqF8GZM2e23t2GDi5dulQ6d+4suq1exowZzVI6jRo1sqFr9AEBBCIQCEI+jyBsDvlfAQpAboWwBIKQMI4cOWLmAR4/flxGjRrFOnWXuAN0TT+dL6k7eWjTrdx0Szfd2o2GAAL+FQhCPvevfvx7TgEY/zHwVQ+CkjDuvvtu+eyzz+Tpp5+WhIQEX41BLDurX/fqU79ly5aZy957770yffp0yZUrVyy7wbUQQMADgaDkcw9onDglBaATwxy9IIOSMLp37y69evWSm2++WaZNmxY9oACdaePGjWZ9vy1btpio2rVrJ/379zfbu9EQQMD/AkHJ5/4fifhEQAEYH3ffXjUoCUPns1WuXFlSp05t5gFmyZLFt2PiRcd132T90leXzcmUKZO89dZbUr9+fS8uxTkRQCBOAkHJ53Hi8/1lKQB9P4SxDSAoCePo0aNmHuCxY8dk5MiRctddd8UW0tKrnTp1yizmrGv8aStcuLC899575otpGgIIBEsgKPk8WKMSu2goAGNnHYgrBSlh6BNAfRLYpEkT83rT9bZv3z7p2LGjeSKqrVq1ajJ16lTJmTOn6zTEj0AgBYKUzwM5QB4HRQHoMXDQTh+khNGzZ0/p0aOH3HjjjTJjxoygDVVY8axfv97M99u2bZs5rkuXLmaOpC6VQ0MAgWAKBCmfB3OEvI2KAtBb38CdPUgJQ79sveeee8w8wM8//1yyZcsWuPEKJaAPP/zQFML6WlznQk6cOFFq164dyqH8BgEEfCwQpHzu42GIW9cpAONG788LBylhaMGTI0cOU/jovDddGsaldvLkSRkyZIhMmjTJhF2kSBGZO3eueSJKQwCB4AsEKZ8Hf7SiHyEFYPRNA33GoCUMXdfu008/NTtaJCYmBnrszg1uz549Jt6VK1eav12rVi2ZPHmyXH755c4YECgCrgsELZ+7Pp7hxk8BGK6Y478PWsLQPYF1b+DixYvLzJkznRjdtWvXmv18//jjDxOvvv7t1q2beRVOQwABdwSCls/dGbnoREoBGB1HZ84StIShc/90CZhUqVKZeYBBfwKmr3i16NVt8HTO45QpU6RmzZrO3L8EigAC/ycQtHzO2IYnQAEYnpfzvw5awtB1AHU9QJ0HOGzYMLM4dBDbiRMnZMCAAWYbN206z0/X9ytatGgQwyUmBBAIQSBo+TyEkPnJOQIUgNwOYQkEMWHcf//98sknn8hTTz0lHTp0CMvDDz/etWuXWedw9erVpruPPfaYvP3225I1a1Y/dJ8+IoCARwJBzOceUQXytBSAgRxW74IKYsLo06ePmQN3ww03yKxZs7zDi8OZv//+e0lISJCdO3ea19z9+vUziz3rX9MQQMBtgSDmc7dHNLzoKQDD83L+10FMGLrzRcWKFQM3D1CLWS34dLkXXe5m2rRpZncPGgIIIKACQcznjGzoAhSAoVvxy4AmDP0gQgukw4cPy9ChQ+W+++7z9VhrPFr4zZ4928Sh+/jqfD/d15eGAAIIJAtQALp9L1AAuj3+YUcf1IRRtWpVWbx4sTz55JPmFalf244dO8wr3zVr1pgQGjRoIGPHjpXMmTP7NST6jQACHgkENZ97xBW401IABm5IvQ0oqAlDn5h17drVfBWb/OTMW8non33VqlXmY4/du3ebPXwHDhxo1vtjvl/0rTkjAkEQCGo+D8LYxCIGCsBYKAfoGkFNGCtWrJAKFSqYkdL1AHVpGL+0M2fOyNSpU2XQoEFmvt+VV15pFrUO6pI2fhkX+omA7QJBzee2u9vSPwpAW0bCJ/0IasLQdfK06PPbPEBdv1AXdp4/f765g0qXLi1z5syRAgUK+OSOopsIIBAvgaDm83h5+u26FIB+G7E49zfICUO/kF20aJE0bNhQOnfuHGfpS1/+999/N694f/zxR/Pjxo0byxtvvCGZMmW69MH8AgEEnBcIcj53fnBDAKAADAGJn/yfQJATRv/+/U3hV6RIEfMUzeaWlJQk7du3l7/++kvSpk1rvl5+/vnnme9n86DRNwQsEwhyPreM2sruUABaOSz2dirICeOrr76S8uXLG/xly5ZJzpw5rRsIne83adIkGTx4sJw+fVry5MljFq+uVKmSdX2lQwggYLdAkPO53fJ29I4C0I5x8E0vgpwwdB6grgd46NAhU2BVqVLFqnHR+Yk9evSQhQsXmn6VLVvWfLGcP39+q/pJZxBAwB8CQc7n/hiB+PaSAjC+/r67etATxgMPPCAfffSRWT+vS5cu1ozP1q1bpU2bNvLzzz+bPjVv3lyGDRsmGTJksKaPdAQBBPwlEPR87q/RiH1vKQBjb+7rKwY9Ybz66qvSqVMnuf76683uGTa0L774Qjp06CAHDhyQ9OnTy8iRI6Vp06Y2dI0+IICAjwWCns99PDQx6ToFYEyYg3ORoCeMlStXmler2pYuXSpXXHFF3AZP5/uNGzdOhg8fLvrX+qpXX/km9y9uHePCCCAQCIGg5/NADJKHQVAAeogbxFMHPWHoQsr68Yc+bdOFlXVpmHg0nYf40ksvyZIlS8zl9SMP/dhDP/qgIYAAAtEQCHo+j4ZRkM9BARjk0fUgNhcSRo0aNWTBggVSr149U4TFuv36669mfb9NmzaZS7du3Vpee+01SZcuXay7wvUQQCDAAi7k8wAPX4pDowBMMaFbJ3AhYegeujrnrnDhwjJv3ryYDrC+dta1CA8ePCgZM2aUMWPGSKNGjWLaBy6GAAJuCLiQz90YyciipACMzM3Zo1xIGF9//bXccccdZow//fRTs7eu103X9NNdPEaPHm0upVu56WLUurUbDQEEEPBCwIV87oVbUM5JARiUkYxRHC4kDJ0HqB9/7N+/X/RpYPXq1T3V1evokjO6+LS2e++9V6ZPny65cuXy9LqcHAEE3BZwIZ+7PcIXj54CkLsjLAFXEkbNmjXlww8/lLp160q3bt3CMgrnx7/88ouZ77dlyxZzWLt27US3pNPt3WgIIICAlwKu5HMvDf18bgpAP49eHPruSsLQjy50r91ChQrJ/PnzPZFetGiR+cjkyJEjkilTJnnrrbekfv36nlyLkyKAAAL/FHAlnzPy5xegAOTOCEvAlYSxatUqKVOmjLH597//HdXXsadOnTJr+40fP96cXz820UWnS5QoEdZY8GMEEEAgJQKu5POUGAX5WArAII+uB7G5kjC0SNN5gPv27ZMBAwaIbhEXjabn0y+MV6xYYU6n6wxOnTrVrD1IQwABBGIp4Eo+j6Wpn65FAein0bKgry4ljIceekjef/99efzxx+Xll19Osf769evNfr7btm0z59IPP3r16iVp0qRJ8bk5AQIIIBCugEv5PFwbF35PAejCKEcxRpcSxuDBg81HGddee60pBFPS9IOSHj16yNGjRyVLliwyceJEqV27dkpOybEIIIBAigRcyucpggrowRSAAR1Yr8JyKWF8++23UqpUKUP5ySefSO7cucNm1SVlhgwZIpMmTTLHFi1a1Mz3u/HGG8M+FwcggAAC0RRwKZ9H0y0o56IADMpIxigOlxKGzgPURaD/+usvszSLbhEXTtuzZ48kJibKypUrzWG1atWSyZMny+WXXx7OafgtAggg4ImAS/ncE0Cfn5QC0OcDGOvuu5YwHnnkEbMd3GOPPWZe4Yba1q5da9b3++OPP8whPXv2NEu+pE6dOtRT8DsEEEDAUwHX8rmnmD48OQWgDwctnl12LWEMHTpU2rZtKwULFpQPPvggJPq5c+dK79695fjx45ItWzaZMmWK6MLSNAQQQMAmAdfyuU32NvSFAtCGUfBRH1xLGN99953cdtttZoSWLFkiefLkueBonThxwiwZo9u4adN5fjrfT+f90RBAAAHbBFzL57b5x7s/FIDxHgGfXd+1hHH69GkzD3Dv3r3yyiuvXPBJ3q5du8wXw6tXrzYjqq+M3377bcmaNavPRpjuIoCAKwKu5XNXxjXUOCkAQ5Xid0bAxYTx6KOPir7W1WVbdC7fP5s+JUxISJA///xTUqVKJf369ZOOHTuav6YhgAACtgq4mM9tHYt49IsCMB7qPr6miwlj2LBhZgHna665RhYsWPC30Zs1a5Yp+HS5lxw5csi0adPM7h40BBBAwHYBF/O57WMSy/5RAMZSOwDXcjFhrFmzRkqWLGlGr3PnzlKkSBG5+eab5dVXX5XZs2ebv6/7+Op8P93Xl4YAAgj4QcDFfO6HcYlVHykAYyUdkOu4mDDeffddqVevnuh8wOSWLl060Y8+tDVo0EDGjh0rmTNnDsgoEwYCCLgg4GI+d2FcQ42RAjBUKX5nBFxLGHPmzJE6derImTNnznsHNGnSRN566y3m+/HvBwII+E7AtXzuuwHyuMMUgB4DB+305yYM3eHiqquuClqIZ+PRnUDKly8v27dvv2CM+fLlkxUrVkiaNGkC60BgCCAQTAHNbXfccYcJbuvWrXL11VcHM1CiOq8ABSA3RlgC5xaAYR3IjxFAAAEErBWgALR2aDzrGAWgZ7TBPDEFYDDHlagQQMBtAQpA98afAtC9MU9RxLrcSfL+tik6kQ8O/vLLL6Vu3bqX7OnMmTPNq2IaAggg4FeBvHnzStq0af3affodgQAFYARofjjkfIsQ65erupXZXXfdJZ06dZJbbrnFD6HErY86B/Daa6+Vbdu2nfcjEDXWOTO//vorcwDjNkpcGAEE4ilw6NAhefPNN2X+/Pmybt06s2uSrohwww03SJUqVaRp06ZSoECBeHaRa19AgAIwoLdGcgHYuHHjsxHu27dPVq1aZSb7pk+fXj766COpXLlyQAWiE1byV8B6tnO/BE721SVidIcQGgIIIOCawFdffWXyn35Mctlll0m5cuXMQwb9b83XX39tdkfKkCGDfPDBB3L//fe7xmN9vBSA1g9RZB1MLlD+uXyJrl337LPPyuTJk80TQF3kmHZxAS0CdScQnf+Y3HRXkKFDh1L8cfMggICTAvrfDi34jhw5Yra+7Nat29/WQtV1U3ULzQ4dOshLL70kumQWzS4BCkC7xiNqvblQAagX2LRpk1x33XXmWvq4Pnv27FG7blBPpK+DP//8c/MnXV36plKlSrz2DepgExcCCFxUQB8s6O5IP/zwg/To0UO6d+9+wd/r00B966S7J9HsEqAAtGs8otabixWAOmcjS5Ys5lr6iP7KK6+M2nU5EQIIIIBAsAV0+tADDzxwdg40H4/4c7wpAP05bpfs9cUKwM8++0zuvvtuU/hpAUhDAAEEEEAgVIHWrVvLiBEjpG3btjJ48OBQD+N3lglQAFo2INHqzvkKQH0Ur7t3tGrVSjZs2GD+xdV/gWkIIIAAAgiEKlCxYkVZvny5mUv+5JNPhnoYv7NMgALQsgGJVnfOtwxM8rlz585tPmBo0KBBtC7HeRBAAAEEHBEoXry4/PTTT2YliWrVqjkSdfDCpAAM3piaiM63DMyxY8dky5YtkpSUJLqH7TvvvGNeBdMQQAABBBAIVUDX+Fu/fj0FYKhglv6OAtDSgUlpty42B/Dbb781hd/x48flxx9/lEKFCqX0chyPAAIIIOCIAK+AgzHQFIDBGMf/iuJiBaD+ODExUQYNGiQJCQny2muvBVSBsBBAAAEEoi2g88hHjhzJRyDRho3x+SgAYwweq8tdqgAcNWqUtGzZUmrUqGFWaachgAACCCAQisDChQvlwQcfZBmYULAs/g0FoMWDk5KuXaoAbN++vXnyV7duXZkxY0ZKLhW3Y//5oYv+/2zZspkdTnQLPN3x5GIfw8St41wYAQQQ8LGALgSteXbt2rWXXAh6//79ZiHom266yccRB7PrFIDBHNezhc8/t4LTcJPnAB44cEAmTJhgiiU/tn9+6KK7dWzcuFF0f0qNu379+jJt2jQ/hkafEUAAAasFvvvuOylfvrwcPXpUOnXqZLZ7y5w589k+aw5+//33RR82dOnSha3gLBxNCkALByUaXTrfV8D60Yd+BawFku7TWKtWLbNXY+rUqaNxyZif40JPORcvXmxeT5w8edIkoJo1a8a8b1wQAQQQCLqArgX42GOPyY4dO+Syyy4zBWGePHlE15z95ptvzN/PmDGjmWZ03333BZ3Dd/FRAPpuyELr8PlefWqhp/v+lihRQp566inzJzK/Fn+qcLHX3M8884y8/fbb5jXwuHHjQkPjVwgggAACYQkcPHhQxowZY/6wvW7dOrO/vG41WqxYMalevbo0bdrUzBWk2SdAAWjfmNCjEAUuVgAOHz5cXnjhBalatap8/PHHIZ6RnyGAAAIIIOCGAAWgG+McyCgvVgD269dPunbtal5zz58/P5DxExQCCCCAAAKRClAARirHcXEXuFABqJOPK1SoIF9++aUpAvv06RP3vtIBBBBAAAEEbBKgALRpNOhLWAL/LAD1K+BNmzaJPv3Tr5szZMhglim47rrrwjovP0YAAQQQQCDoAhSAQR/hAMd3sTX+smbNKhMnTpRHH300wAKEhgACCCCAQGQCFICRuXGUBQL/XOpGv2hOXgi6du3akiNHDgt6SRcQQAABBBCwT4AC0L4xoUchClxqt5MQT8PPHBHYtm2bdOzYUXQbqyNHjkjRokVl/PjxUrp0aUcECBMBBBD4PwEKQO4G3wpQAPp26GLecV2b7LbbbpPKlSvLc889J7lz5za7xlx77bXMEY35aHBBBBCwQYAC0IZRoA8RCVAARsTm5EG6VZXuWvD5559fMP5jx45Jt27dzPaBO3fulAIFCpgtrnQx8aVLl5ri8aOPPjJ/76effjK7HkyfPl1WrVolCQkJok8Ya9SoYZ4q6q4INAQQQMBmAQpAm0eHvl1UgAKQGyRUgRtvvFGqVasmv/32myxbtkzy588vzz//vDRr1uzsKerVq2eWDnr99delZMmS8uuvv8quXbtE/35yAViuXDkZNGiQKfDq1q1rzqNfm/fv3190RwT96CgxMdG8aqYhgAACNgtQANo8OvSNApB7ICoCuh+pNn1S9/jjj8vKlSvlxRdfNFtYNWrUSDZs2GC2rtJ9pO+///7/umZyAbhkyZKze5pq0de5c2fzKrlw4cLmmBYtWsjmzZvNk0IaAgggYLMABaDNo0PfKAC5B6IikD59eilTpoysWLHi7Pl0q8Cvv/7aPPWbOXOmNGzY0Hwcki5dugsWgPpqOFeuXOaf617TrVq1kkOHDp39fffu3c2eqKtXr45KvzkJAggg4JUABaBXspwXAQSsEShYsKBUqVJFxo0bd7ZPb7zxhtklRufuadGmr28vVQDqxyTZs2c359DFxvUp4l9//XX2nD169JC5c+fKd999Z03sdAQBBBA4nwAFIPcFAggEXkCf7m3duvVvH4G0bdtWkpKSzFNBfW2rr3EXLVp00VfAFICBv1UIEAFnBCgAnRlqAkXAXQF91XvnnXdKz549zccbOgdQPwB588035YknnjAwTz/9tHzyyScybNgw8xHIli1bzNfA+vvkOYAUgO7eQ0SOQNAEKACDNqLEgwAC5xX44IMPzEcbP//8sxQqVMh8EHLuV8BHjx6VLl26mKVddu/ebZaB0f+vhSEFIDcVAggETYACMGgjSjwIIIAAAggggMAlBCgAuUUQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBCgAHRtwwkUAAQQQQAABBCgAuQcQQAABBBBAAAHHBP4/Mi7byKpRUgcAAAAASUVORK5CYII=\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib nbagg\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as pat\n",
"from matplotlib.animation import PillowWriter,FuncAnimation\n",
"\n",
"fig = plt.figure()\n",
"ax1 = fig.add_subplot(111)\n",
"\n",
"A=np.array([-3,2])\n",
"B=np.array([-3,-2])\n",
"C=np.array([3,-2])\n",
"D=np.array([3,2])\n",
"\n",
"scale=1.1\n",
"scaleP=1.2\n",
"\n",
"p = pat.Polygon(xy = [A,B,C,D],\n",
" edgecolor='black',\n",
" facecolor='white',\n",
" linewidth=1.6)\n",
"\n",
"def initialize():\n",
" ax1.set_xlim(-4,4)\n",
" ax1.set_ylim(-3,3)\n",
" ax1.add_patch(p)\n",
"\n",
"\n",
" ax1.text(A[0]*scale,A[1]*scale,\"A\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(B[0]*scale,B[1]*scale,\"B\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(C[0]*scale,C[1]*scale,\"C\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(D[0]*scale,D[1]*scale,\"D\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
"\n",
" ax1.text(-3.5,0.0,\"4cm\",horizontalalignment='center',verticalalignment='center')\n",
" ax1.text(0.0,-2.5,\"6cm\",horizontalalignment='center',verticalalignment='center')\n",
"\n",
" \n",
"\n",
"def moveP(x):\n",
" if 0<= x <4:\n",
" return A+np.array([0,-1])*x*velocity\n",
" elif 4<=x <10:\n",
" return B+np.array([1,0])*(x-4)*velocity\n",
" elif 10<= x <14:\n",
" return C+np.array([0,1])*(x-10)*velocity\n",
" else:\n",
" return D\n",
" \n",
"\n",
"velocity=1.0\n",
"timestep=0.1\n",
"\n",
"def animate(t):\n",
" plt.cla()\n",
" initialize()\n",
" \n",
" x=timestep*t\n",
" P=moveP(x)\n",
" \n",
" ax1.plot(P[0],P[1],marker='o',color='black')\n",
" ax1.text(P[0]*scaleP,P[1]*scaleP,\"P\",fontsize=15,horizontalalignment='center',verticalalignment='center')\n",
" \n",
" S = pat.Polygon(xy = [A,P,D],\n",
" edgecolor='black',\n",
" facecolor='lightgray',\n",
" linewidth=1.6)\n",
"\n",
" ax1.add_patch(S)\n",
" \n",
" plt.axis('off')\n",
" plt.title('x=' + '{:.1f}'.format(x)+'sec')\n",
" \n",
"anim = FuncAnimation(fig,animate,frames=140,repeat=True,interval=timestep*1000)\n",
"#anim.save(\"ugokutenP.gif\", writer='pillow',fps=10)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment