Skip to content

Instantly share code, notes, and snippets.

@jburroni
Created March 29, 2016 15:45
Show Gist options
  • Save jburroni/0a8b65bf2c6405a15d79 to your computer and use it in GitHub Desktop.
Save jburroni/0a8b65bf2c6405a15d79 to your computer and use it in GitHub Desktop.
Plot complex inequealities
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/__init__.py:872: UserWarning: axes.color_cycle is deprecated and replaced with axes.prop_cycle; please use the latter.\n",
" warnings.warn(self.msg_depr % (key, alt_key))\n"
]
}
],
"source": [
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib\n",
"from matplotlib import pyplot as plt\n",
"import seaborn as sns"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"sns.set(style= 'whitegrid')"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class GrafGen:\n",
" def __init__(self, max_coor, values=50):\n",
" self._max = max_coor\n",
" self.values = values\n",
" def PointGen(self):\n",
" mp = self._max*2\n",
" C = lambda x:1.0*(x-self._max)/mp\n",
" for x in xrange(self.values+1):\n",
" for y in xrange(self.values+1):\n",
" z = C(x)+(C(y)*1j)\n",
" yield z\n",
" def Show(self, filter_func):\n",
" min_x = min_y = -1 * self._max\n",
" max_x = max_y = self._max\n",
" points_x, points_y = [], []\n",
" for z in self.PointGen():\n",
" if filter_func(z):\n",
" points_x.append(z.real) \n",
" points_y.append(z.imag)\n",
" #print len(points_x)\n",
" plt.scatter(points_x, points_y)\n",
" plt.axis([min_x, max_x, min_y, max_y])\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"F = lambda z: ((1+2*1j)*z).real>=0\n",
"c = GrafGen(3)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<__main__.GrafGen instance at 0x1100f9b00>"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c"
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"c.Show(F)"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x, y = np.mgrid[-6:3:.01, -3:3:.01]"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"C = (x + y *1j).flatten()"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"index = np.where(F(C))"
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAG4CAYAAADVDFZ+AAAgAElEQVR4Xu3df5AkZ33f8W/P7u3d3ukH9hmwZFIo4rZ7b4+LVjj2ErAlHEyQKcgftrDjsrGNjO0gY5djQhBJ2ZRt/KOccrBjW5gYJ45jF9hxRSgB+wy5YkF3ToQh2tu9H9u9hxACVIQICW4P3e3czDypZ3dHGu3N7vb09/vMdM+85x+Btvs73a/vc3sfzdPzPJHwQgABBBBAAAEEEBgpgWik7pabRQABBBBAAAEEEBACIIMAAQQQQAABBBAYMQEC4Ig1nNtFAAEEEEAAAQQIgIwBBBBAAAEEEEBgxAQIgCPWcG4XAQQQQAABBBAgADIGEEAAAQQQQACBERMgAI5Yw7ldBBBAAAEEEECAAMgYQAABBBBAAAEERkyAADhiDed2EUAAAQQQQAABAiBjAAEEEEAAAQQQGDEBAuCINZzbRQABBBBAAAEECICMAQQQQAABBBBAYMQECIAj1nBuFwEEEEAAAQQQIAAyBhBAAAEEEEAAgRETIACOWMO5XQQQQAABBBBAgADIGEAAAQQQQAABBEZMgAA4Yg3ndhFAAAEEEEAAAQIgYwABBBBAAAEEEBgxAQLgiDWc20UAAQQQQAABBAiAjAEEEEAAAQQQQGDEBAiAI9ZwbhcBBBBAAAEEECAAMgYQQAABBBBAAIEREyAAjljDuV0EEEAAAQQQQIAAyBhAAAEEEEAAAQRGTIAAOGIN53YRQAABBBBAAAECIGMAAQQQQAABBBAYMQEC4Ig1nNtFAAEEEEAAAQQIgIwBBBBAAAEEEEBgxAQIgCPWcG4XgWEQmJqael2tVpsSkRtF5IZarfaz586d+8ow3Bv3gAACCPRDgADYD2XeAwEEzARmZmZe2Gw2vzdN03f7onEc/3YURYfSNH2t2ZtQCAEEEBhyAQLgkDeY20Ng2AQ2P/3781ar9Q0rKytrU1NTr42i6ANZll3T7V79z1dWVj5k4RDH8TuiKHJra2t/8Mgjj3zVoiY1EEAAgUEIEAAHoc57IoCARmBsamrqH6ysrDzkiyRJ8tMi8qY0TW/tLHro0KGXnD9//v8kSfLHaZq+8dChQ7f6/7/1jeM4/iMR+U7n3MvHxsamLl++fHancOc/gWw0GndHUfT1Vqv1npWVlf+32830+h671ePnCCCAgFaAAKgV5HwEEBiYwJEjRyauXLnyqSiK3pym6cmOC4niOP6tKIr8p3TXishzW63Wx1dWVv5T58XGcfztzrnrJyYmlq5cufI659xfr6ysfCHPDR0+fPiGVqvlw6eLoug9y8vLj3U7T/Meea6DYxBAAIEiAgTAImqcgwACpRCI4/jficjxLMs+vPWCNsPhv4qi6Aedc7+QZdl/2+GiayLSav/85ptvfv6ePXvuTNP093e70cOHDx9stVpv8UGz1Wr98srKyoVtznnWe+xWl58jgAACIQUIgCF1qY0AAsEENqd+T6VpeuLQoUOHzp8/f77jzWpJkvx1q9W6p1ar+U/2Homi6B+mafqzXS5obDP8uSRJ/n6app/t5aIPHTp0ZGxs7MdE5IvXXHPN73/605++Yv0evVwPxyKAAAJ5BAiAeZQ4BgEESiUQx7H/VO9is9n85OTkZNRoNH4kTdPf7HaRSZK8P03TH+z2sziO50Tklj179vz3tbW1g7Va7R87505EUXTH+Pj4X549e3Zluxufnp7+1lar9YYoitLx8fE/OnPmTD3ve4jIqSiKXi8in3HOvTjLsjeVCpiLQQCBoRcgAA59i7lBBIZL4NChQ/+oVqt9IooiP6Xafn04TdN/uk0A++4sy/7n1p8dPnz4xWtraxcmJiYazrkHRGS51Wp9r39eMIqif91oNN7x8MMPf23reXEcf6eI/IBz7tMrKyt/IiLN7YS3e4+xsbGJVqt174033vjG+fn5xnB1iLtBAIEqCBAAq9AlrhEBBPomcNNNNz1n7969v9FsNn/1/Pnzn+984yRJ7nHOfS7Lsg/4L38oLmosjuM/zrLsDYoanIoAAggUFiAAdtAlSfLzzrk3bv5i/7sbb7zxp/iv88JjixMRqKSAf56wVqv9MxH5H1mWnQpxE3EczzrnXrqysvIHIepTEwEEENhNgAC4KZQkybc5595Xr9fnHnnkkctxHP9JrVb79PLy8u/shsjPEUAAAQQQQACBKgkQADe7tflf/TdkWeafBfLbS73V7zOaZZn/Jy8EEEAAAQQQQGBoBAiAXVr5ohe96HljY2MPisiPtAPh0HScG0EAAQQQQACBkRcgAG4ZAtPT0zc55/y+oX+apulv7DRCnHPRqVOnblxbW1sd+ZEEAAIIIIAAAhUS2Lt377W33HLLY35/7wpdttmlEgA7KP2D2VEU+fD3a2ma3rub8sLCwrc0Go1c20btVoufI4AAAggggEB/BcbHx18wOzv7xf6+aznejQC42YepqSm/9tfi5p6iH8zTngcffPC6sbGxryVJIhMTE3lO4ZhtBJrNppw9e1ZmZmZkbMxvzMCriACORdS6n4MllnYCNpUYkzaOvkq9Xpc0TaXZbF4/Nze33faNdm9YwkoEwM2mJEnyLufcz0VRlImId/EfCfvFZX9hu761A+DRo0cJgMrB7X+xLSwsyOzsLAFQYYmjAm/LqVhiaSdgU4kxaePYDoBLS0sEQDvS0apEALTrN7/YbCxxtHH0VbDE0k7AphJj0saRALjhyCeAivFEAFTg8WmLHV5HJf6CsGPFEks7AZtKjEkbRwIgAVA9kgiAasKnC/CLzcYSRxtHPgG0c8TSzpI/33aW/hlApoDtPEeuEgHQruX8YrOxxNHGkdBi54ilnSV/vu0sCYBMAatGEwFQxfesk/nFZmOJo40jocXOEUs7S/5821kSAAmAqtFEAFTxEQDt+JhKxzKAgF1JgouNJY42jr4KAZAAqBpNBEAVHwHQjo8AiGUAAbuSBBcbSxxtHAmAG458C1gxngiACrwtp/KLzcYSRxtHXwVLLO0EbCoxJm0cCYAEQPVIIgCqCfnkyo5wvRJ/QdiBYomlnYBNJcakjSMBkACoHkkEQDUhAdCOkACIpbGAXTmCi40ljjaOBEACoHokEQDVhARAO0ICIJbGAnblCC42ljjaOBIACYDqkUQAVBMSAO0ICYBYGgvYlSO42FjiaONIACQAqkcSAVBNSAC0IyQAYmksYFeO4GJjiaONIwGQAKgeSQRANSEB0I6QAIilsYBdOYKLjSWONo4EQAKgeiQRANWEBEA7QgIglsYCduUILjaWONo4EgAJgOqRRABUExIA7QgJgFgaC9iVI7jYWOJo40gAJACqRxIBUE1IALQjJABiaSxgV47gYmOJo40jAZAAqB5JBEA1IQHQjpAAiKWxgF05gouNJY42jgRAAqB6JBEA1YQEQDtCAiCWxgJ25QguNpY42jgSAAmA6pFEAFQTEgDtCAmAWBoL2JUjuNhY4mjjSAAkAKpHEgFQTUgAtCMkAGJpLGBXjuBiY4mjjSMBkACoHkkEQDUhAdCOkACIpbGAXTmCi40ljjaOBEACoHokEQDVhARAO0ICIJbGAnblCC42ljjaOBIACYDqkUQAVBMSAO0ICYBYGgvYlSO42FjiaONIACQAqkcSAVBNSAC0IyQAYmksYFeO4GJjWXbHz31uTY4da63f7B131OSFL9xrc+MBqtTrdVlaWpJms3n93NzchQBvUfqSUemvsMQXSAC0a07Zf7HZ3WnYSjja+WKJpZ2ATaWyjsknn2zI3/7tRfnd390vf/M3E+s3++pX1+W973WlDYEEQBECoOLPJQFQgbfl1LL+YrO7w/5UwtHOGUss7QRsKpVxTD744KosLDhZXa3J2952zbNu9Pd+76L89E8/+9/ZSOirEAAJgKpRRABU8T3r5DL+YrO7u/5VwtHOGkss7QRsKpVpTPrp3oceuiRpOi5RJNJqibzjHc8Oe7/+6xflnnsIgDbdt6/CJ4AKUwKgAo9PAO3wOiqV6S+IIDfYx6JY2mFjaWNZFseHHvq6zM+35MqVaD34+deBA07+4i/2yYkTe9b//3d8xxX5/u+/LD/zM9fa3LxxFT4B5BNA1ZAiAKr4+ATQju/pSmX5CyLArfW9JJZ25FjaWA7aceNZv6dkcbG2fkP+kz8f/Pbtc+v//xOfmJCnntr42f79Lbnttrr8xE9cZ3PzxlUIgARA1ZAiAKr4CIB2fARALAMI2JUcdHCxu5PBVhqk47lzl+S++5oyOSlSr4s4J3Lw4ObHf5ssZ8+OS622MbHYajmZmWkQAAc7ZHZ8d6aAFc0hACrwtpw6yF9sdncx+Eo42vUASyztBGwqDWpM+infj3/cyeXLG/fR+alf550RAG363K8qBECFNAFQgUcAtMPrqDSovyCC3MyAi2Jp1wAsbSz77dg55eune9vhb7u7OX9+TMbHNw5sNJwcOtTkGUCb1gepQgBUsBIAFXgEQDs8AiCWQQTsivY7uNhdebkq9dPRL+9y/Hj09JTv/v3PPOu3nQrPAJZrvOx2NQTA3YR2+DkBUIFHALTDIwBiGUTArmg/g4vdVZevUj8cO5d38c/5tT/1a3/RYycVpoDLN2Z2uiICoKJfBEAFHgHQDo8AiGUQAbui/Qgudldb3kqhHf0XPY4da1y1vEteEaaA80qV4zgCoKIPBEAFHgHQDo8AiGUQAbuioYOL3ZWWu1Iox41n/S7J6dMb6/ptXd4lrwpTwHmlynEcAVDRBwKgAo8AaIdHAMQyiIBd0VDBxe4Kq1EphGN7eZexsY3g5wPg1uVd8uowBZxXqhzHEQAVfSAAKvAIgHZ4BEAsgwjYFQ0RXOyurjqVrB3zLu+SV4gAmFeqHMcRABV9IAAq8AiAdngEQCyDCNgVtQ4udldWrUpWjr0u75JXiWcA80qV4zgCoKIPBEAFHgHQDo8AiGUQAbuiVsHF7oqqWcnCceuOHnmWd8mrxTOAeaXKcRwBUNEHAqACjwBoh0cAxDKIgF1Ri+BidzXVraR1tJ7y3SrJFHC1xhYBUNEvAqACjwBoh0cAxDKIgF1RbXCxu5JqVyrquDHle1EWF8fXv+jhX347N+sXU8DWomHrEQAVvgRABR4B0A6PAIhlEAG7okWDi90VDEelIo5+R4+FBSerqzVpNkUsp3y3qjIFXK1xRgBU9IsAqMAjANrhEQCxDCJgV7RIcLF79+Gp1Itj544e7eVd/Kd+eXb0KCrGFHBRucGcRwBUuBMAFXgEQDs8AiCWQQTsivYSXOzedfgq5XX0z/rNz7cK7+hRVI4p4KJygzmPAKhwJwAq8AiAdngEQCyDCNgVzRtc7N5xOCvt5ti5vIsXKLqjR1E9poCLyg3mPAKgwp0AqMAjANrhEQCxDCJgV3S34GL3TsNdaSfHrcu7OFd8R4+iikwBF5UbzHkEQIU7AVCBRwC0wyMAYhlEwK4oAdDGcjvH0Mu75L16AmBeqXIcRwBU9IEAqMAjANrhEQCxDCJgV5QAaGO51THUjh5Fr5ZnAIvKDeY8AqDCnQCowCMA2uERALEMImBXlABoY9np+KlPPSXHj0cyOSlSr4dd3iXv1fMMYF6pchxHANzSh6mpqeuiKDrRaDRe+/DDDz+6U5sIgHaDmL8gbCxxtHH0VbDE0k7AppIfkydPPixPPPFcSdNx8c/5+Vfo5V3yXj1TwHmlynEcAbCjD1NTUy+Noug/RFEUX7lyJSYA9m+Q8petjTWONo4EQDtHLO0sz5x5Sj7ykWbfl3fJewdMAeeVKsdxBMCOPsRx/EdRFP1H59x/aTQaryAA9m+QElxsrHG0cSS02DliaWPpd/SYn4+k1er/8i5574Ap4LxS5TiOANilD3Ecf7bRaNxOAOzfICW42FjjaONIaLFzxFJn2W1Hj4MHW7qigc5mCjgQbKCyBECDADgzMyMTExOBWjQaZX1wWVpakqNHj8rY2Nho3HSAu8TRDhVLLO0EilVaWLgkn/iEe3rKtyzP+m13N90C4F13HSh284HPqtfrcvbsWf+s7/Vzc3MXAr9dKcsTAA0CYCk7y0UhgAACCFRSoF7fJ1/60vNleXnf+vW3d/Qo+810ewbwZS/LSn3ZBMBSt6f/F9frFDCfAOp7xKctekNfAUcbRyztHLHszXJ5eU3uv7/19PIug9jRo7crfubobs8A8glgUc3w5/EJYPdPAB/mSyDhB1/nO/Dsmo03jjaO7dCysLAgs7OzPJagZGVc5gMsy44e+a726qN4BrCo3GDOIwAq3FkHUIG35VT+grCxxNHGkQBo54jl7pYbO3pclMXF8fXpXv/yz/tV7cUyMNXqGAFQ0S8CoAKPAGiH11GJAGjHiiWWdgLbV/LLuywsOFldrUmzWY4dPYreN8vAFJUbzHkEQIU7AVCBRwC0wyMAYhlEwK4oYfpqy27Lu5T9W767jQimgHcTKtfPCYCKfhAAFXgEQDs8AiCWQQTsihIAn2157twlOXasUdodPYp2ningonKDOY8AqHAnACrwCIB2eARALIMI2BUlAG5Ybjzrd0lOny73jh5FO88UcFG5wZxHAFS4EwAVeARAOzwCIJZBBOyKEgBF/Kd+993XFL/Ovf+ih9/Sraw7ehTtPFPAReUGcx4BUOFOAFTgEQDt8AiAWAYRsCs66gGw6su75B0JBMC8UuU4jgCo6AMBUIFHALTDIwBiGUTAruioBsCNKd+nZHGxVunlXfKOBJ4BzCtVjuMIgIo+EAAVeARAOzwCIJZBBOyKjmIA9Mu7HD8ePb2jx/79Tvbtq97afr2MAp4B7EVr8McSABU9IAAq8AiAdngEQCyDCNgVHbUAeOLEBTl5siZ+Gzf/qvryLnlHAlPAeaXKcRwBUNEHAqACjwBoh0cAxDKIgF3RUQmA7R09lpbG18Of/7JHFXf0KNp5poCLyg3mPAKgwp0AqMAjANrhEQCxDCJgV3QUAmDnjh6Nxuh86tc5SpgCtvsz049KBECFMgFQgUcAtMMjAGIZRMCu6DAHwG47egzb8i55RwJTwHmlynEcAVDRBwKgAo8AaIdHAMQyiIBd0WENgH55l/n51tDt6FG080wBF5UbzHkEQIU7AVCBRwC0wyMAYhlEwK7osAXAzuVdvFL7Wb9h/5bvbiOCKeDdhMr1cwKgoh8EQAUeAdAOjwCIZRABu6LDFADbO3pMTorU67L+ZY9RnfLdOkKYArb7M9OPSgRAhTIBUIFHALTDIwBiGUTAruiwBMBR2dGjaOcJgEXlBnMeAVDhTgBU4BEA7fAIgFgGEbArWvUAOGo7ehTtPM8AFpUbzHkEQIU7AVCBRwC0wyMAYhlEwK5olQPgKO7oUbTzPANYVG4w5xEAFe4EQAUeAdAOjwCIZRABu6JVDICdy7uM2o4eRTvPFHBRucGcRwBUuBMAFXgEQDs8AiCWQQTsilYtAPovehw71mB5lx6HAFPAPYIN+HACoKIBBEAFHgHQDo8AiGUQAbuiVQmAG8/6XZLTpyNptVjepdcRwBRwr2KDPZ4AqPAnACrwCIB2eARALIMI2BWtQgBsL+8yNrYR/HwAZHmX3sYAU8C9eQ36aAKgogMEQAUeAdAOjwCIZRABu6JlD4As72LTawKgjWO/qhAAFdIEQAUeAdAOjwCIZRABu6JlDYAs72LXY1+JZwBtPUNXIwAqhAmACjwCoB0eARDLIAJ2RcsYALfu6LF/v5NR38pN23GeAdQK9vd8AqDCmwCowCMA2uERALEMImBXtGwBkClfu952VmIKOIxrqKoEQIUsAVCBRwC0wyMAYhlEwK5oWQLgxpTvRVlcHF//ood/HTjg7G50xCsxBVytAUAAVPSLAKjAIwDa4REAsQwiYFe0DAHQ7+ixsOBkdbUmzaYIU752/W1XYgrY3jRkRQKgQpcAqMAjANrhEQCxDCJgV3SQAbBzR4/28i7+Uz+e97Prb7sSU8D2piErEgAVugRABR4B0A6PAIhlEAG7ooMKgP5Zv/n5Fjt62LVyx0pMAfcJ2uhtCIAKSAKgAo8AaIdHAMQyiIBd0X4HwM7lXfxd+E/++NTPrp/bVWIKOLyx5TsQABWaBEAFHgHQDo8AiGUQAbui/QyAW5d3cY4dPew6uXMlpoD7JW3zPgRAhSMBUIFHALTDIwBiGUTArmi/AiDLu9j1rEglAmARtcGdQwBU2BMAFXgEQDs8AiCWQQTsioYOgOzoYdcrTSWeAdTo9f9cAqDCnACowCMA2uERALEMImBXNGQA9Mu7HD8eyeSkSL3O8i52Xeu9Es8A9m42yDMIgAp9AqACjwBoh0cAxDKIgF3REAGwc3kX/5yff/FFD7ueFanEFHARtcGdQwBU2BMAFXgEQDs8AiCWQQTsiloHQP9Fj2PHGizvYtcik0pMAZsw9q0IAVBBTQBU4BEA7fAIgFgGEbArahkA/ZTv/HwkrRbLu9h1yKYSU8A2jv2qQgBUSBMAFXgEQDs8AiCWQQTsiloEwG47ehw82LK7SCqpBZgCVhP2tQABUMFNAFTgEQDt8AiAWAYRsCuqDYBbd/TgWT+73lhWIgBaaoavRQBUGBMAFXgEQDs8AiCWQQTsihYNgNvt6GF3ZVSyFOAZQEvN8LUIgApjAqACjwBoh0cAxDKIgF3RIgGQHT3s/PtViWcA+yVt8z4EQIUjAVCBRwC0wyMAYhlEwK5orwGQHT3s7PtZiSngfmrr34sAqDAkACrwCIB2eARALIMI2BXNGwA3pnwvyuLiuESbfzv55/14VUOAKeBq9Kl9lQRARb8IgAo8AqAdHgEQyyACdkXzBEC/vMvCgpPV1Zo0m+zoYaffv0pMAffP2uKdCIAKRQKgAo8AaIdHAMQyiIBd0Z0CYLflXfiWr519PysxBdxPbf17EQAVhgRABR4B0A6PAIhlEAG7otsFQHb0sDMuQyWmgMvQhfzXQADMb3XVkQRABR4B0A6PAIhlEAG7olsD4Mazfpfk9Gl29LBTHnwlpoAH34NeroAA2IvWlmMJgAo8AqAdHgEQyyACdkU7A2CW1eW++5oyNraxlZvf0o0dPeysB1mJKeBB6vf+3gTADrMkSV4vIu90zu2JouhP0zT9lZ1ICYC9D7jtzsjzkLjduw1vJRzteoulvaVIIg88IHL58kZtnvWzMy5DJQJgGbqQ/xoIgJtWN9988/PHx8cf3LNnz0vOnDnztSRJjrVard9cWVn56HacBMD8A223I/nLdjehfD/HMZ9TnqOwzKOU75jHH6/LAw9ckOXlfSzvko+skkfxDGC12kYA3OxXkiQ/7Jz7rizLftz/qyRJ3uCcuz3LsjcRAMMPav6ytTHG0cbRV8HSxtIv73L8eCSTkyL1Osu72KiWswrPAJazL9tdFQHwmQD4dufcgSzLfnEzAL7SOfe2LMvuIACGH9T8ZWtjjKONIwHQxvHEiQty8mRN3OZazkz52riWtQpTwGXtTPfrIgBuusRx/A4RmdwSAN+aZdlrdguAMzMzMjExUa3Ol+xqfXBZWlqSo0ePyph/OpxXIQEcC7F1PQnL4pZPPtmUBx98SpaWxtfDn/+yBzt6FPesypndpoDvvnt/KS+/Xq/L2bNn/Sf918/NzV0o5UUGvigC4DOfAD5rytdPCYvIbWma/uRuATBwjyiPAAIIVEbgK1+5QT772WvWd/RoNPiiR2UaZ3Ch3aaAX/KSFYPK4UoQAMPZVqby4cOHb2g2myedc3PXXXfdVy9evPghEbk3TdP7dwuAfAKobzOftugNfQUcbRyx7N3x0UevyKlTlyVNN/bxZXmX3g2rfka3KeC77jpQytviE0ARPgHsGJpTU1PfF0XRO0XEz+d+MMuye3YauXwL2O7PNc+u2VjiaOPYDoALCwsyOzvLYwm7sD700Ndlfr4lV65sLOzsX0z52o3FqlTiW8BV6dTGdRIAFf0iACrwtpxKcLGxxNHGkQCYz3FjR4+nZHGxtvEXyuazfvv2bX7rI18ZjhoSAb4FXK1GEgAV/SIAKvAIgHZ4HZUIgHasWO5s6ffx9Tt6tJd38V/2YEcPu/FXxUp8C7haXSMAKvpFAFTgEQDt8AiAWAYR2L6on/L9+McdO3r02b3sb0cALHuHnn19BEBFvwiACjwCoB0eARDLIAJXF+2c8vXTvf7Fs359wq/A2/AMYAWa1HGJBEBFvwiACjwCoB0eARDLIALPLsqOHn1Arvhb8AxgtRpIAFT0iwCowCMA2uERALEMIrBR9HOfW5OHHrq0vrwLO3oEhB6C0kwBV6uJBEBFvwiACjwCoB0eARDLIAIi/osex441WN4lkO+wlWUKuFodJQAq+kUAVOARAO3wCIBYGgtsPOt3SU6f3ljXj+VdjIGHtBxTwNVqLAFQ0S8CoAKPAGiHRwDE0lCgvbyL35KbHT0MYUegFFPA1WoyAVDRLwKgAo8AaIdHAMTSSIDlXYwgR7QMAbBajScAKvpFAFTgEQDt8AiAWCoFWN5FCcjp6wI8A1itgUAAVPSLAKjAIwDa4REAsVQIbN3RY/9+J2zlpgAd4VN5BrBazScAKvpFAFTgEQDt8AiAWBYUYMq3IByndRVgCrhaA4MAqOgXAVCBRwC0wyMAYtmjwMaU70VZXBxf/6KHf7GjR4+IHH6VAFPA1RoUBEBFvwiACjwCoB0eARDLHgT8jh4LC05WV2vSbIow5dsDHofuKMAUcLUGCAFQ0S8CoAKPAGiHRwDEModA544e7eVd/Kd+PO+XA49DcgkwBZyLqTQHEQAVrSAAKvAIgHZ4BEAsdxHwz/rNz7fY0SPISKFoW4Ap4GqNBQKgol8EQAUeAdAOjwCI5TYCncu7+EPY0SPIUKHopgBTwNUaCgRARb8IgAo8AqAdHgEQyy4CW5d3cU7k4MFWECuKIuAFmAKu1jggACr6RQBU4BEA7fAIgFhuEWB5lyBDgqK7CBAAqzVECICKfhEAFXgEQDs8AiCWmwLs6BFkKFA0pwDPAOaEKslhBEBFI3ucUooAACAASURBVAiACjwCoB0eARBLEfHLuxw/HsnkpEi9zvIuQQYFRXcU4BnAag0QAqCiXwRABR4B0A6PADjSlp3Lu/jn/PyL5V2CDAmK7iLAFHC1hggBUNEvAqACjwBoh0cAHFlL/0WPY8caLO8SZARQtFcBpoB7FRvs8QRAhT8BUIFHALTDIwCOpKWf8p2fj6TVYnmXIAOAoj0LMAXcM9lATyAAKvgJgAo8AqAdHgFwpCy77ejB8i5BhgBFexRgCrhHsAEfTgBUNIAAqMAjANrhEQBHxnLrjh486xek9RQtKEAALAg3oNMIgAp4AqACjwBoh0cAHHrL7Xb0CHLjFEWgoADPABaEG9BpBEAFPAFQgUcAtMMjAA61JTt6BGkvRQMI8AxgANSAJQmAClwCoAKPAGiHRwAcWkt29AjSWooGEmAKOBBsoLIEQAUsAVCBRwC0wyMADp3lxpTvRVlcHJdo87e0f96PFwJlFmAKuMzdufraCICKfhEAFXgEQDs8AuBQWfrlXRYWnKyu1qTZZEePIM2laBABpoCDsAYrSgBU0BIAFXgEQDs8AuBQWHZb3oVv+QZpLUUDCTAFHAg2UFkCoAKWAKjAIwDa4REAK2/Jjh5BWkjRPgswBdxncOXbEQAVgARABR4B0A6PAFhZy41n/S7J6dPs6BGkiRTtqwBTwH3lVr8ZAVBBSABU4BEA7fAIgJW0bC/vMja2sZWb39KNHT2CtJKifRJgCrhP0EZvQwBUQBIAFXgEQDs8AmDlLFneJUjLKDpgAQLggBvQ49sTAHsE6zycAKjAIwDa4REAK2PZuaMHy7sEaRtFByjAM4ADxC/w1gTAAmjtUwiACjwCoB0eAbASln55l+PHI5mcFKnXWd4lSNMoOlABngEcKH/Pb04A7JnsmRMIgAo8AqAdHgGw9JYnTlyQkydr4jbXcmZ5lyAto+iABZgCHnADenx7AmCPYJ2HEwAVeARAOzwCYGkt2zt6LC2Nr4c/P+3Ljh5B2kXREggwBVyCJvRwCQTAHrC2HkoAVOARAO3wCICltOzc0aPR2Ah++/axnVuQZlG0FAJMAZeiDbkvggCYm+rqAwmACjwCoB0eAbBUlt129GB5lyAtomjJBJgCLllDdrkcAqCiXwRABR4B0A6PAFgaS7+8y/x8S65c2VjY2b+Y8g3SHoqWUIAp4BI2ZYdLIgAq+kUAVOARAO3wCIADt+xc3sVfTPtZP6Z8g7SGoiUVYAq4pI3Z5rIIgIp+EQAVeARAOzwC4EAt2zt6tJd38V/2YMo3SEsoWnIBpoBL3qAtl0cAVPSLAKjAIwDa4REAB2bJjh5B6ClaUQECYLUaRwBU9IsAqMAjANrhEQD7bsmOHkHIKVpxAZ4BrFYDCYCKfhEAFXgEQDs8AmBfLdnRIwg3RYdAgGcAq9VEAqCiXwRABR4B0A6PANgXy87lXdjRIwg5RSsuwBRwtRpIAFT0iwCowCMA2uERAINbZlldjh1rsLxLEGmKDosAU8DV6iQBcEu/pqam3lir1W5L0/SNu7WSALibUP6fN5tNWVhYkNnZWRkbG8t/Ikc+SwBHuwHhLT/5yWV54om/J6dP19bX9WN5FztfKg2fAFPA1eopAXCzX1NTU3ujKPplEXlzFEV/mabpXbu1kgC4m1D+nxNc8lvtdCSONo6+ypkzT8n99zdlbCxaD34+ALK8i50vlYZPgCngavWUALjZryRJ7nDOvUJEPhtF0RwBsL8DmeBi442jjSPLu9g4UmW0BAiA1eo3AXBLv+I4/tEoim4nAPZ3IBNcbLxx1DmyvIvOj7NHW4BnAKvV/5ELgNPT03c6594tIm6zVZFz7tEsy17u/3+RADgzMyMTExPV6nzJrtYHl6WlJTl69CjPACp6g2NxvOXlNbn//pa0d/TYv98JW7kV9+TM0RPo9gzgXXcdKCVEvV6Xs2fPSrPZvH5ubu5CKS8y8EWNXADczbNIANytJj9HAIFyCzz55PPl9OnnyOXLG9d54ADhr9wd4+rKKNBtCvglL1kp46U+fU0EwFK3p78XVyQA8gmgvkd8cqU39BVw7M3xySeb8uCDT8ni4vj6Fz3a4a+3KhyNAAJeoNsU8N137y8lDp8AivAJ4JahWSQA+mlLpoB1f8Z5dk3n1z4bx/yOfkePhQUnq6s1aTZFmPLNb8eRCHQTYBmYao0LAqCiXywDo8DbcirBxcYSx90dO3f0aC/vwpTv7m4cgcBuAnwLeDehcv2cAKjoBwFQgUcAtMPrqEQA3JnVL+8yP99iR48go4+ioy7At4CrNQIIgIp+EQAVeARAOzwC4K6Wncu7+IPZ0WNXMg5AoGcBpoB7JhvoCQRABT8BUIFHALTDIwDuaHnu3CW5777m08u7OMeOHkEGH0VHXoAp4GoNAQKgol8EQAUeAdAOjwC4rSU7egQZZhRFoKsAAbBaA4MAqOgXAVCBRwC0wyMAXmXJjh5BhhdFEdhRgGcAqzVACICKfhEAFXgEQDs8AuCzLP3yLsePR+zoEWSEURSB7QV4BrBao4MAqOgXAVCBRwC0wyMArgt0Lu/in/PzL5Z3CTLMKIpAVwGmgKs1MAiAin4RABV4BEA7PAKg+C96HDvWYHmXIKOKogjkE2AKOJ9TWY4iACo6QQBU4BEA7fBGPAD6Kd/5+UhaLZZ3CTKoKIpATgGmgHNCleQwAqCiEQRABR4B0A5vRANgtx09Dh5sBXGlKAII7C7AFPDuRmU6ggCo6AYBUIFHALTDG8EAuHVHD571CzKcKIpATwIEwJ64Bn4wAVDRAgKgAo8AaIc3QgFwux09gmBSFAEEehLgGcCeuAZ+MAFQ0QICoAKPAGiHNyIBkB09ggwZiiJgJsAzgGaUfSlEAFQwEwAVeARAO7wRCIDs6BFkuFAUAVMBpoBNOYMXIwAqiAmACjwCoB3eEAfAjSnfi7K4OC7R5m8r/7wfLwQQKJ8AU8Dl68lOV0QAVPSLAKjAIwDa4Q1pAPTLuywsOFldrUmzKbJ/v5N9+wh/QQYORREwEGAK2ACxjyUIgApsAqACjwBohzdkAbDb8i58yzfIcKEoAqYCTAGbcgYvRgBUEBMAFXgEQDu8IQqA7OgRZFhQFIG+CDAF3BdmszchACooCYAKPAKgHd4QBMCNZ/0uyenT7OgRZGBQFIE+CDAF3Adkw7cgACowCYAKPAKgHV7FA2B7eZexsY2t3PyWbuzoEWR4UBSBoAJMAQflNS9OAFSQEgAVeARAO7wKB0CWdwkyDCiKwEAECIADYS/8pgTAwnQiBEAFHgHQDq+CAbBzRw+WdwkyFCiKQN8FeAaw7+SqNyQAKvgIgAo8AqAdXsUCoF/e5fjxSCYnRep1lncJMhAoisAABHgGcADoirckACrwCIAKPAKgHV6FAuCJExfk5MmauM3l/FjeJcgwoCgCAxFgCngg7IXflABYmI4pYAXdVac2m01ZWFiQ2dlZGfPfBuBVSKCsju0dPZaWxtfDn5/2ZUePQi3mJARKK8AUcGlb0/XCCICKfvEJoAKPTwDt8Er+CWDnjh6NxkbwY0ePIO2nKAIDFWAKeKD8Pb85AbBnsmdOIAAq8AiAdnglDYDddvRgeZcgbacoAqUQYAq4FG3IfREEwNxUVx9IAFTgEQDt8EoYAP3yLvPzLblyZWNhZ/9iyjdIyymKQGkEmAIuTStyXQgBMBdT94MIgAo8AqAdXokCYOfyLv6y2s/6MeUbpN0URaBUAkwBl6odu14MAXBXou0PIAAq8AiAdnglCYDtHT3ay7v4L3sw5RukzRRFoJQCTAGXsi3bXhQBUNEvAqACjwBoh1eCAMiOHkHaSVEEKiVAAKxUu4QAqOgXAVCBRwC0wxtgAGRHjyBtpCgClRTgGcBqtY0AqOgXAVCBRwC0wxtQAGRHjyAtpCgClRXgGcBqtY4AqOgXAVCBRwC0w+tzAOxc3oUdPYK0kaIIVFKAKeBqtY0AqOgXAVCBRwC0w+tjAPRf9Dh2rMHyLkG6R1EEqi3AFHC1+kcAVPSLAKjAIwDa4fUhAG4863dJTp/eWNeP5V2CtI+iCFRagCngarWPAKjoFwFQgUcAtMMLHADby7v4LZp98PMBkOVdgrSPoghUWoAp4Gq1jwCo6BcBUIFHALTDCxgAWd4lSJsoisBQChAAq9VWAqCiXwRABR4B0A4vQABkeZcg7aEoAkMtwDOA1WovAVDRLwKgAo8AaIdnHAC37uixf78TtnIL0i6KIjBUAjwDWK12EgAV/SIAKvAIgHZ4hgGQKd8gbaEoAiMhwBRwtdpMAFT0iwCowCMA2uEZBMCNKd+Lsrg4vv5FD/86cMAFuUaKIoDAcAowBVytvhIAFf0iACrwCIB2eMoA6Hf0WFhwsrpak2ZThCnfIK2hKAJDL8AUcLVaTABU9IsAqMAjANrhFQyAnTt6tJd38Z/68bxfkNZQFIGhF2AKuFotJgAq+kUAVOARAO3wCgRA/6zf/HyLHT2CdIGiCIymAFPA1eo7AVDRLwKgAo8AaIfXQwDsXN7Fn8aOHkHaQFEERlKAKeBqtZ0AqOgXAVCBRwC0w8sZALcu7+IcO3oEaQJFERhRAaaAq9V4AqCiXwRABR4B0A4vRwBkeZcg3BRFAIEOAQJgtYYDAVDRLwKgAo8AaIe3QwBkR48gzBRFAIEuAjwDWK1hQQBU9IsAqMAjANrhbRMAP/Wpp+T48UgmJ0XqdZZ3CQJOUQQQeFqAZwCrNRgIgJv9mp6evqnVar0viqJvcs41arXa25aXlz+2UzsJgHaDvdlsysLCgszOzsrY2Jhd4RGr5B1PnnxYnnjiuZKm4+Kf8/MvlncZsYHA7SIwAAGmgAeArnhLAuAmXpIkH4qi6P3Ly8t/liTJtIjMp2l6g4hsux0CAVAx8vgE0A6vo9KZM0/JRz7SZHmXILoURQCBnQSYAq7W+CAAPhMAf2Btbe3+Rx555LKI1OI4frxWq71weXl5dbuWEgDtBjufAOot/Y4e8/ORtFos76LXpAICCPQqwBRwr2KDPZ4A2MU/SZJ7nHOvyrLslTu1hwBoN3gJgMUtu+3ocfBgq3hBzkQAAQQKCDAFXABtgKeMXACcnp6+0zn37o6p3cg592iWZS/3fUiS5O0i8qYoim5fXl5+LE8AnJmZkYmJiQG2sfpv7QPg0tKSHD16lGcAe2jnwsIl+cQn3NNTvjzr1wMehyKAgKlAtwB4110HTN/Dqli9XpezZ89Ks9m8fm5u7oJV3SrVGbkAuFNz4ji+N4qilzYajTs+85nPfHm3RrY/AdztOH6OgLVAvb5PvvSl58vy8r710u0dPazfh3oIIIBAXoFuzwC+7GVZ3tMHchwBcCDs5XrTOI5/KYqiV+zbt+81p06d+nqeq2sHQD4BzKO18zF8ApjfcHl5Te6/v/X08i7s6JHfjiMRQCCcQLdnAPkEMJy3tjKfAIrILbfccuDy5cuPi8gXRcR/FOxdnHPudVmW+X/X9cUzgNrh98z5PAOYz5IdPfI5cRQCCPRfgGcA+2+ueUcCoEKPAKjA23IqAXBny40dPS7K4uL4+nSvf/nn/XghgAACZRFgGZiydCLfdRAA8znxCaDCKc+pBMDtlfzyLgsLTlZXa9JssqNHnvHEMQgg0H8BloHpv7nmHQmACj0+AVTg8QngrnjdlnfhW767snEAAggMSIAp4AHBF3xbAmBBOH8aAVCBRwDcEe/cuUty7FiDHT3shhiVEEAgsABTwIGBjcsTABWgBEAFHgGwK97Gs36X5PRpdvSwG11UQgCBfggwBdwPZbv3IAAqLAmACjwC4FV4/lO/++5rytjYxrp+fks3dvSwG2NUQgCBsAJMAYf1ta5OAFSIEgAVeATAZwmwvIvdWKISAggMRoAAOBj3ou9KACwqxzOACrmrTx3VbwFvTPk+JYuLNZZ3MR1RFEMAgX4L8Axgv8V170cAVPjxCaACj08AxS/vcvx49PSOHvv3O9m3j7X97EYVlRBAoJ8CPAPYT239exEAFYYEQAXeiAfAEycuyMmTNfHbuPkXy7vYjSUqIYDAYASYAh6Me9F3JQAWlWMKWCF39amjMgXc3tFjaWl8Pfz5L3uwo4fpUKIYAggMSIAp4AHBF3xbAmBBOH8anwAq8EbwE8DOHT0aDT71sxs9VEIAgTIIMAVchi7kvwYCYH6rq44kACrwRigAdtvRg+Vd7MYOlRBAoBwCTAGXow95r4IAmFeqy3EEQAXeiARAv7zL/HyLHT3shgqVEECgpAJMAZe0MdtcFgFQ0S8CoAJvyANg5/Iu/lbbz/rxLV+7MUMlBBAolwBTwOXqx25XQwDcTWiHnxMAFXhDHADbO3pMTorU67L+ZQ+mfO3GCpUQQKCcAkwBl7Mv210VAVDRLwKgAm9IAyA7etiNCSohgEC1BAiA1eoXAVDRLwKgAm/IAiA7etiNBSohgEA1BXgGsFp9IwAq+kUAVOANUQBkRw+7cUAlBBCorgDPAFardwRARb8IgAq8IQiAncu7sKOH3VigEgIIVFOAKeBq9Y0AqOgXAVCBV/EA6L/ocexYg+Vd7IYAlRBAoOICTAFXq4EEQEW/CIAKvIoGwI1n/S7J6dORtFos72I3AqiEAAJVF2AKuFodJAAq+kUAVOBVMAC2l3cZG9sIfj4AsryL3RigEgIIVFuAKeBq9Y8AqOgXAVCBV7EAyPIudr2mEgIIDKcAAbBafSUAKvpFAFTgVSQAsryLXY+phAACwy3AM4DV6i8BUNEvAqACrwIBcOuOHvv3O2ErN7ueUwkBBIZLgGcAq9VPAqCiXwRABV7JAyBTvna9pRICCIyGAFPA1eozAVDRLwKgAq+kAXBjyveiLC6Or3/Rw78OHHB2N0olBBBAYEgFmAKuVmMJgIp+EQAVeCUMgH5Hj4UFJ6urNWk2RZjytesvlRBAYPgFmAKuVo8JgIp+EQAVeCUKgJ07erSXd/Gf+vG8n11/qYQAAsMvwBRwtXpMAFT0iwCowCtJAPTP+s3Pt9jRw66VVEIAgREVYAq4Wo0nACr6RQBU4A04AHYu7+IvxX/yx6d+dv2kEgIIjJ4AU8DV6jkBUNEvAqACb4ABcOvyLs6xo4ddJ6mEAAKjKsAUcLU6TwBU9IsAqMAbUABkeRe7nlEJAQQQ6BQgAFZrPBAAFf0iACrw+hwA2dHDrldUQgABBLoJ8AxgtcYFAVDRLwKgAq+PAdAv73L8eCSTkyL1Osu72HWNSggggMAzAjwDWK3RQABU9IsAqMDrQwDsXN7FP+fnX3zRw65nVEIAAQQ6BZgCrtZ4IAAq+kUAVOAFDoD+ix7HjjVY3sWuRVRCAAEEdhRgCrhaA4QAqOgXAVCBFzAA+inf+flIWi2Wd7HrEJUQQACBnQWYAq7WCCEAKvpFAFTgBQiA3Xb0OHiwZXeRVEIAAQQQ2FaAKeBqDQ4CoKJfBEAFnnEA3LqjB8/62fWGSggggEAeAQJgHqXyHEMAVPSCAKjAMwqA2+3oYXdlVEIAAQQQyCPAM4B5lMpzDAFQ0QsCoALPIACyo4edP5UQQAABrQDPAGoF+3s+AVDhTQBU4CkDIDt62NlTCQEEELAQYArYQrF/NQiACmsCoAKvYADcmPK9KIuL4xJtjl7/vB8vBBBAAIHBCjAFPFj/Xt+dANirWMfxBEAFXoEA6Jd3WVhwsrpak2aTHT3s9KmEAAII6AWYAtYb9rMCAVChTQBU4PUQALst78K3fO3sqYQAAghYCDAFbKHYvxoEQIU1AVCBlzMAsqOHnTGVEEAAgZACTAGH1LWvTQBUmBIAFXi7BMCNZ/0uyenT7Ohhp0wlBBBAIJwAU8DhbENUJgAqVAmACrwdAmCW1eW++5oyNraxlZvf0o0dPeysqYQAAgiEEGAKOIRquJoEwE3bOI5viaLoPSKy3zn3lVar9WPnz5///E70BEC7gdlsNmVhYUFEEnngAZHLlzdq86yfnTGVEEAAgZACBMCQuva1CYDPBMBP1mq1ty8vL38sjuOfiqLotjRNf4gAaD/oulV8/PG6PPDABVle3sfyLv0h510QQAABUwGeATTlDF6MAPgMcU1EWiJSS5LkXSJybZqmP0MADD4GxS/vcvx4JJOTIvU6y7uEF+cdEEAAAXsBngG0Nw1ZkQDYoXv48OGDzWZzSUT2RVH0ijRNFwmAIYefiN/R4yMfceI213JmyjesN9URQACBUAJMAYeSDVN35ALg9PT0nc65d4tIe/uIyDn3aJZlL28TJ0nyPSLyB2ma3tRx3FUdaD8DODMzIxMTE2E6NORVf+u31qTR2LjJa69tDvndcnsIIIDA8Ap0mwK+++79pbzher0uZ8+elWazef3c3NyFUl5k4IsauQC4nWeSJK9P0/S/doTAL4+Pj0+fOXPmie3OaQfAwD0a6vIf/Wgie/eKXHNNa/3ZP/9JYPuf/sa3/rudftbr8Za1eO+re9WrSejj6Xf/e4T5aJlvnQK+/fa63HrrSqn/DiMAlro9/bm4OI6Xoih6W5qmx+I4/u4oin47TdMX7/TufAKo783CwiWZn3cyOenkOc9pyaVL/llAt/5P/2r/763/7PazXo/f6X16rdXr8bz31b3t1bDX4zHHnN8tYX+nnjmzR6LNTdqdc/JDP9SS2dlJ/V8UASrwCaAInwBuDqzDhw+/uNlsvjeKoknn3JO1Wu3u5eXlNE8APHr0KFPAij+g/jnAc+f8PLATP5PuvwjS/qcvu/Xf7fSzXo+3rMV7X92rXk1CH0+/+98jzEfL/NFH96z/Ln/1qyO59dYDir8Zwp7qA+DS0hJTwGGZh7c66wDa9ba9DuDs7KyM+RWgeRUSwLEQW9eTsMTSTsCmEmPSxtFXIQDyCaBqNBEAVXzPOplfbDaWONo4+ipYYmknYFOJMWnjSADccGQKWDGeCIAKvC2n8ovNxhJHG0cCoJ0jlnaW/Pm2s+QTQAKgajQRAFV8fAJox/d0Jf6CsEPFEks7AZtKjEkbRz4B5BNA9UgiAKoJCS52hOuV+AvCDhRLLO0EbCoxJm0cCYAEQPVIIgCqCQmAdoQEQCyNBezKEVxsLHG0cSQAEgDVI4kAqCYkANoREgCxNBawK0dwsbHE0caRAEgAVI8kAqCakABoR0gAxNJYwK4cwcXGEkcbRwIgAVA9kgiAakICoB0hARBLYwG7cgQXG0scbRwJgARA9UgiAKoJCYB2hARALI0F7MoRXGwscbRxJAASANUjiQCoJiQA2hESALE0FrArR3CxscTRxpEASABUjyQCoJqQAGhHSADE0ljArhzBxcYSRxtHAiABUD2SCIBqQgKgHSEBEEtjAbtyBBcbSxxtHAmABED1SCIAqgkJgHaEBEAsjQXsyhFcbCxxtHEkABIA1SOJAKgmJADaERIAsTQWsCtHcLGxxNHGkQBIAFSPJAKgmpAAaEdIAMTSWMCuHMHFxhJHG0cCIAFQPZIIgGpCAqAdIQEQS2MBu3IEFxtLHG0cCYAEQPVIIgCqCQmAdoQEQCyNBezKEVxsLHG0cSQAEgDVI4kAqCYkANoREgCxNBawK0dwsbHE0caRAEgAVI8kAqCakABoR0gAxNJYwK4cwcXGEkcbRwIgAVA9kgiAakICoB0hARBLYwG7cgQXG0scbRwJgARA9UgiAKoJCYB2hARALI0F7MoRXGwscbRxJAASANUjiQCoJiQA2hESALE0FrArR3CxscTRxpEASABUjyQCoJqQAGhHSADE0ljArhzBxcYSRxtHAiABUD2SCIBqQgKgHSEBEEtjAbtyBBcbSxxtHAmABED1SCIAqgkJgHaEBEAsjQXsyhFcbCxxtHEkABIA1SOJAKgmJADaERIAsTQWsCtHcLGxxNHGkQBIAFSPJAKgmpAAaEdIAMTSWMCuHMHFxhJHG0cCIAFQPZIIgGpCAqAdIQEQS2MBu3IEFxtLHG0cCYAEQPVIIgCqCQmAdoQEQCyNBezKEVxsLHG0cSQAEgDVI4kAqCYkANoREgCxNBawK0dwsbHE0caRAEgAVI8kAqCakABoR0gAxNJYwK4cwcXGEkcbRwIgAVA9kgiAakICoB0hARBLYwG7cgQXG0scbRwJgARA9UgiAKoJCYB2hARALI0F7MoRXGwscbRxJAASANUjiQCoJiQA2hESALE0FrArR3CxscTRxpEASABUjyQCoJqQAGhHSADE0ljArhzBxcYSRxtHAiABUD2SCIBqQgKgHSEBEEtjAbtyBBcbSxxtHAmABED1SCIAqgkJgHaEBEAsjQXsyhFcbCxxtHEkABIA1SOJAKgmJADaERIAsTQWsCtHcLGxxNHGkQBIAFSPJAKgmpAAaEdIAMTSWMCuHMHFxhJHG0cCIAFQPZIIgGpCAqAdIQEQS2MBu3IEFxtLHG0cCYAEQPVIIgCqCQmAdoQEQCyNBezKEVxsLHG0cSQAEgDVI4kAqCYkANoREgCxNBawK0dwsbHE0caRAEgAVI8kAqCakABoR0gAxNJYwK4cwcXGEkcbRwIgAVA9kgiAakICoB0hARBLYwG7cgQXG0scbRwJgARA9UgiAKoJCYB2hARALI0F7MoRXGwscbRxJAASANUjiQCoJiQA2hESALE0FrArR3CxscTRxpEASABUjyQCoJqQAGhHSADE0ljArhzBxcYSRxtHAiABUD2SCIBqQgKgHSEBEEtjAbtyBBcbSxxtHAmABED1SCIAqgkJgHaEBEAsjQXsyhFcbCxxtHEkABIA1SOJAKgmJADaERIAsTQWsCtHcLGxxNHGkQBIAOw6kqampl4QRdGpRqNx68MPP/zoTsONAGj3h5FfbDaWONo4+ipYYmknYFOJMWnjSAAkAHYbSVEcx38lIi9vNBovJgDa/WHbrRK/2HYTyvdzHPM55TkKyzxK+Y7BMp/TbkfhuJtQ/p/X63VZWlry/6F3/dzc3IX8Zw7PkdHw3Ir+bjejsAAACL5JREFUTpIkebuIXHHOvaXRaLyCAKg3zVuBX2x5pXY+DkcbRz4BtHPE0s6SP992lgRAEQLg5nianp7+1lar9a4sy74njuPPNhqN2wmAdn/YdqvEL7bdhPL9HMd8TnmOwjKPUr5jsMzntNtROO4mlP/nBMARDIDT09N3OufeLSKuY6g8LiJrrVbr9SsrK1/oNQAmSSITExP5Rx5HXiXgf7GdPXtWZmZmZGxsDKGCAjgWhOtyGpZY2gnYVGJM2jj6Kj4ApmnKFLAdaTUrTU1NvSqKovdGUfRVEYmcczNRFK2IyJ1pmi5vd1cLCwvf0mg0vlDNu+aqEUAAAQQQGG2B8fHxF8zOzn5xFBWYAu7Sdf8JYKvVuu38+fOf32lQOOeiU6dO3bi2trY6ioOHe0YAAQQQQKCqAnv37r32lltueSyKos4ZwareTs/XTQDsHgAfzvMlkJ61OQEBBBBAAAEEECiBAAGwBE3gEhBAAAEEEEAAgX4KEAD7qc17IYAAAggggAACJRAgAJagCVwCAggggAACCCDQTwECYD+1eS8EEEAAAQQQQKAEAgTAEjSBS0AAAQQQQAABBPopQABUat90003P2bt375+JyLeIyGUR+ck0TReVZUfy9Onp6WtbrdZ7oig6IiKtVqv1ppWVlYdGEsPopqempl4QRdGpRqNx62472xi95VCVmZ6evqnVar0viqJvcs41arXa25aXlz82VDcZ+GaSJHm9iLzTObcniqI/TdP0VwK/5dCWT5Lk551zb9zcyODvbrzxxp+an59vDO0NB76xJEn+rYgcTNP0rsBvVcryBEBlW+I4/mURmciy7J6pqanXRlH09izLvlNZdiRPj+P4D6Mo+nKapv9mamrqn9RqtV9J03RuJDFsbjqK4/ivROTljUbjxQTA3lGTJPlQFEXvX15e/rMkSaZFZD5N0xu27CTUe+EROePmm29+/vj4+IN79ux5yZkzZ76WJMmxVqv1mysrKx8dEQKz20yS5Nucc++r1+tzjzzyyOU4jv+kVqt9enl5+XfM3mSECiVJ8koReb+IfIgAOEKNt7zVJEl+1Tl3fZZlb0mS5PtF5MfTNH215XuMSq04jp9wzt20srJywd/z1NTUzMrKytlRuX/r+0yS5O0icsU59xbWtSymmyTJD6ytrd3v/8IVkVocx4/XarUXLi8vs/h7DtIkSX7YOfddWZb9uD88SZI3OOduz7LsTTlO55AOgUOHDh2q1Wo3ZFn2gP/XcRy/VURuzLLM/5NXDwJHjhz5xkaj8eEoij7gnLuFANgDHoc+I3D06NFvWFtb+98ico2IXCsir8qy7EGMehPY/KRgQUT+fRRFr3fOPRlF0b9gOr03x/bR09PT39pqtd6VZdn35N3butg7jc5ZSZLc45zzf779Jwe8cgj4/whxzh3IsuwXNwPgK51zb8uy7I4cp3PINgIvetGLnjc2Nub/nvmRdiAEK79AHMd/UavV7m21Wi+Mouh2AmB+u5E8cnp6+k7n3Ls7p36cc5+PougR59z/yrLs96ampl5aq9X+fHV19fBjjz321EhC5bjpbSwbURS9UER+Nk3T34/j+Lv9/sxpmr4oR8mRPaSbpYg8LiJrrVbr9SsrK18gAO4+PLo4+j3BH82y7OWbwcV/mvom/5fF8vLyY7tX5AgvEMfxO0RkcksAfGuWZa9BqJiAfy7VOfchEfHPU/5GsSqje1aSJP7T5+k0Tf9lHMc/SgAc3bGgvvM4ji9evHjxee3AF8fxJ2u12puXl5c/rS4+QgWOHDkyceXKldWxsbEbz50795XNv3T/r4gcSdPUBxpeOQWmpqZe5cNzFEVfFREfZGaiKFoRkTvTNF3OWYbDNgXiOL43iqKXNhqNOz7zmc98GZj8AlunfP2UsIjclqbpT+avwpFtgTiOZ6Mo8uHv19I0vReZ3gWSJPmIc+6boyhqisg3+k+ofZjOsuzneq9W7TP4Eoiyf3EcnxCRP8yy7D/PzMxMNZvNj0VRdJhnhHqH9Q/ci8hfb34C+O0i8oEsy27uvRJndAr4TwBbrdZt58+f/zwyvQnEcfxLURS9Yt++fa85derU13s7m6MPHz58Q7PZPOmcm7vuuuu+evHiRf9n/N40Te9HpzeBqamp50ZRtBhF0ZvTNP1gb2dzdDcBPgFkXKgENh/Mfa+IPM9Pu/lvAadpelxVdERPPnLkyDdfuXLFW94cRZH/8sI/z7LskyPKYXbbcRw/zJdAeue85ZZbDly+fNl/+vxFEfFfTPL/weycc6/Lssz/O145BKampr4viqJ3+tUSROSDfsWEHKdxyBaBJEne5Zz7uSiKsvZYFJEPp2n6C2AVEyAAFnPjLAQQQAABBBBAAIGKCjAFXNHGcdkIIIAAAggggEBRAQJgUTnOQwABBBBAAAEEKipAAKxo47hsBBBAAAEEEECgqAABsKgc5yGAAAIIIIAAAhUVIABWtHFcNgIIIIAAAgggUFSAAFhUjvMQQAABBBBAAIGKChAAK9o4LhsBBBBAAAEEECgqQAAsKsd5CCCAAAIIIIBARQUIgBVtHJeNAAIIIIAAAggUFSAAFpXjPAQQQAABBBBAoKICBMCKNo7LRgABBBBAAAEEigoQAIvKcR4CCCCAAAIIIFBRAQJgRRvHZSOAAAIIIIAAAkUFCIBF5TgPAQQQQAABBBCoqAABsKKN47IRQAABBBBAAIGiAgTAonKchwACCCCAAAIIVFSAAFjRxnHZCCCAAAIIIIBAUQECYFE5zkMAAQQQQAABBCoqQACsaOO4bAQQQAABBBBAoKgAAbCoHOchgAACCCCAAAIVFSAAVrRxXDYCCCCAAAIIIFBUgABYVI7zEEAAAQQQQACBigoQACvaOC4bAQQQQAABBBAoKkAALCrHeQgggAACCCCAQEUFCIAVbRyXjQACCCCAAAIIFBUgABaV4zwEEEAAAQQQQKCiAgTAijaOy0YAAQQQQAABBIoK/H97mJjxIoXi+wAAAABJRU5ErkJggg==\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<matplotlib.text.Text at 0x116d65610>"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plt.scatter(C.real[index], C.imag[index])\n",
"plt.title('$2*z_i > z_r$')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment