Skip to content

Instantly share code, notes, and snippets.

@ax3l
Created January 5, 2017 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ax3l/9b49780a1bbedbe054f7d98654644e71 to your computer and use it in GitHub Desktop.
Save ax3l/9b49780a1bbedbe054f7d98654644e71 to your computer and use it in GitHub Desktop.
Plot Single Particle
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import yt\n",
"import numpy as np\n",
"%matplotlib notebook\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#yt.funcs.mylog.setLevel(20) # info\n",
"yt.funcs.mylog.setLevel(30) # warning\n",
"#yt.funcs.mylog.setLevel(40) # error"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# laserplasma = yt.UnitSystem(\"laserplasma\", length_unit=\"lambda_0\", mass_unit=\"m_e\", time_unit=\"fs\", temperature_unit=\"eV\", angle_unit=\"deg\", current_mks_unit=\"A\")\n",
"#laser_plasma_units"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ts = yt.load(\"singleParticle-004/simOutput/h5/simData_*\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dumps_sorted = sorted( range(len(ts)),\n",
" key=lambda x: ts[x].current_time )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Either Load the Data Via yt or via openPMD-viewer (see below)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axel/proggen_partiell/python/yt/yt/units/yt_array.py:990: RuntimeWarning: divide by zero encountered in true_divide\n",
" return super(YTArray, self).__truediv__(ro)\n"
]
}
],
"source": [
"pos_x = []\n",
"pos_y = []\n",
"pos_z = []\n",
"mom_z = []\n",
"t = []\n",
"\n",
"for dump_key in dumps_sorted:\n",
" ds = ts[dump_key]\n",
" #print( ds.base_path )\n",
" \n",
" dd = ds.all_data()\n",
" \n",
" pos_x.append( dd.quantities.total_quantity([(\"all\", \"particle_position_x\")]) )\n",
" pos_y.append( dd.quantities.total_quantity([(\"all\", \"particle_position_y\")]) )\n",
" pos_z.append( dd.quantities.total_quantity([(\"all\", \"particle_position_z\")]) )\n",
" \n",
" mom_z.append( dd.quantities.total_quantity([(\"all\", \"particle_momentum_z\")]) )\n",
"\n",
" t.append(ds.current_time.in_units(\"s\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot the Data loaded"
]
},
{
"cell_type": "code",
"execution_count": 7,
"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\", \"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",
" // 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3df5Ac1WHg8e/uYoGErR8gCA6SwLJANsLgkn+sDbGNUxU7HISVEFE5/E6dHbha6lITCwhO2Qj7Tlxikjrn6iouOBMVPwwkIEgpGw8ojolzFhUH48I2SJY5GSywgHUEkpCEY8S7P96s1Ds7I+3qTe/MG30/VV3MdPe+arXG0tc93U8gSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkqUv0ACcC011cXFxcXFyyWk4k/j0uTdiJQHBxcXFxcXHJcjkR6RBMB8KWLVvC9u3bXRKXwcHBth9DNyyeR89lJy6eS89jJy1btmwZCcDpbe4IZWo6ELZv3x6UrlKptPsQuoLnsXU8l63juWwNz2NrbN++3QBUEgOwhfyDrTU8j63juWwdz2VreB5bwwBUKgOwharVarsPoSt4HlvHc9k6nsvW8Dy2hgGoVAagJEmZMQCVygCUJCkzBqBSGYCS1IX27NnT9idVXdKWPXv2NP39NQCVygCUpC6zZ8+ecMIJJ7R7fjqXxOWEE05oGoEGoFIZgJLUZUbiwDle811G5vlr9vezAahUBqAkdZmROPDP9nwd7PfQAFQqA1CSuowBmD8DUGUzACWpyxiA+TMAVTYDUJK6jAGYPwNQZTMAJanLGID5MwBVNgNQkrqMAZg/A1BlMwAlqcsYgPkzAFU2A1CSuowBmD8DUGUzACWpy4wnANesCWF4ePS64eG4PlVZY994442hp6cn/PCHPwwf//jHw7Rp08Lb3/728IUvfGHUfj/+8Y/DkiVLwsyZM8PUqVPDhz70oVCtVkfts2nTprBkyZJw/PHHh6OOOirMmzcvLF++POzdu3dcx/L5z38+TJkyJTz++OP71u3atSuceuqp4ayzzgp79+4Nf/7nfx6OPPLI8Itf/GLMz7/jHe8Iv/d7v9d0fANQZTMAJanLjCcAh4dDuPzy/aFW/z5FWWOvXLky9PT0hAULFoRVq1aFdevWhRUrVoSenp5w0003hRBC+PnPfx5mz54d3vnOd4avf/3r4e///u/DueeeG/r6+kZF4IIFC0J/f3948MEHw7e//e1wzz33hMsuuyz86le/GtexvPHGG+Gss84Kp556ati1a1cIIYQrrrgizJw5Mzz33HMhhBC2bdsWpk6dGr785S+P+tlqtRp6e3vDt7/97abjG4AqmwEoSV1mvF8Bj4TZhg2ti78yx165cmXo7e0Nf/ZnfzZq/Wc+85kwffr0sH379vDZz342vOUtbwmbN2/et33v3r1h4cKF4X3ve18IIYRf/OIXoaenJ6xduzbpeJ599tkwc+bMcOWVV4Z77rkn9PT0hPvuu2/UPldeeWU45ZRTRq1bunRpOO200w44tgGoshmAktRlJnIP4IYNIUD8b6u1euyRAPzpT386av03v/nN0NvbG77zne+ED37wg+EjH/lIw5/t6+sLO3fuDCGE8M53vjMsWrQo3HbbbeEnP/nJIR/TfffdF3p6esJRRx0Vfv/3f3/M9u9+97uht7c3fPOb3wwhhLB169bwlre8JXzlK1854LgGoMpmAEpSl+n2K4C7d+8etf5HP/pR6O3tDX/zN38TFixYEJYvXz7mZ7/61a+G3t7e8LOf/SyEEMJPf/rTcMUVV4Tjjjsu9PT0hPnz54e/+qu/mvAx7dy5M8yePTv09vaGJ598suE+73//+8Pv/u7vhhBC+OIXvximTZsWXnnllQOOawCqbAagJHWZbr4HcDxXAD/60Y+O+dkbb7xx1BXAoieffDJ85jOfCT09PWMeFjmYyy67LBxzzDHhlFNOCf39/Q0fIvna174WpkyZEl544YVw0kknhSuvvPKg4xqAKpsBKEldplufAh4JwD/90z8dtf7Tn/50mD59etixY0e49tprw5QpU/Y9iBFCvAfwXe96V/jABz7QdOwdO3aEnp6ecMstt4z7eO6+++7Q29sbHnjggfC9730vTJkyJXzuc58bs9/u3bvDrFmzwsc+9rHQ29sbHnvssYOObQCqbAagJHWZbp0HsNFTwJ/97GdDb29v+NKXvhRCiE8BH3/88eHUU08NX//618PatWvDueeeG4444ojwyCOPhBBC+MEPfhA+/vGPh69+9avhH//xH8PDDz8cPvWpT4UpU6aEJ554YlzHsnnz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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x7fa1b8b87e10>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plt.figure()\n",
"plt.plot(pos_x, pos_y, \"x\", label=\"pos_xy\")\n",
"plt.legend()\n",
"#plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"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\", \"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",
" // 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdebwV8/8H8JeSFrSjVSjSTuHaKhFFe8lSkTXLtXRtWb6WLCWSJVlKikqRNim34isRImUrhMSNEsqpVJZ6/f74nH6O696W75yZ92k+r+fjMQ/nnjN3vGo+x7x8zswcQERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERP4HfQF8D2AdgNkA6m1j3bIAxgD4FcBqAKMAlMm3zukAPgPwG4BFADrt5DYaApgOYAWALQBO3EaevQEsA7AZQJFtrCciIiIiSdcD+BZAXQDFAfQDsBxAqULWnwZgJoByAMoDmAVgcsrrWQA2AugIoCiAzgA2AGi8E9s4FMCFyd/ZjG0XwOEAXoEKoIiIiMgOWwrgipSfiwL4EUD3AtbdH25Grn7Kcw2Tz1VL/vw0gAn5fm8igGHJxzV2YBuptjUD2A7AvOTrKoAiIiIiO6A0XMHKyvf8DAADC1i/PdxsXn6bALRNPl4AoE++128CMD/5uMMObCNVYQWwAtxHv3UANIcKoIiIiMgOqQZXsGrne34cgKEFrN8D7ry8/FYC6JZ8/BWAS/K9fimAJTuxjVSFFcDn4YolsP0CuBuAqnCFV4sWLVq0aNGy6yxV4Y7jkkalkb4ZwDbJxwuw7RnAbW1jR2cAzwLwPv4ufCfAFcCiBfw+4AYPtWjRokWLFi275FIVknYFnQO4CoWfA7gZ/zx/r1HyudRzAF/M93sT8fc5gDuyjVQFFcARcFcs/5Rcfk2utwrAOQVsozQA5uXlMZFIaDFesrOzzTNo0b7IxEX7I3OWdOyLX39NcPXqBH/8McHlyxP85psEv/wywcWLE/zwwwTnz0/wnXcSnDMnwddeS3DGjARffjnBSZMSHD8+wTFjEhw5MsFhwxJ8/PEEH3kkwQceSHDA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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure()\n",
"plt.plot(pos_z, label=\"z\")\n",
"plt.legend()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"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\", \"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",
" // 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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure()\n",
"plt.plot(mom_z, label=\"mom_z\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"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\", \"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",
" // 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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure()\n",
"plt.plot(t, label=\"t\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"## yt load Group Based (not implemented yet)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ts2 = yt.load(\"singleParticle-004/simOutput/simData.h5\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ts2.current_time.in_units(\"s\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## load same data via openPMD-viewer (also just fileBased)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import opmd_viewer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ts3 = opmd_viewer.OpenPMDTimeSeries(\"singleParticle-004/simOutput/h5/\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ts3.get_particle([\"x\", \"y\", \"z\", \"uz\"], \"e\", iteration=2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pos_x = []\n",
"pos_y = []\n",
"pos_z = []\n",
"mom_z = []\n",
"t = []\n",
"\n",
"for t_it in ts3.iterations:\n",
" tmp = ts3.get_particle([\"x\", \"y\", \"z\", \"uz\"], \"e\", iteration=t_it)\n",
" pos_x.append(tmp[0][0])\n",
" pos_y.append(tmp[1][0])\n",
" pos_z.append(tmp[2][0])\n",
" mom_z.append(tmp[3][0])\n",
" t.append(ts3.current_t)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**note:** run the plot cells above now to see the correct plots"
]
},
{
"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.2"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment