diff --git a/docs/case-studies/PF/TKC_Mag.ipynb b/docs/case-studies/PF/TKC_Mag.ipynb
index 46bd345..4ae9075 100644
--- a/docs/case-studies/PF/TKC_Mag.ipynb
+++ b/docs/case-studies/PF/TKC_Mag.ipynb
@@ -16,55 +16,46 @@
{
"cell_type": "code",
"execution_count": 1,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"## First we need to load all the libraries and set up the path\n",
"## for the input files. Same files as used by the online tutorial\n",
- "import matplotlib.pyplot as plt\n",
- "from SimPEG import Mesh\n",
- "from SimPEG import Utils\n",
- "from SimPEG import Maps\n",
- "from SimPEG import Regularization\n",
- "from SimPEG import DataMisfit\n",
- "from SimPEG import Optimization\n",
- "from SimPEG import InvProblem\n",
- "from SimPEG import Directives\n",
- "from SimPEG import Inversion\n",
- "from SimPEG import PF\n",
- "from SimPEG.Utils.io_utils import download\n",
- "import matplotlib\n",
- "import matplotlib.colors as colors\n",
+ "%matplotlib notebook\n",
"import scipy as sp\n",
"import numpy as np\n",
"import time as tm\n",
"import os\n",
"import shutil\n",
- "from ipywidgets.widgets import interact, IntSlider\n",
- "%matplotlib inline "
+ "import matplotlib.colors as colors\n",
+ "import matplotlib.pyplot as plt\n",
+ "from SimPEG import Mesh, Utils, Maps, Regularization, DataMisfit, Optimization, InvProblem, Directives, Inversion, PF\n",
+ "from SimPEG.Utils.io_utils import download\n",
+ "\n",
+ "\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "overwriting MagData.obs\n",
- "overwriting Mesh.msh\n",
- "overwriting Initm.sus\n",
- "overwriting SimPEG_PF_Input.inp\n",
+ "overwriting C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\MagData.obs\n",
+ "overwriting C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\Mesh.msh\n",
+ "overwriting C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\Initm.sus\n",
+ "overwriting C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\SimPEG_PF_Input.inp\n",
"Downloading https://storage.googleapis.com/simpeg/tkc_synthetic/potential_fields/MagData.obs\n",
+ " saved to: C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\MagData.obs\n",
"Downloading https://storage.googleapis.com/simpeg/tkc_synthetic/potential_fields/Mesh.msh\n",
+ " saved to: C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\Mesh.msh\n",
"Downloading https://storage.googleapis.com/simpeg/tkc_synthetic/potential_fields/Initm.sus\n",
+ " saved to: C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\Initm.sus\n",
"Downloading https://storage.googleapis.com/simpeg/tkc_synthetic/potential_fields/SimPEG_PF_Input.inp\n",
+ " saved to: C:\\Users\\DominiqueFournier\\Desktop\\MagTKC\\SimPEG_PF_Input.inp\n",
"Download completed!\n"
]
}
@@ -83,9 +74,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# Read in the input file which included all parameters at once (mesh, topo, model, survey, inv param, etc.)\n",
@@ -95,9 +84,7 @@
{
"cell_type": "code",
"execution_count": 4,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# We already have created a mesh, model and survey for this example.\n",
@@ -144,9 +131,7 @@
{
"cell_type": "code",
"execution_count": 5,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# We did not include a topography file in this example as the information\n",
@@ -203,14 +188,12 @@
{
"cell_type": "code",
"execution_count": 6,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# Now that we have a model and a survey we can build the linear system ...\n",
"# Create the forward model operator (the argument forwardOnly=False store the forward matrix to memory)\n",
- "prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv, forwardOnly=False, rtype = 'tmi')\n",
+ "prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv, forwardOnly=False)\n",
"\n",
"# Pair the survey and problem\n",
"survey.pair(prob)"
@@ -220,15 +203,14 @@
"cell_type": "code",
"execution_count": 7,
"metadata": {
- "collapsed": false,
- "scrolled": true
+ "scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Begin calculation of forward operator: ind\n",
+ "Begin forward: M=H0, Rx type= tmi\n",
"Done 0.0 %\n",
"Done 10.0 %\n",
"Done 20.0 %\n",
@@ -238,16 +220,796 @@
"Done 60.0 %\n",
"Done 70.0 %\n",
"Done 80.0 %\n",
- "Done 90.0 %\n",
- "Done 100% ...forward operator completed!!\n",
- "\n"
+ "Done 90.0 %\n"
]
},
{
"data": {
- "image/png": "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\n3LFg647QAAAAAElFTkSuQmCC\n",
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('
');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
"text/plain": [
- ""
+ ""
]
},
"metadata": {},
@@ -269,7 +1031,7 @@
"\n",
"# [OPTIONAL] You can write the observations to UBC format here\n",
"#PF.Magnetics.writeUBCobs('MAG_Synthetic_data.obs',survey,data)\n",
- "fig = PF.Magnetics.plot_obs_2D(survey.srcField.rxList[0].locs,d=data ,title='Mag Obs')"
+ "fig = Utils.PlotUtils.plot2Ddata(survey.srcField.rxList[0].locs, data, contourOpts={\"cmap\":\"Spectral_r\"})"
]
},
{
@@ -340,9 +1102,7 @@
{
"cell_type": "code",
"execution_count": 8,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -358,10 +1118,9 @@
"wr = np.sum(prob.G**2.,axis=0)**0.5\n",
"wr = ( wr/np.max(wr) )\n",
" \n",
- "reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)\n",
- "reg.norms = driver.lpnorms\n",
- "reg.eps_p = 5e-3\n",
- "reg.eps_q = 5e-3 \n",
+ "# Create a regularization\n",
+ "reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap, gradientType='total')\n",
+ "reg.norms = np.c_[0.5,0,0,0]\n",
"reg.cell_weights = wr\n",
"\n",
"dmis = DataMisfit.l2_DataMisfit(survey)\n",
@@ -370,13 +1129,13 @@
"# Add directives to the inversion\n",
"opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=0.,upper=1., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3)\n",
"invProb = InvProblem.BaseInvProblem(dmis, reg, opt)\n",
- "betaest = Directives.BetaEstimate_ByEig()\n",
+ "betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1)\n",
"\n",
"# Here is where the norms are applied\n",
"# Use pick a treshold parameter empirically based on the distribution of model\n",
"# parameters (run last cell to see the histogram before and after IRLS)\n",
- "IRLS = Directives.Update_IRLS(f_min_change = 1e-4, minGNiter=2)\n",
- "update_Jacobi = Directives.Update_lin_PreCond()\n",
+ "IRLS = Directives.Update_IRLS(f_min_change = 1e-4, minGNiter=1, betaSearch=False)\n",
+ "update_Jacobi = Directives.UpdatePreconditioner()\n",
"inv = Inversion.BaseInversion(invProb, directiveList=[betaest,IRLS,update_Jacobi])\n",
"\n",
"m0 = np.ones(idenMap.nP)*1e-4\n"
@@ -385,9 +1144,7 @@
{
"cell_type": "code",
"execution_count": 9,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -397,65 +1154,82 @@
"\n",
" SimPEG.InvProblem is setting bfgsH0 to the inverse of the eval2Deriv.\n",
" ***Done using same Solver and solverOpts as the problem***\n",
+ "Approximated diag(JtJ) with linear operator\n",
"model has any nan: 0\n",
"=============================== Projected GNCG ===============================\n",
" # beta phi_d phi_m f |proj(x-g)-x| LS Comment \n",
"-----------------------------------------------------------------------------\n",
"x0 has any nan: 0\n",
- " 0 1.43e+09 2.87e+05 0.00e+00 2.87e+05 1.45e+02 0 \n",
- " 1 7.17e+08 2.44e+05 1.40e-05 2.54e+05 1.44e+02 0 \n",
- " 2 3.59e+08 2.13e+05 4.63e-05 2.29e+05 1.43e+02 0 Skip BFGS \n",
- " 3 1.79e+08 1.68e+05 1.37e-04 1.93e+05 1.42e+02 0 Skip BFGS \n",
- " 4 8.97e+07 1.17e+05 3.41e-04 1.48e+05 1.40e+02 0 Skip BFGS \n",
- " 5 4.48e+07 7.23e+04 7.00e-04 1.04e+05 1.37e+02 0 Skip BFGS \n",
- " 6 2.24e+07 4.05e+04 1.20e-03 6.74e+04 1.33e+02 0 Skip BFGS \n",
- " 7 1.12e+07 2.13e+04 1.80e-03 4.14e+04 1.29e+02 0 Skip BFGS \n",
- " 8 5.60e+06 1.03e+04 2.48e-03 2.42e+04 1.24e+02 0 Skip BFGS \n",
- " 9 2.80e+06 4.48e+03 3.17e-03 1.34e+04 1.22e+02 0 Skip BFGS \n",
- " 10 1.40e+06 1.81e+03 3.82e-03 7.15e+03 1.20e+02 0 Skip BFGS \n",
- " 11 7.01e+05 6.84e+02 4.35e-03 3.73e+03 1.19e+02 0 Skip BFGS \n",
- " 12 3.50e+05 2.57e+02 4.75e-03 1.92e+03 1.17e+02 0 Skip BFGS \n",
- " 13 1.75e+05 9.70e+01 5.04e-03 9.80e+02 1.14e+02 0 Skip BFGS \n",
- "Convergence with smooth l2-norm regularization: Start IRLS steps...\n",
- "L[p qx qy qz]-norm : [ 0. 1. 1. 1. 1.]\n",
- "eps_p: 0.005 eps_q: 0.005\n",
- "Regularization decrease: 8.382e+01\n",
- " 14 1.75e+05 3.88e+01 5.25e-03 9.59e+02 4.07e+01 0 Skip BFGS \n",
- " 15 1.75e+05 3.49e+01 4.84e-03 8.82e+02 1.31e+02 0 \n",
- "Regularization decrease: 1.453e-01\n",
- " 16 4.83e+05 3.06e+01 4.84e-03 2.37e+03 5.17e+01 0 \n",
- " 17 4.83e+05 2.94e+02 4.15e-03 2.30e+03 6.04e+01 0 \n",
- "Regularization decrease: 1.722e-01\n",
- " 18 3.31e+05 1.23e+02 4.15e-03 1.50e+03 1.05e+02 0 \n",
- " 19 3.31e+05 1.56e+02 4.01e-03 1.48e+03 1.43e+02 1 Skip BFGS \n",
- "Regularization decrease: 8.029e-02\n",
- " 20 3.31e+05 8.46e+01 4.01e-03 1.41e+03 6.73e+01 0 \n",
- " 21 3.31e+05 9.35e+01 3.98e-03 1.41e+03 6.64e+01 4 Skip BFGS \n",
- "Regularization decrease: 7.463e-02\n",
- " 22 1.98e+05 1.42e+02 3.98e-03 9.29e+02 1.36e+02 0 \n",
- " 23 1.98e+05 4.99e+01 4.14e-03 8.68e+02 1.31e+02 0 \n",
- "Regularization decrease: 8.676e-03\n",
- " 24 3.04e+05 5.49e+01 4.09e-03 1.30e+03 5.99e+01 3 Skip BFGS \n",
- " 25 3.04e+05 1.00e+02 3.93e-03 1.30e+03 6.56e+01 1 \n",
- "Regularization decrease: 7.008e-02\n",
- " 26 2.35e+05 1.10e+02 3.93e-03 1.03e+03 1.42e+02 0 \n",
- " 27 2.35e+05 9.85e+01 3.93e-03 1.02e+03 1.44e+02 0 \n",
- "Regularization decrease: 2.251e-02\n",
- " 28 1.92e+05 1.03e+02 3.84e-03 8.41e+02 1.08e+02 2 \n",
- " 29 1.92e+05 1.02e+02 3.83e-03 8.38e+02 7.06e+01 2 Skip BFGS \n",
- "Regularization decrease: 5.241e-03\n",
- " 30 2.33e+05 6.96e+01 3.83e-03 9.63e+02 1.12e+02 0 Skip BFGS \n",
- " 31 2.33e+05 7.86e+01 3.69e-03 9.38e+02 1.45e+02 0 \n",
- "Regularization decrease: 4.601e-02\n",
- " 32 2.33e+05 8.26e+01 3.65e-03 9.33e+02 1.35e+02 3 Skip BFGS \n",
- " 33 2.33e+05 8.61e+01 3.62e-03 9.30e+02 7.51e+01 2 \n",
- "Reach maximum number of IRLS cycles: 10\n",
+ " 0 1.43e+07 2.87e+05 0.00e+00 2.87e+05 1.45e+02 0 \n",
+ " 1 7.13e+06 2.37e+04 1.74e-03 3.61e+04 1.25e+02 0 \n",
+ " 2 3.57e+06 6.61e+03 2.93e-03 1.70e+04 8.95e+01 0 Skip BFGS \n",
+ " 3 1.78e+06 2.59e+03 3.60e-03 9.01e+03 1.20e+02 0 Skip BFGS \n",
+ " 4 8.92e+05 9.75e+02 4.18e-03 4.70e+03 1.26e+02 0 Skip BFGS \n",
+ " 5 4.46e+05 3.73e+02 4.63e-03 2.44e+03 1.17e+02 0 Skip BFGS \n",
+ " 6 2.23e+05 1.41e+02 4.97e-03 1.25e+03 8.68e+01 0 Skip BFGS \n",
+ "Reached starting chifact with l2-norm regularization: Start IRLS steps...\n",
+ "eps_p: 0.01038049018907678 eps_q: 0.01038049018907678\n",
+ "delta phim: inf\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\DominiqueFournier\\Documents\\GIT\\SimPEG\\SimPEG\\Directives.py:830: RuntimeWarning: divide by zero encountered in double_scalars\n",
+ " self.f_change = np.abs(self.f_old - phim_new) / self.f_old\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 7 1.11e+05 5.60e+01 7.43e-03 8.85e+02 8.20e+01 0 Skip BFGS \n",
+ "delta phim: 4.506e+03\n",
+ " 8 2.60e+05 3.17e+01 9.05e-03 2.39e+03 1.04e+02 0 Skip BFGS \n",
+ "delta phim: 4.303e-01\n",
+ " 9 1.82e+05 1.29e+02 1.03e-02 2.01e+03 8.41e+01 0 \n",
+ "delta phim: 4.114e-01\n",
+ " 10 1.27e+05 1.32e+02 1.11e-02 1.54e+03 7.61e+01 4 Skip BFGS \n",
+ "delta phim: 3.563e-01\n",
+ " 11 2.12e+05 6.30e+01 1.32e-02 2.87e+03 4.14e+01 0 \n",
+ "delta phim: 4.864e-01\n",
+ " 12 1.32e+05 1.69e+02 1.46e-02 2.11e+03 1.28e+02 0 \n",
+ "delta phim: 3.726e-01\n",
+ " 13 9.20e+04 1.32e+02 1.66e-02 1.66e+03 1.04e+02 0 \n",
+ "delta phim: 2.574e-01\n",
+ " 14 6.53e+04 1.26e+02 1.80e-02 1.30e+03 6.09e+01 0 Skip BFGS \n",
+ "delta phim: 1.432e-01\n",
+ " 15 6.53e+04 9.12e+01 1.89e-02 1.32e+03 9.66e+01 0 \n",
+ "delta phim: 9.413e-02\n",
+ " 16 4.92e+04 1.12e+02 1.91e-02 1.05e+03 1.33e+02 0 \n",
+ "delta phim: 5.729e-02\n",
+ " 17 4.92e+04 8.86e+01 1.98e-02 1.06e+03 6.07e+01 0 \n",
+ "delta phim: 5.693e-02\n",
+ " 18 3.60e+04 1.19e+02 1.99e-02 8.35e+02 6.17e+01 0 \n",
+ "delta phim: 2.921e-02\n",
+ " 19 5.66e+04 7.36e+01 2.27e-02 1.36e+03 6.85e+01 0 \n",
+ "delta phim: 4.892e-02\n",
+ " 20 3.69e+04 1.53e+02 2.38e-02 1.03e+03 7.28e+01 0 \n",
+ "delta phim: 1.463e-02\n",
+ " 21 2.55e+04 1.34e+02 2.62e-02 8.00e+02 8.20e+01 0 \n",
+ "delta phim: 7.278e-03\n",
+ " 22 1.94e+04 1.09e+02 2.69e-02 6.31e+02 7.27e+01 0 \n",
+ "delta phim: 1.310e-02\n",
+ " 23 1.58e+04 9.70e+01 2.61e-02 5.08e+02 7.50e+01 0 \n",
+ "delta phim: 1.923e-02\n",
+ " 24 1.58e+04 8.61e+01 2.42e-02 4.67e+02 7.27e+01 0 \n",
+ "delta phim: 9.146e-03\n",
+ " 25 1.58e+04 9.03e+01 2.22e-02 4.40e+02 7.14e+01 0 \n",
+ "delta phim: 1.966e-02\n",
+ " 26 1.58e+04 9.11e+01 2.09e-02 4.20e+02 8.30e+01 0 \n",
+ "Reach maximum number of IRLS cycles: 20\n",
"------------------------- STOP! -------------------------\n",
- "1 : |fc-fOld| = 0.0000e+00 <= tolF*(1+|f0|) = 2.8740e+04\n",
- "1 : |xc-x_last| = 2.1463e-02 <= tolX*(1+|x0|) = 1.0168e-01\n",
- "0 : |proj(x-g)-x| = 7.5108e+01 <= tolG = 1.0000e-01\n",
- "0 : |proj(x-g)-x| = 7.5108e+01 <= 1e3*eps = 1.0000e-02\n",
- "0 : maxIter = 100 <= iter = 34\n",
+ "1 : |fc-fOld| = 0.0000e+00 <= tolF*(1+|f0|) = 2.8710e+04\n",
+ "1 : |xc-x_last| = 9.6443e-02 <= tolX*(1+|x0|) = 1.0168e-01\n",
+ "0 : |proj(x-g)-x| = 8.3038e+01 <= tolG = 1.0000e-01\n",
+ "0 : |proj(x-g)-x| = 8.3038e+01 <= 1e3*eps = 1.0000e-02\n",
+ "0 : maxIter = 100 <= iter = 27\n",
"------------------------- DONE! -------------------------\n"
]
}
@@ -468,25 +1242,2379 @@
{
"cell_type": "code",
"execution_count": 10,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
- ""
+ ""
]
},
- "execution_count": 10,
"metadata": {},
- "output_type": "execute_result"
+ "output_type": "display_data"
},
{
"data": {
- "image/png": "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\n",
+ "text/html": [
+ "
"
+ ],
"text/plain": [
- ""
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
+ "text/plain": [
+ ""
]
},
"metadata": {},
@@ -499,7 +3627,7 @@
"m_lp[m_lp==ndv] = np.nan\n",
"\n",
"# Get the smooth model aslo\n",
- "m_l2 = actvMap*IRLS.l2model\n",
+ "m_l2 = actvMap*invProb.l2model\n",
"m_l2[m_l2==ndv] = np.nan\n",
"\n",
"m_true = actvMap*driver.m0\n",
@@ -511,95 +3639,805 @@
"# Plot the recoverd models \n",
"vmin, vmax = 0., 0.015\n",
"\n",
- "mesh = Mesh.TensorMesh([mesh.hx, mesh.hy, mesh.hz],x0=\"CCN\")\n",
+ "mesh.plot_3d_slicer(m_true, pcolorOpts={\"vmax\":0.025, \"cmap\":\"CMRmap_r\"})\n",
"\n",
- "def slide(s,normal):\n",
- " \n",
- " if normal == \"Z\":\n",
- " fig = plt.figure(figsize=(10*1.2, 8))\n",
- " else:\n",
- " fig = plt.figure(figsize=(10*1.2, 4))\n",
- " \n",
- " ax1 = plt.subplot(2,2,3)\n",
- " dat = mesh.plotSlice(m_lp, ax = ax1, normal=normal, ind=s, clim=np.r_[vmin, vmax],pcolorOpts={'cmap':'viridis'})\n",
- "# plt.colorbar(dat[0])\n",
- " plt.gca().set_aspect('equal')\n",
- " plt.title('Compact model')\n",
- " \n",
- " if normal == \"Z\":\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-600, 600.) \n",
- " else:\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-500, 0.) \n",
- " \n",
- " ax2 = plt.subplot(2,2,1)\n",
- " dat = mesh.plotSlice(m_l2, ax = ax2, normal=normal, ind=s, clim=np.r_[vmin, vmax],pcolorOpts={'cmap':'viridis'})\n",
- "# plt.colorbar(dat[0])\n",
- " plt.gca().set_aspect('equal')\n",
- " plt.title('Smooth model')\n",
- " \n",
- " if normal == \"Z\":\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-600, 600.) \n",
- " else:\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-500, 0.) \n",
- " \n",
- " ax2.set_xticklabels([])\n",
- " \n",
- " ax2 = plt.subplot(1,2,2)\n",
- " dat = mesh.plotSlice(m_true, ax = ax2, normal=normal, ind=s, clim=np.r_[vmin, vmax],pcolorOpts={'cmap':'viridis'})\n",
- "# plt.colorbar(dat[0])\n",
- " plt.gca().set_aspect('equal')\n",
- " plt.title('True model')\n",
- " \n",
- " pos = ax2.get_position()\n",
- "\n",
- " ax2.yaxis.set_visible(False)\n",
- " if normal == \"Z\":\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-600, 600.) \n",
- " ax2.set_position([pos.x0 -0.04 , pos.y0, pos.width, pos.height])\n",
- " else:\n",
- " plt.xlim(-600, 600)\n",
- " plt.ylim(-500, 0.) \n",
- "\n",
- " pos = ax2.get_position()\n",
- " cbarax = fig.add_axes([pos.x0 + 0.375 , pos.y0 + 0.05, pos.width*0.1, pos.height*0.75]) ## the parameters are the specified position you set\n",
- " cb = fig.colorbar(dat[0],cax=cbarax, orientation=\"vertical\", ax = ax2, ticks=np.linspace(vmin,vmax, 4))\n",
- " cb.set_label(\"Susceptibility (SI)\",size=12)\n",
- " \n",
- " #{OPTIONAL} Save the figure to png\n",
- " #fig.savefig('PF_Compact.png',dpi = 150)\n",
- " \n",
- "interact(slide, s=(0,36), normal=['Y','Z','X'])\n",
+ "mesh.plot_3d_slicer(m_lp, pcolorOpts={\"vmax\":0.025, \"cmap\":\"CMRmap_r\"})\n",
"\n",
- "# interact(lambda ind: viz(m_l2, ind, normal=\"Z\"), ind=IntSlider(min=0, max=32,step=1, value=28))\n"
+ "mesh.plot_3d_slicer(m_l2, pcolorOpts={\"vmax\":0.01, \"cmap\":\"CMRmap_r\"})\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
- ""
+ ""
]
},
- "execution_count": 11,
"metadata": {},
- "output_type": "execute_result"
+ "output_type": "display_data"
},
{
"data": {
- "image/png": "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\n8i2Stsx1u8zUDAA1QR04AADAEEoAQCelJnDcoI1+teaOmw7UggMAAEAf27DhYC24AlAHDsgBdeAA\n9IqLnABQEwXXgWMIJQAAFcRFTgBAJyRwAAAAAFATJHAAAAAAUBOOiLJjkO19kr7V42YWSvpuBuHU\nHe2QoB1ogxbaIVGVdnh+RCwqO4g6aJURkPQqSfeXHE5VVWW/7he0Z3Zoy+w0qS27OkZWIoHLgu0d\nETFUdhxlox0StANt0EI7JGgH9CP262zRntmhLbNDW/4khlACAAAAQE2QwAEAAABATfRTAjdadgAV\nQTskaAfaoIV2SNAO6Efs19miPbNDW2aHtpykb+6BAwAAAIB+1089cAAAAADQ1yqbwNleZfs+27ts\nr+/wvG2/L33+X23//Ezr2n6O7X+wfX/677OL+jxzkVMb/JXtb6Svv9n2kUV9nrnKox3anv8T22F7\nYd6fo1d5tYPtS9N9Yqft9xTxWeYqp7+Jk21/2fbXbO+wvbKozzNXPbbDRtt7bd89aZ1afT+iv3W7\nP872eG/7DNtfsX1X+u9Li/pMRcvp+7KR3xM5tWXtzseykNe5TPp8bc7pehYRlfuRNE/SA5JeIOlQ\nSV+XtGLSa86W9FlJlnSqpDtmWlfSeyStT39fL+ndZX/WEtrgNyTNT39/d5XbIM92SJ8/VtJtSmoQ\nLiz7s5a0P/y6pM9LOix9/DNlf9YS2uB2SWe1rb+17M+aVzukz/2apJ+XdPekdWrz/chP//90sz/O\n8HfdcX1JL5Z0TPr7iZIeKvuz5tR+jT+PqkFb1up8rMptmT5fm3O6LH6q2gO3UtKuiNgdEY9Lul7S\n6kmvWS3pmkh8WdKRtp83w7qrJX00/f2jkl6e9wfpQS5tEBG3R8ST6fpflrSkiA/Tg7z2BUn6W0lv\nkFSHG0HzaoeLJV0eET+WpIjYW8SHmaO82iAkPSv9fUDSt/P+ID3qpR0UEdskPdJhu3X6fkT/62Z/\nnPXxPiL+JSJaf+M7Jf2U7cNyiL9snEdlh/Ox7HBOl5GqJnCLJe1pezyeLuvmNdOte3REPJz+/h1J\nR2cVcA7yaoN2f6DkKkeV5dIOtlcrufL69awDzkle+8MJkn7V9h22/8n2SzKNOlt5tcEfS/or23sk\nbZD0xgxjzkMv7TCdOn0/ov91sz/2erz/LUlfbV3A6jOcR2WH87HscE6XkfllB1CWiAjbjcjSO7H9\nJklPSvp42bEUzfZPS/ozJcMXmm6+pOcoGabwEkk32H5BRDTpb+NiSf87Ij5l+5WSrpb0spJjKlXT\nvx9RDNufl/TcDk+9qf1Br/tjp/Vt/6ySYWscB+aI74lsNPl8LAtNPaeragL3kJKxrC1L0mXdvOaQ\nadb9d9vPi4iH0+7YKg8Xy6sNZPtCSedKOr0GJ+p5tMNxkpZJ+rrt1vKv2l4ZEd/JNPrs5LU/jEu6\nKd0P7rT9lKSFkvZlF3pm8mqD35P0v9LfPynpqozizUsv7TCdOn0/og9ExJQXSmx3sz9Ot59Pub7t\nJZJulvS7EfFAzx+kmjiPyg7nY9nhnC4rUfBNd938KEksdyv5D2ndqPizk15zjp5+k+OdM60r6a/0\n9Jtv31P2Zy2hDVZJukfSorI/Y5ntMGn9B1XxG15z3B/WSXpb+vsJSoYnuOzPW3Ab3CvptPT30yV9\npezPmlc7tD0/qJ+cxKQ234/89P9PN/vjDH/XHdeXdGT6uvPK/ow5t1/jz6Nq0Ja1Oh+rcltOWv9B\nVfycLpO2LDuAaf6Tz5b0b0pmnHlTumydpHXp75Z0Zfr8XZKGpls3XX6UpP8r6X4lM+89p+zPWUIb\n7FJykv619OeDZX/OMtph0vZr8cee0/5wqKSPSbpb0lclvbTsz1lCG/yKpK+kB4M7JP1C2Z8z53a4\nTtLDkp5Q0gN7Ubq8Vt+P/PT3z1T7o6RjJG1pe92sjveS3izph23HwK+pwrPv9tiGjT+Pqnhb1u58\nrKptOWn7D6oG53S9/jj9sAAAAACAiqvqLJQAAAAAgElI4AAAAACgJkjgAAAAAKAmSOAAAAAAoCZI\n4AAAAACgJkjgAAAAAKAmSOAAAAAAoCZI4AAAAACgJv4/dQl8Upoyy2YAAAAASUVORK5CYII=\n",
+ "text/html": [
+ "
"
+ ],
"text/plain": [
- ""
+ ""
]
},
"metadata": {},
@@ -607,27 +4445,819 @@
},
{
"data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3AAAAE/CAYAAAAHeyFHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X+0XGV97/HPpwRNL8GDhlwrhHgiB1hSFqL3FGjr6uVe\nbAmEU6y1SkDvxQvJpYq9Xd5oo/SH1aJRY5e6pGq0mKsiiAjqIVHQu8xNq/wIVhQipYQYVw5SA6EE\nUCkg3/vH7APDYc7JzN6zZ+9nz/u11lnnzJ49e77Pnjnzfb6zn70fR4QAAAAAAPX3K1UHAAAAAADo\nDgUcAAAAACSCAg4AAAAAEkEBBwAAAACJoIADAAAAgERQwAEAAABAIijgkAzb22yfVHUcc7F9ku2p\nLtd9p+3PFXiusD2W9/EAgHKRt/rL9k7br8j+foftT1UVS7te9iHQDxRwqIX2D+W2ZefY/sfp2xHx\n6xGxeR/bGc0Km3klhQoAAHmrYhHxnog4r+h22P9IEQUcgNzcwucIAKAntverOoamoQgdHnS8kIwZ\nQyeOt32z7Qdt/9T232arbcl+P2D7Ydu/2WE777T9Rdufs/2Q7VttH2n77bZ3295l+/fa1j/E9ldt\n3297u+2Vbff9qu0Ntv/N9g8l/caM5zrE9pds32v7R7b/pO87pvU8G2x/3PY3sjb9P9sv3Mf6F9ve\nmK1/o+3D2+7/Ldtbbe/Nfv9W232bbV9k+9uSfi7pRdmyv7H9nWy/T9peaPvS7DXaanu0jLYDQF0N\nW96y/Tbb99j+ie3z3DbUP3vOj9neZPtnkv6L7eW2v5ftk1223zlje6+3/WPbe2xf2GGffK7t9olZ\nDnrA9vfdNnQ1y1Hvtv3tbP9dZ/vgbvd/r7LX/e22f5jt50/bnr+P9Vfb/kGWd7/Qvr7tldnreH/2\nuh7Sdl/YfpPtOyXd2bbsjbbvzNr7btuHZ/vnQdtX2H5W0XaiOhRwSNWHJX04Ip4j6XBJV2TLfyf7\nfVBELIiI62d5/ISkz0p6rqTvSbpWrf+HQyW9S9In2ta9XNKUpEMkvVrSe2z/1+y+v8qe/3BJp0j6\n79MPcuvI1KSk72fbPVnSn9o+JWeb9+VsSe+WdLCkWyRduo/1z5T012rtg+2SLpIk28+TtFHSRyQt\nlPS3kjbaXtj22NdLWiXpQEk/btve69Vq6+GSrpf0aUnPk3S7WvsKAIZVo/OW7WWS3iLpFZLGJJ3U\n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\nv9/X6fE1jv3Fko6StFnSeMmxJtt368PnXyX9sYL7vNL+VcHYK+0vFX2/ZPf33AdK4Qjc8ZK2R8SO\niHhU0uWSzpixzhmSPhMtN0g6yPYLunxsXRRppyJii6T7BxpxPrnbGRH3RMQ/SVJEPCTpdkmHDjL4\nHhVpa0TEw9k6+2c/dT1htdB71/ZiScslfWqQQedQqJ2Jyd1W2yNqdWD+XpIi4tGIeGCQwaN0Z6hV\npCv7/coO68z6HoqIB9vWO0CD/WwrGvt1EfF4tt4NkhaXHG+7orHfHhF3DCTStPtuqfbHUu5fpdxf\nqqQPlEIBd6ikXW23p/TMN9Vs63Tz2Loo0s6U9KWdtkclvVStb1rqqlBbs0Pqt0jaLekbEVHXthZ9\nTT8k6W2SnigrwD4p2s6Q9E3b37W9qrQo+6NIW5dKulfSp7MhIZ+yfUCZwWLgnh8R92R//6uk53dY\nZ873kO2LbO+SdLakvywr0A4Kx97mf6j1rfqg9DP2sqXcd0u1P5Zy/yrl/lIlfaAUCjjgaWwvkPQl\nSX8645vcRomIX0bEcWp9w3u87WOqjqnfbJ8uaXdEfLfqWAbg5dnreaqkN9n+naoDKsk8tYYPfSwi\nXirpZ2oN90JCbH/T9m0dfp72zXJEhHJ82x0RF0bEYZIulXRBn8KWVH7s2XNcKOlxteLvm0HEDswm\n1f5Vqv2lIn2geSXE0293Szqs7fbibFk36+zfxWProkg7U1Konbb3V+vD5dKIuKrEOPuhL69pRDxg\n+1uSlkmq40VqirTzDyX9vu3TJM2X9Bzbn4uI15UYb16FXs+ImP692/bVag272FJatMUUaWtImmr7\nBvRKUcAlJyJeMdt9tn86PewqGwa0u8Nq3earSyVtkvRXReJtV3bsts+RdLqkk7NCqm8GuN/LlnLf\nLdX+WMr9q5T7S9X0gWKAJ1jm+VGryNyh1rCc6ZMDf33GOsv19JMDb+r2sXX5KdLOtvtHVf+LmBR5\nPS3pM5I+VHU7BtDWRcou/CDpVyX9g6TTq25Tv9s5Y52TVO+LmBR5PQ+QdGDb39+RtKzqNpX1mmbv\n16Oyv98p6QNVt4mfvr4/PqCnX0zj/b28hyQd0bbemyVdmVDsyyT9UNKi1PZ72zqbVf5FTJLtuxX9\n/MvuH9XgL2KSbP+qYOyV9pf68X7J1jlJPfSBBv4i5dw5p6l1RZy7JF2YLTtf0vltb7yLs/tvbf9g\n6vTYuv4UbOdlku6R9JhaY2vPrbo9/W6npJer9e3+DyTdkv2cVnV7SmrrsZK+l7X1Nkl/WXVbynrv\ntm2jpw+vlNqp1tWpvp/9bKv7Z1HR11TScZJuzt6/X5b03Krbw09f3xsLJf1fSXdK+qak52XLD5G0\naa73ULb8S9nn2g8kTUo6NKHYt6t1Lst0DhrkFTSLxv4HavUP/l3STyVdW3K8yfbdCsZeWX8sb9yq\nQf+qQOyV95eKvF/atnGSeugDOXsQAAAAAKDmuIgJAAAAACSCAg4AAAAAEkEBBwAAAACJoIADAAAA\ngERQwAEAAABAIijgAAAAACARFHAAAAAAkAgKOAAAAABIxP8HTLP+feluVmMAAAAASUVORK5CYII=\n",
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support. ' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.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",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\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 = $('');\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 = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('');\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 = $('');\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 = $('');\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 = $('');\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 = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\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",
+ " '', {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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (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(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('
');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '
';\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 = $('');\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 = $('');\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 = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 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": [
- ""
+ ""
]
},
"metadata": {},
"output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
"source": [
"# Lets compare the distribution of model parameters and model gradients\n",
"plt.figure(figsize=[15,5])\n",
"ax = plt.subplot(121)\n",
- "plt.hist(IRLS.l2model,100)\n",
+ "plt.hist(invProb.l2model,100)\n",
"plt.plot((reg.eps_p,reg.eps_p),(0,mesh.nC),'r--')\n",
"plt.yscale('log', nonposy='clip')\n",
"plt.title('Hist model - l2-norm')\n",
"plt.legend(['$\\epsilon_p$'])\n",
"\n",
"ax = plt.subplot(122)\n",
- "plt.hist(reg.regmesh.cellDiffxStencil*IRLS.l2model,100)\n",
+ "plt.hist(reg.regmesh.cellDiffxStencil*invProb.l2model,100)\n",
"plt.plot((reg.eps_q,reg.eps_q),(0,mesh.nC),'r--')\n",
"plt.yscale('log', nonposy='clip')\n",
"plt.title('Hist model gradient - l2-norm')\n",
@@ -653,9 +5283,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": []
}
@@ -663,21 +5291,21 @@
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
- "display_name": "Python 2",
+ "display_name": "Python 3",
"language": "python",
- "name": "python2"
+ "name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
- "version": 2
+ "version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
- "pygments_lexer": "ipython2",
- "version": "2.7.13"
+ "pygments_lexer": "ipython3",
+ "version": "3.7.3"
},
"widgets": {
"state": {