diff --git a/doc/DSSC fine delay with SCS toolbox.ipynb b/doc/DSSC fine delay with SCS toolbox.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..0b40ec3cf8abbbca0a6f153779732cc773b5f42d --- /dev/null +++ b/doc/DSSC fine delay with SCS toolbox.ipynb @@ -0,0 +1,930 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "1bfd1581", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dask: 2.11.0\n", + "/home/lleguy/notebooks/ToolBox/src/toolbox_scs/__init__.py\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "%matplotlib notebook\n", + "import matplotlib.pyplot as plt\n", + "plt.rcParams['figure.constrained_layout.use'] = True\n", + "\n", + "import dask\n", + "print(f'dask: {dask.__version__}')\n", + "\n", + "import toolbox_scs as tb\n", + "print(tb.__file__)\n", + "import toolbox_scs.routines.boz as boz" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "69c17cda", + "metadata": {}, + "outputs": [], + "source": [ + "runs = np.arange(775, 814+1)\n", + "delay = np.arange(4756930, 4756969+1)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b436e44e", + "metadata": {}, + "outputs": [], + "source": [ + "proposal = 2937" + ] + }, + { + "cell_type": "markdown", + "id": "fdec2470", + "metadata": {}, + "source": [ + "use first run as dark" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6d5673f2", + "metadata": {}, + "outputs": [], + "source": [ + "arr_dark, tid_dark = boz.load_dssc_module(proposal, runs[0])\n", + "dark = boz.average_module(arr_dark).compute()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "542d140c", + "metadata": {}, + "outputs": [], + "source": [ + "intensity = np.zeros((len(runs)))\n", + "for k,r in enumerate(runs):\n", + " arr, tid = boz.load_dssc_module(proposal, r)\n", + " data = boz.average_module(arr, dark=dark).compute()\n", + " sensor = data[:,:,:256]\n", + " intensity[k] = sensor.mean(axis=(0,1,2))" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "eab988af", + "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 / mpl.ratio, fig.canvas.height / mpl.ratio);\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", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i<ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code'){\n", + " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdeXjU1aH/8aClWGvrcq+t9/6sB1TUXtFqq63Y1mrpYrXV6hWrbW213lqrrUsXT9gEFxBkcUMobiiKiAiingTCvoQlEAgJYd8TIGwhO1lnPr8/BqZGtmSSyZnl/XqeeVpDSD6PpfBmvjPnmyIAAAAklRTfAwAAANC2CEAAAIAkk1QBGAgEVFhYqNLSUpWVlfHgwYMHDx48eCT8o7S0VIWFhQoEAuEmSqoALCwsVEpKCg8ePHjw4MGDR9I9CgsLw02UVAFYWloa/hfgu8Z58ODBgwcPHjza4nHoCbDS0tJwEyVVAJaVlSklJUVlZWW+pwAAALSJI/UPAQgAAJDACEACEAAAJBkCkAAEAABJhgAkAAEAQJIhAAlAAACQZAhAAhAAACQZApAABAAASYYAJAABAECSIQAJQAAAkGQIQAIQAAAkGQKQAAQAAEmGACQAAQBAkiEACUAAAJBkCEACEAAAJBkCkAAEAABJhgAkAIGYsHFPhaasLFJDIOh7CgAkPAKQAAS82VFyQKPmbtSNL86TsU7GOg2assb3LABIeAQgAQi0qeLKWr29aKu6/2thOPqMdeqUGvrPzr3SVVBc5XsmACQ0ApAABKKuoqZek5YX6u43snRej7RG4dd95EK9vWiriitr9etXF8lYpwfeWeZ7MgAkNAKQAASioqa+QRn5RXpg7DJd2Du9UfTd8MI8jZq7UTtKDjT6Oat3loWfCczaXOxpOQAkPgKQAARaVTAY1JCMtbqk79RG0Xfd4NkaNm2dNu6pOObP7zEpT8Y63fjiPAV4QwgARAUBSAACreqT3B3h6PtO/xl62q1SXmGpgsGmxdzeihp1eTwUj+8vLYjyWgBITt4CcO7cufr5z3+u//qv/1JKSoo+/PDDRj8eDAbVp08fnXXWWTrppJPUrVs3rV+/vtHnFBcX69e//rW+9KUv6dRTT9Uf/vAHVVQc+9mFzyIAgdZTVVuvqwbMCL+bN9Jn8EbN3Shjna54eroqa+pbeSUAwFsApqenq1evXpo0adIRA3DgwIE69dRTNXnyZOXm5uqmm25Sp06dVF1dHf6c66+/Xt/4xje0ePFizZ8/X+eff77uvPPOZu0gAIHW8+zUNTLW6bsDZ6q6riHir1NT36Brnp0lY50GT13bigsBAFKMXAL+bAAGg0GdddZZGjx4cPhjpaWl6tChg8aNGydJWr16tVJSUrR06dLw50yZMkXt2rXTjh07mvy9CUCgdWzZW6nOPUNv9sjIL2rx15uaX8SxMAAQJTEZgJs2bVJKSopycnIafd4111yjhx56SJL0+uuv67TTTmv04/X19TrxxBM1adKko36vmpoalZWVhR+FhYUEINAK7hm9RMY63fV6VpNf73cswWBQd4w6eCzMWI6FAYDWFJMBuGDBAqWkpGjnzp2NPq979+66/fbbJUn9+/fXBRdccNjXOvPMMzVixIijfq++ffsqJSXlsAcBCERu5ppdMtbp/J5px32Xb3Os2lGmjgePhVmyhWNhAKC1JF0A8gwg0Lqq6/79er0B6atb/eunTsyVsU4/f3E+x8IAQCuJyQCM5iXgz+I1gEDLDJ+1QcY6Xfn0dFVE4R27eytqdPHBY2EmZBe2+tcHgGQUkwF46E0gQ4YMCX+srKzsiG8Cyc7ODn9ORkYGbwIB2tCOkgO6qPcUGev04fLtUfs+/5qzMRyZHAsDAC3nLQArKiqUk5OjnJwcpaSkaNiwYcrJydG2bdskhY6BOe200/TRRx8pLy9PN9988xGPgbn88suVlZWlzMxMde7cmWNggDb04NhlMtbptpELWuWNH0dTU9+g7w8KXWYeksGxMADQUt4CcPbs2Ud8M8bvf/97Sf8+CPqrX/2qOnTooG7dumndunWNvkZxcbHuvPNOnXLKKfryl7+se+65h4OggTayYONeGevUKdUpf0dp1L/flJWhY2Eu6JWuwv0cCwMALRETl4B9IgCB5qtvCOgnw+bKWKfeH65sk+8ZDAb1q1ELZazTX95d3ibfEwASFQFIAALN9kbmZhnrdNkTGSqpqm2z75u/ozR8LEz2Vo6FAYBIEYAEINAseytq1KVv6F25Yxdva/Pvbz8IHQtz00scCwMAkSIACUCgWf45YYWMdbrxxXlq8BBge8r/fSzMxGUcCwMAkSAACUCgyXIKSmTsoUuw+73tGDE7dCzMt/tzLAwARIIAJACBJgkEgrrppfky1ulv41d43VJd16DvDZopY52GciwMADQbAUgAAk3y3pJtMtbp4senand59fF/QpSl5+0MHwuzveSA7zkAEFcIQAIQOK7Sqjp988lpMtbp1XmbfM+RFDoW5vZ/LQwfRL2miP8PA0BTEYAEIHBcfT/Kl7FO3YbOUV1DwPecsPwdpercKz38usQ/jcnWqh38fxkAjocAJACBY1pTVKZze6TJWKf56/f6nnOYdbvK9cDYZeHzAY11+uNbS7Vye/TvTgIA8YoAJACBo/r0Zdb73872PeeY1u0q11/eXd4oBO99c4nyCglBAPgsApAABI5qysrQGy0u7B0/99/dsLtcD41brk6fCsF7Ri9RTkGJ72kAEDMIQAIQOKrfv5ElY50GTlnje0qzbdxToUfey2kUgr97PUvLtvk7vxAAYgUBSAACR1RcWavzDr72b8PuCt9zIrZpT4X+Nn5F+HWMxjr99rXFhCCApEYAEoDAEY1dHDr372fPz/M9pVVs2Vupf7z/7xA8r0cabxQBkLQIQAIQOKI7X1kkY51GzN7oe0qr2ravSreOWCBjnQZP5S4iAJITAUgAAofZXVYdfjdtQXF8vPmjOd5fWiBjnW4enul7CgB4QQASgMBhRmdulrFOv3w5MQNpR8kBGevUKdWp9ECd7zkA0OYIQAIQOMyhS6Svzd/se0rUXDdktox1mppf5HsKALQ5ApAABBrZfvDZsY6pTkWl1b7nRE2fyStlrFOfySt9TwGANkcAEoBAI6PmbpSxTrf/a6HvKVE1Nb9IxjpdN2S27ykA0OYIQAIQaOTnL86XsU5vL9rqe0pUlVXXhQ+J3lFywPccAGhTBCABCIRt3lspY53O7ZGmfRU1vudE3S9fzpSxTu8vLfA9BQDaFAFIAAJhL85YH75TRjIYkrFWxjo9PG657ykA0KYIQAIQCPvxsDky1ml8kjwjtmjTPhnr9K2npisYDPqeAwBthgAkAAFJ0tqichnrdH7PtKQ5G6+mvkEX9Z4iY53WFpX7ngMAbYYAJAABSf++HHrvm0t9T2lTv3s9K+HPPASAzyIACUBAwWBQP3h2lox1mpyz3fecNvXK3E0y1ume0Ut8TwGANkMAEoCA8gpLZazThb3TVVlT73tOm1q1o0zGOn29zxTVNQR8zwGANkEAEoCA+qetlrFOD7yzzPeUNhcIBPXNJ6fJWKeszcW+5wBAmyAACUAkuUAgqK4DZshYpykrd/qe48Vf3l0uY52GTlvnewoAtAkCkABEksveWixjnS5+fKqq6xp8z/HivSXbZKzTrSMW+J4CAG2CACQAkeT6fpQvY50efS/H9xRvCvdXhe+AUl6dHEfgAEhuBCABiCTWEAjqW09Nl7FOM9fs8j3Hq0Pvgp6+Krn/PQBIDgQgAYgktmDDXhnrdGm/DNXWJ/c7YHtOypOxTn0/yvc9BQCijgAkAJHEUifmylgn+0Gu7ynepeftlLFOPxo6x/cUAIg6ApAARJKqawjoG09kyFinzA17fc/xrqSqVh1TnYx12lVW7XsOAEQVAUgAIknNWrtbxjp966npaggEfc+JCb94ab6MdZq4rND3FACIKgKQAESSenR8jox1enzySt9TYsbAKWtC74gen7zviAaQHAhAAhBJqLquQRc/PlXGOi3Zwt0vDsk8+KaYb/efrmCQZ0UBJC4CkABEEpqyskjGOl01YIYCXP4Nq65r0AW90mWs04bd5b7nAEDUEIAEIJLQA2OXyVinp90q31Nizm9eXSxjnUZnbvY9BQCihgAkAJFkqmrrdVHvKTLWKbewxPecmDNi9kYZ63Tvm0t9TwGAqCEACUAkmY9W7JCxTtc8O4vXuR1BXmFp+N7I9Q3JfTg2gMRFABKASDL/99ZSGev07NQ1vqfEpIZAMHw+YvbW/b7nAEBUEIAEIJJI6YE6de4ZepPDmiJ+zR/NA++EXiP5woz1vqcAQFQQgAQgksj7SwvCtzvj8u/RjV28TcY6df/XQt9TACAqCEACEEnkrtezeGarCbbtq5KxTuf3TFNlTb3vOQDQ6ghAAhBJoriyVuf2SJOxTpv2VPieE/O+N2imjHWatXa37ykA0OoIQAIQSeKdxVtlrNMNL8zzPSUupE7MlbFOT33CWYkAEg8BSAAiSfxq1EIZ6zRyzkbfU+LCJ7mh43J++txc31MAoNURgAQgkkBpVZ06pToZ61RQXOV7TlworqyVsaF/Z7vLq33PAYBWRQASgEgCLnenjHXqNnSO7ylx5YYX5slYp8k5231PAYBWRQASgEgC/5ywQsY6Pcnr2ZplQNpqGev0j/dX+J4CAK2KACQAkeCCwaC+3X+6jHWat36P7zlxZe66PTLWqeuAGZybCCChEIAEIBLc6p1lMtbpwt7pqq5r8D0nrhyobQjfOYWjcwAkEgKQAESCGzlno4x1uvuNLN9T4tIdoxbJWKcxC7f4ngIArYYAJACR4A4FzOjMzb6nxKXhszbIWKf7xiz1PQUAWg0BSAAigVXU1Ov8nqG7f2zeW+l7TlzKKSiRsU5d+k5VQ4DXAQJIDAQgAYgElpFfJGOdrnl2lu8pcashEFSXvlNlrFNOQYnvOQDQKghAAhAJrOekPBnr1GfySt9T4tp9Y5bKWKfhszb4ngIArYIAJACRoILBoL47cKaMdZqxepfvOXFtzMItMtbpjlGLfE8BgFZBABKASFAb91TIWKfOPdNVWVPve05c2/Spf5cHajlKB0D8IwAJQCSo1+dvlrFOv36VZ61aKhgMquuAGTLWae46DtMGEP8IQAIQCequ17NkrNMrczf5npIQ/vF+6HZ6A9JW+54CAC0WswHY0NCg3r17q2PHjjrppJN07rnn6sknn2x0O6ZgMKg+ffrorLPO0kknnaRu3bpp/fr1zfo+BCASUXVdgy7oFbqDxbpd5b7nJITJOdtlrNPPX5zvewoAtFjMBmD//v31H//xH3LOacuWLZowYYJOOeUUvfDCC+HPGThwoE499VRNnjxZubm5uummm9SpUydVV1c3+fsQgEhEs9fulrFOV3EP21azs/SAjHXqlOpUwWsqAcS5mA3AG2+8UX/4wx8afezWW2/Vb37zG0mhZ//OOussDR48OPzjpaWl6tChg8aNG9fk70MAIhH1+zhfxjrZD3J9T0ko3xsUelf1HF4HCCDOxWwA9u/fX8YYrVu3TpK0YsUKfeUrX9E777wjSdq0aZNSUlKUk5PT6Oddc801euihh476dWtqalRWVhZ+FBYWEoBIONcNmS1jnaas3Ol7SkL52/jQ6wAHT13rewoAtEjMBmAgEJC1Vu3atdPnPvc5tWvXTgMGDAj/+IIFC5SSkqKdOxv/Ade9e3fdfvvtR/26ffv2VUpKymEPAhCJoqC4SsY6ndsjTWXVdb7nJJT3lmyTsU7dRy70PQUAWiRmA3DcuHE6++yzNW7cOOXl5WnMmDE644wz9Oabb0qKPAB5BhCJbsyirURKlGzeWxk+D7C6jvMAAcSvmA3As88+W8OHD2/0saeeekoXXnihpMgvAX8WrwFEorn3TW5bFi3BYFDfemq6jHXK2lzsew4ARCxmA/CMM87QiBEjGn1swIAB6ty5s6R/vwlkyJAh4R8vKyvjTSBIarX1AX29zxQZ67Rye6nvOQnpgXeWyVinl2Y278gpAIglMRuAv//97/X//t//Cx8DM2nSJP3nf/6nHnvssfDnDBw4UKeddpo++ugj5eXl6eabb+YYGCS1BRv3ylinbz01XYEAx79Ew5sLQvcFvuv1LN9TACBiMRuA5eXlevjhh3XOOeeED4Lu1auXamtrw59z6CDor371q+rQoYO6desWftdwUxGASCQD0lbLWKdHx+cc/5MRkVU7ymSs0//0maL6hoDvOQAQkZgNwLZCACKR/PS5uTLWaXLOdt9TElZDIKhL+k6VsU65hSW+5wBARAhAAhAJoqi0WsY6dUx1Kq6sPf5PQMTuGb1Exjq9Oo/7LAOITwQgAYgEMX5JgYx1uml4pu8pCW/knI0y1umPby31PQUAIkIAEoBIEIfenTpsWvNeB4vmW7Ztv4x1uuyJDO61DCAuEYAEIBJAfUMg/Lq0Zdv2+56T8GrrA7qwd7qMdVq/q9z3HABoNgKQAEQCWLqlWMY6XdovQw0c/9Im7nxlkYx1envRVt9TAKDZCEACEAlgSMZaGev04NhlvqckjWHT1slYp4fGLfc9BQCajQAkAJEAfvHSfBnr9P7SAt9TksaCDaFDt68aMIPXAQKIOwQgAYg4t7eiRsY6Geu0u6zpd8FByxyobdB5PdJkrFNBcZXvOQDQLAQgAYg4N2l5oYx1+tnz83xPSTq/fDlTxjp9kF3oewoANAsBSAAizj08brmMdRo4ZY3vKUlnQHro1nuPTcj1PQUAmoUAJAARxwKBoC5/cpqMdVq0aZ/vOUlnxupdMtbpusGzfU8BgGYhAAlAxLHcwhIZ63Tx41NV1xDwPSfplFbVqWPqwddflvP6SwDxgwAkABHHXpyxXsY63TeGW5L5cv3z82SsU1reTt9TAKDJCEACEHHs1hELZKzT2MXbfE9JWo9PXiljnfp+lO97CgA0GQFIACJOlVbVqdPBy4+F+zmGxBeXu5N3YQOIOwQgAYg4dSg8ug2d43tKUttdXi1jnTqmOpUeqPM9BwCahAAkABGn/jlhhYx1euqTVb6nJL1rB8+WsU4z1+zyPQUAmoQAJAARh4LBoL7df7qMdZq3fo/vOUnvsQm5MtbpmXTOYgQQHwhAAhBxaPXOMhnrdGHvdFXXNfiek/QmZIfuxnLLy5m+pwBAkxCABCDi0Mg5G2Ws091vZPmeAkkFxVUy1un8nmk6UEuQA4h9BCABiDh0x6hFMtZpdOZm31Og0CX57/SfIWOdFmzc63sOABwXAUgAIs5U1NTr/J5pMtZpy95K33Nw0F/fDd2T+bnp63xPAYDjIgAJQMSZqflFMtbpmmdn+Z6CT3l70VYZ6/TrVxf5ngIAx0UAEoCIM4+Oz+HOEzFo3a5yGet0Ue8p3JcZQMwjAAlAxJG6hoAu6TtVxjot3rTP9xx8SiAQ1GVPZMhYp+Xb9vueAwDHRAASgIgj89bvkbFO33xymhoCQd9z8Bn/99ZSGev0rzkbfU8BgGMiAAlAxJGek/JkrFPqxFzfU3AEr87bJGOd/jB6ie8pAHBMBCABiDjREAjqW0+F7v4xZx13/4hFuYUlMtbpkr5TFeAZWgAxjAAkABEnlm4plrFOXfpOVW09bzKIRfUNAf1Pnyky1mn1Tn5PARC7CEACEHHiqU9WyVinR97L8T0Fx/Db1xbLWKe3Fm7xPQUAjooAJAARB4LBoL47cKaMdZqyssj3HBzDizPWy1inB8Yu8z0FAI6KACQAEQdWbi+VsU4X9k7nXrMxbvGmfTLW6YqnpysY5HWAAGITAUgAIg4MyVgrY53+NCbb9xQcR3Vdgzr3TOdWfQBiGgFIACIO/GjoHBnr9OHy7b6noAluG7lAxjqNX1LgewoAHBEBSAAixm3YXSFjnc7vmabSA3W+56AJnp26RsY6/f39Fb6nAMAREYAEIGLc8FkbZKzT717P8j0FTTR77W4Z6/T9QbN8TwGAIyIACUDEuJ+/OF/GOr2btc33FDRReXWdOqU6GetUVFrtew4AHIYAJAARwwr3V8lYp06pTnsranzPQTMcCvePVuzwPQUADkMAEoCIYa/N3yxjnW7/10LfU9BMT3wcOri714d5vqcAwGEIQAIQMaz7yIUy1umNzM2+p6CZpqwskrFOPxk21/cUADgMAUgAIkbtKa9Rx4OvI9tRcsD3HDTTvooaGRv6329/Za3vOQDQCAFIACJGjV28TcY63fTSfN9TEKFuB89vnLZql+8pANAIAUgAIkbd9XqWjHV6efYG31MQoR6T8mSs09Nule8pANAIAUgAIgaVHqjTeT3SZKzTpj0VvucgQh8u386zuABiEgFIACIGTVpeKGOdfjxsju8paIEdJQdkrNO5PdJUWVPvew4AhBGABCBi0B/fWipjnYZmrPU9BS101YAZMtZp6ZZi31MAIIwAJAARY6pq63VBr3QZ65S/o9T3HLTQ798IvZbzncVbfU8BgDACkABEjEnP2xm+j2wwGPQ9By00IG21jHV6fPJK31MAIIwAJAARYx4at1zGOvVPW+17ClrBxGWh13P+ahR3cwEQOwhAAhAxpKa+QV0enypjnbK37vc9B61g5fZSGet02RMZPKMLIGYQgAQgYsistbtlrNOVT09XIEAsJILqugZ1OnhHl93l1b7nAIAkApAAREyxH+TKWKfeH/J6sURy3eDZMtZp/vq9vqcAgCQCkABEzGgIBHX5k9NkrFPmBkIhkfxpTLaMdXpt/mbfUwBAEgFIACJmLNq0T8Y6feOJDNU1BHzPQSsaOm2djHV6bEKu7ykAIIkAJAARM/p+lC9jnf7+/grfU9DK0g4e7XPT8EzfUwBAEgFIACImBIPB8B0jpq/a5XsOWtmG3RUy1unrfabw5h4AMYEAJAARA3IKSmSs0//0maLqugbfc9DK6hsC6twzdHeXguIq33MAgAAkABELnklfI2OdHhy7zPcURMn1z8/jGV4AMYMAJADhWTAY1A+enSVjnT7J3eF7DqLk4YN3eBk+a4PvKQBAABKA8G1tUbmMdercK10VNfW+5yBKRszeKGOd/vruct9TAIAAJADh2/PT18tYp3vfXOJ7CqJo5ppdMtbpp8/N9T0FAAhAAhC+HXpt2PtLC3xPQRQV7q+SsU7n90zjnEcA3hGABCA82rqvUsY6ndsjTfsra33PQRQFg0H9T58pMtZp/a5y33MAJDkCkACER6Pmhl4X9utXF/megjbwy5czebMPgJgQ0wG4fft2/eY3v9EZZ5yhk046SV26dNHSpUvDPx4MBtWnTx+dddZZOumkk9StWzetX7++Wd+DAIQPgUBQozM366LeoWeE3lq4xfcktIHUibky1mlIxlrfUwAkuZgNwP3798sYo7vvvltZWVnavHmzMjIytHHjxvDnDBw4UKeeeqomT56s3Nxc3XTTTerUqZOqq6ub/H0IQLS1TXsqdNvIBTLWyVinX41aqAO1HP6cDN7I3Cxjnf741tLjfzIARFGLAnDx4sU6/fTTNWvWrFYfZq3V9773vaP+eDAY1FlnnaXBgweHP1ZaWqoOHTpo3LhxTf4+BCDaSkMgqH/N2agLeqWH7/oxZtFWbg2WRBZs2CtjnX7wbOv/ngkAzdGiALz//vv1+c9/XnfddVerD/v617+uRx55RLfddpvOPPNMXXbZZXrllVfCP75p0yalpKQoJyen0c+75ppr9NBDDzX5+xCAaAvrdpXrpuGZ4Wf9fvvaYhXu55ZgyWZvRY2MdeqY6njWF4BXEQdgTU2NzjjjDA0aNEhf/OIXVVFR0arDOnTooA4dOqhHjx5avny5Ro0apZNOOklvvvmmJGnBggVKSUnRzp07G/287t276/bbbz/m7rKysvCjsLCQAETU1DUE9OKM9Tq/Z5qMderSd6rGLylQMMizfsnqm09Ok7FOeYWlvqcASGIRB+D48eN1zjnnKBgM6uKLL9bo0aNbdVj79u3VtWvXRh/761//qquuukpS5AHYt29fpaSkHPYgANHa8neU6mcHz/gz1ukPo5eoqLTpr09FYrpj1CIZ6zQhu9D3FABJLOIAvOGGG9SjRw9J0jPPPKNrrrmmVYedc845uvfeext9bMSIEfrv//5vSZFfAuYZQERbTX2DhmSs1Xk9Qs/6feOJDH24fDvP+kGS1PejfBnr9LRb5XsKgCQWUQAWFRWpffv2Wrs2dJRBQUGBTjzxRG3evLnVht15552HvQnkkUceCT8reOhNIEOGDAn/eFlZGW8CgVc5BSX68bA54Wf9/vxOtvaU1/iehRjybtY2Get01+tZvqcASGIRBeDgwYN15ZVXNvrYD3/4Q/Xr16/Vhi1ZskSf+9zn1L9/f23YsEFjx47VySefrHfeeSf8OQMHDtRpp52mjz76SHl5ebr55ps5BgbeDM1Yq06pofD71lPTlJa38/g/CUkne+t+Gev0nf4zfE8BkMQiCsAuXbropZdeavSx0aNH69xzz23VcZ988om6dOmiDh066KKLLmr0LmDp3wdBf/WrX1WHDh3UrVs3rVu3rlnfgwBEa1i+bX/4Wb+Hxy1XMbd1w1GUV9eFf62UVtX5ngMgSTU7AAsKCnTddddp3759jT5eUVER0Z04fCMA0RpGzgnd0u3eNzngF8d39TMzZazTki3FvqcASFIxeyeQtkIAojXc++ZSGev0ytxNvqcgDtwzeomMdRqzaKvvKQCSVEQBuGlT4vwhRwCipYLBoC4/eLbbsm37fc9BHHgmfY2Mder94UrfUwAkqYgCsF27drr22mv19ttvN+sNF7GIAERLbdxTIWOdLuiVrtr6gO85iAOTlhfKWKfu/1roewqAJBVRAObk5Oihhx7SmWeeqVNPPVX33XefsrLi80gDAhAtNX5JQegP85H8YY6myd9RGj4jkvMhAfjQotcA1tfXa+LEifrFL36h9u3b6+KLL9bQoUO1Z8+eqIyNBgIQLfXYhFwZ6/RM+hrfUxAnqusadO7Bg8J3l8X3VRQA8alV3gRSU1OjYcOGqUOHDmrXrp06dOigu+6667DbtMUiAhAt9cMhs2Ws0/RVu3xPQRw59Otm7lajC2YAACAASURBVLr4+QszgMTRogBcunSp/vznP+v000/X2WefrV69emnz5s2aN2+eunXrdthh0bGIAERL7K+sDZ/ptp+z/9AMf34nW8Y6vTovcd5UByB+RBSAQ4cOVZcuXdS+fXvdfPPN+uSTTxQINH7xe2FhoU488cTWX9zKCEC0xPRVu2Ss0w+HzPY9BXHmuenrZKzTP95f4XsKgCQUUQCef/75GjBgwDEv8dbW1urNN99snZVRRACiJQ4d5/HYhFzfUxBn0vN2ylinm16a73sKgCQUUQBu2bLlsGf8pNB5aNu2bWvdhVFGAKIlbhu5QMY6jV9a4HsK4syh44Mu6j1FgQDvBAbQtiIKwBNOOEG7d+8+7OP79u3TCSec0LoLo4wARKRq6hvUuVe6jHXatKfC9xzEmYZAMPzrZ+u+St9zACSZiA+CPlIAbt26VSeffHLrLowyAhCRWrZtv4x1uvzJaZzlhojc8MI8GeuUkV/kewqAJNOsAHz00Uf16KOP6oQTTtCf/vSn8D8/+uijeuihh/Sd73xHV199dZsMby0EICL1ytxNMtbp3jeX+p6COPXoezky1umlmet9TwGQZJoVgNdee62uvfZatWvXTldffXX4n6+99lr95Cc/0X333af16+PrNzICEJG6b8xSGes0cs5G31MQp0bO2Shjnf7y7nLfUwAkmYguAd99990JE0wEICIRDAb1raemyVinpVuKfc9BnJq1ZreMdfrJsLm+pwBIMq1yJ5B4RgAiElv2VspYp84901Vd1+B7DuLU9pIDMtbpvB5pqq0//GQFAIiWJgfgLbfcEv6kW2655ZiPeEIAIhITsgtlrNOtIxb4noI4FgwG1eXxqTLWaW1Rue85AJJIkwPw7rvvVnl5efi/H+sRTwhARCJ1Yq6MdRqQttr3FMS5W0eEzpL8aMUO31MAJBEuAROAiMCPh82RsU5TOb4DLZQ6MU/GOg2eutb3FABJJKIAPHDggKqqqsL/vHXrVj333HPKyMiIzsooIgDRXKVVdTLWyVinvRU1vucgzo3O3Cxjnf7vLY4TAtB2IgrAH//4xxo5cqQkqaSkRF/5yld09tln66STTtKIESOitzYKCEA016F3bl47eLbvKUgACzbulbFO3x80y/cUAEkkogD8j//4D+Xn50uSXn31VV166aUKBAJ6//33ddFFF0VvbRQQgGiuZ6eukbFOf39/he8pSAD7KmrCzyhX1db7ngMgSUQUgF/4whe0bds2SVL37t3Vr18/SVJBQYG+8IUvRGlqdBCAaK7b/7VQxjqNy9rmewoSxLeemi5jnVYUlPieAiBJRBSAl1xyiV544QUVFBToy1/+shYuXChJys7O1le/+tXorY0CAhDNUdcQ0IW902Ws04bdHNuB1vHrVxfJWKfxSwt8TwGQJCIKwAkTJqh9+/Y64YQT9OMf/zj88QEDBuj666+PztIoIQDRHCsKSmSs0zeeyFAgEPQ9Bwmi38f5MtbpqU9W+Z4CIElEfAxMUVGRli9frkDg36fXZ2Vlac2aNa2/MooIQDTHa/ND79i8Z/QS31OQQMZlbZOxTr99bbHvKQCSBOcAEoBohj+/ky1jnYbP2uB7ChLI8m37ZazTlU9P9z0FQJKIKAArKyvVu3dvde3aVeedd546derU6BFPCEA0VTAY1JVPh16sv3jTPt9zkEAqaurD7wTeX1nrew6AJBBRAN5xxx36r//6Lz322GN67rnn9Pzzzzd6xBMCEE1VUFwlY53O75mm6roG33OQYL47cCZ/uQDQZiIKwFNPPVWZmZlRHdZWCEA01aTlhTLW6ebhifFrH7HlD6OXyFinMQu3+J4CIAlEFIAdO3bU6tWrozqsrRCAaKqek/J4pyaiZuCU0AHjPSfl+Z4CIAlEFIBvv/22brvttkb3A45XBCCa6qfPzZWxTlNW7vQ9BQnow+XbZazTbSMX+J4CIAlEFICXXXaZvvSlL+mUU05Rly5ddPnllzd6xBMCEE1RVl2njqmhF+nvLq/2PQcJaPXOMhnrdEnfqQoGOWMSQHRFFID9+vU75iOeEIBoijnr9shYp+8PmuV7ChJUTX2Dzu2RJmOdikr5SwaA6OIcQAIQTTA0Y62MdXr0vRzfU5DAug2dI2Od5qzb43sKgAQXcQCWlJTo1VdfVWpqqoqLiyVJy5Yt0/bt26OzNEoIQDTFna+E7tX6zuKtvqcggT3wzjIZ6zRq7kbfUwAkuIgCMDc3V2eeeabOP/98fe5zn9OmTZskSb169dJdd90VvbVRQADieOobAvp6nyky1mltUbnvOUhgz09fL2Od/jZ+he8pABJcRAHYrVs3/fOf/5QknXLKKeEAXLBggYwx0VkaJQQgjmfl9tLwi/MDAV6cj+iZsrJIxjr9/MX5vqcASHARBeCXv/xlbdwYukTx6QDcunWrOnToEKWp0UEA4nhGZ26WsU6/fyPL9xQkuM17K2Ws04W909XAXzYARFFEAXjmmWdq+fLlkhoH4LRp03T22WdHaWp0EIA4ngfHhl6X9eKM9b6nIME1BIK6oFe6jHXasrfS9xwACSyiALz33nv1y1/+UnV1dTrllFO0efNmbdu2TZdffrkefvjhqA5ubQQgjueqATNkrNOCjXt9T0ESuPHFeTLWaWp+ke8pABJYRAFYWlqqH/3oRzrttNN04okn6mtf+5rat2+va665RpWV8fW3VgIQx7K95ICMdTq3R5qqaut9z0ESeHR8jox1eoFnnAFEUYvOAczMzNTLL7+sQYMGafr06VEZGG0EII5lck7o9ly/eIkX5aNtjJq7UcY6PTB2me8pABJYRAH41ltvqaam5rCP19bW6q233mrdhVFGAOJY+kxeKWOd+n2c73sKksTstbtlrNOPhs7xPQVAAosoAE844QTt3r37sI/v27dPJ5xwQusujDICEMdywwuh12O53J2+pyBJ7CwNvezgvB5pqqlv8D0HQIKKKADbtWunPXsOv1XRihUrdPrpp7fuwigjAHE0FTX16pTquDcr2lQwGFSXvlNlrNOaIn5fAhAdzQrAyy67TJdffrlOOOEEXXLJJbr88svDj0svvVRf+tKX1L179zYZ3loIQBzN/PV7ZazT1c/M9D0FSeZ/RyyQsU6Tc+Lr1poA4kezArBfv37q16+f2rVrp3/84x/hf+7Xr58GDBigd999V7W1tW0yvLUQgDia56avk7FOD41b7nsKkkzPSXky1mlA+mrfUwAkqIguAb/55puqrk6MS2IEII7mt68tlrFOYxZu8T0FSWbS8kIZ69Rt6BwFg9wRBEDra9ExMLW1tSosLNS2bdsaPeIJAYgjaQgEdfHjoddhrdrBrw20rfLqOnU+eEeQtUXlvucASEARBeD69ev1ve99TyeccEKjR7t27XgXMBLCqh1lMtap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\" width=\"640\">" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Text(0, 0.5, '<intensity>')" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plt.figure()\n", + "plt.plot(delay-delay[0], intensity)\n", + "plt.xlabel(f'delay - {delay[0]}')\n", + "plt.ylabel('<intensity>')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "369b3289", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "xfel (Python 3.7)", + "language": "python", + "name": "xfel" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/changelog.rst b/doc/changelog.rst index 2fd0653230967e25621eb0ae056148ddccb89a58..49da25044d5f58c398e1047ae4b253fcd15a2ad8 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -18,6 +18,7 @@ unreleased - update version GATT-related mnemonics, add `transmission_col2` :mr:`172` - reorganize the Howto section :mr:`169` - improve SLURM scripts with named arguments :mr:`176` + - adds notebook for DSSC fine timing analysis - **New Features** - add routine for fluence calibration :mr:`180` diff --git a/doc/howtos.rst b/doc/howtos.rst index 5ce280acfa51e2fa0e230cf5f3a9aa0006a61753..c72f34ed989a3c43a52eb2e4d3931428b93dba2f 100644 --- a/doc/howtos.rst +++ b/doc/howtos.rst @@ -79,6 +79,14 @@ hexagonal pixel shape information from the DSSC geometry to split the intensity in a pixel in the bins covered by it. An example notebook :doc:`Azimuthal integration of DSSC with pyFAI <Azimuthal integration of DSSC with pyFAI>` is available. +DSSC fine timing +################ + +When DSSC is reused after a period of inactivity or when the DSSC gain setting +use a different operation frequency the DSSC fine trigger delay needs to be +checked. To analysis runs recorded with different fine delay, one can use +the notebook :doc:`DSSC fine delay with SCS toolbox.ipynb <DSSC fine delay with SCS toolbox>`. + Legacy DSSC binning procedure #############################