Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save GeorgyGol/5229aa25bba97815ea99ceaa8c272cf0 to your computer and use it in GitHub Desktop.

Select an option

Save GeorgyGol/5229aa25bba97815ea99ceaa8c272cf0 to your computer and use it in GitHub Desktop.
Practice Assignment for Week 3 of Applied Plotting, Charting and Data Representation in Python Coursera course
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Practice Assignment: Understanding Distributions Through Sampling\n",
"\n",
"** *This assignment is optional, and I encourage you to share your solutions with me and your peers in the discussion forums!* **\n",
"\n",
"\n",
"To complete this assignment, create a code cell that:\n",
"* Creates a number of subplots using the `pyplot subplots` or `matplotlib gridspec` functionality.\n",
"* Creates an animation, pulling between 100 and 1000 samples from each of the random variables (`x1`, `x2`, `x3`, `x4`) for each plot and plotting this as we did in the lecture on animation.\n",
"* **Bonus:** Go above and beyond and \"wow\" your classmates (and me!) by looking into matplotlib widgets and adding a widget which allows for parameterization of the distributions behind the sampling animations.\n",
"\n",
"\n",
"Tips:\n",
"* Before you start, think about the different ways you can create this visualization to be as interesting and effective as possible.\n",
"* Take a look at the histograms below to get an idea of what the random variables look like, as well as their positioning with respect to one another. This is just a guide, so be creative in how you lay things out!\n",
"* Try to keep the length of your animation reasonable (roughly between 10 and 30 seconds)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"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",
" 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 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, 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 * 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 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",
" 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",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\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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bjdXbbE6babTavbCb59SW6rGi8rMYUsgLL7o6t7SQqC95P8z1Ox5g5ep2XNs7qz7xC07/sp+USIQFptYuyJogeYnuc3tlTMJh6P97PmDVmjslWzteUZHqdlbnfCYW+DB+pbdmpy/km8v62+vZsvDX4A1Wt704drV/hi7QM1+P7I1a3V4XflDtn7P92uE9nvLA9R+q2Z369iLebAOi039KL8/ZR0WwttSbbm/jmDPKbTXmLDfo+3F8r5c6KiJbkQgTHTiGTYCCCCAAAIIIIAAAgggQCBkDSCAAAIIIIAAAggggAACiQoQCBOdeIaNAAIIIIAAAggggAACCBAIWQMIIIAAAggggAACCCCAQKICBMJEJ55hI4AAAggggAACCCCAAAIEQtYAAggggAACCCCAAAIIIJCoAIEw0Yln2AgggAACCCCAAAIIIIAAgZA1gAACCCCAAAIIIIAAAggkKkAgTHTiGTYCCCCAAAIIIIAAAgggQCBkDSCAAAIIIIAAAggggAACiQoQCBOdeIaNAAIIIIAAAggggAACCBAIWQMIIIAAAggggAACCCCAQKICBMJEJ55hI4AAAggggAACCCCAAAIEQtYAAggggAACCCCAAAIIIJCoAIEw0Yln2AgggAACCCCAAAIIIIAAgZA1gAACCCCAAAIIIIAAAggkKkAgTHTiGTYCCCCAAAIIIIAAAgggQCBkDSCAAAIIIIAAAggggAACiQoQCBOdeIaNAAIIIIAAAggggAACCBAIWQMIIIAAAggggAACCCCAQKICBMJEJ55hI4AAAggggAACCCCAAAIEQtYAAggggAACCCCAAAIIIJCoAIEw0Yln2AgggAACCCCAAAIIIIAAgZA1gAACCCCAAAIIIIAAAggkKkAgTHTiGTYCCCCAAAIIIIAAAgggQCBkDSCAAAIIIIAAAggggAACiQoQCBOdeIaNAAIIIIAAAggggAACCBAIWQMIIIAAAggggAACCCCAQKICBMJEJ55hI4AAAggggAACCCCAAAIEQtYAAggggAACCCCAAAIIIJCoAIEw0Yln2AgggAACCCCAAAIIIIAAgZA1gAACCCCAAAIIIIAAAggkKkAgTHTiGTYCCCCAAAIIIIAAAgggQCBkDSCAAAIIIIAAAggggAACiQoQCBOdeIaNAAIIIIAAAggggAACCMQSCK2fu6jdzJQhgAACCCBQQGBbbfMLtW6BbZuyCbWuKTNBPxBAAIE4BFxqXSyB8EGakxvimBd6iQACCCDQEIEHqx8/b0hfinSDWldEiW0QQAABBPIClWtdLIFwiUa9Pst+pn/sQx4IIGACj8muzS7LDs6++85PZ3sc8khQEEBAAjfffEu2697LzOK+ajdFhDJb616t/y6OqNeRdPUxv8yyy1Zl2bfPPyXb/eCnR9JruokAAgiMFrBa94hHPMml1kUWCJUJCYT8XCCwWWC/7Gr9b1n2nQ98MdvzuXshgwAClgBvujnb8aF7uhTJwKCzgfBY/XfrwGdO4HT76Qbiqz+QZdde9C/ZI5767ARGzBARQKDNAlbrHvjA/VxqHYGwzSuFsbVegEDY+ilmgCUECIQl0BLYhUCYwCQzRAQSEiAQJjTZDBWBLQkQCFkfCNxTgEDIqhglQCBkXSCAQJsECIRtmk3GgkAFAQJhBTx2ba0AgbC1U1tpYATCSnzsjAACDRMgEDZsQugOApMSIBBOSp7zNllgjED4ZI3jH9XsFWgeqHaI2qfmGdtyff/tanur2Sudnay2amifY/T5CWr2cuD2the/V7tS7Y1qX9vC8XkOYY0Li0BYIy6HRgCB4AIFA+Fx6tihavbKg7epfV3NatT38x3mOYTBp48TIuAnQCD0s+RI7REYIxD+uUb9RLWr1C5Umy8Q7qptvqP2PrUz1Z6qdrraM9S+0Bd8nv79qNqP1d6k9qdqz1R7l9rlahdtQZpAWOMyJBDWiMuhEUAguEDBQHixOna+2hVqC9VOVXuUmr0S4a2DTocMhI/TSU9R21dt+yG1+V4avP+2E7zKaPDVxgkbLUAgbPT00LkJCYwRCPM9tCt58wXCt2gbC39WTAcPK7Tbqf1Z/wt2JdCuOC5Xu1RtSs2uJP6r2pvnISEQ1rhmCIQ14nJoBBAILlAwEA73ayd94ddqB6t9ZfDNUIFwH53wv9TerfZhtYeonad2jZpeBDr7eKEiaW9FyNtOBF9wnLC5AgTC5s4NPZucQI2B0Irn1WpH50Z3lD62q4T2h82t1P5XbYOaXUW0N5C4Q+0sNQuN873XAYGwxmVDIKwRl0MjgEBwgZKBcHd19Idqj1azO156j1CB0P5K+nO1F+S0LBzaX1EfX0CQK4QFkNgkPQECYXpzzojnF6gxEP5AZ/+I2mm5Xtg7nH9W7d5q9+vXuuP1rz038V5qFiDtKuE2ao+Zp/cEwvmnt/QWBMLSdOyIAAINFCgRCK0W2dMW7A+UB+WHFCIQ3l8n1NvB9i5NfjV3crv15klqTyhgTCAsgMQm6QkQCNObc0Y8v0ADAqHVNbsDxmqcPV3ib9V2UbOriau2MAIC4fzTW3oLAmFpOnZEAIEGCpQIhGdoGPbceQuDN+SHFCIQDv56aoXu5tzJv6iPv6v2qgLGBMICSGySngCBML05Z8TzC9QYCIveMnqYepl/tVK7ZXR5v+cPIxDOP4d1bEEgrEOVYyKAwKQExgyEdmemPW3BXl3bXvTsbo8QgdBeXe0zavaS3r/sn91um7En3lunvlkAkkBYAIlN0hMgEKY354x4foEaA6Hd2WJ/5LTnXgwe9nx4e6G0wYvK2PPl7dVEX9nfwG7R+anatWp2tXDHLYyAK4TzT2/pLQiEpenYEQEEGihQMBBa1rMXNbMXTVuuZs8fvMcjRCC0V7P5idon1OxVRndTe4/aJ9VeXdCXQFgQis3SEiAQpjXfjLaYwBiB8D46oj3B3h52i+dr1L6s9js1C3H2XMEHqR3Z32bwthNWw+wF0p6iZm8nkX/biZfoc3uxtA+qfV7N3obiL9TsxWbsj6P2/bkeBMJiU1xqKwJhKTZ2QgCBhgoUDITvVfftNVzs6mD+vQftlTrtfQntsTpEILQT2VXCf1GzYmpF1l59zd7Yd6agMYGwIBSbpSVAIExrvhltMYExAuFyHdEC4PDDbvFcqbZKbamabTd42MfvULP3cLLnYNh7Ddp2g8difWDBz543b686anXO3nbibDV7/6dBAR4+p31OIByl4vQ1AqETJIdBAIFGCBQMhPaWSqMe+ee0rwkVCKvCEQirCrJ/KwUIhK2cVgZVUWCMQFjxTO67EwjdSe86IIGwRlwOjQACwQUKBsJC/SIQFmJiIwSaKUAgbOa80KvJChAIJ+vf1LMTCJs6M/QLAQTKCBAIy6ixDwItFCAQtnBSGVJlAQJhZcJWHoBA2MppZVAIJCtAIEx26hk4AncXIBCyIhC4pwCBkFUxSoBAyLpAAIE2CRAI2zSbjAWBCgIEwgp47NpaAQJha6e20sAIhJX42BkBBBomQCBs2ITQHQQmJUAgnJQ8522yAIGwybMzub4RCCdnz5kRQMBfgEDob8oREYhSgEAY5bTR6ZoFCIQ1A0d6eAJhpBNHtxFAYKRAwoHQ3srJXpWbBwIImMBjsmuzy/R2Z99956ezPQ55JCgIICCBm2++Jdt172VmcV+1myJCmX3biVfrv/ZuhjxcBR7zyyy7bFWWffv8U7LdD36667E5GAIIIBBawGrdIx7xJJdaF8vbTjxIo7U3AOaBAAIIIIBAUYEHa8OfF924AdtR6xowCXQBAQQQiEygcq2LJRBaP3dRuzmyCaK7CCCAAAKTEdhWp/2FWncypy91VmpdKTZ2QgABBJIVcKl1sQTCZGeZgSOAAAIIIIAAAggggAACdQkQCOuS5bgIIIAAAggggAACCCCAQMMFCIQNnyC6hwACCCCAAAIIIIAAAgjUJUAgrEuW4yKAAAIIIIAAAggggAACDRcgEDZ8gugeAggggAACCCCAAAIIIFCXAIGwLlmOiwACCCCAAAIIIIAAAgg0XIBA2PAJonsIIIAAAggggAACCCCAQF0CBMK6ZDkuAggggAACCCCAAAIIINBwAQJhwyeI7iGAAAIIIIAAAggggAACdQkQCOuS5bgIIIAAAggggAACCCCAQMMFCIQNnyC6hwACCCCAAAIIIIAAAgjUJUAgrEuW4yKAAAIIIIAAAggggAACDRcgEDZ8gugeAggggAACCCCAAAIIIFCXAIGwLlmOiwACCCCAAAIIIIAAAgg0XIBA2PAJonsIIIAAAggggAACCCCAQF0CBMK6ZDkuAggggAACCCCAAAIIINBwAQJhwyeI7iGAAAIIIIAAAggggAACdQkQCOuS5bgIBBK48sgjD+rMzLyl0+k8Mut27511Oj/Rqd+//9lnvyNQFzgNAggggAACQQSuPPVPnjjVnbm0m2XfWXbCpfsGOSknQaDlAgTClk8ww2u/wBVHHrnfwpmZR3YWLPi2wuCtMxs3HmSBsNvpvHrZ2Wd/oP0CjBABBBBAIAWBa6eXbzezKLtKY72+m3XvTyBMYdYZYwgBAmEIZc6BQAWBa1784p26GzZc1+1237XsnHNOtUNds2LFE/T5Gn345/ufc86Xhg9/9YoVF+qvp7cqEK6ocGp2RQABBBBAoHaBa0590k7d7tR13U72rmXHXzpb505+8hO6nak1+kPnn+9//Jd7de6qU5efrzthfqg7YjapBj6HQFj71HCCRAQIhIlMNMOMW0C3hT59ambmU9nU1BNuW7To+/e6885rVQw/rYD4muGR2RXDBd3u52e63dcfcM45Z8Y9cnqPAAIIIJCCwJWnHaw61/mUxqo6t+H799qw6FpdBfy0Ql+vzl192vKjujPZy27ekD1hyVbZ6wmEKawKxhhKgEAYSprzIFBRQFf93qMC+DT9ZfRKHerR297vfgfu8a533TE47FVHHHGD/pK6k/56ulBXB6cVBt9U8ZTsjgACCCCAQDCBq09drjqXPU2/nF6ZdVTn7nOvA/d41efvuOZNB+8xs6Dz1YWdTU/a57jLfqDtpgmEwaaFEyUgQCBMYJIZYjsEvnH44fdavPXW31Hge4iu/i074Nxzr8uP7FsrVuy6YWbmPvqhflxnaurNnW73Ffudc85H2zF6RoEAAggg0HaBb7z98fdafNvi72icD5mZUZ37p0uv+/jHD1+w2/W//man2/nQ/ieseZ8ZEAjbvhIYX2gBAmFocc6HQEmBK1aseJRuBb1CVwEX6RCH6FVEPzPXoXQ10W6nWaFbSvcseTp2QwABBBBAIKjAFacuf9SCTHWum83WuRMu/Yy9kMymRd3f6xfWTYPOdLPOVJbppdP0NdW6P132+q9cErSjnAyBlgkQCFs2oQynnQJrDz98q9sXL75ct4vqORXZ93WV8OiFnc6j9zn77F+PGrFuH32DguOL9aIyS9spwqgQQAABBNoksHZ6761uX7Tj5Z2sX+c62dEL77zz0Y/Jvv4/V261fK/8WPXH0ZfrltKnbMo6h2211VY/3ue1/3FrmywYCwKhBQiEocU5HwIlBK4+4oi3KQgetjHL9nns7rvfcs3111+qwLdeVwmfedWKFX+nH+SfdjZt+l7v0AsWPFl/MX2H/nb6LgXC15c4HbsggAACCCAQVODqUw6erXMbbt/nsdl/3XLNVgdfqg6s3//4S5853BFuGQ06NZwsAQECYQKTzBDjFrjyiCOWT3U6/znT6fzJAatXf9VGc+3KlUtnNm361kyWHTs1+yIyf6Mf5l0VEjfq6uGPtO0Hl+222/s709PahAcCCCCAAALNFbjy5OXLp6a6/zkzozr3+jWzde7Ny5fOzGS9OnfA8WvOyPeeQNjcuaRncQoQCOOcN3qNAAIIIIAAAggggAACCFQWIBBWJuQACCCAAAIIIIAAAggggECcAgTCOOeNXiOAAAIIIIAAAggggAAClQUIhJUJOQACCCCAAAIIIIAAAgggEKcAgTDOeaPXCCCAAAIIIIAAAggggEBlAQJhZUIOgED7BfTWFuv06qWn643uTy8yWm2/Uv/ncrreFmO7ItuzDQIIIIBAugJXnXqwakzn9GUnrOnVmMvftvwBCzZ0z9Z7Ej5BtWeD3qCeWpLu8mDkAQQIhAGQOUXcAlevWLFK7+v3ouFR6IfnC/ufc86fxT26u/d+riB3zYtfvNPMokW3Lnv/+/+3yHgJhEWU2AYBBBCIW+CqUw5eY28kv/8Ja47Oj+SqU5brj4Ld04sGuWtOfdJOM3feduuy6St7NUb7vyXrdJ8xtSk7ZGrThvX7TH/913FL0XsEmi1AIGz2/NC7Bgj0A+H9Ny1ceFS+O1vfeecdjznvvN83oItuXfAKcl7HcRsYB0IAAQQQcBfwCoTDHdMVw3/Lss6ty45fc48/xhYdxNrpvbfae3rtnUW3ZzsEUhYgEKY8+4y9kEA/EG6n2yWfM7xD703js+w/9MbwT9X3L7Pva/vX6Yriazds2vTox330o7+66ogj9BfU7Du9fTudFXb7i7Y/Q1cX36Cv68Ms+/YLXnC/DVNT79SHz+p0Oou1/6VTMzOv2u+8835o3x8ErG6n87yObt3U9x+ifb+qN+w96oBzzrlx0C/156/1Jvb/oO/vquOs07/vUr/ea9+3N7PftHHjjztTU3+pPrxSX/pjff+H+vxv91+9+hs2Fh3zy/kx6vOT1M/p4VtGrz7iiNdoOwvID1effqc+fWbxHXe8bu8LLrgl319uGS20xNgIAQQQiFKgSCC8+pTlq7qd7naqf1/tzHT/Qf9upcGe393hlqOX/c2VG3o1I3fL6OzH2cMGILoCeZauQK688s0HPbSzaeG/qmw+VV+byTrZxXdmC175uOO/9Kte7T11+bRq2nO6Wefdujp5ggruw3QL6pT1Udte1+l2NqkfCpgdC4mvX7jVVudtuvOOd6sIH6Za96tON3vlfidc+vkoJ4JOI1BRgEBYEZDd2y+wpUDYK0IrVrxVBeW53dtv36d7r3s9fKrb/aYC0uEKUhf1Cp0CoQrgMv2wfWhTt3uGAtsB+v4HVLiOXnbuuR/sB6hPK6TtoY//Rt+/Sd97i465W7bNNnvpNs0NvUBo+2TZpQpwx83ooeOdo9B3jULXC/vHeKG+9jad6xULut1rNnU6++mYH5zpdl+j0HjW5kDY6XxPX3vtoqmpH27sdk/Rvgfe/LOf7b7TTjtN3b548ct0zDduXLBgTzvmNrfeeouFvOFAqDEdrT5+a+GiRT/etGnTw3Xe9+pcl2jMLycQtv9nghEigAACvf+vL3DLqAVCBbJDuln3PIWxd+rj3RW+PqZ6drSuAM7WwFwg7N0+2p1ardB308atsr+f2rTwtmW3f/Hmq7c6+CrVmlu6namjte/CzszMe7TrLctOuHR5LhC+Vh9fNrMgO37BzMym/Y+/7Nv9Pu6v875VkfBj3QWd56leTeuPmf+hbT85tam7pjuVvVofP7e74daHDm5bZYYRSEmAQJjSbDPWUgIWCLXjEQpAtw8d4FRdfTt17eGHb3X71lv/l36YfqAi9Sj9+zWFtJcOtu0FwizbWWFp78EVQX3tzfraX2j/va55wQv2mJma+oGC4BP3O/vsr9t+lx955A4Lu92f6XgvWnb22RdYIFQB+0h3wYLdDzjrrB/1CugRR7xc4e0NOtcDesXwiCOu1/H/ab9zzvno4Nzq++vV76frPE8YBEKd5691ng/ZNtccccReusq4NpuZ+aNl5533vblu9ZzvRWV0nMPU1/dpjDv2+saLypRaa+yEAAIIxCRQNBDqytzyH+2+827Pfe4Fm3r16tTlH1fNmFEgfH6vZgy9qIw+/5Su6P3Brgza96889eD/M9XNPq8/qu564Ou/8rNe/Tr1SXspOK6dmsoeu99xl15hVwh1ZfH4TmfTg/Y7/rLfbK7BFlo72YL9j7/0Sfa1j3/88AW7/fDX6/XhhQqTR/Zqrr2IzZ1d3W3TebyuKn4zpjmgrwh4CBAIPRQ5RqsF+lcIH6Tw9bL8QO+4/fbfPf6CC37XK0wKVvpr47f14U8WZNlj9jn77Fs3F6PZQPjfCmUvHnztmiOPfLaC2r9df/vtW+++ePEzdFXvE/bxcy+YLZa9ArlixTUKgZ/Ufm/sXyF8jwLXNrnjHmL7KTBOfWvFim10te8W9fE2HVcZb/NjoT5ar2Pcf3MgzFQ8zznnCtuif6uq3fJ58P7nnvuVooFQ/X9ad2bmOI35kTrMEu2/UMV9a13R3MZeeIZA2OofCQaHAAIIzNapolcIs2wnhbtnDNgU3t6p8PZofe0pvePMFwhPOfhV+oX11Qpwu+bptd/vFRT/Xrd6ru7fMvpCbWN322x+9PrY6azd//g1f7f5/Kcs/4lq1rsV/t5mX+vqPtOrTz14pjOVPXv/4y7t3d3DA4GUBAiEKc02Yy0lMN8to3bQ/nP33qcwdvPMxo2POfD883t/wewVOq9AOPQ2Dgpdz+kHxs43/+qv7r9owYJfKiAeoR/q/8oPVAF1kwLqjweBULeT7rfvuedea9voa9vpeYW/V2H8E91WuqZIIOwf53sqsGdovB9bODX1u00zMwfpGB9asHDh/fZdteoPBMJSS42dEEAAgagErjp1+UV6vt5vdfXtbi+6plcJPdoCnALfwwbPIVx2/KWbn4evr52uW0j3Hdzu6RgIn6Nj7ptHHBVah8/Xq9WnHKxY2DlEVy0/FdUk0FkEHAQIhA6IHKLdAvMFwitf9KLd9FyGa/XD9CoFtOfZE+b32223p3Wmp3tX6vrPIdxJV/L2HkjpmKcpTD17vltGdeXtSF3N+7dRASsfCHvnWbHi5zrm+xTs3jRqRooEwitf+MIX6DmK71dft71bQc29D6H6bi9K89H9dt9968EY+7emvolA2O6fBUaHAAII5AWuPuXgtylF/amutO0zFMJW6zl7D1QI/D8ugXALt4zquYYHKnheOXhRGQIhaxSB8QUIhOObsUdiAnO97cSCO+/c+KMNG36/+9Zbf1VB7OcKd4fpSuED9aqj1+lq2Vv0ee9WlMGLyvRe4CXL3q97OPfXvx/UD98/6BbQ9/e3+ZSC5B66BfNvdAXvZr3oiz3HcPe7vajMFq4Q2jH6VynfpWMfu6jTuVivcrp4amrqAJ33fjrP24sEwmtWrHiCzv019c1uCf1Wtu22/9u/BXTzG9Nrm320jV1hPFqvbfMZhcAnatvT9PmDCISJ/XAwXAQQSFrgitMOeviC7oK1uuXyg53OzJmbNi26Y0Fn0zOyqUzvI9h51v7HrbnYIxD2buk87eCr9bzCm2eyGXvPw4UKgvYK2sMvKsMVwqRXJIMvK0AgLCvHfskIzPnG9J3O9xUEz9Otk3+7sdN59GNXr/6toVx95JGH6usfVTB8rF685Vu9t53Q8xf0Nb2eS+cFCoub9IN3hr73+uG3ndD3/0KH2Eoh7iu66vjK4bedyL+Nw/AVwl4onL3C94/6cC81ex7jdTrW6QqnnywSCPvh9Az163D1c4c533ZixQp7RTY7z3bW12xq6lyFwtUEwmR+LBgoAggg0BO45rSDD+zOdE5RzdhXt4/aW0p8T3/cfPPg1kuPQNirbwXfdoIrhCxMBMYXIBCOb8YeCIwl0A+E1yrM2V81eSCAAAIIIIAAAggg0BgBAmFjpoKOtFWAQNjWmWVcCCCAAAIIIIBA/AIEwvjnkBE0XIBA2PAJonsIIIAAAggggEDCAgTChCefoSOAAAIIIIAAAggggEDaAgTCtOef0SOAAAIIIIAAAggggEDCAgTChCefoSOAAAIIIIAAAggggEDaAgTCtOef0SOAAAIIIIAAAggggEDCAgTChCefoSOAAAIIIIAAAggggEDaArEEQuvntmo3q+m9T3kggAACCCDQOgFqXeumlAEhgAACzReIJRAuEeV6PbIlS+xDHggggAACCMwt0NEjQh9qXYSTRpcRQACBSQl41bpYCiZFclIrjfMigAACEQp4FcnAQ6fWBQbndAgggEDMAl61zisQ7iHMs9R2VFuvtlJF46s2AAAgAElEQVRt7RDwcn3+ebXv577+eH18W4GJoEgWQGITBBBAAIFZAa8imfOsu87Zqah1LGAEEEAAgcICXrXOKxBeop6vVluldpjaMWoHjgiEp+tr+xYe5V0bUiRLoLELAgggkKqAV5HM+dVd5wiEqS5Wxo0AAgiUFPCqdR6BcGeN4Xq17dU2qtkxb1Q7qP/1wRCX6wMCYckJZzcEEEAAgeICXkWyf8YQdY5AWHx62RIBBBBAwEKX0/PlPQLhMvXnPLU9czNzuT4+Vs3+opoPhJ/RJz9U26T2EbX3zjGbi/V1a4OHvcLoDbyoDGsfAQQQQKCIgFeR7J+rjjpnh6bWFZlMtkEAAQQQGCngVetCBkK77dPOZ88xfLDa59ROVvv4iBFO62snDn+dQMhPAwIIIIBAEQGvIjlmIBynztmhqXVFJpNtEEAAAQQaHwiL3kozPJDj9IVd1F45YoT81ZSFjwACCCBQWsA5ENZR52xs1LrSM8yOCCCAAAJetc7jCqHNxhq1Vf1mLypjt4seMDRND9Tnv1KbUbNbQC9W+5DahwtMJy8qUwCJTRBAAAEEZgW8imTOs+46Z6ei1rGAEUAAAQQKC3jVOq9AaM8fXKW2g9pNakepXad2ptpF/fYK/fsyNXvhmYVqF6idpNYtMGqKZAEkNkEAAQQQmBXwKpI5z7rrnJ2KWscCRgABBBAoLOBV67wCYeGOl9zQrUj+4sILe13Y5dBDS3aF3RBAAAEEmi7gVSQDj9Ot1gXuN6dDAAEEEJiAgFetIxBOYPI4JQIIIIBAvQJeRbLeXt7j6ATCwOCcDgEEEIhZwKvWEQhjXgX0HQEEEEBgpIBXkQzMSyAMDM7pEEAAgZgFvGodgTDmVUDfEUAAAQQIhKwBBBBAAIEkBQiEJaed5xCWhGM3BBBAICIBryIZeMhcIQwMzukQQACBmAW8ah1XCGNeBfQdAQQQQIArhKwBBBBAAIEkBQiEJaedK4Ql4dgNAQQQiEjAq0gGHjJXCAODczoEEEAgZgGvWscVwphXAX1HAAEEEOAKIWsAAQQQQCBJAQJhyWnnCmFJOHZDAAEEIhLwKpKBh8wVwsDgnA4BBBCIWcCr1nGFMOZVQN8RQAABBLhCyBpAAAEEEEhSgEBYctq5QlgSjt0QQACBiAS8imTgIXOFMDA4p0MAAQRiFvCqdVwhjHkV0HcEEEAAAa4QsgYQQAABBJIUIBCWnHauEJaEYzcEEEAgIgGvIhl4yFwhDAzO6RBAAIGYBbxqHVcIY14F9B0BBBBAgCuErAEEEEAAgSQFCIQlp50rhCXh2A0BBBCISMCrSAYeMlcIA4NzOgQQQCBmAa9al+wVQpv8XQ49NOY1QN8RQAABBOYQ8CqSgYEJhIHBOR0CCCAQs4BXrSMQxrwK6DsCCCCAwEgBryIZmJdAGBic0yGAAAIxC3jVuqQD4WABcKUw5h8F+o4AAgjcU8CrSAa2JRAGBud0CCCAQMwCXrWOQKhVQCCM+UeBviOAAAIEQtYAAggggEB6AgTCknM+eFGZ/O4EwpKY7IYAAgg0VMCrSAYeHlcIA4NzOgQQQCBmAa9axxVCrhDG/HNA3xFAAIGRAl5FMjAvgTAwOKdDAAEEYhbwqnUEQgJhzD8H9B0BBBAgELIGEEAAAQSSFCAQlpx2bhktCcduCCCAQEQCXkUy8JC5QhgYnNMhgAACMQt41TquEHKFMOafA/qOAAIIcIWQNYAAAgggkKQAgbDktHOFsCQcuyGAAAIRCXgVycBD5gphYHBOhwACCMQs4FXruELIFcKYfw7oOwIIIMAVQtYAAggggECSAgTCktPOFcKScOyGAAIIRCTgVSQDD5krhIHBOR0CCCAQs4BXreMKIVcIY/45oO8IIIAAVwhZAwgggAACSQoQCEtOO1cIS8KxGwIIIBCRgFeRDDxkrhAGBud0CCCAQMwCXrWOK4RcIYz554C+I4AAAlwhZA0ggAACCCQpQCAsOe1cISwJx24IIIBARAJeRTLwkLlCGBic0yGAAAIxC3jVOq4Q9lfBLoceGvN6oO8IIIAAAjkBryIZGJVAGBic0yGAAAIxC3jVOgLh0CogGMb8Y0HfEUAAgVkBryIZ2JNAGBic0yGAAAIxC3jVOq9AuIcwz1LbUW292kq1tXMA2zm/pLa/2nYFJ8GtSI66ZTTfBwJhwRlhMwQQQKDBAl5FMjfEuuucncqt1jV4augaAggggICTgFet8wqEl2hcq9VWqR2mdozagXOM9TX6+h+pHU4gdFoNHAYBBBBA4G4CXkUyd9C66xyBkDWMAAIIIDCWgFet8wiEO6vn16ttr7ZRzY55o9pB/a/nB7a3PjlD7Si1qwiEY805GyOAAAIIFBTwKpL904WocwTCgnPLZggggAACswJetc4jEC5Tf85T2zM3OZfr42PV7C+qg8cifXCp2kvUblO7Vm2uW0YX63vWBo9t9cEN69evz5YssTtqyj+4ZbS8HXsigAACsQh4Fcn+eOuoc3bo2mpdLPNEPxFAAAEEygt41bqQgfBkDfcPav+stnSeQDit7584zEMgLL9g2BMBBBBIScCrSI4ZCMepc3bo2mpdSnPNWBFAAIFUBbxqnUcgLHorzWWarIeqddUWqu2i9lM1e67hb4Ymsra/mnKFMNUfGcaNAAIpCXgVyb5ZHXXODl1brUtprhkrAgggkKqAV63zCIQ2B2vUVvWbvaiM3S56wBYmZ6m+t6VbRod3dXvlNQJhqj8yjBsBBFIS8CqSObO665ydyq3WpTTXjBUBBBBIVcCr1nkFQnv+oAXCHdRuUrMXjblO7Uy1i/otP1cEwlRXLuNGAAEEAgh4FclcV+uucwTCAOuCUyCAAAJtEvCqdV6BsG5bt7+acoWw7qni+AgggMDkBbyKZOCRuNW6wP3mdAgggAACExDwqnUEwqHJ443pJ7CaOSUCCCDgLOBVJJ27Nd/hCITzCfF9BBBAAIHNAl61jkA4YlERCvlJQwABBOIW8CqSgRUIhIHBOR0CCCAQs4BXrSMQEghj/jmg7wgggMBIAa8iGZiXQBgYnNMhgAACMQt41ToCIYEw5p8D+o4AAggQCFkDCCCAAAJJChAIS077fC8qY4flltGSuOyGAAIINETAq0gGHg5XCAODczoEEEAgZgGvWscVQq4QxvxzQN8RQAABrhCyBhBAAAEEkhQgEJacdq4QloRjNwQQQCAiAa8iGXjIXCEMDM7pEEAAgZgFvGodVwi5QhjzzwF9RwABBLhCyBpAAAEEEEhSgEBYctq5QlgSjt0QQACBiAS8imTgIXOFMDA4p0MAAQRiFvCqdVwh5AphzD8H9B0BBBDgCiFrAAEEEEAgSQECYclpL3KFcHBoXm20JDK7IYAAAhMW8CqSgYfBFcLA4JwOAQQQiFnAq9ZxhXALq4BAGPOPCH1HAIGUBbyKZGBDAmFgcE6HAAIIxCzgVesIhATCmH8O6DsCCCAwUsCrSAbmJRAGBud0CCCAQMwCXrWOQEggjPnngL4jgAACBELWAAIIIIBAkgIEwpLTznMIS8KxGwIIIBCRgFeRDDxkrhAGBud0CCCAQMwCXrWOK4RcIYz554C+I4AAAlwhZA0ggAACCCQpQCAsOe1cISwJx24IIIBARAJeRTLwkLlCGBic0yGAAAIxC3jVOq4QzrMKeKXRmH9M6DsCCKQq4FUkA/sRCAODczoEEEAgZgGvWkcgJBDG/HNA3xFAAIGRAl5FMjAvgTAwOKdDAAEEYhbwqnUEQgJhzD8H9B0BBBAgELIGEEAAAQSSFCAQlpz2cZ5DODgFt42WxGY3BBBAYEICXkUycPe5QhgYnNMhgAACMQt41TquEBZYBQTCAkhsggACCDRIwKtIBh4SgTAwOKdDAAEEYhbwqnUEwgKrgEBYAIlNEEAAgQYJeBXJwEMiEAYG53QIIIBAzAJetY5AWGAVEAgLILEJAggg0CABryIZeEgEwsDgnA4BBBCIWcCr1hEIC6wCAmEBJDZBAAEEGiTgVSQDD4lAGBic0yGAAAIxC3jVOgJhgVVAICyAxCYIIIBAgwS8imTgIREIA4NzOgQQQCBmAa9aRyAssAoIhAWQ2AQBBBBokIBXkQw8JAJhYHBOhwACCMQs4FXrCIQFVgGBsAASmyCAAAINEvAqkoGHRCAMDM7pEEAAgZgFvGodgbDAKiAQFkBiEwQQQKBBAl5FMvCQCISBwTkdAgggELOAV60jEBZYBQTCAkhsggACCDRIwKtIBh4SgTAwOKdDAAEEYhbwqnUEwgKrYBAIf3HhhRnhsAAYmyCAAAITFvAqkoGHQSAMDM7pEEAAgZgFvGodgbDAKiAQFkBiEwQQQKBBAl5FMvCQCISBwTkdAgggELOAV63zCoR7CPMstR3V1qutVFs7BPx4fX5G/2uL9O9X1V6ldkeBiXArknaVb9wHgXBcMbZHAAEEJivgVSRzo6i7ztmp3GrdZPU5OwIIIIBACAGvWucVCC/RoFerrVI7TO0YtQOHIO6tzzf025T+/YTaV9TeUQDMrUiWCYT5/nHLaIHZYhMEEEBgwgJeRTI3jLrrHIFwwmuG0yOAAAKxCXjVOo9AuLPwrlfbXm2jmh3zRrWD+l8fZbu1vvgptYvVTi+ATyAsgMQmCCCAAAKzAl5Fsu8Zos4RCFm8CCCAAAJjCXjVOo9AuEw9P09tz9wILtfHx6rZX1Tzj6X65NNqu6l9Vm2F2p0jRr5YX7M2eGyrD25Yv359tmSJZcPyD64QlrdjTwQQQCAWAa8i2R9vHXXODl1brYtlnugnAggggEB5Aa9aFzoQDkZ8H31wjtr5/TYsMa0vnDj8RQJh+QXDnggggEBKAl5FskQgLFrnbLvaal1Kc81YEUAAgVQFvGqdRyAscyuNzdvz1V6o9qwRk1jbX025QpjqjwzjRgCBlAS8imTfrI46Z4eurdalNNeMFQEEEEhVwKvWeQRCm4M1aqv6zV5Uxm4XPWBocnbX5z9RsxeW2UrtbDV77uEJBSaR5xAWQGITBBBAAIFZAa8imfOsu87ZqdxqHesAAQQQQKD9Al61zisQ2vMHV6ntoHaT2lFq16mdqXZRv71U/9rbTGxSW6j2JbXXqd1eYLrciiRXCAtoswkCCCAQuYBXkcwx1F3nCISRrzm6jwACCIQW8Kp1XoGw7vE3JhAOBsrbT9Q95RwfAQQQKC/gVSTL96DUnm61rtTZ2QkBBBBAICoBr1pHICw57QTCknDshgACCAQQ8CqSAbqaPwWBMDA4p0MAAQRiFvCqdQTCkquAQFgSjt0QQACBAAJeRTJAVwmEgZE5HQIIINAWAa9aRyAsuSIIhCXh2A0BBBAIIOBVJAN0lUAYGJnTIYAAAm0R8Kp1BMKSK4JAWBKO3RBAAIEAAl5FMkBXCYSBkTkdAggg0BYBr1pHIKywIgiFFfDYFQEEEKhRwKtI1tjFUYfmOYSBwTkdAgggELOAV60jEFZYBQTCCnjsigACCNQo4FUka+wigTAwLqdDAAEE2ibgVesIhBVWBoGwAh67IoAAAjUKeBXJGrtIIAyMy+kQQACBtgl41ToCYYWVQSCsgMeuCCCAQI0CXkWyxi4SCAPjcjoEEECgbQJetY5A6LAyCIYOiBwCAQQQcBTwKpKOXSpyKJ5DWESJbRBAAAEEegJetY5A6LCgCIQOiBwCAQQQcBTwKpKOXSpyKAJhESW2QQABBBAgEFZZA7+48MIqu4/cl0DoTsoBEUAAgUoCBMJKfOyMAAIIIBCBgFet4wqhw2QTCB0QOQQCCCDgKOBVJB27VORQXCEsosQ2CCCAAAJcIayyBuq4Qmj9IRRWmRX2RQABBHwFCIS+nhwNAQQQQKB5Al61jiuETnNLIHSC5DAIIICAg4BXkXToyjiH4ArhOFpsiwACCCQu4FXrCIROC4lA6ATJYRBAAAEHAa8i6dCVcQ5BIBxHi20RQACBxAW8ah2B0HkhEQydQTkcAgggUELAq0iWOHWVXQiEVfTYFwEEEEhMwKvWEQidFw6B0BmUwyGAAAIlBLyKZIlTV9mFQFhFj30RQACBxAS8ah2B0HnhEAidQTkcAgggUELAq0iWOHWVXQiEVfTYFwEEEEhMwKvWEQidFw6B0BmUwyGAAAIlBLyKZIlTV9mFQFhFj30RQACBxAS8ah2B0HnhEAidQTkcAgggUELAq0iWOHWVXQiEVfTYFwEEEEhMwKvWEQidFw6B0BmUwyGAAAIlBLyKZIlTV9mFQFhFj30RQACBxAS8ah2BsIaFQyisAZVDIoAAAmMIeBXJMU7psSmB0EORYyCAAAKJCHjVOgJhDQuGQFgDKodEAAEExhDwKpJjnNJjUwKhhyLHQAABBBIR8Kp1BMIaFgyBsAZUDokAAgiMIeBVJMc4pcemBEIPRY6BAAIIJCLgVesIhDUsGAJhDagcEgEEEBhDwKtIjnFKj00JhB6KHAMBBBBIRMCr1hEIa1gwBMIaUDkkAgggMIaAV5Ec45QemxIIPRQ5BgIIIJCIgFetIxDWsGAIhDWgckgEEEBgDAGvIjnGKT02JRB6KHIMBBBAIBEBr1pHIKxhwRAIa0DlkAgggMAYAl5FcoxTemxKIPRQ5BgIIIBAIgJetY5AWMOCIRDWgMohEUAAgTEEvIrkGKf02JRA6KHIMRBAAIFEBLxqHYGwhgVDIKwBlUMigAACYwh4FckxTumxKYHQQ5FjIIAAAokIeNU6AmFNC4ZQ+P/auxvYaba7LuAFX4pIb6WtlSriRagN9Y3SVhOteEWCBqWB2kQNJN6GGBVFjVFbMNonBKLGiERriLHap8XUF+QBbsKbQn1seEnqG9pUDTZ4Y+u9gog+9V0r9ffr3e2dZ7OzM3PmzO6cmc8mJ/+3PbPnfM7ZPfOdmd3/QrA2S4AAgRECtRbJEQ9V8y4CYU1N2yJAgMDGBWqtdQLhQhNFIFwI1mYJECAwQqDWIjnioWreRSCsqWlbBAgQ2LhArbVOIFxoogiEC8HaLAECBEYI1FokRzxUzbsIhDU1bYsAAQIbF6i11tUKhC8N77dHeVGUB1Eej/K+kzH4vPj5z0T5pCgfifIdUd4U5adGjFW1RfKpe/dGPNz8uwiE8w1tgQABAqUCtRbJzuMvvc7lQ1Vb60rd1CNAgACBdgRqrXW1AuG7gu4dUe5GeX2UN0Z59QnnK+LnDIs/GuUTonxvlLce6gzJV1skrxUIjx0SDIeG1t8JECBQX6DWItlp2dLrnEBYfxrYIgECBDYtUGutqxEIXxzS74/ygigfjpLbfDrKaw6/7xuIt8QffiLKnREj1WwgzL4JhSNG2F0IECBQUaDWInlo0jXWOYGw4vjbFAECBPYgUGutqxEIXxng74zysg78e+L7vBw0j6ieu31K/PKHo/zWKP/4zB2eG7/Lcrw9L7754IMHD57zyCOZDctv1z5DmC0VCMvHS00CBAiUCNRaJA+PvcQ6l5tebK0rMVOHAAECBNoSqLXW3SIQZqL7vih/M8rX97Dfid+/+fRvAmFbk1RrCRAgcCuBWotkYSAcs87lphdb627l7nEJECBA4HoCtda6GoFwyqU0eabve6J8Z5SvvcC12FFTZwivN0k9EgECBG4lUGuRPLR/iXUuN73YWncrd49LgAABAtcTqLXW1QiE2ev7Ue4eSn6oTF4u+qoTjvx00QyDWb5mIpX3EE4Ec3cCBAjsWaDWItkxXHqdy4eqttbteez1nQABAnsRqLXW1QqE+f7BDIQvjPKhKG+I8t4o+SmiTxzKn4ivd6J0/x3FN8fPXzdi0Kotks4QjtB2FwIECDQuUGuR7DAsvc4JhI3POc0nQIDAtQVqrXW1AuHS/RcIlxa2fQIECGxIoNYieWWSamvdldu9q4d76t1ve87P/9w87j3tVlpv2qO4NwECexKotdYJhFecNT5t9IrYHooAgV0L1Fokr4woEF4ZvOThSoNdab2SNqpD4FYCOc+Pt5IDJ7dq91KPu/TzvtZaJxAuNQPObFcgvCK2hyJAYNcCtRbJKyMKhFcGL3m4Szt4pX8raYc6+xI4Bq21hazTOS8QPjwvBcK6z9Nqi+Qt3kPYpRAK604MWyNAgMA5AYHQvFhKoDT0Lb1jODUwLN2epfz3ut2p41viVDInhgLhNdpd0tcadcaE3xLTKW2rtdY5QzhFvcJ9BcIKiDZBgACBAYFai+SVoasd/Lxyuxd7uDXuTAqEw8M9Zkd5eCvrucfYnfqx95vas2t5lrS/NBCWPNZUt6H7j3l9GXq+Hx+j78zt0v2stdYJhEOzpfLfBcLKoDZHgACBMwK1Fskr4wqEJ+DndtiW3sEaGvPSHcRuvbF9mBIExuzcdvs2tg1j63Qff0q7h7wv/b2kDyWPN/Zxxt5vahvW7CkQPjOaAuHUWV12/2qL5K0vGf3YkYTXva5MQi0CBAgQGBQQCAeJHrrDuZ26NbxXaUwgnBqETmXG7MSPDXOXdtzHbuM0gH1sv2Hgk02nOozp9xSrMYGw5DGHAuFYn2nPiIfv3Rd6Tp8jtft3bMXpvKr9OHMC55KBsHY/0/PcPL30Wld6AKg7dku+ltZa65whnPMKMbOus4UzAVUnQIBAj0CtRfLKwNUOfo7Zie7upJQEwho7a0PbGBsy5oSCoTYcdyKPXqU7iN2d7tzmmJ3EMXWO7akZCE8ftzufTufNsS9jx2pMv8c8787ZDB1AqGXVZz02OJY8P7tzvG8OjpnL50J+3/iOaefpc+9ceO2bI+fmQrcP5/pzyX7M82pMIOxrw1D4Pec1J2yPeR7UWusEwjHaC91HIFwI1mYJENi9QK1F8sqQ1QLhpZ2Qkh33oR3tIadLO7CnO7rdnbqxbZ0aCE+3OxRShnZSj49/KcCN+du5M07nbM+F+VsGwtNA0Tf/SgJL39yqFQjHuF0Kepfm0pht9wW0HOPTPg4F86FA1Pc8PrfdobHqm899gfDcHDl3cOH0+d/3nBjz+6FA2RcOLwXCc69Xl9wvPe+HXjfH/L3WWicQjtFe6D4C4UKwNkuAwO4Fai2SV4ZcZSAs2bk/t1PYdzbgWoFwzM5fd7zHniU4rTNmp/1c6D23U9kXCKYEwjHjd9rXS/O+byd+TJ2+tox9nl1qZzdA9Z39Pta/NBdOx+FSiDoX2vrOoJ7r49jAMuagwOl9hg4udM94XwqEY0Jk3/iNDbWXwuWlfgxZj/U9nTtzwm7f/Om+zo2d72PuV2utEwjHaC90H4FwIVibJUBg9wK1FskrQ940EJ6GlHM7jKc7eH1n1s4FmWsEwnOh6jiGYwLhmB3TS2d9LvX70tmevp3FsYHwdIf+XF/H7qgOtbMkEPYFmj7LczvyuY1bBsLuGPX5jgmTx35MHfO+wDdmjpw+5ulzvS8Qnvv9uW3VDoRjtzd0+fKxn5fG6/Q+fXN1ar9PX3f6xnvuGlNrrRMI547EjPoC4Qw8VQkQIHBBoNYieWXkxQLh0A7R6c7KEmeMhoLEubA5J9icjt1Q0CndERzTr7E7k0Nndc6FknNBocRt7Fwf6u/Y7Qx5j3l/2WlgGXM2q+9s0NDZrL729h1E6I75pTNQY8f83DhfmldD2x1zhvDUty/k9I35kGlfG8Zur1YgHJqzc9vZ5zj0uGP+XmutEwjHaC90H4FwIVibJUBg9wK1FskrQ948EJb0d2xAGLpfrUB4buerJAzmdsbsCI7p15RAOCWMjw0p3SA5dae+L4iM7dOUOdX1HvP9pUA4ZsyHAstQ2y/VH7oM8dyY1Da9NH+3GgjPzdexB8QuBdEpYzM0r84d7Biaa31/r7XWCYSlI1CxnmBYEdOmCBAgEAK1FskrYy4SCPt2mmv1bUxo6oarvh2rS4GwtK1j2zZnR3AoEE5p+9FgTruHQsqUHdu+wDk3VI7x7guEl+pO3fEf2nEfGru59cc8L4baUPvvc+bepTBWo53nXiOWmounr5tTnjdD80IgLJ8N9RbJe/fKW7FgTaFwQVybJkBgdwIC4dtWO+ZDO0vHho+936WOzt25HVO/ZiBcetDG9GeoDUv2d+pZwdOd9jFnBYf6N+XvNefolMAxpY1T71tjjkx9zNL7LzkXBcLSUVm2nkC4rK+tEyBAYFMCAuF6A+HYiVZzZ3vpoNDKTnSNdtbYRt8cmHpWcOxcWup+NefoWgLhUla2+6yAM4Tls0EgLLdTkwABArsTEAgFwt1N+g10eMmwuWaevfZ7zWOyZNsEwnJdgbDcTk0CBAjsTkAgFAh3N+l1uFkBgbDZoStquEBYxPbRSpsPhNlJ7yMsnyBqEiBAoCsgEAqEnhEEWhEQCFsZqTrtFAjLHQXCcjs1CRAgsDsBgbD9QLi7SavDBAjsQkAgLB9mgbDcTk0CBAjsTkAgFAh3N+l1mACBJgQEwvJhEgjL7dQkQIDA7gQEQoFwd5NehwkQaEJAICwfJoGw3E5NAgQI7E5AIBQIdzfpdZgAgSYEBMLyYdpFIDzy+HCZ8omiJgECBFJAIBQIPRMIECCwRgGBsHxUdhUIk0koLJ8sahIgQEAgFAg9CwgQILBGAYGwfFQEwnI7NQkQILA7AYFQINzdpNdhAgSaEBAIy4dpd4HwSOVMYfmkUZMAgf0KCIQC4X5nv54TILBmAYGwfHQEwnI7NQkQILA7AYFQINzdpNdhAgSaEBAIy4dJICy3U5MAAQK7ExAIBcLdTXodJkCgCQGBsHyYdhsIk8xlo+UTR00CBPYpIBAKhPuc+XpNgMDaBQTC8hESCMvt1CRAgMDuBARCgXB3k16HCRBoQkAgLB8mgbDcTk0CBAjsTkAgFAh3N+l1mACBJgQEwvJh2nUgPLK5dLR8AqlJgMC+BARCgXBfM15vCRBoRWDLgfClMQhvj/KiKA+iPB7lfScD82j8fDfKK6L82yifPWHgBMLAEggnzBh3JUBg1wILBMKl17kcr3pr3bsFwl0/AR/oClIAABZnSURBVHSeAIHVCmw5EL4r1N9xCHyvj69vjPLqk5F4Qfz88ijPj/J1AuH0eSoQTjdTgwCBfQosEAiXXucEwn1OVb0mQGBnAlsNhC+OcXx/lAx8H47ycVGejvKaw+9Ph/mx+MU3CIRls/8YCp+6d88ZwzJCtQgQ2IFA5UB4jXVOINzBvNRFAgQIbDUQvjKG9p1RXtYZ4vfE92+KkkdUSwLhc6NSluPtefHNBx88ePCcRx7JK2rKbxmktnJzxnArI6kfBAjUFqgcCJdY57LLy611LhmtPaVsjwABAlUEBMJnGB+LMnSG8E7c582n6gLhwyICYZXnpY0QILBBgUYC4XJrnUC4wVmtSwQIbEFgq4FwiUtpljtq6gzhFp5L+kCAAIGLApUD4RLrXLZ/ubVOIPQMIUCAwCoFthoIE/t+lLuHkh8qk5eLvqpnFB6L3w+dITytWu+T1zYUCBPJWcJVPtc1igCBGwtUDoTXWOfyMeqtdQLhjWeghydAgMB5gS0Hwnz/YAbCF0b5UJQ3RHlvlLdGeeJQPjG+/kiUPCKanzT641G+KcpXjZgw9RbJjQXCo51gOGIWuQsBArsRWCAQLr3OCYS7mZ06SoDAngW2HAiXHleBcEBYIFx6Cto+AQItCSwQCK/R/XprnTOE1xgvj0GAAIHJAgLhZLKPVai3SDpDWD4KahIgQKARAYHQP6ZvZKpqJgECOxMQCMsHXCCcYOds4QQsdyVAYJMCAqFAuMmJrVMECDQvIBCWD6FAOMFOIJyA5a4ECGxSQCAUCDc5sXWKAIHmBQTC8iEUCCfaCYUTwdydAIFNCQiEAuGmJrTOECCwGQGBsHwoBcJCO8GwEE41AgSaFhAIBcKmJ7DGEyCwWQGBsHxoBcJCO4GwEE41AgSaFhAIBcKmJ7DGEyCwWQGBsHxoBcJCO4GwEE41AgSaFhAIBcKmJ7DGEyCwWQGBsHxoBcJCO4GwEE41AgSaFhAIBcKmJ7DGEyCwWQGBsHxoBcJCuwyET8X/XhQMCwFVI0CgSQGBUCBscuJqNAECmxcQCMuHWCAst3uopmBYCdJmCBBYtYBAKBCueoJqHAECuxUQCMuHXiAstxMIK9nZDAEC7QgIhAJhO7NVSwkQ2JOAQFg+2gJhuV1vTWcLF0C1SQIEViEgEAqEq5iIGkGAAIETAYGwfEoIhOV2AuECdjZJgMC6BQRCgXDdM1TrCBDYq4BAWD7yAmG53cWazhIuBGuzBAjcVEAgFAhvOgE9OAECBHoEBMLyqSEQltuNqikYjmJyJwIEGhEQCAXCRqaqZhIgsDMBgbB8wAXCcrvRNYXC0VTuSIDAygUEQoFw5VNU8wgQ2KmAQFg+8AJhud3omsdA6P8WjiZzRwIEViogEAqEK52amkWAwM4FBMLyCSAQltsV13TGsJhORQIEbiwgEAqEN56CHp4AAQJnBQTC8okhEJbbFdcUCIvpVCRA4MYCAqFAeOMp6OEJECAgEFaeAwJhZdApmxMMp2i5LwECaxAQCAXCNcxDbSBAgMCpgDOE5XNCICy3q15TQKxOaoMECFQWEAgFwspTyuYIECBQRUAgLGcUCMvtqtcUCKuT2iABApUFBEKBsPKUsjkCBAhUERAIyxkFwnK7RWsKh4vy2jgBAoUCAqFAWDh1VCNAgMCiAgJhOa9AWG53tZrC4dWoPRABAgMCAqFA6ElCgACBNQoIhOWjIhCW2121plB4VW4PRoBAj4BAKBB6chAgQGCNAgJh+agIhOV2N6spHN6M3gMT2L2AQCgQ7v5JAIAAgVUKCITlwyIQltvdvGYGw6fu3ftoO4TEmw+HBhDYhYBAKBDuYqLrJAECzQkIhOVDJhCW262qpnC4quHQGAKbFRAIBcLNTm4dI0CgaQGBsHz4BMJyu1XXFBBXPTwaR6BZAYFQIGx28mo4AQKbFhAIy4dXICy3a6rm8ZLSvMTU5aVNDZ3GEliVgEAoEK5qQmoMAQIEDgICYflUEAjL7TZRsxsUs0PC4iaGVScILCYgEAqEi00uGyZAgMAMAYGwHE8gLLfbdE3BcNPDq3MEigUEQoGwePKoSIAAgQUFthwIXxpub4/yoigPojwe5X1nLL88fvemKB8f5V1RviLK/x1hLhCOQHKXZ88cuuTUbCCwb4EFAuHS61wOWL217t0C4b6fAXpPgMBaBbYcCDPcvSPK3Sivj/LGKK8+GYhPj59/IMrnRPmxKN8e5Xui/OURA1ZvkTz8+4MRj+kuGxbwXsUND66uEQiBBQLh0uucQGjmEiBAYAcCWw2EL46xe3+UF0T5cK7DUZ6O8prD749D+8fim8+I8nsPv/jC+PrVh/sNDb9AOCTk74sKdD8NNR+o71JVZyYXHQYbJzBaoHIgvMY6JxCOHl13JECAQLsCWw2Er4wheWeUl3WG5j3xfV4amkdUj7e/FN88FeVPH37x8vj63VE+7cyQPjd+l+V4e15888EPfOADz3nkkcyG5benn3iivLKaBBYWeMlrX/vQIxzna/4+vz/9+8LNsXkCzQo8P27R+P8a5SMVOrHEOpfNWm6t+4G/UaHbNkGAAAECtQVe8mu/rNoma611eTZv7m2JhfJONOrNcxumPgECBAjsWiBD4YcqCCyxzmWzrHUVBscmCBAgsHOB2WtdjUC4xKU0p0dNc5zzktSf3PGAf/QsaZRPjZJHvd2GBZgNG53egxmz6QLTa1xrntU6Q7jEOpdqS6111/KdPvLL1NDfZVzXslXju5aRWKYdxne+6+y1rkYgzG7cj3L3UPJDZfJy0Ved9O8Xx8/fH6X7oTJ/L35+y3yHXWzho++jjDL7KMAutJ7pJLPpg82M2XSB6TVanGctrXMt+k6fRc/W0N85euuva3zXP0ZzWmh85+hVqlsrEOb7BzMQvjBKXp7zhijvjfLWKPmmveMb9353fJ9hMW+5uOYHzIz5txOVutv0Zvb2hKkxWMymKzJjNl1geo0W51lL61yLvtNn0bM19HeO3vrrGt/1j9GcFhrfOXqV6tYKhJWaYzMXBPb2hKkxGZhNV2TGbLrA9Brm2XSzKTX25qu/U2ZHe/c1vu2N2ZQWG98pWgvdVyBcCHaBzeZ7Tb4qSn5K6/9eYPtb3CSz6aPKjNl0gek1zLPpZlNq7M1Xf6fMjvbua3zbG7MpLTa+U7QWuq9AuBCszRIgQIAAAQIECBAgQGDtAgLh2kdI+wgQIECAAAECBAgQILCQgEC4EKzNEiBAgAABAgQIECBAYO0CAuHaR0j7CBAgQIAAAQIECBAgsJCAQLgQ7MzN/sWo/9oovyjKK6L88GF7L42vb4/yoij5Pwkfj/K+mY+1lep9Zk9GB/NDeP7noaP5oTx/eyudntmPT4j6fyvKyw8+Px5ff1+U90fJf8T9jiifcfD7ivj67pmPt4Xql8zuH56z+dzMWz5X/8IWOl2hD/k/Zz8lyk9FyX+g+wej/LMoXtPm4/a99h23nP8G6q9H+ZIo3zb/4W6+hb291vf1Nz+I489H+U1R/leUfx7ly24+OvMbcK6/+S/Nvq+z6U+M7/N/W+c69ZPzH/KmW+gb3y+MVn1tlI+P8tOj/LkouaZs4dbX59986PPPjK//I8rvOczrlvvczH6WQLjOafa50awfjfL9Ub44yjEQviu+z530u1FeH+WNUV69zi5cvVV9Zk+eGF69YSt+wHyh+rwo3xXlI1H+wGFePRZfcwfy30W5c5hj3xpfPz3K3v9v6CWz++HzDVG2sNNde9r+nNjgfzlsNINJzqtfGcVr2nzpvte+3PKjUd4ZJdf6P7uRubm31/q+/ubBpgwKeXAlX7/zgMt/mD+dbr6FS/P52Lg/Gt/8+ihfdPPWzm/Auf7m8/U/RXksyr84PI//dXz9uVHygFrrt3N9/uToVB6Mzr/liY5fF+Ubo/yyxjvbzH6WQLjumfZkNO8YCPNIWD5ZXhDlw1Fy7J6O8prD79fdk+u1rmuWj3r68/Va0t4jvSqa/HejPBrlv0X5zCjHHYz3xPdfHeV72+vWoi3umt2PRxIIh7kfj7v84Shf4DVtGGvCPU5f6/LMQp6ZzQOHeSZpa3Nzb6/13f7+7BjPXP8/NcqHJsyRlu56Or7dtv+r+CH/DdeWDr51+5v7dz8RJQ+e5ZU5vyJKHrjNg7L/p6VBHGhrt8+5lubBq1/SqZNz+7Eo/3RDfV7tfpZAuO5Z1n2yvPLwZHlZp8m5k/6mKHmU3e0Zga7Z8ed8Ucm5fvT6j7DOCnxT/DYvv/maKE9FyUuSjre/E998d5Q8c+j2rMDR7A/Fr+5HyaP0eRb1X0bJHZY80+/2jEBe3fAbDhh5OVReFpQ7AF7T6syQJ2Mz3StK8izK86K8+TA39xAIt/xa3x3fDAhPRMlL/j8/Sr4l4k6U7mWVdWbV7bZyOp+PLfk18c29KBmG8+D4Vm6n/c1xzfH971Hy7NnromztgGy3z8+P/uV6mWd9fzBKvm3q26P8tsN4b2WcV7ufJRCue4p1nywC4bixOn1R/bSolpc+/owoeT3+L4+SO6NuDwvk2b98If6NUX5WFIFweIZ0zfL9Dr8wygei5Ovq74+S77vM92e6PSzwu+LH3x7lT0YRCOvNju5rX15m9Vej5OVXeYDifpStB8Ktv9Z3x/dzYjz/SZR8LuWBlvysgb8f5ZdG+bF6U+qmW+r2t9uQvxY/5OWUf/ymrav/4N3+5qXAGf7+VJQ8Q5hvDcoDALn/kmcOt3I7HeM8YHgnyidF+aEo+XMeWM2+b+G26v0sgXDdU6z7ZHHJ6LixOn2B6dZ6SfzwI1HyqLnbswJ5JuF3RMkjksf3eeVRyfxAGZeMnp8p58xO75kf9PALouTOi9vDAnlG49Eo/yaKy+DrzI7ua19+OFTuTOYHauUtz1zn2bM8W5jvy9nCrdvf0/5s8bW+29/8YLkMfnmW/f8dOv+P4mvuPG/lLNK58c2gkJfKZkDK99Rt6dbt77nLJ3N8M1Bk8N/K7dJzOK9Qyv2PHOt8u1Trt9XvZwmE655ip0+W+9Hcu4eSHyqTl4vmC4fbswJds3yfRZ4ZPIacPxLf5yVVedTc7RmBNPnSKBkG/3MHJedZWt6Jki/I+V6NR6Ps/UNl+szyiG5+Et7x6Hxe5vL1UfKTgvd+yw+UyU8FzLPOecvn4Fui5BnVfxAl51oWr2nzZsqTB9vjh5B1t3Y/ftjyGcI9vNafjm++PzTH9Duj5HvLMjDkBzX9+3nTaDW1z83nL4/W5afm5mcnbO3W7e/Pi85lCPpVUfL9kvl+/nzLy2dHySuetnI7HeM8kJOBP295RddnRcm1tPVbE/tZAuE6p9lfiWb9lih5VDfPLuSnSuULQr7X5m6U3PHMo735wvjedXbh6q06Z5YfWvEtUX5alJzreX16vtfryau3bp0PmO/ByEsc0+X4yWV5RuFXR8kFKa91P76JPT+BNHfe937rM8tPa/2HUfKoZv5rhbysJxeB/Cj4vd8yFH9zlLwUOW3yPbx5tDSDi9e0+bOjb73obvl+/LCVQLi31/q+8c1/u5CXT+bZwnxe5Xu/c71r/XZpPud7y/JS6Le13slO+/v6+zvjPnlGMMc2PyAq/2VWXmK/hVtfn3Ns89NF8wBrXjL6lVGOB/Rb7Xcz+1kCYatTTLsJECBAgAABAgQIECAwU0AgnAmoOgECBAgQIECAAAECBFoVEAhbHTntJkCAAAECBAgQIECAwEwBgXAmoOoECBAgQIAAAQIECBBoVUAgbHXktJsAAQIECBAgQIAAAQIzBQTCmYCqEyBAgAABAgQIECBAoFUBgbDVkdNuAgQIECBAgAABAgQIzBQQCGcCqk6AAAECBAgQIECAAIFWBQTCVkdOuwkQIECAAAECBAgQIDBTQCCcCag6AQIECBAgQIAAAQIEWhUQCFsdOe0mQIAAAQIECBAgQIDATAGBcCag6gQIECBAgAABAgQIEGhVQCBsdeS0mwABAgQIECBAgAABAjMFBMKZgKoTIECAAAECBAgQIECgVQGBsNWR024CBAgQIECAAAECBAjMFBAIZwKqToAAAQIECBAgQIAAgVYFBMJWR067CRAgQIAAAQIECBAgMFNAIJwJqDoBAgQIECBAgAABAgRaFRAIWx057SZAgAABAgQIECBAgMBMAYFwJqDqBAgQIECAAAECBAgQaFVAIGx15LSbAAECBAgQIECAAAECMwUEwpmAqhMgQIAAAQIECBAgQKBVAYGw1ZHTbgIECBAgQIAAAQIECMwUEAhnAqpOgAABAgQIECBAgACBVgUEwlZHTrsJECBAgAABAgQIECAwU0AgnAmoOgECBAgQIECAAAECBFoVEAhbHTntJkCAAAECBAgQIECAwEwBgXAmoOoECBAgQIAAAQIECBBoVUAgbHXktJsAAQIECBAgQIAAAQIzBQTCmYCqEyBAgAABAgQIECBAoFUBgbDVkdNuAgQIECBAgAABAgQIzBQQCGcCqk6AAAECBAgQIECAAIFWBQTCVkdOuwkQIECAAAECBAgQIDBTQCCcCag6AQIECBAgQIAAAQIEWhUQCFsdOe0mQIAAAQIECBAgQIDATAGBcCag6gQIECBAgAABAgQIEGhVQCBsdeS0mwABAgQIECBAgAABAjMFBMKZgKoTIECAAAECBAgQIECgVQGBsNWR024CBAgQIECAAAECBAjMFBAIZwKqToAAAQIECBAgQIAAgVYFBMJWR067CRAgQIAAAQIECBAgMFNAIJwJqDoBAgQIECBAgAABAgRaFRAIWx057SZAgAABAgQIECBAgMBMAYFwJqDqBAgQIECAAAECBAgQaFVAIGx15LSbAAECBAgQIECAAAECMwUEwpmAqhMgQIAAAQIECBAgQKBVAYGw1ZHTbgIECBAgQIAAAQIECMwUEAhnAqpOgAABAgQIECBAgACBVgUEwlZHTrsJECBAgAABAgQIECAwU0AgnAmoOgECBAgQIECAAAECBFoVEAhbHTntJkCAAAECBAgQIECAwEwBgXAmoOoECBAgQIAAAQIECBBoVUAgbHXktJsAAQIECBAgQIAAAQIzBQTCmYCqEyBAgAABAgQIECBAoFUBgbDVkdNuAgQIECBAgAABAgQIzBQQCGcCqk6AAAECBAgQIECAAIFWBQTCVkdOuwkQIECAAAECBAgQIDBTQCCcCag6AQIECBAgQIAAAQIEWhUQCFsdOe0mQIAAAQIECBAgQIDATAGBcCag6gQIECBAgAABAgQIEGhVQCBsdeS0mwABAgQIECBAgAABAjMFBMKZgKoTIECAAAECBAgQIECgVQGBsNWR024CBAgQIECAAAECBAjMFBAIZwKqToAAAQIECBAgQIAAgVYFBMJWR067CRAgQIAAAQIECBAgMFNAIJwJqDoBAgQIECBAgAABAgRaFRAIWx057SZAgAABAgQIECBAgMBMAYFwJqDqBAgQIECAAAECBAgQaFVAIGx15LSbAAECBAgQIECAAAECMwUEwpmAqhMgQIAAAQIECBAgQKBVAYGw1ZHTbgIECBAgQIAAAQIECMwUEAhnAqpOgAABAgQIECBAgACBVgUEwlZHTrsJECBAgAABAgQIECAwU0AgnAmoOgECBAgQIECAAAECBFoVEAhbHTntJkCAAAECBAgQIECAwEyB/w9DhGn+z+fHEAAAAABJRU5ErkJggg==\" width=\"900\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/opt/conda/lib/python3.5/site-packages/ipykernel/__main__.py:108: MatplotlibDeprecationWarning: The set_axis_bgcolor function was deprecated in version 2.0. Use set_facecolor instead.\n",
"/opt/conda/lib/python3.5/site-packages/ipykernel/__main__.py:122: MatplotlibDeprecationWarning: The set_axis_bgcolor function was deprecated in version 2.0. Use set_facecolor instead.\n"
]
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import matplotlib.animation as animation\n",
"import matplotlib.gridspec as gridspec\n",
"from matplotlib.widgets import Slider\n",
"\n",
"%matplotlib notebook\n",
"\n",
"i_mult=100\n",
"\n",
"i_npar_size=1000*i_mult\n",
"i_frames=21\n",
"i_ani_step=50*i_mult\n",
"\n",
"n_bins=250\n",
"\n",
"cstrStart='Start animation'\n",
"cstrStop='Stop animation'\n",
"\n",
"\n",
"anime=None\n",
"\n",
"class cHist:\n",
" num_bins=200\n",
" font_size=10\n",
" \n",
" _ax=None \n",
" dt=None\n",
" color='black' \n",
" cap=''\n",
" alpha=0.5\n",
" \n",
" def __init__(self, data, draw_color='black', caption='', bins=n_bins, alfa=0.5, fontsize=10):\n",
" self.dt=data\n",
" self.color=draw_color\n",
" self.cap=caption\n",
" self.num_bins=bins\n",
" self.alpha=alfa\n",
" self.font_size=fontsize\n",
" \n",
" @property\n",
" def ax(self):\n",
" return self._ax\n",
" @ax.setter\n",
" def ax(self, value):\n",
" self._ax = value\n",
" \n",
" def set_ticks_font_size(self):\n",
" for label in (self._ax.get_xticklabels() + self._ax.get_yticklabels()):\n",
" #label.set_fontname('Arial')\n",
" label.set_fontsize(self.font_size-2)\n",
"\n",
" \n",
" def write_text(self, strText, x=0.8, y=0.9, f_size=font_size):\n",
" self._ax.text(x, y, strText, fontsize=f_size, \n",
" transform=self._ax.transAxes, va='center', ha='center')\n",
" \n",
" def write_title(self):\n",
" self._ax.set_title(self.cap, fontsize=self.font_size, color=self.color)\n",
" \n",
" def init_draw(self):\n",
" self.write_title()\n",
" \n",
" self._ax.spines['top'].set_visible(False)\n",
" self._ax.spines['right'].set_visible(False)\n",
" self.set_ticks_font_size()\n",
" \n",
" def draw_hist(self, srez1=-1, srez0=0):\n",
" self._ax.hist(self.dt[srez0:srez1], normed=True, bins=self.num_bins, \n",
" alpha=self.alpha, facecolor=self.color)\n",
" self.init_draw()\n",
"\n",
"def init_draw(bDrawHist=False):\n",
" for x in tplAni:\n",
" if bDrawHist:\n",
" x.draw_hist()\n",
" x.init_draw()\n",
" plt.tight_layout()\n",
" \n",
"def update(curr):\n",
" # check if animation is at the last frame, and if so, stop the animation a\n",
" global tplAni, i_frames, i_ani_step, init_draw, fig\n",
" #if curr >= i_frames: \n",
" # anime.event_source.stop()\n",
" fig.suptitle('Animation n = {}'.format(curr*i_ani_step), fontsize=14, fontweight='bold')\n",
" \n",
" for x in tplAni:\n",
" x.ax.cla()\n",
" x.draw_hist(srez1=curr*i_ani_step)\n",
" #tplAni[-1].write_text(' ', y=0.05, x=0.95, f_size=7)\n",
" #tplAni[-1].write_text('n = {}'.format(curr*i_ani_step), y=0.05, x=0.95, f_size=7)\n",
" return tplAni \n",
" \n",
"x_norm=cHist(np.random.normal(-2.5, 1, i_npar_size), caption='x1\\nNormal', draw_color='blue')\n",
"x_gamma=cHist(np.random.gamma(2, 1.5, i_npar_size), caption='x2\\nGamma', draw_color='green')\n",
"x_exp=cHist(np.random.exponential(2, i_npar_size)+7, caption='x3\\nExponential', draw_color='indianred')\n",
"x_uni=cHist(np.random.uniform(14,20, i_npar_size), caption='x4\\nUniform', draw_color='peru')\n",
"\n",
"# plot the histograms\n",
"\n",
"fig = plt.figure(figsize=(9, 7))\n",
"fig.suptitle('Animation', fontsize=14, fontweight='bold')\n",
"\n",
"gs = gridspec.GridSpec(4, 2, height_ratios=[4.5, 0.5, 4.5, 0.5])\n",
"x_norm.ax = fig.add_subplot(gs[0, 0])\n",
"\n",
"x_sp=fig.add_subplot(gs[1,0])\n",
"x_sp.set_axis_bgcolor('linen')\n",
"x_sp.set_xlim(0, 2)\n",
"xsp = Slider(x_sp, '$\\sigma$', 0, 2, valinit=1, color='blue')\n",
"\n",
"def x_sp_xhange(val):\n",
" x_norm.dt=np.random.normal(-2.5, xsp.val, i_npar_size)\n",
" x_norm.ax.cla()\n",
" x_norm.draw_hist()\n",
" \n",
"xsp.on_changed(x_sp_xhange) \n",
"\n",
"x_gamma.ax = fig.add_subplot(gs[0,1], sharey=x_norm.ax)\n",
"\n",
"x_sh=fig.add_subplot(gs[1,1])\n",
"x_sh.set_axis_bgcolor('beige')\n",
"x_sh.set_xlim(0, 9)\n",
"xsh = Slider(x_sh, 'S', 0, 9, valinit=2, color='green')\n",
"\n",
"def x_sh_xhange(val):\n",
" x_gamma.dt=np.random.gamma(val, 1.5, i_npar_size)\n",
" x_gamma.ax.cla()\n",
" x_gamma.draw_hist()\n",
"\n",
"xsh.on_changed(x_sh_xhange)\n",
"\n",
"x_exp.ax = fig.add_subplot(gs[2,0], sharey=x_norm.ax)\n",
"x_uni.ax = fig.add_subplot(gs[2,1], sharey=x_norm.ax)\n",
"#x_butt = fig.add_subplot(gs[2,:])\n",
"\n",
"tplAni=(x_norm, x_gamma, x_exp, x_uni)\n",
"\n",
"#plt.axis([-7,21,0,0.7])\n",
"\n",
"init_draw(bDrawHist=True)\n",
"\n",
"#anime = animation.FuncAnimation(fig, update, init_func=init_draw, interval=200, \n",
"# blit=False, frames=i_frames, repeat=True)\n",
"\n",
"\n"
]
}
],
"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.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment