Created
September 19, 2018 08:44
-
-
Save kif/f5b5407e292fa209c05675a3d694b943 to your computer and use it in GitHub Desktop.
Variance propagation without pixel splitting...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "%matplotlib nbagg" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Variance of SAXS data\n", | |
| "\n", | |
| "There has been a long discussion about the validity (or not) of pixel splitting regarding the propagation of errors.\n", | |
| "\n", | |
| "## System under study\n", | |
| "\n", | |
| "Let's do a numerical experiment, simulating the following experiment:\n", | |
| "\n", | |
| "* Detector: 1024x1024 square pixels of 100µm each, assumed to be poissonian. \n", | |
| "* Geometry: The detector is placed at 1m from the sample, the beam center is in the corner of the detector\n", | |
| "* Sample: It is a set of spheres of Rg = 1nm, following the Guinier's law\n", | |
| "* Intensity: the maximum signal on the detector is 100 000 photons.\n", | |
| "* Wavelength: 1 Angstrom\n", | |
| "* During the whole studdy, the solid-angle correction will be discarded\n", | |
| "\n", | |
| "Now we define some constants for the studdy:" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "pix = 100e-6\n", | |
| "shape = (1024, 1024)\n", | |
| "npt = 1000\n", | |
| "nimg = 1000\n", | |
| "wl = 1e-10\n", | |
| "I0 = 1e3\n", | |
| "Rg = 1.\n", | |
| "kwarg = {\"npt\":npt, \n", | |
| " \"method\": \"csr_nosplit_ocl_gpu\", \n", | |
| " \"correctSolidAngle\":False, \n", | |
| " \"polarization_factor\":None,\n", | |
| " \"safe\":False}" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "0.16.0-beta0\n", | |
| "Detector Detector\t Spline= None\t PixelSize= 1.000e-04, 1.000e-04 m\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "import numpy\n", | |
| "from matplotlib.pyplot import subplots\n", | |
| "from matplotlib.colors import LogNorm\n", | |
| "import pyFAI\n", | |
| "print(pyFAI.version)\n", | |
| "from pyFAI.detectors import Detector\n", | |
| "from pyFAI.azimuthalIntegrator import AzimuthalIntegrator\n", | |
| "from pyFAI.gui import jupyter\n", | |
| "detector = Detector(pix, pix)\n", | |
| "detector.shape = detector.max_shape = shape\n", | |
| "print(detector)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Detector Detector\t Spline= None\t PixelSize= 1.000e-04, 1.000e-04 m\n", | |
| "Wavelength= 1.000000e-10m\n", | |
| "SampleDetDist= 1.000000e+00m\tPONI= 0.000000e+00, 0.000000e+00m\trot1=0.000000 rot2= 0.000000 rot3= 0.000000 rad\n", | |
| "DirectBeamDist= 1000.000mm\tCenter: x=0.000, y=0.000 pix\tTilt=0.000 deg tiltPlanRotation= 0.000 deg\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "ai =AzimuthalIntegrator(dist=1, poni1=0., poni2=0., detector=detector, wavelength=wl)\n", | |
| "print(ai)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stderr", | |
| "output_type": "stream", | |
| "text": [ | |
| "WARNING:pyFAI.ext.splitBBoxCSR:Pixel splitting desactivated !\n" | |
| ] | |
| }, | |
| { | |
| "data": { | |
| "application/javascript": [ | |
| "/* Put everything inside the global mpl namespace */\n", | |
| "window.mpl = {};\n", | |
| "\n", | |
| "\n", | |
| "mpl.get_websocket_type = function() {\n", | |
| " if (typeof(WebSocket) !== 'undefined') {\n", | |
| " return WebSocket;\n", | |
| " } else if (typeof(MozWebSocket) !== 'undefined') {\n", | |
| " return MozWebSocket;\n", | |
| " } else {\n", | |
| " alert('Your browser does not have WebSocket support.' +\n", | |
| " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", | |
| " 'Firefox 4 and 5 are also supported but you ' +\n", | |
| " 'have to enable WebSockets in about:config.');\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", | |
| " this.id = figure_id;\n", | |
| "\n", | |
| " this.ws = websocket;\n", | |
| "\n", | |
| " this.supports_binary = (this.ws.binaryType != undefined);\n", | |
| "\n", | |
| " if (!this.supports_binary) {\n", | |
| " var warnings = document.getElementById(\"mpl-warnings\");\n", | |
| " if (warnings) {\n", | |
| " warnings.style.display = 'block';\n", | |
| " warnings.textContent = (\n", | |
| " \"This browser does not support binary websocket messages. \" +\n", | |
| " \"Performance may be slow.\");\n", | |
| " }\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj = new Image();\n", | |
| "\n", | |
| " this.context = undefined;\n", | |
| " this.message = undefined;\n", | |
| " this.canvas = undefined;\n", | |
| " this.rubberband_canvas = undefined;\n", | |
| " this.rubberband_context = undefined;\n", | |
| " this.format_dropdown = undefined;\n", | |
| "\n", | |
| " this.image_mode = 'full';\n", | |
| "\n", | |
| " this.root = $('<div/>');\n", | |
| " this._root_extra_style(this.root)\n", | |
| " this.root.attr('style', 'display: inline-block');\n", | |
| "\n", | |
| " $(parent_element).append(this.root);\n", | |
| "\n", | |
| " this._init_header(this);\n", | |
| " this._init_canvas(this);\n", | |
| " this._init_toolbar(this);\n", | |
| "\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " this.waiting = false;\n", | |
| "\n", | |
| " this.ws.onopen = function () {\n", | |
| " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |
| " fig.send_message(\"send_image_mode\", {});\n", | |
| " if (mpl.ratio != 1) {\n", | |
| " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |
| " }\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj.onload = function() {\n", | |
| " if (fig.image_mode == 'full') {\n", | |
| " // Full images could contain transparency (where diff images\n", | |
| " // almost always do), so we need to clear the canvas so that\n", | |
| " // there is no ghosting.\n", | |
| " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| " }\n", | |
| " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |
| " };\n", | |
| "\n", | |
| " this.imageObj.onunload = function() {\n", | |
| " 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", | |
| " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |
| " 'ui-helper-clearfix\"/>');\n", | |
| " var titletext = $(\n", | |
| " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |
| " 'text-align: center; padding: 3px;\"/>');\n", | |
| " titlebar.append(titletext)\n", | |
| " this.root.append(titlebar);\n", | |
| " this.header = titletext[0];\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_canvas = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var canvas_div = $('<div/>');\n", | |
| "\n", | |
| " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |
| "\n", | |
| " function canvas_keyboard_event(event) {\n", | |
| " return fig.key_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |
| " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |
| " this.canvas_div = canvas_div\n", | |
| " this._canvas_extra_style(canvas_div)\n", | |
| " this.root.append(canvas_div);\n", | |
| "\n", | |
| " var canvas = $('<canvas/>');\n", | |
| " canvas.addClass('mpl-canvas');\n", | |
| " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |
| "\n", | |
| " this.canvas = canvas[0];\n", | |
| " this.context = canvas[0].getContext(\"2d\");\n", | |
| "\n", | |
| " var backingStore = this.context.backingStorePixelRatio ||\n", | |
| "\tthis.context.webkitBackingStorePixelRatio ||\n", | |
| "\tthis.context.mozBackingStorePixelRatio ||\n", | |
| "\tthis.context.msBackingStorePixelRatio ||\n", | |
| "\tthis.context.oBackingStorePixelRatio ||\n", | |
| "\tthis.context.backingStorePixelRatio || 1;\n", | |
| "\n", | |
| " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |
| "\n", | |
| " var rubberband = $('<canvas/>');\n", | |
| " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |
| "\n", | |
| " var pass_mouse_events = true;\n", | |
| "\n", | |
| " canvas_div.resizable({\n", | |
| " start: function(event, ui) {\n", | |
| " pass_mouse_events = false;\n", | |
| " },\n", | |
| " resize: function(event, ui) {\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " stop: function(event, ui) {\n", | |
| " pass_mouse_events = true;\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " });\n", | |
| "\n", | |
| " function mouse_event_fn(event) {\n", | |
| " if (pass_mouse_events)\n", | |
| " return fig.mouse_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " rubberband.mousedown('button_press', mouse_event_fn);\n", | |
| " rubberband.mouseup('button_release', mouse_event_fn);\n", | |
| " // Throttle sequential mouse events to 1 every 20ms.\n", | |
| " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |
| "\n", | |
| " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |
| " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |
| "\n", | |
| " canvas_div.on(\"wheel\", function (event) {\n", | |
| " event = event.originalEvent;\n", | |
| " event['data'] = 'scroll'\n", | |
| " if (event.deltaY < 0) {\n", | |
| " event.step = 1;\n", | |
| " } else {\n", | |
| " event.step = -1;\n", | |
| " }\n", | |
| " mouse_event_fn(event);\n", | |
| " });\n", | |
| "\n", | |
| " canvas_div.append(canvas);\n", | |
| " canvas_div.append(rubberband);\n", | |
| "\n", | |
| " this.rubberband = rubberband;\n", | |
| " this.rubberband_canvas = rubberband[0];\n", | |
| " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |
| " this.rubberband_context.strokeStyle = \"#000000\";\n", | |
| "\n", | |
| " this._resize_canvas = function(width, height) {\n", | |
| " // Keep the size of the canvas, canvas container, and rubber band\n", | |
| " // canvas in synch.\n", | |
| " canvas_div.css('width', width)\n", | |
| " canvas_div.css('height', height)\n", | |
| "\n", | |
| " canvas.attr('width', width * mpl.ratio);\n", | |
| " canvas.attr('height', height * mpl.ratio);\n", | |
| " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |
| "\n", | |
| " rubberband.attr('width', width);\n", | |
| " rubberband.attr('height', height);\n", | |
| " }\n", | |
| "\n", | |
| " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |
| " // upon first draw.\n", | |
| " this._resize_canvas(600, 600);\n", | |
| "\n", | |
| " // Disable right mouse context menu.\n", | |
| " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |
| " return false;\n", | |
| " });\n", | |
| "\n", | |
| " function set_focus () {\n", | |
| " canvas.focus();\n", | |
| " canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " window.setTimeout(set_focus, 100);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items) {\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) {\n", | |
| " // put a spacer in here.\n", | |
| " continue;\n", | |
| " }\n", | |
| " var button = $('<button/>');\n", | |
| " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |
| " 'ui-button-icon-only');\n", | |
| " button.attr('role', 'button');\n", | |
| " button.attr('aria-disabled', 'false');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| "\n", | |
| " var icon_img = $('<span/>');\n", | |
| " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |
| " icon_img.addClass(image);\n", | |
| " icon_img.addClass('ui-corner-all');\n", | |
| "\n", | |
| " var tooltip_span = $('<span/>');\n", | |
| " tooltip_span.addClass('ui-button-text');\n", | |
| " tooltip_span.html(tooltip);\n", | |
| "\n", | |
| " button.append(icon_img);\n", | |
| " button.append(tooltip_span);\n", | |
| "\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " var fmt_picker_span = $('<span/>');\n", | |
| "\n", | |
| " var fmt_picker = $('<select/>');\n", | |
| " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |
| " fmt_picker_span.append(fmt_picker);\n", | |
| " nav_element.append(fmt_picker_span);\n", | |
| " this.format_dropdown = fmt_picker[0];\n", | |
| "\n", | |
| " for (var ind in mpl.extensions) {\n", | |
| " var fmt = mpl.extensions[ind];\n", | |
| " var option = $(\n", | |
| " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |
| " fmt_picker.append(option)\n", | |
| " }\n", | |
| "\n", | |
| " // Add hover states to the ui-buttons\n", | |
| " $( \".ui-button\" ).hover(\n", | |
| " function() { $(this).addClass(\"ui-state-hover\");},\n", | |
| " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |
| " );\n", | |
| "\n", | |
| " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |
| " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |
| " // which will in turn request a refresh of the image.\n", | |
| " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_message = function(type, properties) {\n", | |
| " properties['type'] = type;\n", | |
| " properties['figure_id'] = this.id;\n", | |
| " this.ws.send(JSON.stringify(properties));\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_draw_message = function() {\n", | |
| " if (!this.waiting) {\n", | |
| " this.waiting = true;\n", | |
| " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " var format_dropdown = fig.format_dropdown;\n", | |
| " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |
| " fig.ondownload(fig, format);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |
| " var size = msg['size'];\n", | |
| " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |
| " fig._resize_canvas(size[0], size[1]);\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |
| " var x0 = msg['x0'] / mpl.ratio;\n", | |
| " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |
| " var x1 = msg['x1'] / mpl.ratio;\n", | |
| " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |
| " x0 = Math.floor(x0) + 0.5;\n", | |
| " y0 = Math.floor(y0) + 0.5;\n", | |
| " x1 = Math.floor(x1) + 0.5;\n", | |
| " y1 = Math.floor(y1) + 0.5;\n", | |
| " var min_x = Math.min(x0, x1);\n", | |
| " var min_y = Math.min(y0, y1);\n", | |
| " var width = Math.abs(x1 - x0);\n", | |
| " var height = Math.abs(y1 - y0);\n", | |
| "\n", | |
| " fig.rubberband_context.clearRect(\n", | |
| " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| "\n", | |
| " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |
| " // Updates the figure title.\n", | |
| " fig.header.textContent = msg['label'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |
| " var cursor = msg['cursor'];\n", | |
| " switch(cursor)\n", | |
| " {\n", | |
| " case 0:\n", | |
| " cursor = 'pointer';\n", | |
| " break;\n", | |
| " case 1:\n", | |
| " cursor = 'default';\n", | |
| " break;\n", | |
| " case 2:\n", | |
| " cursor = 'crosshair';\n", | |
| " break;\n", | |
| " case 3:\n", | |
| " cursor = 'move';\n", | |
| " break;\n", | |
| " }\n", | |
| " fig.rubberband_canvas.style.cursor = cursor;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |
| " fig.message.textContent = msg['message'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |
| " // Request the server to send over a new figure.\n", | |
| " fig.send_draw_message();\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |
| " fig.image_mode = msg['mode'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Called whenever the canvas gets updated.\n", | |
| " this.send_message(\"ack\", {});\n", | |
| "}\n", | |
| "\n", | |
| "// A function to construct a web socket function for onmessage handling.\n", | |
| "// Called in the figure constructor.\n", | |
| "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |
| " return function socket_on_message(evt) {\n", | |
| " if (evt.data instanceof Blob) {\n", | |
| " /* FIXME: We get \"Resource interpreted as Image but\n", | |
| " * transferred with MIME type text/plain:\" errors on\n", | |
| " * Chrome. But how to set the MIME type? It doesn't seem\n", | |
| " * to be part of the websocket stream */\n", | |
| " evt.data.type = \"image/png\";\n", | |
| "\n", | |
| " /* Free the memory for the previous frames */\n", | |
| " if (fig.imageObj.src) {\n", | |
| " (window.URL || window.webkitURL).revokeObjectURL(\n", | |
| " fig.imageObj.src);\n", | |
| " }\n", | |
| "\n", | |
| " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |
| " evt.data);\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |
| " fig.imageObj.src = evt.data;\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var msg = JSON.parse(evt.data);\n", | |
| " var msg_type = msg['type'];\n", | |
| "\n", | |
| " // Call the \"handle_{type}\" callback, which takes\n", | |
| " // the figure and JSON message as its only arguments.\n", | |
| " try {\n", | |
| " var callback = fig[\"handle_\" + msg_type];\n", | |
| " } catch (e) {\n", | |
| " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " if (callback) {\n", | |
| " try {\n", | |
| " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |
| " callback(fig, msg);\n", | |
| " } catch (e) {\n", | |
| " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |
| " }\n", | |
| " }\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |
| "mpl.findpos = function(e) {\n", | |
| " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |
| " var targ;\n", | |
| " if (!e)\n", | |
| " e = window.event;\n", | |
| " if (e.target)\n", | |
| " targ = e.target;\n", | |
| " else if (e.srcElement)\n", | |
| " targ = e.srcElement;\n", | |
| " if (targ.nodeType == 3) // defeat Safari bug\n", | |
| " targ = targ.parentNode;\n", | |
| "\n", | |
| " // jQuery normalizes the pageX and pageY\n", | |
| " // pageX,Y are the mouse positions relative to the document\n", | |
| " // offset() returns the position of the element relative to the document\n", | |
| " var x = e.pageX - $(targ).offset().left;\n", | |
| " var y = e.pageY - $(targ).offset().top;\n", | |
| "\n", | |
| " return {\"x\": x, \"y\": y};\n", | |
| "};\n", | |
| "\n", | |
| "/*\n", | |
| " * return a copy of an object with only non-object keys\n", | |
| " * we need this to avoid circular references\n", | |
| " * http://stackoverflow.com/a/24161582/3208463\n", | |
| " */\n", | |
| "function simpleKeys (original) {\n", | |
| " return Object.keys(original).reduce(function (obj, key) {\n", | |
| " if (typeof original[key] !== 'object')\n", | |
| " obj[key] = original[key]\n", | |
| " return obj;\n", | |
| " }, {});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |
| " var canvas_pos = mpl.findpos(event)\n", | |
| "\n", | |
| " if (name === 'button_press')\n", | |
| " {\n", | |
| " this.canvas.focus();\n", | |
| " this.canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " var x = canvas_pos.x * mpl.ratio;\n", | |
| " var y = canvas_pos.y * mpl.ratio;\n", | |
| "\n", | |
| " this.send_message(name, {x: x, y: y, button: event.button,\n", | |
| " step: event.step,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| "\n", | |
| " /* This prevents the web browser from automatically changing to\n", | |
| " * the text insertion cursor when the button is pressed. We want\n", | |
| " * to control all of the cursor setting manually through the\n", | |
| " * 'cursor' event from matplotlib */\n", | |
| " event.preventDefault();\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " // Handle any extra behaviour associated with a key event\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.key_event = function(event, name) {\n", | |
| "\n", | |
| " // Prevent repeat events\n", | |
| " if (name == 'key_press')\n", | |
| " {\n", | |
| " if (event.which === this._key)\n", | |
| " return;\n", | |
| " else\n", | |
| " this._key = event.which;\n", | |
| " }\n", | |
| " if (name == 'key_release')\n", | |
| " this._key = null;\n", | |
| "\n", | |
| " var value = '';\n", | |
| " if (event.ctrlKey && event.which != 17)\n", | |
| " value += \"ctrl+\";\n", | |
| " if (event.altKey && event.which != 18)\n", | |
| " value += \"alt+\";\n", | |
| " if (event.shiftKey && event.which != 16)\n", | |
| " value += \"shift+\";\n", | |
| "\n", | |
| " value += 'k';\n", | |
| " value += event.which.toString();\n", | |
| "\n", | |
| " this._key_event_extra(event, name);\n", | |
| "\n", | |
| " this.send_message(name, {key: value,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |
| " if (name == 'download') {\n", | |
| " this.handle_save(this, null);\n", | |
| " } else {\n", | |
| " this.send_message(\"toolbar_button\", {name: name});\n", | |
| " }\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |
| " this.message.textContent = tooltip;\n", | |
| "};\n", | |
| "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |
| "\n", | |
| "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |
| "\n", | |
| "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |
| " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |
| " // object with the appropriate methods. Currently this is a non binary\n", | |
| " // socket, so there is still some room for performance tuning.\n", | |
| " var ws = {};\n", | |
| "\n", | |
| " ws.close = function() {\n", | |
| " comm.close()\n", | |
| " };\n", | |
| " ws.send = function(m) {\n", | |
| " //console.log('sending', m);\n", | |
| " comm.send(m);\n", | |
| " };\n", | |
| " // Register the callback with on_msg.\n", | |
| " comm.on_msg(function(msg) {\n", | |
| " //console.log('receiving', msg['content']['data'], msg);\n", | |
| " // Pass the mpl event to the 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(\"<div id='\" + id + \"'></div>\");\n", | |
| " if (!fig.cell_info) {\n", | |
| " console.error(\"Failed to find cell for figure\", id, fig);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var output_index = fig.cell_info[2]\n", | |
| " var cell = fig.cell_info[0];\n", | |
| "\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |
| " var width = fig.canvas.width/mpl.ratio\n", | |
| " fig.root.unbind('remove')\n", | |
| "\n", | |
| " // Update the output cell to use the data from the current canvas.\n", | |
| " fig.push_to_output();\n", | |
| " var dataURL = fig.canvas.toDataURL();\n", | |
| " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |
| " // the notebook keyboard shortcuts fail.\n", | |
| " IPython.keyboard_manager.enable()\n", | |
| " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |
| " fig.close_ws(fig, msg);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |
| " fig.send_message('closing', msg);\n", | |
| " // fig.ws.close()\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |
| " // Turn the data on the canvas into data in the output cell.\n", | |
| " var width = this.canvas.width/mpl.ratio\n", | |
| " var dataURL = this.canvas.toDataURL();\n", | |
| " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Tell IPython that the notebook contents must change.\n", | |
| " IPython.notebook.set_dirty(true);\n", | |
| " this.send_message(\"ack\", {});\n", | |
| " var fig = this;\n", | |
| " // Wait a second, then push the new image to the DOM so\n", | |
| " // that it is saved nicely (might be nice to debounce this).\n", | |
| " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items){\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) { continue; };\n", | |
| "\n", | |
| " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " // Add the status bar.\n", | |
| " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "\n", | |
| " // Add the close button to the window.\n", | |
| " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |
| " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |
| " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |
| " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |
| " buttongrp.append(button);\n", | |
| " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |
| " titlebar.prepend(buttongrp);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(el){\n", | |
| " var fig = this\n", | |
| " el.on(\"remove\", function(){\n", | |
| "\tfig.close_ws(fig, {});\n", | |
| " });\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |
| " // this is important to make the div 'focusable\n", | |
| " el.attr('tabindex', 0)\n", | |
| " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |
| " // off when our div gets focus\n", | |
| "\n", | |
| " // location in version 3\n", | |
| " if (IPython.notebook.keyboard_manager) {\n", | |
| " IPython.notebook.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| " else {\n", | |
| " // location in version 2\n", | |
| " IPython.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " var manager = IPython.notebook.keyboard_manager;\n", | |
| " if (!manager)\n", | |
| " manager = IPython.keyboard_manager;\n", | |
| "\n", | |
| " // Check for shift+enter\n", | |
| " if (event.shiftKey && event.which == 13) {\n", | |
| " this.canvas_div.blur();\n", | |
| " event.shiftKey = false;\n", | |
| " // Send a \"J\" for go to next cell\n", | |
| " event.which = 74;\n", | |
| " event.keyCode = 74;\n", | |
| " manager.command_mode();\n", | |
| " manager.handle_keydown(event);\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " fig.ondownload(fig, null);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.find_output_cell = function(html_output) {\n", | |
| " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |
| " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |
| " // IPython event is triggered only after the cells have been serialised, which for\n", | |
| " // our purposes (turning an active figure into a static one), is too late.\n", | |
| " var cells = IPython.notebook.get_cells();\n", | |
| " var ncells = cells.length;\n", | |
| " for (var i=0; i<ncells; i++) {\n", | |
| " var cell = cells[i];\n", | |
| " if (cell.cell_type === 'code'){\n", | |
| " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |
| " var data = cell.output_area.outputs[j];\n", | |
| " if (data.data) {\n", | |
| " // IPython >= 3 moved mimebundle to data attribute of output\n", | |
| " data = data.data;\n", | |
| " }\n", | |
| " if (data['text/html'] == html_output) {\n", | |
| " return [cell, data, j];\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "// Register the function which deals with the matplotlib target/channel.\n", | |
| "// The kernel may be null if the page has been refreshed.\n", | |
| "if (IPython.notebook.kernel != null) {\n", | |
| " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |
| "}\n" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.Javascript object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<img src=\"data:image/png;base64,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rMbeStD68ssvNWzYMMXFxSkiIkJdu3bVxx9/3NjbCkrffvutHnjgAZ1//vmKiIhQamqqxo8frxMnTjT21hCgCIABZtasWXK5XJo6dao2btyokSNHKiYmRvv27WvsrQWd/v37a9q0afrss8/06aef6pprrlFycrIOHz7c2FsLeh999JHOP/98devWjQDYSL7++mulpKTopptu0urVq7Vt2za9/fbbKioqauytBaXHHntM8fHxevPNN7V9+3bNnj1bzZo107PPPtvYW0OAIgAGmLS0NGVmZvoee71eJSUl1flfRcEPp7S0VMYYLV++vLG3EtQOHTqk9u3ba8mSJfJ4PATARnLffffpiiuuaOxt4H9de+21+sMf/uA3N3jwYA0bNqyRdoRARwAMIE7+XWT88L744gsZY7Rhw4bG3kpQGzFihO666y5JIgA2ok6dOumuu+7Sb3/7W7Vo0UIXX3yxXnjhhcbeVtB67LHHlJKSos8//1yS9Omnn+rcc8/VjBkzGnlnCFQEwACye/duGWO0cuVKv/ns7GylpaU10q4gffdN7LXXXqvLL7+8sbcS1F555RV17dpVlZWVkgiAjcntdsvtdmvcuHFau3atJk+erIiICE2fPr2xtxaUvF6v7rvvPoWEhKhJkyYKCQnRhAkTGntbCGAEwABCAAxco0ePVkpKikpKShp7K0Fr165dOvfcc7Vu3TrfHAGw8YSHh1f7t9PvuOMO9ezZs5F2FNxeeeUVtW7dWq+88orWr1+vl156SXFxcQRy1IoAGEA4BRyYMjMz1bp1a23btq2xtxLU5s2bJ2OMwsLCfMMYo5CQEIWFhenbb79t7C0GleTkZN1yyy1+c88//7ySkpIaaUfBrXXr1srPz/ebe+SRR9SxY8dG2hECHQEwwKSlpWns2LG+x16vV61ateIikEZw4sQJZWZmKikpSVu3bm3s7QS9gwcPasOGDX6je/fuuvHGG/m7zEYwdOjQaheB3HXXXdW+FcR/R1xcnJ5//nm/uQkTJqh9+/aNtCMEOgJggJk1a5bcbremT5+uTZs2adSoUYqJidHevXsbe2tB5/bbb1d0dLSWLVumPXv2+MbRo0cbe2v4X5wCbjwfffSRmjRposcee0xffPGFZs6cqaioKC46aCQZGRlq1aqV7zYwc+fOVUJCgnJychp7awhQBMAANGnSJCUnJ8vlciktLU2rVq1q7C0FJWNMjWPatGmNvTX8LwJg43rjjTfUtWtXud1u/eQnP+Eq4EZ08OBBZWVlKTk52Xcj6Pvvv1/Hjh1r7K0hQBEAAQAAggwBEAAAIMgQAAEAAIIMARAAACDIEAABAACCDAEQAAAgyBAAAQAAggwBEAAAIMgQAAEAAIIMARAAACDIEAABAD+46667TjExMfrNb37T2FsBIAIgAOC/oKCgQP/+978JgECAIAACaBQej0dZWVmNvY0frQMHDqhFixbavn17Y2/Fp6CgoFoAHDJkiP70pz810o6A4EUABCxTWlqq0aNHq02bNnK5XDrvvPN09dVX6/3332+Q49cWzBo6sH311Vc6ePBggx2vsQRqkL377rt16623NvY2/NQUADds2KDY2FiVl5c30q6A4EQABCzTu3dv/exnP9O7776rHTt2aPXq1ZowYYLmz5/fIMf/oQPgsWPHHB8jkATi53LkyBE1b95cH374YYMd83QuuugidenSpdrYvXu337qaAqAkde/eXfn5+f+VvQL4DgEQsEhZWZmMMVq2bFmta7xer5588km1a9dOLpdLbdq00aOPPup7fuHChbr88ssVHR2tuLg4XXvttSoqKpIkZWRkyBjjN7Zv317rvNfr1YQJE3T++ecrIiJC3bp10+zZs/324/F4lJmZqaysLMXHx+vKK6/0zZ8MTh6PR3fccYeys7MVGxur8847T3l5eX7HOXjwoG644QZFRUWpZcuWmjhx4mnD1+TJk5WYmCiv1+s3P3DgQN18881+n9fpfobTfZ61fS5VVVW644471KJFC7ndbl1++eX66KOP6vS51GTz5s268sor5Xa71b59ey1YsEDGGBUWFta4fvbs2WrRooXfXFFRkYwxeuONN9S3b19FRkaqQ4cOWrVqlW/N9u3bZYzRnDlz1Lt3b0VERKh79+7auXOnVqxYoZ/97GeKjIxU3759VVZWVut+a1NbAHz44Yd1xRVX1Pt4AM4eARCwyDfffKNmzZrprrvuUlVVVY1rcnJyFBsbq+nTp6uoqEjvvfee/vGPf/ienzNnjl577TV98cUXKiws1K9//WtdeOGF8nq9Ki8vV69evTRy5Ejt2bNHe/bs0bffflvr/KOPPqqf/OQnWrRokYqLizVt2jS53W6/gOrxeNSsWTNlZ2dry5Yt2rJli2/++wGwefPmeuihh7R161a9+OKLCgkJ0eLFi33HufXWW5WSkqJ33nlHGzZs0KBBg3TOOefUGgC//vpruVwuvfPOO765r776qtrcmX6G032etX0ud955p5KSkvTWW29p48aNysjIUGxsrL766qszfi6n2rx5s5o3b64//vGPKioq0ty5cxUfH6/w8PBavzW888479ctf/tJv7rXXXlNISIh+/vOfq6CgQFu3btVVV13lFzxff/11GWPUr18/vffee1q7dq3atGmj3r1765prrtHHH3+sVatWKT4+XhMnTqzxvU+ntgC4cOFCuVyuWmsaQMMjAAKWmTNnjmJjYxUREaHLLrtM48aN07p16yR99y2Z2+32C3xnsn//fhljtGHDBkl1PwVcVVWlqKgorVy50m/dLbfcoqFDh/q97pJLLjnt8TweT7VvgHr06KH77rvP93OFh4f7fTNXXl6uqKio055+TU9P1x/+8Aff48mTJyspKcn3reCZfoa6fJ6nfi6HDx9WeHi4Zs6c6Zs7fvy4kpKS9NRTT53xczlV3759/b6xlKTBgwfrwgsvrPU1p/7ckvTggw8qNjZWpaWlvrm//vWv6tKli+/xQw89pLi4OB04cMA3d+ONN+r888/XkSNHfHO//OUvlZOTc8a9f1+/fv2UkJCgyMhItWrVyu8zX7dunYwx2rFjR72OCeDsEQABC1VWVmrx4sUaP368evXqpbCwME2bNk2rV6+WMUbbtm2r9bVbt27V73//e7Vt21bnnHOOmjZtKmOMFixYIKnuAfCzzz6TMUZNmzb1G+Hh4UpLS/N7XU0XI5waAMeMGeP3/PdP1X766acyxmjnzp1+ay655JLTBsBXX31V0dHRvm+W+vTpo3vuuafOP0NdPs9TP5fawsx1113nF+Rq+1y+b8eOHTLG+AL+Sb///e9144031vq6q6++utrnmZ6erptuuslv7u6771Z6errv8aBBg3TLLbf4renTp48viJ/UuXNn/e1vfzvt3utj69atMsZo06ZNDXZMAKdHAAR+BG655RYlJydr/fr1ZwwsHTt21NVXX6133nlHmzZt8oWgefPmSap7AFy1apXv7xG/+OILv7Fr165aX1fTfE1r0tPTlZGRIensA2BlZaWaN2+u1157Tbt27VJISIg++eSTOv8Mdfk8nQTAM1088vrrrys8PFzffPON33zXrl319NNP1/q6G264we9bWEk6//zzNXnyZL+5n//8535/a9m2bVu98MILfmuio6N9tSF995mGhYVV+9bUiZO/h/379zfYMQGcHgEQ+BH485//rPj4eFVWVioyMrLWU5YHDhyQMUYrVqzwzb333nt+AfAXv/iFxo4dW+21p86fPD360ksvnXZvDREAT54CnjNnju/58vJyNW3a9Iwh6qabbtLgwYP15JNP6ic/+Ynfc2f6Gc70eUrVP5fDhw/L5XJVOwXcqlUrv9BWlwD473//W6GhoX5/G7dw4UIZY/z+PvJUTz/9tC666CLf4/Lychljql2IEGmFnQAAAzBJREFUEhsb6/u9V1RUKCQkRB9//LHv+W3btlULsx999JFCQ0N16NCh0+69PqZMmaLWrVs32PEAnBkBELDIgQMH9POf/1wvv/yy1q1bp23btunVV1/Veeed5/ubr4ceekixsbF68cUXVVRUpA8//FBTpkyR9N0VrfHx8brxxhv1xRdfaOnSperRo4dfABw5cqR69Oih7du3a//+/b6/l6tp/v7771d8fLzvAolPPvlEf/3rXzV9+nTfnhsiAErfXQTStm1bvfvuu/rss8/0m9/8Ruecc47uuuuu035mS5YskdvtVseOHfXII49Ue/5MP8PpPs/aPpesrCwlJSVp4cKFfheBfP3112f8XL5v9+7dcrvduueee1RcXKw5c+YoNTVVxhjt27ev1tetX79eTZo08b3fihUr1KRJE1VWVvrWnDy9fPJG0TWtmTt3ruLi4vyO/cILL6h9+/an3Xd9ZWRkVPubRQA/LAIgYJGqqirl5ubq0ksvVXR0tKKiotSxY0c98MADOnr0qKTvQt6jjz6qlJQUhYeHKzk5WRMmTPAdY8mSJerUqZPcbre6deumZcuW+QXAzz//XD179lRkZKRfQKhp/sSJE/rLX/6ijh07Kjw8XC1atFD//v21fPly3/s1VACs6TYwaWlpys3NPe1n5vV6lZiYKGOMiouLqz1/pp/hTJ9nTZ9LZWWl7rjjDiUkJJz2NjB1uX/gyy+/rNatW6tZs2b63e9+p8cff1wtW7Y84+vS0tL097//XZI0adIkv4s9JGnevHmKiYnxPa5pTV5envr16+c3l5mZqd/+9rdnfP+6qqysVHR09H/tnoUAvkMABGClw4cPKzo62u/buGBw9913q3///mdc9+abb6pTp07V7oMYaJ5//nn94he/aOxtAEGHAAjACmvXrtU///lP32na9PR0RUdHB92FA/369avzLVieeeYZvwtyAtE//vGPWu+BCOCHQwAEYIW1a9fq0ksvVdOmTRUbG6urrrpK69evb+xt/dede+65mjFjRmNvA4DlCIAAAABBhgAIAAAQZAiAAAAAQYYACAAAEGQIgAAAAEGGAAgAABBk/j+ZIn2J3eOnEQAAAABJRU5ErkJggg==\" width=\"640\">" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.HTML object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "(0.9, 1.1)" | |
| ] | |
| }, | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "res_flat = ai.integrate1d(numpy.ones(detector.shape), **kwarg)\n", | |
| "crv = jupyter.plot1d(res_flat)\n", | |
| "crv.axes.set_ylim(0.9,1.1)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stderr", | |
| "output_type": "stream", | |
| "text": [ | |
| "/mntdirect/_scisoft/users/jupyter/jupy35/lib/python3.5/site-packages/ipykernel_launcher.py:4: RuntimeWarning: divide by zero encountered in true_divide\n", | |
| " after removing the cwd from sys.path.\n" | |
| ] | |
| }, | |
| { | |
| "data": { | |
| "application/javascript": [ | |
| "/* Put everything inside the global mpl namespace */\n", | |
| "window.mpl = {};\n", | |
| "\n", | |
| "\n", | |
| "mpl.get_websocket_type = function() {\n", | |
| " if (typeof(WebSocket) !== 'undefined') {\n", | |
| " return WebSocket;\n", | |
| " } else if (typeof(MozWebSocket) !== 'undefined') {\n", | |
| " return MozWebSocket;\n", | |
| " } else {\n", | |
| " alert('Your browser does not have WebSocket support.' +\n", | |
| " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", | |
| " 'Firefox 4 and 5 are also supported but you ' +\n", | |
| " 'have to enable WebSockets in about:config.');\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", | |
| " this.id = figure_id;\n", | |
| "\n", | |
| " this.ws = websocket;\n", | |
| "\n", | |
| " this.supports_binary = (this.ws.binaryType != undefined);\n", | |
| "\n", | |
| " if (!this.supports_binary) {\n", | |
| " var warnings = document.getElementById(\"mpl-warnings\");\n", | |
| " if (warnings) {\n", | |
| " warnings.style.display = 'block';\n", | |
| " warnings.textContent = (\n", | |
| " \"This browser does not support binary websocket messages. \" +\n", | |
| " \"Performance may be slow.\");\n", | |
| " }\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj = new Image();\n", | |
| "\n", | |
| " this.context = undefined;\n", | |
| " this.message = undefined;\n", | |
| " this.canvas = undefined;\n", | |
| " this.rubberband_canvas = undefined;\n", | |
| " this.rubberband_context = undefined;\n", | |
| " this.format_dropdown = undefined;\n", | |
| "\n", | |
| " this.image_mode = 'full';\n", | |
| "\n", | |
| " this.root = $('<div/>');\n", | |
| " this._root_extra_style(this.root)\n", | |
| " this.root.attr('style', 'display: inline-block');\n", | |
| "\n", | |
| " $(parent_element).append(this.root);\n", | |
| "\n", | |
| " this._init_header(this);\n", | |
| " this._init_canvas(this);\n", | |
| " this._init_toolbar(this);\n", | |
| "\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " this.waiting = false;\n", | |
| "\n", | |
| " this.ws.onopen = function () {\n", | |
| " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |
| " fig.send_message(\"send_image_mode\", {});\n", | |
| " if (mpl.ratio != 1) {\n", | |
| " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |
| " }\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj.onload = function() {\n", | |
| " if (fig.image_mode == 'full') {\n", | |
| " // Full images could contain transparency (where diff images\n", | |
| " // almost always do), so we need to clear the canvas so that\n", | |
| " // there is no ghosting.\n", | |
| " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| " }\n", | |
| " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |
| " };\n", | |
| "\n", | |
| " this.imageObj.onunload = function() {\n", | |
| " 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", | |
| " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |
| " 'ui-helper-clearfix\"/>');\n", | |
| " var titletext = $(\n", | |
| " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |
| " 'text-align: center; padding: 3px;\"/>');\n", | |
| " titlebar.append(titletext)\n", | |
| " this.root.append(titlebar);\n", | |
| " this.header = titletext[0];\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_canvas = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var canvas_div = $('<div/>');\n", | |
| "\n", | |
| " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |
| "\n", | |
| " function canvas_keyboard_event(event) {\n", | |
| " return fig.key_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |
| " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |
| " this.canvas_div = canvas_div\n", | |
| " this._canvas_extra_style(canvas_div)\n", | |
| " this.root.append(canvas_div);\n", | |
| "\n", | |
| " var canvas = $('<canvas/>');\n", | |
| " canvas.addClass('mpl-canvas');\n", | |
| " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |
| "\n", | |
| " this.canvas = canvas[0];\n", | |
| " this.context = canvas[0].getContext(\"2d\");\n", | |
| "\n", | |
| " var backingStore = this.context.backingStorePixelRatio ||\n", | |
| "\tthis.context.webkitBackingStorePixelRatio ||\n", | |
| "\tthis.context.mozBackingStorePixelRatio ||\n", | |
| "\tthis.context.msBackingStorePixelRatio ||\n", | |
| "\tthis.context.oBackingStorePixelRatio ||\n", | |
| "\tthis.context.backingStorePixelRatio || 1;\n", | |
| "\n", | |
| " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |
| "\n", | |
| " var rubberband = $('<canvas/>');\n", | |
| " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |
| "\n", | |
| " var pass_mouse_events = true;\n", | |
| "\n", | |
| " canvas_div.resizable({\n", | |
| " start: function(event, ui) {\n", | |
| " pass_mouse_events = false;\n", | |
| " },\n", | |
| " resize: function(event, ui) {\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " stop: function(event, ui) {\n", | |
| " pass_mouse_events = true;\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " });\n", | |
| "\n", | |
| " function mouse_event_fn(event) {\n", | |
| " if (pass_mouse_events)\n", | |
| " return fig.mouse_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " rubberband.mousedown('button_press', mouse_event_fn);\n", | |
| " rubberband.mouseup('button_release', mouse_event_fn);\n", | |
| " // Throttle sequential mouse events to 1 every 20ms.\n", | |
| " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |
| "\n", | |
| " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |
| " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |
| "\n", | |
| " canvas_div.on(\"wheel\", function (event) {\n", | |
| " event = event.originalEvent;\n", | |
| " event['data'] = 'scroll'\n", | |
| " if (event.deltaY < 0) {\n", | |
| " event.step = 1;\n", | |
| " } else {\n", | |
| " event.step = -1;\n", | |
| " }\n", | |
| " mouse_event_fn(event);\n", | |
| " });\n", | |
| "\n", | |
| " canvas_div.append(canvas);\n", | |
| " canvas_div.append(rubberband);\n", | |
| "\n", | |
| " this.rubberband = rubberband;\n", | |
| " this.rubberband_canvas = rubberband[0];\n", | |
| " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |
| " this.rubberband_context.strokeStyle = \"#000000\";\n", | |
| "\n", | |
| " this._resize_canvas = function(width, height) {\n", | |
| " // Keep the size of the canvas, canvas container, and rubber band\n", | |
| " // canvas in synch.\n", | |
| " canvas_div.css('width', width)\n", | |
| " canvas_div.css('height', height)\n", | |
| "\n", | |
| " canvas.attr('width', width * mpl.ratio);\n", | |
| " canvas.attr('height', height * mpl.ratio);\n", | |
| " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |
| "\n", | |
| " rubberband.attr('width', width);\n", | |
| " rubberband.attr('height', height);\n", | |
| " }\n", | |
| "\n", | |
| " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |
| " // upon first draw.\n", | |
| " this._resize_canvas(600, 600);\n", | |
| "\n", | |
| " // Disable right mouse context menu.\n", | |
| " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |
| " return false;\n", | |
| " });\n", | |
| "\n", | |
| " function set_focus () {\n", | |
| " canvas.focus();\n", | |
| " canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " window.setTimeout(set_focus, 100);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items) {\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) {\n", | |
| " // put a spacer in here.\n", | |
| " continue;\n", | |
| " }\n", | |
| " var button = $('<button/>');\n", | |
| " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |
| " 'ui-button-icon-only');\n", | |
| " button.attr('role', 'button');\n", | |
| " button.attr('aria-disabled', 'false');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| "\n", | |
| " var icon_img = $('<span/>');\n", | |
| " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |
| " icon_img.addClass(image);\n", | |
| " icon_img.addClass('ui-corner-all');\n", | |
| "\n", | |
| " var tooltip_span = $('<span/>');\n", | |
| " tooltip_span.addClass('ui-button-text');\n", | |
| " tooltip_span.html(tooltip);\n", | |
| "\n", | |
| " button.append(icon_img);\n", | |
| " button.append(tooltip_span);\n", | |
| "\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " var fmt_picker_span = $('<span/>');\n", | |
| "\n", | |
| " var fmt_picker = $('<select/>');\n", | |
| " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |
| " fmt_picker_span.append(fmt_picker);\n", | |
| " nav_element.append(fmt_picker_span);\n", | |
| " this.format_dropdown = fmt_picker[0];\n", | |
| "\n", | |
| " for (var ind in mpl.extensions) {\n", | |
| " var fmt = mpl.extensions[ind];\n", | |
| " var option = $(\n", | |
| " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |
| " fmt_picker.append(option)\n", | |
| " }\n", | |
| "\n", | |
| " // Add hover states to the ui-buttons\n", | |
| " $( \".ui-button\" ).hover(\n", | |
| " function() { $(this).addClass(\"ui-state-hover\");},\n", | |
| " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |
| " );\n", | |
| "\n", | |
| " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |
| " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |
| " // which will in turn request a refresh of the image.\n", | |
| " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_message = function(type, properties) {\n", | |
| " properties['type'] = type;\n", | |
| " properties['figure_id'] = this.id;\n", | |
| " this.ws.send(JSON.stringify(properties));\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_draw_message = function() {\n", | |
| " if (!this.waiting) {\n", | |
| " this.waiting = true;\n", | |
| " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " var format_dropdown = fig.format_dropdown;\n", | |
| " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |
| " fig.ondownload(fig, format);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |
| " var size = msg['size'];\n", | |
| " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |
| " fig._resize_canvas(size[0], size[1]);\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |
| " var x0 = msg['x0'] / mpl.ratio;\n", | |
| " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |
| " var x1 = msg['x1'] / mpl.ratio;\n", | |
| " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |
| " x0 = Math.floor(x0) + 0.5;\n", | |
| " y0 = Math.floor(y0) + 0.5;\n", | |
| " x1 = Math.floor(x1) + 0.5;\n", | |
| " y1 = Math.floor(y1) + 0.5;\n", | |
| " var min_x = Math.min(x0, x1);\n", | |
| " var min_y = Math.min(y0, y1);\n", | |
| " var width = Math.abs(x1 - x0);\n", | |
| " var height = Math.abs(y1 - y0);\n", | |
| "\n", | |
| " fig.rubberband_context.clearRect(\n", | |
| " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| "\n", | |
| " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |
| " // Updates the figure title.\n", | |
| " fig.header.textContent = msg['label'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |
| " var cursor = msg['cursor'];\n", | |
| " switch(cursor)\n", | |
| " {\n", | |
| " case 0:\n", | |
| " cursor = 'pointer';\n", | |
| " break;\n", | |
| " case 1:\n", | |
| " cursor = 'default';\n", | |
| " break;\n", | |
| " case 2:\n", | |
| " cursor = 'crosshair';\n", | |
| " break;\n", | |
| " case 3:\n", | |
| " cursor = 'move';\n", | |
| " break;\n", | |
| " }\n", | |
| " fig.rubberband_canvas.style.cursor = cursor;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |
| " fig.message.textContent = msg['message'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |
| " // Request the server to send over a new figure.\n", | |
| " fig.send_draw_message();\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |
| " fig.image_mode = msg['mode'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Called whenever the canvas gets updated.\n", | |
| " this.send_message(\"ack\", {});\n", | |
| "}\n", | |
| "\n", | |
| "// A function to construct a web socket function for onmessage handling.\n", | |
| "// Called in the figure constructor.\n", | |
| "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |
| " return function socket_on_message(evt) {\n", | |
| " if (evt.data instanceof Blob) {\n", | |
| " /* FIXME: We get \"Resource interpreted as Image but\n", | |
| " * transferred with MIME type text/plain:\" errors on\n", | |
| " * Chrome. But how to set the MIME type? It doesn't seem\n", | |
| " * to be part of the websocket stream */\n", | |
| " evt.data.type = \"image/png\";\n", | |
| "\n", | |
| " /* Free the memory for the previous frames */\n", | |
| " if (fig.imageObj.src) {\n", | |
| " (window.URL || window.webkitURL).revokeObjectURL(\n", | |
| " fig.imageObj.src);\n", | |
| " }\n", | |
| "\n", | |
| " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |
| " evt.data);\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |
| " fig.imageObj.src = evt.data;\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var msg = JSON.parse(evt.data);\n", | |
| " var msg_type = msg['type'];\n", | |
| "\n", | |
| " // Call the \"handle_{type}\" callback, which takes\n", | |
| " // the figure and JSON message as its only arguments.\n", | |
| " try {\n", | |
| " var callback = fig[\"handle_\" + msg_type];\n", | |
| " } catch (e) {\n", | |
| " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " if (callback) {\n", | |
| " try {\n", | |
| " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |
| " callback(fig, msg);\n", | |
| " } catch (e) {\n", | |
| " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |
| " }\n", | |
| " }\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |
| "mpl.findpos = function(e) {\n", | |
| " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |
| " var targ;\n", | |
| " if (!e)\n", | |
| " e = window.event;\n", | |
| " if (e.target)\n", | |
| " targ = e.target;\n", | |
| " else if (e.srcElement)\n", | |
| " targ = e.srcElement;\n", | |
| " if (targ.nodeType == 3) // defeat Safari bug\n", | |
| " targ = targ.parentNode;\n", | |
| "\n", | |
| " // jQuery normalizes the pageX and pageY\n", | |
| " // pageX,Y are the mouse positions relative to the document\n", | |
| " // offset() returns the position of the element relative to the document\n", | |
| " var x = e.pageX - $(targ).offset().left;\n", | |
| " var y = e.pageY - $(targ).offset().top;\n", | |
| "\n", | |
| " return {\"x\": x, \"y\": y};\n", | |
| "};\n", | |
| "\n", | |
| "/*\n", | |
| " * return a copy of an object with only non-object keys\n", | |
| " * we need this to avoid circular references\n", | |
| " * http://stackoverflow.com/a/24161582/3208463\n", | |
| " */\n", | |
| "function simpleKeys (original) {\n", | |
| " return Object.keys(original).reduce(function (obj, key) {\n", | |
| " if (typeof original[key] !== 'object')\n", | |
| " obj[key] = original[key]\n", | |
| " return obj;\n", | |
| " }, {});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |
| " var canvas_pos = mpl.findpos(event)\n", | |
| "\n", | |
| " if (name === 'button_press')\n", | |
| " {\n", | |
| " this.canvas.focus();\n", | |
| " this.canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " var x = canvas_pos.x * mpl.ratio;\n", | |
| " var y = canvas_pos.y * mpl.ratio;\n", | |
| "\n", | |
| " this.send_message(name, {x: x, y: y, button: event.button,\n", | |
| " step: event.step,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| "\n", | |
| " /* This prevents the web browser from automatically changing to\n", | |
| " * the text insertion cursor when the button is pressed. We want\n", | |
| " * to control all of the cursor setting manually through the\n", | |
| " * 'cursor' event from matplotlib */\n", | |
| " event.preventDefault();\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " // Handle any extra behaviour associated with a key event\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.key_event = function(event, name) {\n", | |
| "\n", | |
| " // Prevent repeat events\n", | |
| " if (name == 'key_press')\n", | |
| " {\n", | |
| " if (event.which === this._key)\n", | |
| " return;\n", | |
| " else\n", | |
| " this._key = event.which;\n", | |
| " }\n", | |
| " if (name == 'key_release')\n", | |
| " this._key = null;\n", | |
| "\n", | |
| " var value = '';\n", | |
| " if (event.ctrlKey && event.which != 17)\n", | |
| " value += \"ctrl+\";\n", | |
| " if (event.altKey && event.which != 18)\n", | |
| " value += \"alt+\";\n", | |
| " if (event.shiftKey && event.which != 16)\n", | |
| " value += \"shift+\";\n", | |
| "\n", | |
| " value += 'k';\n", | |
| " value += event.which.toString();\n", | |
| "\n", | |
| " this._key_event_extra(event, name);\n", | |
| "\n", | |
| " this.send_message(name, {key: value,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |
| " if (name == 'download') {\n", | |
| " this.handle_save(this, null);\n", | |
| " } else {\n", | |
| " this.send_message(\"toolbar_button\", {name: name});\n", | |
| " }\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |
| " this.message.textContent = tooltip;\n", | |
| "};\n", | |
| "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |
| "\n", | |
| "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |
| "\n", | |
| "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |
| " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |
| " // object with the appropriate methods. Currently this is a non binary\n", | |
| " // socket, so there is still some room for performance tuning.\n", | |
| " var ws = {};\n", | |
| "\n", | |
| " ws.close = function() {\n", | |
| " comm.close()\n", | |
| " };\n", | |
| " ws.send = function(m) {\n", | |
| " //console.log('sending', m);\n", | |
| " comm.send(m);\n", | |
| " };\n", | |
| " // Register the callback with on_msg.\n", | |
| " comm.on_msg(function(msg) {\n", | |
| " //console.log('receiving', msg['content']['data'], msg);\n", | |
| " // Pass the mpl event to the 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(\"<div id='\" + id + \"'></div>\");\n", | |
| " if (!fig.cell_info) {\n", | |
| " console.error(\"Failed to find cell for figure\", id, fig);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var output_index = fig.cell_info[2]\n", | |
| " var cell = fig.cell_info[0];\n", | |
| "\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |
| " var width = fig.canvas.width/mpl.ratio\n", | |
| " fig.root.unbind('remove')\n", | |
| "\n", | |
| " // Update the output cell to use the data from the current canvas.\n", | |
| " fig.push_to_output();\n", | |
| " var dataURL = fig.canvas.toDataURL();\n", | |
| " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |
| " // the notebook keyboard shortcuts fail.\n", | |
| " IPython.keyboard_manager.enable()\n", | |
| " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |
| " fig.close_ws(fig, msg);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |
| " fig.send_message('closing', msg);\n", | |
| " // fig.ws.close()\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |
| " // Turn the data on the canvas into data in the output cell.\n", | |
| " var width = this.canvas.width/mpl.ratio\n", | |
| " var dataURL = this.canvas.toDataURL();\n", | |
| " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Tell IPython that the notebook contents must change.\n", | |
| " IPython.notebook.set_dirty(true);\n", | |
| " this.send_message(\"ack\", {});\n", | |
| " var fig = this;\n", | |
| " // Wait a second, then push the new image to the DOM so\n", | |
| " // that it is saved nicely (might be nice to debounce this).\n", | |
| " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items){\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) { continue; };\n", | |
| "\n", | |
| " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " // Add the status bar.\n", | |
| " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "\n", | |
| " // Add the close button to the window.\n", | |
| " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |
| " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |
| " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |
| " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |
| " buttongrp.append(button);\n", | |
| " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |
| " titlebar.prepend(buttongrp);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(el){\n", | |
| " var fig = this\n", | |
| " el.on(\"remove\", function(){\n", | |
| "\tfig.close_ws(fig, {});\n", | |
| " });\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |
| " // this is important to make the div 'focusable\n", | |
| " el.attr('tabindex', 0)\n", | |
| " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |
| " // off when our div gets focus\n", | |
| "\n", | |
| " // location in version 3\n", | |
| " if (IPython.notebook.keyboard_manager) {\n", | |
| " IPython.notebook.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| " else {\n", | |
| " // location in version 2\n", | |
| " IPython.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " var manager = IPython.notebook.keyboard_manager;\n", | |
| " if (!manager)\n", | |
| " manager = IPython.keyboard_manager;\n", | |
| "\n", | |
| " // Check for shift+enter\n", | |
| " if (event.shiftKey && event.which == 13) {\n", | |
| " this.canvas_div.blur();\n", | |
| " event.shiftKey = false;\n", | |
| " // Send a \"J\" for go to next cell\n", | |
| " event.which = 74;\n", | |
| " event.keyCode = 74;\n", | |
| " manager.command_mode();\n", | |
| " manager.handle_keydown(event);\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " fig.ondownload(fig, null);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.find_output_cell = function(html_output) {\n", | |
| " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |
| " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |
| " // IPython event is triggered only after the cells have been serialised, which for\n", | |
| " // our purposes (turning an active figure into a static one), is too late.\n", | |
| " var cells = IPython.notebook.get_cells();\n", | |
| " var ncells = cells.length;\n", | |
| " for (var i=0; i<ncells; i++) {\n", | |
| " var cell = cells[i];\n", | |
| " if (cell.cell_type === 'code'){\n", | |
| " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |
| " var data = cell.output_area.outputs[j];\n", | |
| " if (data.data) {\n", | |
| " // IPython >= 3 moved mimebundle to data attribute of output\n", | |
| " data = data.data;\n", | |
| " }\n", | |
| " if (data['text/html'] == html_output) {\n", | |
| " return [cell, data, j];\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "// Register the function which deals with the matplotlib target/channel.\n", | |
| "// The kernel may be null if the page has been refreshed.\n", | |
| "if (IPython.notebook.kernel != null) {\n", | |
| " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |
| "}\n" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.Javascript object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<img src=\"data:image/png;base64,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\" width=\"640\">" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.HTML object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "<matplotlib.legend.Legend at 0x7f15e0ff6208>" | |
| ] | |
| }, | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "\n", | |
| "q = numpy.linspace(0, 10, npt)\n", | |
| "# Simple decay in q**2 to take into account the solid angle\n", | |
| "I = I0/q**2 \n", | |
| "fig, ax = subplots()\n", | |
| "ax.semilogy(q, I, label=\"Guinier law\")\n", | |
| "ax.set_xlabel(\"q ($nm^{-1}$)\")\n", | |
| "ax.set_ylabel(\"I (count)\")\n", | |
| "fig.legend()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "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 = $('<div/>');\n", | |
| " this._root_extra_style(this.root)\n", | |
| " this.root.attr('style', 'display: inline-block');\n", | |
| "\n", | |
| " $(parent_element).append(this.root);\n", | |
| "\n", | |
| " this._init_header(this);\n", | |
| " this._init_canvas(this);\n", | |
| " this._init_toolbar(this);\n", | |
| "\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " this.waiting = false;\n", | |
| "\n", | |
| " this.ws.onopen = function () {\n", | |
| " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |
| " fig.send_message(\"send_image_mode\", {});\n", | |
| " if (mpl.ratio != 1) {\n", | |
| " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |
| " }\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj.onload = function() {\n", | |
| " if (fig.image_mode == 'full') {\n", | |
| " // Full images could contain transparency (where diff images\n", | |
| " // almost always do), so we need to clear the canvas so that\n", | |
| " // there is no ghosting.\n", | |
| " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| " }\n", | |
| " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |
| " };\n", | |
| "\n", | |
| " this.imageObj.onunload = function() {\n", | |
| " 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", | |
| " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |
| " 'ui-helper-clearfix\"/>');\n", | |
| " var titletext = $(\n", | |
| " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |
| " 'text-align: center; padding: 3px;\"/>');\n", | |
| " titlebar.append(titletext)\n", | |
| " this.root.append(titlebar);\n", | |
| " this.header = titletext[0];\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_canvas = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var canvas_div = $('<div/>');\n", | |
| "\n", | |
| " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |
| "\n", | |
| " function canvas_keyboard_event(event) {\n", | |
| " return fig.key_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |
| " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |
| " this.canvas_div = canvas_div\n", | |
| " this._canvas_extra_style(canvas_div)\n", | |
| " this.root.append(canvas_div);\n", | |
| "\n", | |
| " var canvas = $('<canvas/>');\n", | |
| " canvas.addClass('mpl-canvas');\n", | |
| " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |
| "\n", | |
| " this.canvas = canvas[0];\n", | |
| " this.context = canvas[0].getContext(\"2d\");\n", | |
| "\n", | |
| " var backingStore = this.context.backingStorePixelRatio ||\n", | |
| "\tthis.context.webkitBackingStorePixelRatio ||\n", | |
| "\tthis.context.mozBackingStorePixelRatio ||\n", | |
| "\tthis.context.msBackingStorePixelRatio ||\n", | |
| "\tthis.context.oBackingStorePixelRatio ||\n", | |
| "\tthis.context.backingStorePixelRatio || 1;\n", | |
| "\n", | |
| " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |
| "\n", | |
| " var rubberband = $('<canvas/>');\n", | |
| " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |
| "\n", | |
| " var pass_mouse_events = true;\n", | |
| "\n", | |
| " canvas_div.resizable({\n", | |
| " start: function(event, ui) {\n", | |
| " pass_mouse_events = false;\n", | |
| " },\n", | |
| " resize: function(event, ui) {\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " stop: function(event, ui) {\n", | |
| " pass_mouse_events = true;\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " });\n", | |
| "\n", | |
| " function mouse_event_fn(event) {\n", | |
| " if (pass_mouse_events)\n", | |
| " return fig.mouse_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " rubberband.mousedown('button_press', mouse_event_fn);\n", | |
| " rubberband.mouseup('button_release', mouse_event_fn);\n", | |
| " // Throttle sequential mouse events to 1 every 20ms.\n", | |
| " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |
| "\n", | |
| " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |
| " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |
| "\n", | |
| " canvas_div.on(\"wheel\", function (event) {\n", | |
| " event = event.originalEvent;\n", | |
| " event['data'] = 'scroll'\n", | |
| " if (event.deltaY < 0) {\n", | |
| " event.step = 1;\n", | |
| " } else {\n", | |
| " event.step = -1;\n", | |
| " }\n", | |
| " mouse_event_fn(event);\n", | |
| " });\n", | |
| "\n", | |
| " canvas_div.append(canvas);\n", | |
| " canvas_div.append(rubberband);\n", | |
| "\n", | |
| " this.rubberband = rubberband;\n", | |
| " this.rubberband_canvas = rubberband[0];\n", | |
| " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |
| " this.rubberband_context.strokeStyle = \"#000000\";\n", | |
| "\n", | |
| " this._resize_canvas = function(width, height) {\n", | |
| " // Keep the size of the canvas, canvas container, and rubber band\n", | |
| " // canvas in synch.\n", | |
| " canvas_div.css('width', width)\n", | |
| " canvas_div.css('height', height)\n", | |
| "\n", | |
| " canvas.attr('width', width * mpl.ratio);\n", | |
| " canvas.attr('height', height * mpl.ratio);\n", | |
| " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |
| "\n", | |
| " rubberband.attr('width', width);\n", | |
| " rubberband.attr('height', height);\n", | |
| " }\n", | |
| "\n", | |
| " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |
| " // upon first draw.\n", | |
| " this._resize_canvas(600, 600);\n", | |
| "\n", | |
| " // Disable right mouse context menu.\n", | |
| " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |
| " return false;\n", | |
| " });\n", | |
| "\n", | |
| " function set_focus () {\n", | |
| " canvas.focus();\n", | |
| " canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " window.setTimeout(set_focus, 100);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items) {\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) {\n", | |
| " // put a spacer in here.\n", | |
| " continue;\n", | |
| " }\n", | |
| " var button = $('<button/>');\n", | |
| " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |
| " 'ui-button-icon-only');\n", | |
| " button.attr('role', 'button');\n", | |
| " button.attr('aria-disabled', 'false');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| "\n", | |
| " var icon_img = $('<span/>');\n", | |
| " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |
| " icon_img.addClass(image);\n", | |
| " icon_img.addClass('ui-corner-all');\n", | |
| "\n", | |
| " var tooltip_span = $('<span/>');\n", | |
| " tooltip_span.addClass('ui-button-text');\n", | |
| " tooltip_span.html(tooltip);\n", | |
| "\n", | |
| " button.append(icon_img);\n", | |
| " button.append(tooltip_span);\n", | |
| "\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " var fmt_picker_span = $('<span/>');\n", | |
| "\n", | |
| " var fmt_picker = $('<select/>');\n", | |
| " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |
| " fmt_picker_span.append(fmt_picker);\n", | |
| " nav_element.append(fmt_picker_span);\n", | |
| " this.format_dropdown = fmt_picker[0];\n", | |
| "\n", | |
| " for (var ind in mpl.extensions) {\n", | |
| " var fmt = mpl.extensions[ind];\n", | |
| " var option = $(\n", | |
| " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |
| " fmt_picker.append(option)\n", | |
| " }\n", | |
| "\n", | |
| " // Add hover states to the ui-buttons\n", | |
| " $( \".ui-button\" ).hover(\n", | |
| " function() { $(this).addClass(\"ui-state-hover\");},\n", | |
| " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |
| " );\n", | |
| "\n", | |
| " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |
| " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |
| " // which will in turn request a refresh of the image.\n", | |
| " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_message = function(type, properties) {\n", | |
| " properties['type'] = type;\n", | |
| " properties['figure_id'] = this.id;\n", | |
| " this.ws.send(JSON.stringify(properties));\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_draw_message = function() {\n", | |
| " if (!this.waiting) {\n", | |
| " this.waiting = true;\n", | |
| " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " var format_dropdown = fig.format_dropdown;\n", | |
| " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |
| " fig.ondownload(fig, format);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |
| " var size = msg['size'];\n", | |
| " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |
| " fig._resize_canvas(size[0], size[1]);\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |
| " var x0 = msg['x0'] / mpl.ratio;\n", | |
| " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |
| " var x1 = msg['x1'] / mpl.ratio;\n", | |
| " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |
| " x0 = Math.floor(x0) + 0.5;\n", | |
| " y0 = Math.floor(y0) + 0.5;\n", | |
| " x1 = Math.floor(x1) + 0.5;\n", | |
| " y1 = Math.floor(y1) + 0.5;\n", | |
| " var min_x = Math.min(x0, x1);\n", | |
| " var min_y = Math.min(y0, y1);\n", | |
| " var width = Math.abs(x1 - x0);\n", | |
| " var height = Math.abs(y1 - y0);\n", | |
| "\n", | |
| " fig.rubberband_context.clearRect(\n", | |
| " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| "\n", | |
| " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |
| " // Updates the figure title.\n", | |
| " fig.header.textContent = msg['label'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |
| " var cursor = msg['cursor'];\n", | |
| " switch(cursor)\n", | |
| " {\n", | |
| " case 0:\n", | |
| " cursor = 'pointer';\n", | |
| " break;\n", | |
| " case 1:\n", | |
| " cursor = 'default';\n", | |
| " break;\n", | |
| " case 2:\n", | |
| " cursor = 'crosshair';\n", | |
| " break;\n", | |
| " case 3:\n", | |
| " cursor = 'move';\n", | |
| " break;\n", | |
| " }\n", | |
| " fig.rubberband_canvas.style.cursor = cursor;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |
| " fig.message.textContent = msg['message'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |
| " // Request the server to send over a new figure.\n", | |
| " fig.send_draw_message();\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |
| " fig.image_mode = msg['mode'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Called whenever the canvas gets updated.\n", | |
| " this.send_message(\"ack\", {});\n", | |
| "}\n", | |
| "\n", | |
| "// A function to construct a web socket function for onmessage handling.\n", | |
| "// Called in the figure constructor.\n", | |
| "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |
| " return function socket_on_message(evt) {\n", | |
| " if (evt.data instanceof Blob) {\n", | |
| " /* FIXME: We get \"Resource interpreted as Image but\n", | |
| " * transferred with MIME type text/plain:\" errors on\n", | |
| " * Chrome. But how to set the MIME type? It doesn't seem\n", | |
| " * to be part of the websocket stream */\n", | |
| " evt.data.type = \"image/png\";\n", | |
| "\n", | |
| " /* Free the memory for the previous frames */\n", | |
| " if (fig.imageObj.src) {\n", | |
| " (window.URL || window.webkitURL).revokeObjectURL(\n", | |
| " fig.imageObj.src);\n", | |
| " }\n", | |
| "\n", | |
| " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |
| " evt.data);\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |
| " fig.imageObj.src = evt.data;\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var msg = JSON.parse(evt.data);\n", | |
| " var msg_type = msg['type'];\n", | |
| "\n", | |
| " // Call the \"handle_{type}\" callback, which takes\n", | |
| " // the figure and JSON message as its only arguments.\n", | |
| " try {\n", | |
| " var callback = fig[\"handle_\" + msg_type];\n", | |
| " } catch (e) {\n", | |
| " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " if (callback) {\n", | |
| " try {\n", | |
| " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |
| " callback(fig, msg);\n", | |
| " } catch (e) {\n", | |
| " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |
| " }\n", | |
| " }\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |
| "mpl.findpos = function(e) {\n", | |
| " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |
| " var targ;\n", | |
| " if (!e)\n", | |
| " e = window.event;\n", | |
| " if (e.target)\n", | |
| " targ = e.target;\n", | |
| " else if (e.srcElement)\n", | |
| " targ = e.srcElement;\n", | |
| " if (targ.nodeType == 3) // defeat Safari bug\n", | |
| " targ = targ.parentNode;\n", | |
| "\n", | |
| " // jQuery normalizes the pageX and pageY\n", | |
| " // pageX,Y are the mouse positions relative to the document\n", | |
| " // offset() returns the position of the element relative to the document\n", | |
| " var x = e.pageX - $(targ).offset().left;\n", | |
| " var y = e.pageY - $(targ).offset().top;\n", | |
| "\n", | |
| " return {\"x\": x, \"y\": y};\n", | |
| "};\n", | |
| "\n", | |
| "/*\n", | |
| " * return a copy of an object with only non-object keys\n", | |
| " * we need this to avoid circular references\n", | |
| " * http://stackoverflow.com/a/24161582/3208463\n", | |
| " */\n", | |
| "function simpleKeys (original) {\n", | |
| " return Object.keys(original).reduce(function (obj, key) {\n", | |
| " if (typeof original[key] !== 'object')\n", | |
| " obj[key] = original[key]\n", | |
| " return obj;\n", | |
| " }, {});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |
| " var canvas_pos = mpl.findpos(event)\n", | |
| "\n", | |
| " if (name === 'button_press')\n", | |
| " {\n", | |
| " this.canvas.focus();\n", | |
| " this.canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " var x = canvas_pos.x * mpl.ratio;\n", | |
| " var y = canvas_pos.y * mpl.ratio;\n", | |
| "\n", | |
| " this.send_message(name, {x: x, y: y, button: event.button,\n", | |
| " step: event.step,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| "\n", | |
| " /* This prevents the web browser from automatically changing to\n", | |
| " * the text insertion cursor when the button is pressed. We want\n", | |
| " * to control all of the cursor setting manually through the\n", | |
| " * 'cursor' event from matplotlib */\n", | |
| " event.preventDefault();\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " // Handle any extra behaviour associated with a key event\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.key_event = function(event, name) {\n", | |
| "\n", | |
| " // Prevent repeat events\n", | |
| " if (name == 'key_press')\n", | |
| " {\n", | |
| " if (event.which === this._key)\n", | |
| " return;\n", | |
| " else\n", | |
| " this._key = event.which;\n", | |
| " }\n", | |
| " if (name == 'key_release')\n", | |
| " this._key = null;\n", | |
| "\n", | |
| " var value = '';\n", | |
| " if (event.ctrlKey && event.which != 17)\n", | |
| " value += \"ctrl+\";\n", | |
| " if (event.altKey && event.which != 18)\n", | |
| " value += \"alt+\";\n", | |
| " if (event.shiftKey && event.which != 16)\n", | |
| " value += \"shift+\";\n", | |
| "\n", | |
| " value += 'k';\n", | |
| " value += event.which.toString();\n", | |
| "\n", | |
| " this._key_event_extra(event, name);\n", | |
| "\n", | |
| " this.send_message(name, {key: value,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |
| " if (name == 'download') {\n", | |
| " this.handle_save(this, null);\n", | |
| " } else {\n", | |
| " this.send_message(\"toolbar_button\", {name: name});\n", | |
| " }\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |
| " this.message.textContent = tooltip;\n", | |
| "};\n", | |
| "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |
| "\n", | |
| "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |
| "\n", | |
| "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |
| " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |
| " // object with the appropriate methods. Currently this is a non binary\n", | |
| " // socket, so there is still some room for performance tuning.\n", | |
| " var ws = {};\n", | |
| "\n", | |
| " ws.close = function() {\n", | |
| " comm.close()\n", | |
| " };\n", | |
| " ws.send = function(m) {\n", | |
| " //console.log('sending', m);\n", | |
| " comm.send(m);\n", | |
| " };\n", | |
| " // Register the callback with on_msg.\n", | |
| " comm.on_msg(function(msg) {\n", | |
| " //console.log('receiving', msg['content']['data'], msg);\n", | |
| " // Pass the mpl event to the 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(\"<div id='\" + id + \"'></div>\");\n", | |
| " if (!fig.cell_info) {\n", | |
| " console.error(\"Failed to find cell for figure\", id, fig);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var output_index = fig.cell_info[2]\n", | |
| " var cell = fig.cell_info[0];\n", | |
| "\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |
| " var width = fig.canvas.width/mpl.ratio\n", | |
| " fig.root.unbind('remove')\n", | |
| "\n", | |
| " // Update the output cell to use the data from the current canvas.\n", | |
| " fig.push_to_output();\n", | |
| " var dataURL = fig.canvas.toDataURL();\n", | |
| " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |
| " // the notebook keyboard shortcuts fail.\n", | |
| " IPython.keyboard_manager.enable()\n", | |
| " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |
| " fig.close_ws(fig, msg);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |
| " fig.send_message('closing', msg);\n", | |
| " // fig.ws.close()\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |
| " // Turn the data on the canvas into data in the output cell.\n", | |
| " var width = this.canvas.width/mpl.ratio\n", | |
| " var dataURL = this.canvas.toDataURL();\n", | |
| " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Tell IPython that the notebook contents must change.\n", | |
| " IPython.notebook.set_dirty(true);\n", | |
| " this.send_message(\"ack\", {});\n", | |
| " var fig = this;\n", | |
| " // Wait a second, then push the new image to the DOM so\n", | |
| " // that it is saved nicely (might be nice to debounce this).\n", | |
| " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items){\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) { continue; };\n", | |
| "\n", | |
| " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " // Add the status bar.\n", | |
| " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "\n", | |
| " // Add the close button to the window.\n", | |
| " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |
| " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |
| " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |
| " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |
| " buttongrp.append(button);\n", | |
| " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |
| " titlebar.prepend(buttongrp);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(el){\n", | |
| " var fig = this\n", | |
| " el.on(\"remove\", function(){\n", | |
| "\tfig.close_ws(fig, {});\n", | |
| " });\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |
| " // this is important to make the div 'focusable\n", | |
| " el.attr('tabindex', 0)\n", | |
| " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |
| " // off when our div gets focus\n", | |
| "\n", | |
| " // location in version 3\n", | |
| " if (IPython.notebook.keyboard_manager) {\n", | |
| " IPython.notebook.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| " else {\n", | |
| " // location in version 2\n", | |
| " IPython.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " var manager = IPython.notebook.keyboard_manager;\n", | |
| " if (!manager)\n", | |
| " manager = IPython.keyboard_manager;\n", | |
| "\n", | |
| " // Check for shift+enter\n", | |
| " if (event.shiftKey && event.which == 13) {\n", | |
| " this.canvas_div.blur();\n", | |
| " event.shiftKey = false;\n", | |
| " // Send a \"J\" for go to next cell\n", | |
| " event.which = 74;\n", | |
| " event.keyCode = 74;\n", | |
| " manager.command_mode();\n", | |
| " manager.handle_keydown(event);\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " fig.ondownload(fig, null);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.find_output_cell = function(html_output) {\n", | |
| " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |
| " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |
| " // IPython event is triggered only after the cells have been serialised, which for\n", | |
| " // our purposes (turning an active figure into a static one), is too late.\n", | |
| " var cells = IPython.notebook.get_cells();\n", | |
| " var ncells = cells.length;\n", | |
| " for (var i=0; i<ncells; i++) {\n", | |
| " var cell = cells[i];\n", | |
| " if (cell.cell_type === 'code'){\n", | |
| " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |
| " var data = cell.output_area.outputs[j];\n", | |
| " if (data.data) {\n", | |
| " // IPython >= 3 moved mimebundle to data attribute of output\n", | |
| " data = data.data;\n", | |
| " }\n", | |
| " if (data['text/html'] == html_output) {\n", | |
| " return [cell, data, j];\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "// Register the function which deals with the matplotlib target/channel.\n", | |
| "// The kernel may be null if the page has been refreshed.\n", | |
| "if (IPython.notebook.kernel != null) {\n", | |
| " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |
| "}\n" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.Javascript object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3daZRV1bno/YUoBYh0oYQAVgHSaEJEohJQYhMQ2wORqAmgIhgIig05KoQgEpEqMWDl+saDwfcavbl68Fw9qDd5UUaiiUNNRBkCNsQmkiixyxholSQBgvC8H4q9qF21m7XmnmvNOdf8/8eYH0KVWtYYJ/mdZzY7ECIiIiLyqsD0D0BERERE6QYAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwA6Hl33XWX1NbWSlVVlYwaNUo2bNhg+kciIiKihAOAHvfQQw9Jhw4d5Oc//7m8/vrrMmvWLOnevbt8/PHHpn80IiIiSjAA6HGjRo2SuXPnhv9537590rdvX7ntttsM/lRERESUdADQ0/bs2SPt27eXRx99NO/PL7vsMpk4caKhn4qIiIjSCAB62vvvvy9BEMjvf//7vD+/8cYbZdSoUW2+f/fu3dLU1BSuTz/9VN555x1pbGzM+3MWi8ViubEaGxtl+/btsm/fvrT+p4csCgB6WlwALlmyRIIgYLFYLFbG1vbt29P6nx6yKADoaXG3gFtPAN977z0JgkCueOJ8ueTpKXLuk1fI2P87V07473ky/L9ukKEP/kAG3f9Dqb33JjnqnpvlqJ8tkf53/Uj633mL9P/JUjnqjlvlqBW3Ss3ty6TmtmVSW79MapfVyYCldTLwljoZuKROBt1cJ4NuqpNBi+rk6IX1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qxf4WQu/rOIPABIAJKUyC0DTYHMdfFlEH/BLDn7gzxj+ACABQFIqEwA0jbWswQ/8gT/w5wz+ACABQFKqsbFRgiCQ03pMlXE9L7dv9Zie7dX9UjtW10tSX984Ylo66/Apya3O30lmdbw4kXVGleZ12EX616Hf0rZOP2Sy3tXum/pWMEnbGhucK0EQSGNjo+n/SSEDAUBSKvckDYvFYrHcXtu3bzf9PylkIABISn366acSBIG89957ee8Dstq+lbh9+3bjP4uNi98Pvx9+P2Z/P42NjbJ9+3bZt2+f6f9JIQMBQFKqqan5DGBTE2dHisXvqHT8fkrH76d0/H5Kx++HygUASSn+y6V8/I5Kx++ndPx+Ssfvp3T8fqhcAJCU4r9cysfvqHT8fkrH76d0/H5Kx++HygUASandu3fLkiVLZPfu3aZ/FGvjd1Q6fj+l4/dTOn4/peP3Q+UCgERERESeBQCJiIiIPAsAEhEREXkWACQiIiLyLABIRERE5FkAkJS66667pLa2VqqqqmTUqFGyYcMG0z9S4tXX18uJJ54oXbp0kerqapk0aZK88cYbed+za9cuueqqq6Rnz55y+OGHy+TJk+Wjjz7K+553331Xzj33XOnUqZNUV1fLDTfcIHv37k3zXyWVbrvtNgmCQK677rrwz/j9iPz1r3+VadOmSc+ePaVjx44yfPhweemll8Kv79+/XxYvXix9+vSRjh07yrhx4+Stt97K+3vs2LFDpk6dKkcccYR069ZNZs6cKTt37kz7X0V7n3/+udx0000yYMAA6dixowwaNEiWLl0q+/fvD7/Hp9/PM888I+eff7588YtflCAI5NFHH837uq7fxZYtW2Ts2LFSVVUl/fv3l9tvvz3xfzcyHwCk2D300EPSoUMH+fnPfy6vv/66zJo1S7p37y4ff/yx6R8t0c466yy577775LXXXpPNmzfLueeeKzU1NfL3v/89/J45c+bIUUcdJU899ZRs3LhRRo8eLSeffHL49c8//1yGDx8u48ePl02bNsm6deukV69esnDhQhP/Son14osvyoABA+S4447LA6Dvv59PPvlEamtr5fLLL5cNGzbItm3bZP369fKnP/0p/J7ly5dLt27d5LHHHpMtW7bIxIkTZeDAgbJr167we84++2wZMWKEvPDCC/Lss8/K4MGDZcqUKSb+lbRWV1cnX/jCF+RXv/qV/PnPf5aHH35YunTpInfeeWf4PT79ftatWyeLFi2StWvXFgSgjt9FU1OT9O7dW6ZNmyavvfaarFmzRjp16iSrV69O7d+TzAQAKXajRo2SuXPnhv9537590rdvX7ntttsM/lTp97e//U2CIJBnnnlGREQaGxvlsMMOk4cffjj8nj/+8Y8SBIH84Q9/EJHm/0I/5JBD8qZed999t3Tt2lX27NmT7r9AQu3cuVOGDBkiv/71r+W0004LAcjvR2TBggUyduzYol/fv3+/9OnTR1asWBH+WWNjo1RVVcmaNWtERGTr1q0SBEHe1PCJJ56Qdu3ayfvvv5/cD59C5513nsycOTPvzyZPnizTpk0TEb9/P60BqOt3sWrVKunRo0fe/30tWLBAhg0blvS/EhkOAFKs9uzZI+3bt2/z/4ledtllMnHiREM/lZnefvttCYJAXn31VREReeqppyQIAvn000/zvq+mpkYaGhpERGTx4sUyYsSIvK9v27ZNgiCQl19+OZ0fPOEuu+wymTdvnohIHgD5/Ygce+yxMm/ePLnwwgulurpajj/+eLnnnnvCr7/zzjsSBIFs2rQp76879dRT5dprrxURkXvvvVe6d++e9/W9e/dK+/btZe3atcn/SyRYXV2d1NbWyptvvikiIps3b5YjjzxSHnjgARHx+/fTGoC6fheXXnqpTJo0Ke97nn76aQmCQD755JMk/lXIkgAgxer999+XIAjk97//fd6f33jjjTJq1ChDP1X67du3T8477zw55ZRTwj978MEHpUOHDm2+96STTpL58+eLiMisWbNkwoQJeV//xz/+IUEQyLp165L9oVNozZo1Mnz48HALqiUA+f2IVFVVSVVVlSxcuFBefvllWb16tXTs2FHuv/9+ERF5/vnnJQgC+eCDD/L+uosuukguvvhiEWlG0tChQ9v8vaurq2XVqlXJ/0sk2L59+2TBggXSrl07OfTQQ6Vdu3ZSX18fft3n309rAOr6XZx55pkye/bsvK+//vrrEgSBbN26Vfe/BlkUAKRYAcDm5syZI7W1tbJ9+/bwz3wHznvvvSdHHnmkbNmyJfwzAJjfYYcdJmPGjMn7s2uuuUZGjx4tIn4DR6T5/4Ho37+/rFmzRl555RX5xS9+IT179gTIAgBJfwCQYsUWsMjcuXOlf//+sm3btrw/932L89FHH5UgCKR9+/bhCoJA2rVrJ+3bt5ff/OY3Xv9+RJr/Xa+44oq8P1u1apX07dtXRPze4hQR6d+/v9x11115f3brrbeG59F8/v2wBUy6A4AUu1GjRsnVV18d/ud9+/ZJv379Mn8JZP/+/TJ37lzp27dvm6cWRA5ecnjkkUfCP3vjjTcKXnJoeWN69erV0rVrV+c/tP2zzz6TV199NW+deOKJcskll8irr77q/e9HRGTKlCltLoHMmzcvnArmDvavXLky/HpTU1PBg/0bN24Mv2f9+vXOX3IQEenZs2ebKV19fb0MGTJERPz+/RS7BFLp7yJ3CeRf//pX+D0LFy7kEogHAUCK3UMPPSRVVVVy//33y9atW2X27NnSvXv3Nu+5Za0rr7xSunXrJr/73e/kww8/DNc///nP8HvmzJkjNTU18vTTT8vGjRtlzJgxeVt+uWdOJkyYIJs3b5Ynn3xSqqurM/PMSetabgGL8Pt58cUX5dBDD5W6ujp5++235cEHH5TOnTuHlxxEmp/26N69uzz++OPyyiuvyKRJkwo+7TFy5EjZsGGDPPfcczJkyBAnnzlp3fTp06Vfv37hMzBr166VXr16hUcERPz6/ezcuVM2bdokmzZtkiAIpKGhQTZt2iTvvvuuiOj5XTQ2Nkrv3r3l0ksvlddee00eeugh6dy5M8/AeBAAJKV++tOfSk1NjXTo0EFGjRolL7zwgukfKfGCICi47rvvvvB7cg8d9+jRQzp37iwXXHCBfPjhh3l/n7/85S9yzjnnSKdOnaRXr15y/fXXZ+qh45a1BiC/H5Ff/vKXMnz4cKmqqpJjjjkm7xawyMHHfXv37i1VVVUybty48FZsrh07dsiUKVOkS5cu0rVrV5kxY4aTDx237rPPPpPrrrtOampqwoegFy1alPdEiU+/n9/+9rcF/ztn+vTpIqLvd9HyIeh+/frJ8uXL0/pXJIMBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWcBQCIiIiLPAoBEREREngUAiYiIiDwLABIRERF5FgAkIiIi8iwASERERORZAJCIiIjIswAgERERkWf9/5S3MYbss1V3AAAAAElFTkSuQmCC\" width=\"640\">" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.HTML object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "<matplotlib.image.AxesImage at 0x7f15e0f9a860>" | |
| ] | |
| }, | |
| "execution_count": 7, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "#Reconstruction of diffusion image:\n", | |
| "\n", | |
| "img_theo = ai.calcfrom1d(q, I, dim1_unit=\"q_nm^-1\", correctSolidAngle=False)\n", | |
| "fig, ax = subplots()\n", | |
| "ax.imshow(img_theo, norm=LogNorm())" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 8, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stderr", | |
| "output_type": "stream", | |
| "text": [ | |
| "/mntdirect/_scisoft/users/jupyter/jupy35/lib/python3.5/site-packages/ipykernel_launcher.py:3: RuntimeWarning: invalid value encountered in less\n", | |
| " This is separate from the ipykernel package so we can avoid doing imports until\n", | |
| "/mntdirect/_scisoft/users/jupyter/jupy35/lib/python3.5/site-packages/ipykernel_launcher.py:3: RuntimeWarning: invalid value encountered in greater\n", | |
| " This is separate from the ipykernel package so we can avoid doing imports until\n" | |
| ] | |
| }, | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "1000.0 MBytes (1000, 1024, 1024)\n", | |
| "CPU times: user 1min 43s, sys: 1.45 s, total: 1min 44s\n", | |
| "Wall time: 1min 44s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "%%time\n", | |
| "# Now construct the large dataset from poissonian statistics\n", | |
| "#this is slow and takes a lot of memory !\n", | |
| "dataset = numpy.random.poisson(img_theo, (nimg,)+img_theo.shape)\n", | |
| "print(dataset.size/(1<<20), \"MBytes\", dataset.shape)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 9, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Error max: nan Error mean nan\n", | |
| "Deviation on variance nan\n", | |
| "CPU times: user 5.77 s, sys: 1.42 s, total: 7.19 s\n", | |
| "Wall time: 7.19 s\n" | |
| ] | |
| }, | |
| { | |
| "name": "stderr", | |
| "output_type": "stream", | |
| "text": [ | |
| "/mntdirect/_scisoft/users/jupyter/jupy35/lib/python3.5/site-packages/numpy/core/_methods.py:28: RuntimeWarning: invalid value encountered in reduce\n", | |
| " return umr_maximum(a, axis, None, out, keepdims, initial)\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "%%time\n", | |
| "img_avg = dataset.mean(axis=0)\n", | |
| "img_std = dataset.std(axis=0)\n", | |
| "error = img_theo - img_avg\n", | |
| "print(\"Error max:\", abs(error.max()), \"Error mean\", abs(error.mean()))\n", | |
| "print(\"Deviation on variance\", abs(img_std**2-img_theo).max())" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 10, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "def chi2(res1, res2):\n", | |
| " \"\"\"Calculate the Chi2 value for a pair of integrated data\"\"\"\n", | |
| " I = res1.intensity\n", | |
| " J = res2.intensity\n", | |
| " l = len(I)\n", | |
| " assert len(J) == l\n", | |
| " sigma_I = res1.sigma\n", | |
| " sigma_J = res2.sigma\n", | |
| " return ((I-J)**2/(sigma_I**2+sigma_J**2)).sum()/(l-1)\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 11, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "(1024, 1024)\n", | |
| "CPU times: user 4.37 s, sys: 104 ms, total: 4.48 s\n", | |
| "Wall time: 4.47 s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "%%time\n", | |
| "results = []\n", | |
| "for i in range(nimg):\n", | |
| " data = dataset[i, :, :]\n", | |
| " results.append(ai.integrate1d(data, variance=data, **kwarg))\n", | |
| "print(data.shape)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "0.9827676186929116" | |
| ] | |
| }, | |
| "execution_count": 12, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "chi2(results[0], results[1])" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "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 = $('<div/>');\n", | |
| " this._root_extra_style(this.root)\n", | |
| " this.root.attr('style', 'display: inline-block');\n", | |
| "\n", | |
| " $(parent_element).append(this.root);\n", | |
| "\n", | |
| " this._init_header(this);\n", | |
| " this._init_canvas(this);\n", | |
| " this._init_toolbar(this);\n", | |
| "\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " this.waiting = false;\n", | |
| "\n", | |
| " this.ws.onopen = function () {\n", | |
| " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |
| " fig.send_message(\"send_image_mode\", {});\n", | |
| " if (mpl.ratio != 1) {\n", | |
| " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |
| " }\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj.onload = function() {\n", | |
| " if (fig.image_mode == 'full') {\n", | |
| " // Full images could contain transparency (where diff images\n", | |
| " // almost always do), so we need to clear the canvas so that\n", | |
| " // there is no ghosting.\n", | |
| " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| " }\n", | |
| " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |
| " };\n", | |
| "\n", | |
| " this.imageObj.onunload = function() {\n", | |
| " 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", | |
| " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |
| " 'ui-helper-clearfix\"/>');\n", | |
| " var titletext = $(\n", | |
| " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |
| " 'text-align: center; padding: 3px;\"/>');\n", | |
| " titlebar.append(titletext)\n", | |
| " this.root.append(titlebar);\n", | |
| " this.header = titletext[0];\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_canvas = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var canvas_div = $('<div/>');\n", | |
| "\n", | |
| " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |
| "\n", | |
| " function canvas_keyboard_event(event) {\n", | |
| " return fig.key_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |
| " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |
| " this.canvas_div = canvas_div\n", | |
| " this._canvas_extra_style(canvas_div)\n", | |
| " this.root.append(canvas_div);\n", | |
| "\n", | |
| " var canvas = $('<canvas/>');\n", | |
| " canvas.addClass('mpl-canvas');\n", | |
| " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |
| "\n", | |
| " this.canvas = canvas[0];\n", | |
| " this.context = canvas[0].getContext(\"2d\");\n", | |
| "\n", | |
| " var backingStore = this.context.backingStorePixelRatio ||\n", | |
| "\tthis.context.webkitBackingStorePixelRatio ||\n", | |
| "\tthis.context.mozBackingStorePixelRatio ||\n", | |
| "\tthis.context.msBackingStorePixelRatio ||\n", | |
| "\tthis.context.oBackingStorePixelRatio ||\n", | |
| "\tthis.context.backingStorePixelRatio || 1;\n", | |
| "\n", | |
| " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |
| "\n", | |
| " var rubberband = $('<canvas/>');\n", | |
| " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |
| "\n", | |
| " var pass_mouse_events = true;\n", | |
| "\n", | |
| " canvas_div.resizable({\n", | |
| " start: function(event, ui) {\n", | |
| " pass_mouse_events = false;\n", | |
| " },\n", | |
| " resize: function(event, ui) {\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " stop: function(event, ui) {\n", | |
| " pass_mouse_events = true;\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " });\n", | |
| "\n", | |
| " function mouse_event_fn(event) {\n", | |
| " if (pass_mouse_events)\n", | |
| " return fig.mouse_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " rubberband.mousedown('button_press', mouse_event_fn);\n", | |
| " rubberband.mouseup('button_release', mouse_event_fn);\n", | |
| " // Throttle sequential mouse events to 1 every 20ms.\n", | |
| " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |
| "\n", | |
| " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |
| " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |
| "\n", | |
| " canvas_div.on(\"wheel\", function (event) {\n", | |
| " event = event.originalEvent;\n", | |
| " event['data'] = 'scroll'\n", | |
| " if (event.deltaY < 0) {\n", | |
| " event.step = 1;\n", | |
| " } else {\n", | |
| " event.step = -1;\n", | |
| " }\n", | |
| " mouse_event_fn(event);\n", | |
| " });\n", | |
| "\n", | |
| " canvas_div.append(canvas);\n", | |
| " canvas_div.append(rubberband);\n", | |
| "\n", | |
| " this.rubberband = rubberband;\n", | |
| " this.rubberband_canvas = rubberband[0];\n", | |
| " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |
| " this.rubberband_context.strokeStyle = \"#000000\";\n", | |
| "\n", | |
| " this._resize_canvas = function(width, height) {\n", | |
| " // Keep the size of the canvas, canvas container, and rubber band\n", | |
| " // canvas in synch.\n", | |
| " canvas_div.css('width', width)\n", | |
| " canvas_div.css('height', height)\n", | |
| "\n", | |
| " canvas.attr('width', width * mpl.ratio);\n", | |
| " canvas.attr('height', height * mpl.ratio);\n", | |
| " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |
| "\n", | |
| " rubberband.attr('width', width);\n", | |
| " rubberband.attr('height', height);\n", | |
| " }\n", | |
| "\n", | |
| " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |
| " // upon first draw.\n", | |
| " this._resize_canvas(600, 600);\n", | |
| "\n", | |
| " // Disable right mouse context menu.\n", | |
| " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |
| " return false;\n", | |
| " });\n", | |
| "\n", | |
| " function set_focus () {\n", | |
| " canvas.focus();\n", | |
| " canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " window.setTimeout(set_focus, 100);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items) {\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) {\n", | |
| " // put a spacer in here.\n", | |
| " continue;\n", | |
| " }\n", | |
| " var button = $('<button/>');\n", | |
| " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |
| " 'ui-button-icon-only');\n", | |
| " button.attr('role', 'button');\n", | |
| " button.attr('aria-disabled', 'false');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| "\n", | |
| " var icon_img = $('<span/>');\n", | |
| " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |
| " icon_img.addClass(image);\n", | |
| " icon_img.addClass('ui-corner-all');\n", | |
| "\n", | |
| " var tooltip_span = $('<span/>');\n", | |
| " tooltip_span.addClass('ui-button-text');\n", | |
| " tooltip_span.html(tooltip);\n", | |
| "\n", | |
| " button.append(icon_img);\n", | |
| " button.append(tooltip_span);\n", | |
| "\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " var fmt_picker_span = $('<span/>');\n", | |
| "\n", | |
| " var fmt_picker = $('<select/>');\n", | |
| " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |
| " fmt_picker_span.append(fmt_picker);\n", | |
| " nav_element.append(fmt_picker_span);\n", | |
| " this.format_dropdown = fmt_picker[0];\n", | |
| "\n", | |
| " for (var ind in mpl.extensions) {\n", | |
| " var fmt = mpl.extensions[ind];\n", | |
| " var option = $(\n", | |
| " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |
| " fmt_picker.append(option)\n", | |
| " }\n", | |
| "\n", | |
| " // Add hover states to the ui-buttons\n", | |
| " $( \".ui-button\" ).hover(\n", | |
| " function() { $(this).addClass(\"ui-state-hover\");},\n", | |
| " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |
| " );\n", | |
| "\n", | |
| " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |
| " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |
| " // which will in turn request a refresh of the image.\n", | |
| " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_message = function(type, properties) {\n", | |
| " properties['type'] = type;\n", | |
| " properties['figure_id'] = this.id;\n", | |
| " this.ws.send(JSON.stringify(properties));\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_draw_message = function() {\n", | |
| " if (!this.waiting) {\n", | |
| " this.waiting = true;\n", | |
| " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " var format_dropdown = fig.format_dropdown;\n", | |
| " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |
| " fig.ondownload(fig, format);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |
| " var size = msg['size'];\n", | |
| " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |
| " fig._resize_canvas(size[0], size[1]);\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |
| " var x0 = msg['x0'] / mpl.ratio;\n", | |
| " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |
| " var x1 = msg['x1'] / mpl.ratio;\n", | |
| " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |
| " x0 = Math.floor(x0) + 0.5;\n", | |
| " y0 = Math.floor(y0) + 0.5;\n", | |
| " x1 = Math.floor(x1) + 0.5;\n", | |
| " y1 = Math.floor(y1) + 0.5;\n", | |
| " var min_x = Math.min(x0, x1);\n", | |
| " var min_y = Math.min(y0, y1);\n", | |
| " var width = Math.abs(x1 - x0);\n", | |
| " var height = Math.abs(y1 - y0);\n", | |
| "\n", | |
| " fig.rubberband_context.clearRect(\n", | |
| " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| "\n", | |
| " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |
| " // Updates the figure title.\n", | |
| " fig.header.textContent = msg['label'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |
| " var cursor = msg['cursor'];\n", | |
| " switch(cursor)\n", | |
| " {\n", | |
| " case 0:\n", | |
| " cursor = 'pointer';\n", | |
| " break;\n", | |
| " case 1:\n", | |
| " cursor = 'default';\n", | |
| " break;\n", | |
| " case 2:\n", | |
| " cursor = 'crosshair';\n", | |
| " break;\n", | |
| " case 3:\n", | |
| " cursor = 'move';\n", | |
| " break;\n", | |
| " }\n", | |
| " fig.rubberband_canvas.style.cursor = cursor;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |
| " fig.message.textContent = msg['message'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |
| " // Request the server to send over a new figure.\n", | |
| " fig.send_draw_message();\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |
| " fig.image_mode = msg['mode'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Called whenever the canvas gets updated.\n", | |
| " this.send_message(\"ack\", {});\n", | |
| "}\n", | |
| "\n", | |
| "// A function to construct a web socket function for onmessage handling.\n", | |
| "// Called in the figure constructor.\n", | |
| "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |
| " return function socket_on_message(evt) {\n", | |
| " if (evt.data instanceof Blob) {\n", | |
| " /* FIXME: We get \"Resource interpreted as Image but\n", | |
| " * transferred with MIME type text/plain:\" errors on\n", | |
| " * Chrome. But how to set the MIME type? It doesn't seem\n", | |
| " * to be part of the websocket stream */\n", | |
| " evt.data.type = \"image/png\";\n", | |
| "\n", | |
| " /* Free the memory for the previous frames */\n", | |
| " if (fig.imageObj.src) {\n", | |
| " (window.URL || window.webkitURL).revokeObjectURL(\n", | |
| " fig.imageObj.src);\n", | |
| " }\n", | |
| "\n", | |
| " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |
| " evt.data);\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |
| " fig.imageObj.src = evt.data;\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var msg = JSON.parse(evt.data);\n", | |
| " var msg_type = msg['type'];\n", | |
| "\n", | |
| " // Call the \"handle_{type}\" callback, which takes\n", | |
| " // the figure and JSON message as its only arguments.\n", | |
| " try {\n", | |
| " var callback = fig[\"handle_\" + msg_type];\n", | |
| " } catch (e) {\n", | |
| " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " if (callback) {\n", | |
| " try {\n", | |
| " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |
| " callback(fig, msg);\n", | |
| " } catch (e) {\n", | |
| " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |
| " }\n", | |
| " }\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |
| "mpl.findpos = function(e) {\n", | |
| " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |
| " var targ;\n", | |
| " if (!e)\n", | |
| " e = window.event;\n", | |
| " if (e.target)\n", | |
| " targ = e.target;\n", | |
| " else if (e.srcElement)\n", | |
| " targ = e.srcElement;\n", | |
| " if (targ.nodeType == 3) // defeat Safari bug\n", | |
| " targ = targ.parentNode;\n", | |
| "\n", | |
| " // jQuery normalizes the pageX and pageY\n", | |
| " // pageX,Y are the mouse positions relative to the document\n", | |
| " // offset() returns the position of the element relative to the document\n", | |
| " var x = e.pageX - $(targ).offset().left;\n", | |
| " var y = e.pageY - $(targ).offset().top;\n", | |
| "\n", | |
| " return {\"x\": x, \"y\": y};\n", | |
| "};\n", | |
| "\n", | |
| "/*\n", | |
| " * return a copy of an object with only non-object keys\n", | |
| " * we need this to avoid circular references\n", | |
| " * http://stackoverflow.com/a/24161582/3208463\n", | |
| " */\n", | |
| "function simpleKeys (original) {\n", | |
| " return Object.keys(original).reduce(function (obj, key) {\n", | |
| " if (typeof original[key] !== 'object')\n", | |
| " obj[key] = original[key]\n", | |
| " return obj;\n", | |
| " }, {});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |
| " var canvas_pos = mpl.findpos(event)\n", | |
| "\n", | |
| " if (name === 'button_press')\n", | |
| " {\n", | |
| " this.canvas.focus();\n", | |
| " this.canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " var x = canvas_pos.x * mpl.ratio;\n", | |
| " var y = canvas_pos.y * mpl.ratio;\n", | |
| "\n", | |
| " this.send_message(name, {x: x, y: y, button: event.button,\n", | |
| " step: event.step,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| "\n", | |
| " /* This prevents the web browser from automatically changing to\n", | |
| " * the text insertion cursor when the button is pressed. We want\n", | |
| " * to control all of the cursor setting manually through the\n", | |
| " * 'cursor' event from matplotlib */\n", | |
| " event.preventDefault();\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " // Handle any extra behaviour associated with a key event\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.key_event = function(event, name) {\n", | |
| "\n", | |
| " // Prevent repeat events\n", | |
| " if (name == 'key_press')\n", | |
| " {\n", | |
| " if (event.which === this._key)\n", | |
| " return;\n", | |
| " else\n", | |
| " this._key = event.which;\n", | |
| " }\n", | |
| " if (name == 'key_release')\n", | |
| " this._key = null;\n", | |
| "\n", | |
| " var value = '';\n", | |
| " if (event.ctrlKey && event.which != 17)\n", | |
| " value += \"ctrl+\";\n", | |
| " if (event.altKey && event.which != 18)\n", | |
| " value += \"alt+\";\n", | |
| " if (event.shiftKey && event.which != 16)\n", | |
| " value += \"shift+\";\n", | |
| "\n", | |
| " value += 'k';\n", | |
| " value += event.which.toString();\n", | |
| "\n", | |
| " this._key_event_extra(event, name);\n", | |
| "\n", | |
| " this.send_message(name, {key: value,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |
| " if (name == 'download') {\n", | |
| " this.handle_save(this, null);\n", | |
| " } else {\n", | |
| " this.send_message(\"toolbar_button\", {name: name});\n", | |
| " }\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |
| " this.message.textContent = tooltip;\n", | |
| "};\n", | |
| "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |
| "\n", | |
| "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |
| "\n", | |
| "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |
| " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |
| " // object with the appropriate methods. Currently this is a non binary\n", | |
| " // socket, so there is still some room for performance tuning.\n", | |
| " var ws = {};\n", | |
| "\n", | |
| " ws.close = function() {\n", | |
| " comm.close()\n", | |
| " };\n", | |
| " ws.send = function(m) {\n", | |
| " //console.log('sending', m);\n", | |
| " comm.send(m);\n", | |
| " };\n", | |
| " // Register the callback with on_msg.\n", | |
| " comm.on_msg(function(msg) {\n", | |
| " //console.log('receiving', msg['content']['data'], msg);\n", | |
| " // Pass the mpl event to the 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(\"<div id='\" + id + \"'></div>\");\n", | |
| " if (!fig.cell_info) {\n", | |
| " console.error(\"Failed to find cell for figure\", id, fig);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var output_index = fig.cell_info[2]\n", | |
| " var cell = fig.cell_info[0];\n", | |
| "\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |
| " var width = fig.canvas.width/mpl.ratio\n", | |
| " fig.root.unbind('remove')\n", | |
| "\n", | |
| " // Update the output cell to use the data from the current canvas.\n", | |
| " fig.push_to_output();\n", | |
| " var dataURL = fig.canvas.toDataURL();\n", | |
| " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |
| " // the notebook keyboard shortcuts fail.\n", | |
| " IPython.keyboard_manager.enable()\n", | |
| " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |
| " fig.close_ws(fig, msg);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |
| " fig.send_message('closing', msg);\n", | |
| " // fig.ws.close()\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |
| " // Turn the data on the canvas into data in the output cell.\n", | |
| " var width = this.canvas.width/mpl.ratio\n", | |
| " var dataURL = this.canvas.toDataURL();\n", | |
| " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Tell IPython that the notebook contents must change.\n", | |
| " IPython.notebook.set_dirty(true);\n", | |
| " this.send_message(\"ack\", {});\n", | |
| " var fig = this;\n", | |
| " // Wait a second, then push the new image to the DOM so\n", | |
| " // that it is saved nicely (might be nice to debounce this).\n", | |
| " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items){\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) { continue; };\n", | |
| "\n", | |
| " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " // Add the status bar.\n", | |
| " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "\n", | |
| " // Add the close button to the window.\n", | |
| " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |
| " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |
| " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |
| " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |
| " buttongrp.append(button);\n", | |
| " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |
| " titlebar.prepend(buttongrp);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(el){\n", | |
| " var fig = this\n", | |
| " el.on(\"remove\", function(){\n", | |
| "\tfig.close_ws(fig, {});\n", | |
| " });\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |
| " // this is important to make the div 'focusable\n", | |
| " el.attr('tabindex', 0)\n", | |
| " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |
| " // off when our div gets focus\n", | |
| "\n", | |
| " // location in version 3\n", | |
| " if (IPython.notebook.keyboard_manager) {\n", | |
| " IPython.notebook.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| " else {\n", | |
| " // location in version 2\n", | |
| " IPython.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " var manager = IPython.notebook.keyboard_manager;\n", | |
| " if (!manager)\n", | |
| " manager = IPython.keyboard_manager;\n", | |
| "\n", | |
| " // Check for shift+enter\n", | |
| " if (event.shiftKey && event.which == 13) {\n", | |
| " this.canvas_div.blur();\n", | |
| " event.shiftKey = false;\n", | |
| " // Send a \"J\" for go to next cell\n", | |
| " event.which = 74;\n", | |
| " event.keyCode = 74;\n", | |
| " manager.command_mode();\n", | |
| " manager.handle_keydown(event);\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " fig.ondownload(fig, null);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.find_output_cell = function(html_output) {\n", | |
| " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |
| " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |
| " // IPython event is triggered only after the cells have been serialised, which for\n", | |
| " // our purposes (turning an active figure into a static one), is too late.\n", | |
| " var cells = IPython.notebook.get_cells();\n", | |
| " var ncells = cells.length;\n", | |
| " for (var i=0; i<ncells; i++) {\n", | |
| " var cell = cells[i];\n", | |
| " if (cell.cell_type === 'code'){\n", | |
| " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |
| " var data = cell.output_area.outputs[j];\n", | |
| " if (data.data) {\n", | |
| " // IPython >= 3 moved mimebundle to data attribute of output\n", | |
| " data = data.data;\n", | |
| " }\n", | |
| " if (data['text/html'] == html_output) {\n", | |
| " return [cell, data, j];\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "// Register the function which deals with the matplotlib target/channel.\n", | |
| "// The kernel may be null if the page has been refreshed.\n", | |
| "if (IPython.notebook.kernel != null) {\n", | |
| " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |
| "}\n" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.Javascript object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<img src=\"data:image/png;base64,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XnvtNR06dEg7d+6Mfx7U8ePHfX++t956S7/85S914MAB/fa3v9VNN92kK664Qp999lmnHzPT0nFGP72GJ06cUCwWUywWk+d5Wr58uWKxWPxNDQ8//LAqKiri17d9TMr8+fO1b98+rVq1KunHwPjlNUzH+fz0+kldP6Ok+PXXXnutZsyYoVgspr1798bv37lzp3r16qVly5Zp3759qqystPYxMOk43+OPP66XXnpJBw4c0DvvvKPvf//76t27d8I1mdLV823cuFG9evXSqlWrEj7GpqmpKX6Nn34PuoAC2A0rV67U4MGDFYlENGbMGL311lvx+8aPH69Zs2bFf33mzBn927/9m4YOHarevXtr0KBBuvvuuxMW6zc9pg2pPuO0adNUVFSkSCSiAQMGaNq0adq/f38mj5SgK+d77bXXdNVVVykajeqSSy5RRUWFjhw50qXHtCHVZ/TTa1hbW9vuA3E9z4ufadasWRo/fny7rxk1apQikYiGDBmS9IOg/fIapuN8fnr9pO6dMdn1579TXTr3QdDDhw9XJBJRaWmptQ+CTsf5fvzjH8fns7CwULfddlvC5+hlUlfPN378+K+9vo1ffg+6gAIIAADgGAogAACAYyiAAAAAjqEAAgAAOIYCCAAA4BgKIAAAgGMogAAAAI6hAAIAADiGAggAAOAYCiAAAIBjKIAAAACOoQACAAA4hgIIAADgGAogAACAYyiAAAAAjqEAAgAAOIYCCAAA4BgKIAAAgGMogAAAAI6hAAIAADiGAggAAOAYCiAAAIBjKIAAAACOoQACAAA4hgIIAADgGAogAACAYyiAAAAAjqEAAgAAOIYCCAAA4BgKIAAAgGMogAAAAI6hAAIAADjm/wE1Qg9Sz4g+jQAAAABJRU5ErkJggg==\" width=\"640\">" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.HTML object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "c2 = []\n", | |
| "for i in range(nimg):\n", | |
| " res1 = results[i]\n", | |
| " for j in range(i):\n", | |
| " c2.append(chi2(res1, results[j]))\n", | |
| "fig, ax = subplots()\n", | |
| "h,b,_ = ax.hist(c2, 100)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "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 = $('<div/>');\n", | |
| " this._root_extra_style(this.root)\n", | |
| " this.root.attr('style', 'display: inline-block');\n", | |
| "\n", | |
| " $(parent_element).append(this.root);\n", | |
| "\n", | |
| " this._init_header(this);\n", | |
| " this._init_canvas(this);\n", | |
| " this._init_toolbar(this);\n", | |
| "\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " this.waiting = false;\n", | |
| "\n", | |
| " this.ws.onopen = function () {\n", | |
| " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |
| " fig.send_message(\"send_image_mode\", {});\n", | |
| " if (mpl.ratio != 1) {\n", | |
| " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |
| " }\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " }\n", | |
| "\n", | |
| " this.imageObj.onload = function() {\n", | |
| " if (fig.image_mode == 'full') {\n", | |
| " // Full images could contain transparency (where diff images\n", | |
| " // almost always do), so we need to clear the canvas so that\n", | |
| " // there is no ghosting.\n", | |
| " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| " }\n", | |
| " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |
| " };\n", | |
| "\n", | |
| " this.imageObj.onunload = function() {\n", | |
| " 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", | |
| " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |
| " 'ui-helper-clearfix\"/>');\n", | |
| " var titletext = $(\n", | |
| " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |
| " 'text-align: center; padding: 3px;\"/>');\n", | |
| " titlebar.append(titletext)\n", | |
| " this.root.append(titlebar);\n", | |
| " this.header = titletext[0];\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_canvas = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var canvas_div = $('<div/>');\n", | |
| "\n", | |
| " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |
| "\n", | |
| " function canvas_keyboard_event(event) {\n", | |
| " return fig.key_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |
| " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |
| " this.canvas_div = canvas_div\n", | |
| " this._canvas_extra_style(canvas_div)\n", | |
| " this.root.append(canvas_div);\n", | |
| "\n", | |
| " var canvas = $('<canvas/>');\n", | |
| " canvas.addClass('mpl-canvas');\n", | |
| " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |
| "\n", | |
| " this.canvas = canvas[0];\n", | |
| " this.context = canvas[0].getContext(\"2d\");\n", | |
| "\n", | |
| " var backingStore = this.context.backingStorePixelRatio ||\n", | |
| "\tthis.context.webkitBackingStorePixelRatio ||\n", | |
| "\tthis.context.mozBackingStorePixelRatio ||\n", | |
| "\tthis.context.msBackingStorePixelRatio ||\n", | |
| "\tthis.context.oBackingStorePixelRatio ||\n", | |
| "\tthis.context.backingStorePixelRatio || 1;\n", | |
| "\n", | |
| " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |
| "\n", | |
| " var rubberband = $('<canvas/>');\n", | |
| " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |
| "\n", | |
| " var pass_mouse_events = true;\n", | |
| "\n", | |
| " canvas_div.resizable({\n", | |
| " start: function(event, ui) {\n", | |
| " pass_mouse_events = false;\n", | |
| " },\n", | |
| " resize: function(event, ui) {\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " stop: function(event, ui) {\n", | |
| " pass_mouse_events = true;\n", | |
| " fig.request_resize(ui.size.width, ui.size.height);\n", | |
| " },\n", | |
| " });\n", | |
| "\n", | |
| " function mouse_event_fn(event) {\n", | |
| " if (pass_mouse_events)\n", | |
| " return fig.mouse_event(event, event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " rubberband.mousedown('button_press', mouse_event_fn);\n", | |
| " rubberband.mouseup('button_release', mouse_event_fn);\n", | |
| " // Throttle sequential mouse events to 1 every 20ms.\n", | |
| " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |
| "\n", | |
| " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |
| " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |
| "\n", | |
| " canvas_div.on(\"wheel\", function (event) {\n", | |
| " event = event.originalEvent;\n", | |
| " event['data'] = 'scroll'\n", | |
| " if (event.deltaY < 0) {\n", | |
| " event.step = 1;\n", | |
| " } else {\n", | |
| " event.step = -1;\n", | |
| " }\n", | |
| " mouse_event_fn(event);\n", | |
| " });\n", | |
| "\n", | |
| " canvas_div.append(canvas);\n", | |
| " canvas_div.append(rubberband);\n", | |
| "\n", | |
| " this.rubberband = rubberband;\n", | |
| " this.rubberband_canvas = rubberband[0];\n", | |
| " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |
| " this.rubberband_context.strokeStyle = \"#000000\";\n", | |
| "\n", | |
| " this._resize_canvas = function(width, height) {\n", | |
| " // Keep the size of the canvas, canvas container, and rubber band\n", | |
| " // canvas in synch.\n", | |
| " canvas_div.css('width', width)\n", | |
| " canvas_div.css('height', height)\n", | |
| "\n", | |
| " canvas.attr('width', width * mpl.ratio);\n", | |
| " canvas.attr('height', height * mpl.ratio);\n", | |
| " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |
| "\n", | |
| " rubberband.attr('width', width);\n", | |
| " rubberband.attr('height', height);\n", | |
| " }\n", | |
| "\n", | |
| " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |
| " // upon first draw.\n", | |
| " this._resize_canvas(600, 600);\n", | |
| "\n", | |
| " // Disable right mouse context menu.\n", | |
| " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |
| " return false;\n", | |
| " });\n", | |
| "\n", | |
| " function set_focus () {\n", | |
| " canvas.focus();\n", | |
| " canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " window.setTimeout(set_focus, 100);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items) {\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) {\n", | |
| " // put a spacer in here.\n", | |
| " continue;\n", | |
| " }\n", | |
| " var button = $('<button/>');\n", | |
| " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |
| " 'ui-button-icon-only');\n", | |
| " button.attr('role', 'button');\n", | |
| " button.attr('aria-disabled', 'false');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| "\n", | |
| " var icon_img = $('<span/>');\n", | |
| " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |
| " icon_img.addClass(image);\n", | |
| " icon_img.addClass('ui-corner-all');\n", | |
| "\n", | |
| " var tooltip_span = $('<span/>');\n", | |
| " tooltip_span.addClass('ui-button-text');\n", | |
| " tooltip_span.html(tooltip);\n", | |
| "\n", | |
| " button.append(icon_img);\n", | |
| " button.append(tooltip_span);\n", | |
| "\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " var fmt_picker_span = $('<span/>');\n", | |
| "\n", | |
| " var fmt_picker = $('<select/>');\n", | |
| " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |
| " fmt_picker_span.append(fmt_picker);\n", | |
| " nav_element.append(fmt_picker_span);\n", | |
| " this.format_dropdown = fmt_picker[0];\n", | |
| "\n", | |
| " for (var ind in mpl.extensions) {\n", | |
| " var fmt = mpl.extensions[ind];\n", | |
| " var option = $(\n", | |
| " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |
| " fmt_picker.append(option)\n", | |
| " }\n", | |
| "\n", | |
| " // Add hover states to the ui-buttons\n", | |
| " $( \".ui-button\" ).hover(\n", | |
| " function() { $(this).addClass(\"ui-state-hover\");},\n", | |
| " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |
| " );\n", | |
| "\n", | |
| " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |
| " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |
| " // which will in turn request a refresh of the image.\n", | |
| " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_message = function(type, properties) {\n", | |
| " properties['type'] = type;\n", | |
| " properties['figure_id'] = this.id;\n", | |
| " this.ws.send(JSON.stringify(properties));\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.send_draw_message = function() {\n", | |
| " if (!this.waiting) {\n", | |
| " this.waiting = true;\n", | |
| " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " var format_dropdown = fig.format_dropdown;\n", | |
| " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |
| " fig.ondownload(fig, format);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |
| " var size = msg['size'];\n", | |
| " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |
| " fig._resize_canvas(size[0], size[1]);\n", | |
| " fig.send_message(\"refresh\", {});\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |
| " var x0 = msg['x0'] / mpl.ratio;\n", | |
| " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |
| " var x1 = msg['x1'] / mpl.ratio;\n", | |
| " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |
| " x0 = Math.floor(x0) + 0.5;\n", | |
| " y0 = Math.floor(y0) + 0.5;\n", | |
| " x1 = Math.floor(x1) + 0.5;\n", | |
| " y1 = Math.floor(y1) + 0.5;\n", | |
| " var min_x = Math.min(x0, x1);\n", | |
| " var min_y = Math.min(y0, y1);\n", | |
| " var width = Math.abs(x1 - x0);\n", | |
| " var height = Math.abs(y1 - y0);\n", | |
| "\n", | |
| " fig.rubberband_context.clearRect(\n", | |
| " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |
| "\n", | |
| " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |
| " // Updates the figure title.\n", | |
| " fig.header.textContent = msg['label'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |
| " var cursor = msg['cursor'];\n", | |
| " switch(cursor)\n", | |
| " {\n", | |
| " case 0:\n", | |
| " cursor = 'pointer';\n", | |
| " break;\n", | |
| " case 1:\n", | |
| " cursor = 'default';\n", | |
| " break;\n", | |
| " case 2:\n", | |
| " cursor = 'crosshair';\n", | |
| " break;\n", | |
| " case 3:\n", | |
| " cursor = 'move';\n", | |
| " break;\n", | |
| " }\n", | |
| " fig.rubberband_canvas.style.cursor = cursor;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |
| " fig.message.textContent = msg['message'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |
| " // Request the server to send over a new figure.\n", | |
| " fig.send_draw_message();\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |
| " fig.image_mode = msg['mode'];\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Called whenever the canvas gets updated.\n", | |
| " this.send_message(\"ack\", {});\n", | |
| "}\n", | |
| "\n", | |
| "// A function to construct a web socket function for onmessage handling.\n", | |
| "// Called in the figure constructor.\n", | |
| "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |
| " return function socket_on_message(evt) {\n", | |
| " if (evt.data instanceof Blob) {\n", | |
| " /* FIXME: We get \"Resource interpreted as Image but\n", | |
| " * transferred with MIME type text/plain:\" errors on\n", | |
| " * Chrome. But how to set the MIME type? It doesn't seem\n", | |
| " * to be part of the websocket stream */\n", | |
| " evt.data.type = \"image/png\";\n", | |
| "\n", | |
| " /* Free the memory for the previous frames */\n", | |
| " if (fig.imageObj.src) {\n", | |
| " (window.URL || window.webkitURL).revokeObjectURL(\n", | |
| " fig.imageObj.src);\n", | |
| " }\n", | |
| "\n", | |
| " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |
| " evt.data);\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |
| " fig.imageObj.src = evt.data;\n", | |
| " fig.updated_canvas_event();\n", | |
| " fig.waiting = false;\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var msg = JSON.parse(evt.data);\n", | |
| " var msg_type = msg['type'];\n", | |
| "\n", | |
| " // Call the \"handle_{type}\" callback, which takes\n", | |
| " // the figure and JSON message as its only arguments.\n", | |
| " try {\n", | |
| " var callback = fig[\"handle_\" + msg_type];\n", | |
| " } catch (e) {\n", | |
| " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " if (callback) {\n", | |
| " try {\n", | |
| " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |
| " callback(fig, msg);\n", | |
| " } catch (e) {\n", | |
| " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |
| " }\n", | |
| " }\n", | |
| " };\n", | |
| "}\n", | |
| "\n", | |
| "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |
| "mpl.findpos = function(e) {\n", | |
| " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |
| " var targ;\n", | |
| " if (!e)\n", | |
| " e = window.event;\n", | |
| " if (e.target)\n", | |
| " targ = e.target;\n", | |
| " else if (e.srcElement)\n", | |
| " targ = e.srcElement;\n", | |
| " if (targ.nodeType == 3) // defeat Safari bug\n", | |
| " targ = targ.parentNode;\n", | |
| "\n", | |
| " // jQuery normalizes the pageX and pageY\n", | |
| " // pageX,Y are the mouse positions relative to the document\n", | |
| " // offset() returns the position of the element relative to the document\n", | |
| " var x = e.pageX - $(targ).offset().left;\n", | |
| " var y = e.pageY - $(targ).offset().top;\n", | |
| "\n", | |
| " return {\"x\": x, \"y\": y};\n", | |
| "};\n", | |
| "\n", | |
| "/*\n", | |
| " * return a copy of an object with only non-object keys\n", | |
| " * we need this to avoid circular references\n", | |
| " * http://stackoverflow.com/a/24161582/3208463\n", | |
| " */\n", | |
| "function simpleKeys (original) {\n", | |
| " return Object.keys(original).reduce(function (obj, key) {\n", | |
| " if (typeof original[key] !== 'object')\n", | |
| " obj[key] = original[key]\n", | |
| " return obj;\n", | |
| " }, {});\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |
| " var canvas_pos = mpl.findpos(event)\n", | |
| "\n", | |
| " if (name === 'button_press')\n", | |
| " {\n", | |
| " this.canvas.focus();\n", | |
| " this.canvas_div.focus();\n", | |
| " }\n", | |
| "\n", | |
| " var x = canvas_pos.x * mpl.ratio;\n", | |
| " var y = canvas_pos.y * mpl.ratio;\n", | |
| "\n", | |
| " this.send_message(name, {x: x, y: y, button: event.button,\n", | |
| " step: event.step,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| "\n", | |
| " /* This prevents the web browser from automatically changing to\n", | |
| " * the text insertion cursor when the button is pressed. We want\n", | |
| " * to control all of the cursor setting manually through the\n", | |
| " * 'cursor' event from matplotlib */\n", | |
| " event.preventDefault();\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " // Handle any extra behaviour associated with a key event\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.key_event = function(event, name) {\n", | |
| "\n", | |
| " // Prevent repeat events\n", | |
| " if (name == 'key_press')\n", | |
| " {\n", | |
| " if (event.which === this._key)\n", | |
| " return;\n", | |
| " else\n", | |
| " this._key = event.which;\n", | |
| " }\n", | |
| " if (name == 'key_release')\n", | |
| " this._key = null;\n", | |
| "\n", | |
| " var value = '';\n", | |
| " if (event.ctrlKey && event.which != 17)\n", | |
| " value += \"ctrl+\";\n", | |
| " if (event.altKey && event.which != 18)\n", | |
| " value += \"alt+\";\n", | |
| " if (event.shiftKey && event.which != 16)\n", | |
| " value += \"shift+\";\n", | |
| "\n", | |
| " value += 'k';\n", | |
| " value += event.which.toString();\n", | |
| "\n", | |
| " this._key_event_extra(event, name);\n", | |
| "\n", | |
| " this.send_message(name, {key: value,\n", | |
| " guiEvent: simpleKeys(event)});\n", | |
| " return false;\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |
| " if (name == 'download') {\n", | |
| " this.handle_save(this, null);\n", | |
| " } else {\n", | |
| " this.send_message(\"toolbar_button\", {name: name});\n", | |
| " }\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |
| " this.message.textContent = tooltip;\n", | |
| "};\n", | |
| "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |
| "\n", | |
| "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |
| "\n", | |
| "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |
| " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |
| " // object with the appropriate methods. Currently this is a non binary\n", | |
| " // socket, so there is still some room for performance tuning.\n", | |
| " var ws = {};\n", | |
| "\n", | |
| " ws.close = function() {\n", | |
| " comm.close()\n", | |
| " };\n", | |
| " ws.send = function(m) {\n", | |
| " //console.log('sending', m);\n", | |
| " comm.send(m);\n", | |
| " };\n", | |
| " // Register the callback with on_msg.\n", | |
| " comm.on_msg(function(msg) {\n", | |
| " //console.log('receiving', msg['content']['data'], msg);\n", | |
| " // Pass the mpl event to the 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(\"<div id='\" + id + \"'></div>\");\n", | |
| " if (!fig.cell_info) {\n", | |
| " console.error(\"Failed to find cell for figure\", id, fig);\n", | |
| " return;\n", | |
| " }\n", | |
| "\n", | |
| " var output_index = fig.cell_info[2]\n", | |
| " var cell = fig.cell_info[0];\n", | |
| "\n", | |
| "};\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |
| " var width = fig.canvas.width/mpl.ratio\n", | |
| " fig.root.unbind('remove')\n", | |
| "\n", | |
| " // Update the output cell to use the data from the current canvas.\n", | |
| " fig.push_to_output();\n", | |
| " var dataURL = fig.canvas.toDataURL();\n", | |
| " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |
| " // the notebook keyboard shortcuts fail.\n", | |
| " IPython.keyboard_manager.enable()\n", | |
| " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |
| " fig.close_ws(fig, msg);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |
| " fig.send_message('closing', msg);\n", | |
| " // fig.ws.close()\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |
| " // Turn the data on the canvas into data in the output cell.\n", | |
| " var width = this.canvas.width/mpl.ratio\n", | |
| " var dataURL = this.canvas.toDataURL();\n", | |
| " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.updated_canvas_event = function() {\n", | |
| " // Tell IPython that the notebook contents must change.\n", | |
| " IPython.notebook.set_dirty(true);\n", | |
| " this.send_message(\"ack\", {});\n", | |
| " var fig = this;\n", | |
| " // Wait a second, then push the new image to the DOM so\n", | |
| " // that it is saved nicely (might be nice to debounce this).\n", | |
| " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._init_toolbar = function() {\n", | |
| " var fig = this;\n", | |
| "\n", | |
| " var nav_element = $('<div/>')\n", | |
| " nav_element.attr('style', 'width: 100%');\n", | |
| " this.root.append(nav_element);\n", | |
| "\n", | |
| " // Define a callback function for later on.\n", | |
| " function toolbar_event(event) {\n", | |
| " return fig.toolbar_button_onclick(event['data']);\n", | |
| " }\n", | |
| " function toolbar_mouse_event(event) {\n", | |
| " return fig.toolbar_button_onmouseover(event['data']);\n", | |
| " }\n", | |
| "\n", | |
| " for(var toolbar_ind in mpl.toolbar_items){\n", | |
| " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |
| " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |
| " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |
| " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |
| "\n", | |
| " if (!name) { continue; };\n", | |
| "\n", | |
| " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |
| " button.click(method_name, toolbar_event);\n", | |
| " button.mouseover(tooltip, toolbar_mouse_event);\n", | |
| " nav_element.append(button);\n", | |
| " }\n", | |
| "\n", | |
| " // Add the status bar.\n", | |
| " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |
| " nav_element.append(status_bar);\n", | |
| " this.message = status_bar[0];\n", | |
| "\n", | |
| " // Add the close button to the window.\n", | |
| " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |
| " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |
| " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |
| " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |
| " buttongrp.append(button);\n", | |
| " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |
| " titlebar.prepend(buttongrp);\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._root_extra_style = function(el){\n", | |
| " var fig = this\n", | |
| " el.on(\"remove\", function(){\n", | |
| "\tfig.close_ws(fig, {});\n", | |
| " });\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |
| " // this is important to make the div 'focusable\n", | |
| " el.attr('tabindex', 0)\n", | |
| " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |
| " // off when our div gets focus\n", | |
| "\n", | |
| " // location in version 3\n", | |
| " if (IPython.notebook.keyboard_manager) {\n", | |
| " IPython.notebook.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| " else {\n", | |
| " // location in version 2\n", | |
| " IPython.keyboard_manager.register_events(el);\n", | |
| " }\n", | |
| "\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |
| " var manager = IPython.notebook.keyboard_manager;\n", | |
| " if (!manager)\n", | |
| " manager = IPython.keyboard_manager;\n", | |
| "\n", | |
| " // Check for shift+enter\n", | |
| " if (event.shiftKey && event.which == 13) {\n", | |
| " this.canvas_div.blur();\n", | |
| " event.shiftKey = false;\n", | |
| " // Send a \"J\" for go to next cell\n", | |
| " event.which = 74;\n", | |
| " event.keyCode = 74;\n", | |
| " manager.command_mode();\n", | |
| " manager.handle_keydown(event);\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |
| " fig.ondownload(fig, null);\n", | |
| "}\n", | |
| "\n", | |
| "\n", | |
| "mpl.find_output_cell = function(html_output) {\n", | |
| " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |
| " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |
| " // IPython event is triggered only after the cells have been serialised, which for\n", | |
| " // our purposes (turning an active figure into a static one), is too late.\n", | |
| " var cells = IPython.notebook.get_cells();\n", | |
| " var ncells = cells.length;\n", | |
| " for (var i=0; i<ncells; i++) {\n", | |
| " var cell = cells[i];\n", | |
| " if (cell.cell_type === 'code'){\n", | |
| " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |
| " var data = cell.output_area.outputs[j];\n", | |
| " if (data.data) {\n", | |
| " // IPython >= 3 moved mimebundle to data attribute of output\n", | |
| " data = data.data;\n", | |
| " }\n", | |
| " if (data['text/html'] == html_output) {\n", | |
| " return [cell, data, j];\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| " }\n", | |
| "}\n", | |
| "\n", | |
| "// Register the function which deals with the matplotlib target/channel.\n", | |
| "// The kernel may be null if the page has been refreshed.\n", | |
| "if (IPython.notebook.kernel != null) {\n", | |
| " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |
| "}\n" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.Javascript object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<img src=\"data:image/png;base64,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\" width=\"640\">" | |
| ], | |
| "text/plain": [ | |
| "<IPython.core.display.HTML object>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "[<matplotlib.lines.Line2D at 0x7f15e0fd6ba8>]" | |
| ] | |
| }, | |
| "execution_count": 14, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "x_data = 0.5*(b[1:] +b[:-1])\n", | |
| "y_data = h\n", | |
| "fig, ax = subplots()\n", | |
| "ax.plot(x_data, y_data, label=\"data\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "<matplotlib.legend.Legend at 0x7f15d41a2390>" | |
| ] | |
| }, | |
| "execution_count": 15, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "#Let's fit a gaussian to it:\n", | |
| "def gauss(x, center, amplitude, sigma): \n", | |
| " return amplitude*numpy.exp( - (x-center)**2 / (2*sigma*sigma))\n", | |
| "guess = [1, 20000, 0.1]\n", | |
| "ax.plot(x_data, gauss(x_data, *guess), label=\"guess\")\n", | |
| "fig.legend()\n", | |
| "\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 16, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Fitted:\n", | |
| "center= 1.0000307247699545\n", | |
| "amplitude=17816.09484542221\n", | |
| "sigma= 0.044770906714848575\n" | |
| ] | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "<matplotlib.legend.Legend at 0x7f15d41a2128>" | |
| ] | |
| }, | |
| "execution_count": 16, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "from scipy.optimize import curve_fit\n", | |
| "p1, cov = curve_fit(gauss, x_data, y_data, p0=guess)\n", | |
| "print(\"Fitted:\\ncenter= %s\\namplitude=%s\\nsigma= %s\"%tuple(p1))\n", | |
| "ax.plot(x_data, gauss(x_data, *p1), label=\"fitted\")\n", | |
| "fig.legend()" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.5.3" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 1 | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note, this is no more a guinier scatterer