Skip to content

Instantly share code, notes, and snippets.

@jburroni
Created March 29, 2016 15:20
Show Gist options
  • Save jburroni/050d1b9561f65823091c to your computer and use it in GitHub Desktop.
Save jburroni/050d1b9561f65823091c to your computer and use it in GitHub Desktop.
Plots complex inequalities using ipython
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": 96,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"C = x + y *1j"
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"f = (C*F(C)).flatten()\n",
"r, i = f.real, f.imag"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is a problem when 0 is in the set to plot. This could be solve in the $C*F(C)$ using something like \n",
" np.inf*(1-F(C))"
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"index = np.where((r != 0) & (i != 0))"
]
},
{
"cell_type": "code",
"execution_count": 100,
"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"
},
{
"data": {
"text/plain": [
"<matplotlib.text.Text at 0x116af5590>"
]
},
"execution_count": 100,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plt.scatter(r[index], i[index])\n",
"plt.title('$2*z_i > z_r$')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"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