Skip to content

Instantly share code, notes, and snippets.

@pedritomelenas
Created November 26, 2015 23:13
Show Gist options
  • Save pedritomelenas/996b999a5c249249643e to your computer and use it in GitHub Desktop.
Save pedritomelenas/996b999a5c249249643e to your computer and use it in GitHub Desktop.
otra prueba
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%matplotlib notebook\n",
"#%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from numpy import sin, cos\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.animation as animation"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false,
"scrolled": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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9vN4azcpCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAC3hD4f1k2GxVYBCRJAAAAAElFTkSuQmCC\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\n",
"\n",
"L1 = 1.0 # length of pendulum 1 in m\n",
"L2 = 1.0 # length of pendulum 2 in m\n",
"\n",
"\n",
"# create a time array from 0..100 sampled at 0.05 second steps\n",
"dt = 0.05\n",
"t = np.arange(0.0, 20, dt)\n",
"\n",
"\n",
"\n",
"x1 = L1*sin(t)\n",
"y1 = -L1*cos(t)\n",
"\n",
"x2 = x1 #L2*cos(y[:, 2]) + x1\n",
"y2 = y1 #-L2*cos(y[:, 2]) + y1\n",
"\n",
"\n",
"\n",
"fig = plt.figure()\n",
"ax = fig.add_subplot(111, autoscale_on=False, xlim=(-2, 2), ylim=(-2, 2))\n",
"\n",
"circ=plt.Circle((0,0), radius=L1, color='g', fill=False)\n",
"ax.add_patch(circ)\n",
"#ax.grid()\n",
"\n",
"line, = ax.plot([], [], '> ' , lw=2)\n",
"time_template = 'time = %.1fs'\n",
"time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)\n",
"\n",
"\n",
"def init():\n",
" line.set_data([], [])\n",
" time_text.set_text('')\n",
" return line, time_text\n",
"\n",
"\n",
"def animate(i):\n",
" thisx = [0, x1[i], x2[i]]\n",
" thisy = [0, y1[i], y2[i]]\n",
"\n",
" line.set_data(thisx, thisy)\n",
" time_text.set_text(time_template % (i*dt))\n",
" return line, time_text\n",
"\n",
"ani = animation.FuncAnimation(fig, animate, np.arange(1, 200),\n",
" interval=25, blit=True, init_func=init)\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment