From eff7d14ee6a6c19394b93afbec2ad2dd70930e1a Mon Sep 17 00:00:00 2001 From: Laurent Mercadier <laurent.mercadier@xfel.eu> Date: Tue, 27 Apr 2021 17:28:56 +0200 Subject: [PATCH] Simplified calibrate_xgm(), removed unused XGM functions, moved TIM functions in digitizer, removed tim.py --- doc/Loading_data_in_memory.ipynb | 1011 +++ doc/bunch_pattern_decoding.rst | 29 +- doc/conf.py | 7 +- doc/howtos.rst | 15 +- doc/load.rst | 12 +- doc/point_detectors/point_detectors.rst | 1 + doc/requirements.txt | 3 +- ...fe edge scan and fluence calculation.ipynb | 7535 +---------------- ... and XMCD energy shift investigation.ipynb | 343 + notebook_examples/tim-normalization.ipynb | 72 +- src/toolbox_scs/__init__.py | 4 +- src/toolbox_scs/constants.py | 714 +- src/toolbox_scs/detectors/__init__.py | 37 +- src/toolbox_scs/detectors/bam_detectors.py | 109 + src/toolbox_scs/detectors/digitizers.py | 1053 +++ src/toolbox_scs/detectors/dssc.py | 4 +- src/toolbox_scs/detectors/dssc_misc.py | 79 +- src/toolbox_scs/detectors/tim.py | 54 - src/toolbox_scs/detectors/xgm.py | 1256 +-- src/toolbox_scs/load.py | 279 +- src/toolbox_scs/misc/__init__.py | 9 +- src/toolbox_scs/misc/bunch_pattern.py | 48 - .../misc/bunch_pattern_external.py | 35 +- src/toolbox_scs/routines/XAS.py | 97 +- src/toolbox_scs/routines/__init__.py | 29 + src/toolbox_scs/routines/knife_edge.py | 133 +- src/toolbox_scs/test/test_top_level.py | 14 +- 27 files changed, 3717 insertions(+), 9265 deletions(-) create mode 100644 doc/Loading_data_in_memory.ipynb create mode 100644 doc/point_detectors/point_detectors.rst create mode 100644 notebook_examples/XAS and XMCD energy shift investigation.ipynb create mode 100644 src/toolbox_scs/detectors/bam_detectors.py create mode 100644 src/toolbox_scs/detectors/digitizers.py delete mode 100644 src/toolbox_scs/detectors/tim.py diff --git a/doc/Loading_data_in_memory.ipynb b/doc/Loading_data_in_memory.ipynb new file mode 100644 index 0000000..b553347 --- /dev/null +++ b/doc/Loading_data_in_memory.ipynb @@ -0,0 +1,1011 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Loading data in memory with the SCS ToolBox" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ToolBox mnemonics" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Within the framework of the [extra_data](https://extra-data.readthedocs.io/en/latest/) package, which the SCS ToolBox is built upon, the European XFEL data is organized in a hierachical structure, in which a *source* (for instance, a motor, or the output of a digitizer) contains a few datasets, accessed with a *key* (the actual position of the motor, the various channels of the digitizer). The ToolBox *mnemonics* are simple words that represent frequently used variables at the SCS instrument. Each menmonic is associated with a dictionnary containing the source, the key and the dimension names of the variable.\n", + "\n", + "The mnemonics are stored in a dictionnary, accessible as `toolbox_scs.mnemonics`. Let us read the content of the mnemonic `SCS_SA3`, which corresponds to the pulse energy of the SASE 3 pulses measured by the XGM in the SCS experiment hutch:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'source': 'SCS_BLU_XGM/XGM/DOOCS:output',\n", + " 'key': 'data.intensityTD',\n", + " 'dim': ['XGMbunchId']}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import toolbox_scs as tb\n", + "tb.mnemonics['SCS_XGM']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The available mnemonics can be display with: `print(list(tb.mnemonics.keys()))`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The `load` function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `load` function of the ToolBox loads the variables recorded in a run into memory. Given a proposal number and a run number, the function in its simplest form takes a list of mnemonics as the `fields` argument. The data associated to the mnemonics is loaded and all variables are aligned by train Id and pulse Id.\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n", + "<defs>\n", + "<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n", + "<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n", + "<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n", + "<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n", + "</symbol>\n", + "<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n", + "<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n", + "<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "</symbol>\n", + "</defs>\n", + "</svg>\n", + "<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n", + " *\n", + " */\n", + "\n", + ":root {\n", + " --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n", + " --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n", + " --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n", + " --xr-border-color: var(--jp-border-color2, #e0e0e0);\n", + " --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n", + " --xr-background-color: var(--jp-layout-color0, white);\n", + " --xr-background-color-row-even: var(--jp-layout-color1, white);\n", + " --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n", + "}\n", + "\n", + "html[theme=dark],\n", + "body.vscode-dark {\n", + " --xr-font-color0: rgba(255, 255, 255, 1);\n", + " --xr-font-color2: rgba(255, 255, 255, 0.54);\n", + " --xr-font-color3: rgba(255, 255, 255, 0.38);\n", + " --xr-border-color: #1F1F1F;\n", + " --xr-disabled-color: #515151;\n", + " --xr-background-color: #111111;\n", + " --xr-background-color-row-even: #111111;\n", + " --xr-background-color-row-odd: #313131;\n", + "}\n", + "\n", + ".xr-wrap {\n", + " display: block;\n", + " min-width: 300px;\n", + " max-width: 700px;\n", + "}\n", + "\n", + ".xr-text-repr-fallback {\n", + " /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n", + " display: none;\n", + "}\n", + "\n", + ".xr-header {\n", + " padding-top: 6px;\n", + " padding-bottom: 6px;\n", + " margin-bottom: 4px;\n", + " border-bottom: solid 1px var(--xr-border-color);\n", + "}\n", + "\n", + ".xr-header > div,\n", + ".xr-header > ul {\n", + " display: inline;\n", + " margin-top: 0;\n", + " margin-bottom: 0;\n", + "}\n", + "\n", + ".xr-obj-type,\n", + ".xr-array-name {\n", + " margin-left: 2px;\n", + " margin-right: 10px;\n", + "}\n", + "\n", + ".xr-obj-type {\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-sections {\n", + " padding-left: 0 !important;\n", + " display: grid;\n", + " grid-template-columns: 150px auto auto 1fr 20px 20px;\n", + "}\n", + "\n", + ".xr-section-item {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-section-item input {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-section-item input + label {\n", + " color: var(--xr-disabled-color);\n", + "}\n", + "\n", + ".xr-section-item input:enabled + label {\n", + " cursor: pointer;\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-section-item input:enabled + label:hover {\n", + " color: var(--xr-font-color0);\n", + "}\n", + "\n", + ".xr-section-summary {\n", + " grid-column: 1;\n", + " color: var(--xr-font-color2);\n", + " font-weight: 500;\n", + "}\n", + "\n", + ".xr-section-summary > span {\n", + " display: inline-block;\n", + " padding-left: 0.5em;\n", + "}\n", + "\n", + ".xr-section-summary-in:disabled + label {\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-section-summary-in + label:before {\n", + " display: inline-block;\n", + " content: '►';\n", + " font-size: 11px;\n", + " width: 15px;\n", + " text-align: center;\n", + "}\n", + "\n", + ".xr-section-summary-in:disabled + label:before {\n", + " color: var(--xr-disabled-color);\n", + "}\n", + "\n", + ".xr-section-summary-in:checked + label:before {\n", + " content: '▼';\n", + "}\n", + "\n", + ".xr-section-summary-in:checked + label > span {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-section-summary,\n", + ".xr-section-inline-details {\n", + " padding-top: 4px;\n", + " padding-bottom: 4px;\n", + "}\n", + "\n", + ".xr-section-inline-details {\n", + " grid-column: 2 / -1;\n", + "}\n", + "\n", + ".xr-section-details {\n", + " display: none;\n", + " grid-column: 1 / -1;\n", + " margin-bottom: 5px;\n", + "}\n", + "\n", + ".xr-section-summary-in:checked ~ .xr-section-details {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-array-wrap {\n", + " grid-column: 1 / -1;\n", + " display: grid;\n", + " grid-template-columns: 20px auto;\n", + "}\n", + "\n", + ".xr-array-wrap > label {\n", + " grid-column: 1;\n", + " vertical-align: top;\n", + "}\n", + "\n", + ".xr-preview {\n", + " color: var(--xr-font-color3);\n", + "}\n", + "\n", + ".xr-array-preview,\n", + ".xr-array-data {\n", + " padding: 0 5px !important;\n", + " grid-column: 2;\n", + "}\n", + "\n", + ".xr-array-data,\n", + ".xr-array-in:checked ~ .xr-array-preview {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-array-in:checked ~ .xr-array-data,\n", + ".xr-array-preview {\n", + " display: inline-block;\n", + "}\n", + "\n", + ".xr-dim-list {\n", + " display: inline-block !important;\n", + " list-style: none;\n", + " padding: 0 !important;\n", + " margin: 0;\n", + "}\n", + "\n", + ".xr-dim-list li {\n", + " display: inline-block;\n", + " padding: 0;\n", + " margin: 0;\n", + "}\n", + "\n", + ".xr-dim-list:before {\n", + " content: '(';\n", + "}\n", + "\n", + ".xr-dim-list:after {\n", + " content: ')';\n", + "}\n", + "\n", + ".xr-dim-list li:not(:last-child):after {\n", + " content: ',';\n", + " padding-right: 5px;\n", + "}\n", + "\n", + ".xr-has-index {\n", + " font-weight: bold;\n", + "}\n", + "\n", + ".xr-var-list,\n", + ".xr-var-item {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-var-item > div,\n", + ".xr-var-item label,\n", + ".xr-var-item > .xr-var-name span {\n", + " background-color: var(--xr-background-color-row-even);\n", + " margin-bottom: 0;\n", + "}\n", + "\n", + ".xr-var-item > .xr-var-name:hover span {\n", + " padding-right: 5px;\n", + "}\n", + "\n", + ".xr-var-list > li:nth-child(odd) > div,\n", + ".xr-var-list > li:nth-child(odd) > label,\n", + ".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n", + " background-color: var(--xr-background-color-row-odd);\n", + "}\n", + "\n", + ".xr-var-name {\n", + " grid-column: 1;\n", + "}\n", + "\n", + ".xr-var-dims {\n", + " grid-column: 2;\n", + "}\n", + "\n", + ".xr-var-dtype {\n", + " grid-column: 3;\n", + " text-align: right;\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-var-preview {\n", + " grid-column: 4;\n", + "}\n", + "\n", + ".xr-var-name,\n", + ".xr-var-dims,\n", + ".xr-var-dtype,\n", + ".xr-preview,\n", + ".xr-attrs dt {\n", + " white-space: nowrap;\n", + " overflow: hidden;\n", + " text-overflow: ellipsis;\n", + " padding-right: 10px;\n", + "}\n", + "\n", + ".xr-var-name:hover,\n", + ".xr-var-dims:hover,\n", + ".xr-var-dtype:hover,\n", + ".xr-attrs dt:hover {\n", + " overflow: visible;\n", + " width: auto;\n", + " z-index: 1;\n", + "}\n", + "\n", + ".xr-var-attrs,\n", + ".xr-var-data {\n", + " display: none;\n", + " background-color: var(--xr-background-color) !important;\n", + " padding-bottom: 5px !important;\n", + "}\n", + "\n", + ".xr-var-attrs-in:checked ~ .xr-var-attrs,\n", + ".xr-var-data-in:checked ~ .xr-var-data {\n", + " display: block;\n", + "}\n", + "\n", + ".xr-var-data > table {\n", + " float: right;\n", + "}\n", + "\n", + ".xr-var-name span,\n", + ".xr-var-data,\n", + ".xr-attrs {\n", + " padding-left: 25px !important;\n", + "}\n", + "\n", + ".xr-attrs,\n", + ".xr-var-attrs,\n", + ".xr-var-data {\n", + " grid-column: 1 / -1;\n", + "}\n", + "\n", + "dl.xr-attrs {\n", + " padding: 0;\n", + " margin: 0;\n", + " display: grid;\n", + " grid-template-columns: 125px auto;\n", + "}\n", + "\n", + ".xr-attrs dt, dd {\n", + " padding: 0;\n", + " margin: 0;\n", + " float: left;\n", + " padding-right: 10px;\n", + " width: auto;\n", + "}\n", + "\n", + ".xr-attrs dt {\n", + " font-weight: normal;\n", + " grid-column: 1;\n", + "}\n", + "\n", + ".xr-attrs dt:hover span {\n", + " display: inline-block;\n", + " background: var(--xr-background-color);\n", + " padding-right: 10px;\n", + "}\n", + "\n", + ".xr-attrs dd {\n", + " grid-column: 2;\n", + " white-space: pre-wrap;\n", + " word-break: break-all;\n", + "}\n", + "\n", + ".xr-icon-database,\n", + ".xr-icon-file-text2 {\n", + " display: inline-block;\n", + " vertical-align: middle;\n", + " width: 1em;\n", + " height: 1.5em !important;\n", + " stroke-width: 0;\n", + " stroke: currentColor;\n", + " fill: currentColor;\n", + "}\n", + "</style><pre class='xr-text-repr-fallback'><xarray.Dataset>\n", + "Dimensions: (pulse_slot: 2700, sa3_pId: 125, trainId: 3066)\n", + "Coordinates:\n", + " * trainId (trainId) uint64 520069541 520069542 ... 520072606\n", + " * sa3_pId (sa3_pId) int64 1040 1048 1056 1064 ... 2016 2024 2032\n", + "Dimensions without coordinates: pulse_slot\n", + "Data variables:\n", + " bunchPatternTable (trainId, pulse_slot) uint32 2139945 0 2129961 ... 0 0 0\n", + " nrj (trainId) float64 778.6 778.6 778.5 ... 783.4 783.4 783.4\n", + " MCP3peaks (trainId, sa3_pId) float64 -197.7 -34.67 ... -1.213e+03\n", + " SCS_SA3 (trainId, sa3_pId) float64 2.839e+03 897.9 ... 8.069e+03\n", + "Attributes:\n", + " runFolder: /gpfs/exfel/exp/SCS/201901/p002212/raw/r0208</pre><div class='xr-wrap' hidden><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-d190895c-429f-49c5-b6d3-a746eeba5ee7' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-d190895c-429f-49c5-b6d3-a746eeba5ee7' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span>pulse_slot</span>: 2700</li><li><span class='xr-has-index'>sa3_pId</span>: 125</li><li><span class='xr-has-index'>trainId</span>: 3066</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-4b85fc5e-de13-43f7-963b-b77286fd62b5' class='xr-section-summary-in' type='checkbox' checked><label for='section-4b85fc5e-de13-43f7-963b-b77286fd62b5' class='xr-section-summary' >Coordinates: <span>(2)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>trainId</span></div><div class='xr-var-dims'>(trainId)</div><div class='xr-var-dtype'>uint64</div><div class='xr-var-preview xr-preview'>520069541 520069542 ... 520072606</div><input id='attrs-07fa6d2e-5dd2-4fed-9bc9-4bddb9616c4d' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-07fa6d2e-5dd2-4fed-9bc9-4bddb9616c4d' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-3b328c4e-f541-4092-8778-ce46b92ce7e0' class='xr-var-data-in' type='checkbox'><label for='data-3b328c4e-f541-4092-8778-ce46b92ce7e0' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([520069541, 520069542, 520069543, ..., 520072604, 520072605, 520072606],\n", + " dtype=uint64)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>sa3_pId</span></div><div class='xr-var-dims'>(sa3_pId)</div><div class='xr-var-dtype'>int64</div><div class='xr-var-preview xr-preview'>1040 1048 1056 ... 2016 2024 2032</div><input id='attrs-7e7b0279-e00c-4e72-b9b9-cf39b39185ac' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-7e7b0279-e00c-4e72-b9b9-cf39b39185ac' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-e4074543-0528-49db-8695-cd0f8b95bab2' class='xr-var-data-in' type='checkbox'><label for='data-e4074543-0528-49db-8695-cd0f8b95bab2' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([1040, 1048, 1056, 1064, 1072, 1080, 1088, 1096, 1104, 1112, 1120, 1128,\n", + " 1136, 1144, 1152, 1160, 1168, 1176, 1184, 1192, 1200, 1208, 1216, 1224,\n", + " 1232, 1240, 1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320,\n", + " 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416,\n", + " 1424, 1432, 1440, 1448, 1456, 1464, 1472, 1480, 1488, 1496, 1504, 1512,\n", + " 1520, 1528, 1536, 1544, 1552, 1560, 1568, 1576, 1584, 1592, 1600, 1608,\n", + " 1616, 1624, 1632, 1640, 1648, 1656, 1664, 1672, 1680, 1688, 1696, 1704,\n", + " 1712, 1720, 1728, 1736, 1744, 1752, 1760, 1768, 1776, 1784, 1792, 1800,\n", + " 1808, 1816, 1824, 1832, 1840, 1848, 1856, 1864, 1872, 1880, 1888, 1896,\n", + " 1904, 1912, 1920, 1928, 1936, 1944, 1952, 1960, 1968, 1976, 1984, 1992,\n", + " 2000, 2008, 2016, 2024, 2032])</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-0744a4dc-6a08-4bd6-a4ec-28ab10915d87' class='xr-section-summary-in' type='checkbox' checked><label for='section-0744a4dc-6a08-4bd6-a4ec-28ab10915d87' class='xr-section-summary' >Data variables: <span>(4)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>bunchPatternTable</span></div><div class='xr-var-dims'>(trainId, pulse_slot)</div><div class='xr-var-dtype'>uint32</div><div class='xr-var-preview xr-preview'>2139945 0 2129961 0 ... 0 0 0 0</div><input id='attrs-4a316316-f1a1-4c1c-9e40-6be175d58c3c' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-4a316316-f1a1-4c1c-9e40-6be175d58c3c' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-3998e9f3-e48a-4d1b-80f6-3cdc00fab4c8' class='xr-var-data-in' type='checkbox'><label for='data-3998e9f3-e48a-4d1b-80f6-3cdc00fab4c8' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[2139945, 0, 2129961, ..., 0, 0, 0],\n", + " [2141993, 0, 2129961, ..., 0, 0, 0],\n", + " [2139945, 0, 2129961, ..., 0, 0, 0],\n", + " ...,\n", + " [2141993, 0, 2129961, ..., 0, 0, 0],\n", + " [2139945, 0, 2129961, ..., 0, 0, 0],\n", + " [2141993, 0, 2129961, ..., 0, 0, 0]],\n", + " dtype=uint32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>nrj</span></div><div class='xr-var-dims'>(trainId)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>778.6 778.6 778.5 ... 783.4 783.4</div><input id='attrs-3133f05d-246a-498b-bbd1-a695804ca7aa' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-3133f05d-246a-498b-bbd1-a695804ca7aa' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-8a408860-cf45-47b6-8d6c-bd86b50714b4' class='xr-var-data-in' type='checkbox'><label for='data-8a408860-cf45-47b6-8d6c-bd86b50714b4' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([778.62824057, 778.55124428, 778.52251822, ..., 783.36562112,\n", + " 783.3947057 , 783.37531574])</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>MCP3peaks</span></div><div class='xr-var-dims'>(trainId, sa3_pId)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>-197.7 -34.67 ... -1.213e+03</div><input id='attrs-5734ac8d-335a-4815-9ee2-78fb4203170e' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-5734ac8d-335a-4815-9ee2-78fb4203170e' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-ae539ba8-cec2-4f31-b1b7-2c3813777b7c' class='xr-var-data-in' type='checkbox'><label for='data-ae539ba8-cec2-4f31-b1b7-2c3813777b7c' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[-1.97666667e+02, -3.46666667e+01, 1.83333333e+01, ...,\n", + " -4.95533333e+03, -2.58333333e+03, -3.64000000e+03],\n", + " [-1.14000000e+02, -4.00000000e+02, -2.75000000e+02, ...,\n", + " -1.89733333e+03, -1.63966667e+03, -9.57000000e+02],\n", + " [-5.61000000e+02, -1.00366667e+03, -3.75000000e+02, ...,\n", + " -7.72000000e+02, -2.23633333e+03, -1.49466667e+03],\n", + " ...,\n", + " [-1.51333333e+02, -6.10000000e+01, -4.74333333e+02, ...,\n", + " -9.53333333e+02, -9.39000000e+02, -1.34033333e+03],\n", + " [-6.08666667e+02, -7.73333333e+01, 2.33333333e+00, ...,\n", + " -1.58466667e+03, -9.06333333e+02, -1.04700000e+03],\n", + " [-4.16666667e+01, -4.10333333e+02, 5.00000000e+01, ...,\n", + " -9.43666667e+02, -2.86800000e+03, -1.21266667e+03]])</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>SCS_SA3</span></div><div class='xr-var-dims'>(trainId, sa3_pId)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>2.839e+03 897.9 ... 8.069e+03</div><input id='attrs-8d82e392-da97-41ca-83db-d29849d6dd1c' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-8d82e392-da97-41ca-83db-d29849d6dd1c' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-49ac9135-f9d9-43a0-95da-0a48aff881c3' class='xr-var-data-in' type='checkbox'><label for='data-49ac9135-f9d9-43a0-95da-0a48aff881c3' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[ 2838.68261719, 897.93481445, 1270.12817383, ...,\n", + " 33158.98046875, 19836.09570312, 27724.03515625],\n", + " [ 2088.77197266, 861.36578369, 3565.16918945, ...,\n", + " 16303.64941406, 12787.91503906, 6092.00097656],\n", + " [ 603.07495117, 4487.36669922, 2917.90380859, ...,\n", + " 7453.79638672, 11550.72070312, 10727.46191406],\n", + " ...,\n", + " [ 1868.02709961, 1402.94287109, 1433.98071289, ...,\n", + " 7914.3984375 , 4954.84765625, 6647.52441406],\n", + " [ 3646.75048828, 2033.26245117, 569.56018066, ...,\n", + " 9144.62402344, 7623.27978516, 4444.45361328],\n", + " [ 708.95373535, 1963.84277344, 912.64025879, ...,\n", + " 5079.55371094, 12632.79003906, 8069.31152344]])</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-7ad05c3b-49ee-497e-9b89-5cd235a25de5' class='xr-section-summary-in' type='checkbox' checked><label for='section-7ad05c3b-49ee-497e-9b89-5cd235a25de5' class='xr-section-summary' >Attributes: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>runFolder :</span></dt><dd>/gpfs/exfel/exp/SCS/201901/p002212/raw/r0208</dd></dl></div></li></ul></div></div>" + ], + "text/plain": [ + "<xarray.Dataset>\n", + "Dimensions: (pulse_slot: 2700, sa3_pId: 125, trainId: 3066)\n", + "Coordinates:\n", + " * trainId (trainId) uint64 520069541 520069542 ... 520072606\n", + " * sa3_pId (sa3_pId) int64 1040 1048 1056 1064 ... 2016 2024 2032\n", + "Dimensions without coordinates: pulse_slot\n", + "Data variables:\n", + " bunchPatternTable (trainId, pulse_slot) uint32 2139945 0 2129961 ... 0 0 0\n", + " nrj (trainId) float64 778.6 778.6 778.5 ... 783.4 783.4 783.4\n", + " MCP3peaks (trainId, sa3_pId) float64 -197.7 -34.67 ... -1.213e+03\n", + " SCS_SA3 (trainId, sa3_pId) float64 2.839e+03 897.9 ... 8.069e+03\n", + "Attributes:\n", + " runFolder: /gpfs/exfel/exp/SCS/201901/p002212/raw/r0208" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "proposalNB = 2212\n", + "runNB = 208\n", + "fields = ['SCS_SA3', 'MCP3apd', 'nrj']\n", + "run, data = tb.load(proposalNB, runNB, fields)\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function returns an `extra_data` `DataCollection` (run) and an `xarray` `Dataset` (data, which is displayed here in a summarized form). The DataCollection is the key element of the `extra_data` package and it is used in many functions of the ToolBox. It contains information on the run and enables data handling and loading (see the `extra_data` [documentation](https://extra-data.readthedocs.io/en/latest/) for details). The Dataset data is the main result of our loading operation. In it, we can find:\n", + "\n", + "* Dimensions `pulse_slot`, `trainId`, `sa3_pId`\n", + "* Coordinates: `trainId` and `sa3_pId`: the train Id values and the SASE 3 pulse Id values.\n", + "* Data variables: The loaded data arrays. In this example, nrj is the monochromator energy, in eV, for each train. MCP3peaks is one of the MCPs of the TIM detector, SCS_SA3 is the pulse energy of the SASE 3 pulses measured by the XGM in the SCS hutch. The bunchPatternTable is loaded by default. It is an array of 2700 values per train (the maximum number of pulses at 4.5 MHz provided by the machine) and contains information on how the pulses are distributed among SASE 1, 2, 3, and the various lasers at European XFEL. The `sa3_pId` coordinates are extracted from this table. \n", + "* Attribute `runFolder`, the name of the folder that contains the raw files of the run. It can be accessed via: `data.attrs['runFolder']`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The (maximum) number of pulses per train is given by `data.sa3_pId.size`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Accessing the raw arrays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function `load`, by default, loads the raw arrays using the `get_array` function of `extra_data`, and extracts only the relevant data from them, according to the bunch pattern table. It may be required, in some cases, to access the raw array of a specific mnemonic. For this, we can use the `DataCollection` returned earlier by the call to `load`:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n", + "<defs>\n", + "<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n", + "<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n", + "<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n", + "<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n", + "</symbol>\n", + "<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n", + "<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n", + "<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n", + "</symbol>\n", + "</defs>\n", + "</svg>\n", + "<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n", + " *\n", + " */\n", + "\n", + ":root {\n", + " --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n", + " --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n", + " --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n", + " --xr-border-color: var(--jp-border-color2, #e0e0e0);\n", + " --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n", + " --xr-background-color: var(--jp-layout-color0, white);\n", + " --xr-background-color-row-even: var(--jp-layout-color1, white);\n", + " --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n", + "}\n", + "\n", + "html[theme=dark],\n", + "body.vscode-dark {\n", + " --xr-font-color0: rgba(255, 255, 255, 1);\n", + " --xr-font-color2: rgba(255, 255, 255, 0.54);\n", + " --xr-font-color3: rgba(255, 255, 255, 0.38);\n", + " --xr-border-color: #1F1F1F;\n", + " --xr-disabled-color: #515151;\n", + " --xr-background-color: #111111;\n", + " --xr-background-color-row-even: #111111;\n", + " --xr-background-color-row-odd: #313131;\n", + "}\n", + "\n", + ".xr-wrap {\n", + " display: block;\n", + " min-width: 300px;\n", + " max-width: 700px;\n", + "}\n", + "\n", + ".xr-text-repr-fallback {\n", + " /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n", + " display: none;\n", + "}\n", + "\n", + ".xr-header {\n", + " padding-top: 6px;\n", + " padding-bottom: 6px;\n", + " margin-bottom: 4px;\n", + " border-bottom: solid 1px var(--xr-border-color);\n", + "}\n", + "\n", + ".xr-header > div,\n", + ".xr-header > ul {\n", + " display: inline;\n", + " margin-top: 0;\n", + " margin-bottom: 0;\n", + "}\n", + "\n", + ".xr-obj-type,\n", + ".xr-array-name {\n", + " margin-left: 2px;\n", + " margin-right: 10px;\n", + "}\n", + "\n", + ".xr-obj-type {\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-sections {\n", + " padding-left: 0 !important;\n", + " display: grid;\n", + " grid-template-columns: 150px auto auto 1fr 20px 20px;\n", + "}\n", + "\n", + ".xr-section-item {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-section-item input {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-section-item input + label {\n", + " color: var(--xr-disabled-color);\n", + "}\n", + "\n", + ".xr-section-item input:enabled + label {\n", + " cursor: pointer;\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-section-item input:enabled + label:hover {\n", + " color: var(--xr-font-color0);\n", + "}\n", + "\n", + ".xr-section-summary {\n", + " grid-column: 1;\n", + " color: var(--xr-font-color2);\n", + " font-weight: 500;\n", + "}\n", + "\n", + ".xr-section-summary > span {\n", + " display: inline-block;\n", + " padding-left: 0.5em;\n", + "}\n", + "\n", + ".xr-section-summary-in:disabled + label {\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-section-summary-in + label:before {\n", + " display: inline-block;\n", + " content: '►';\n", + " font-size: 11px;\n", + " width: 15px;\n", + " text-align: center;\n", + "}\n", + "\n", + ".xr-section-summary-in:disabled + label:before {\n", + " color: var(--xr-disabled-color);\n", + "}\n", + "\n", + ".xr-section-summary-in:checked + label:before {\n", + " content: '▼';\n", + "}\n", + "\n", + ".xr-section-summary-in:checked + label > span {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-section-summary,\n", + ".xr-section-inline-details {\n", + " padding-top: 4px;\n", + " padding-bottom: 4px;\n", + "}\n", + "\n", + ".xr-section-inline-details {\n", + " grid-column: 2 / -1;\n", + "}\n", + "\n", + ".xr-section-details {\n", + " display: none;\n", + " grid-column: 1 / -1;\n", + " margin-bottom: 5px;\n", + "}\n", + "\n", + ".xr-section-summary-in:checked ~ .xr-section-details {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-array-wrap {\n", + " grid-column: 1 / -1;\n", + " display: grid;\n", + " grid-template-columns: 20px auto;\n", + "}\n", + "\n", + ".xr-array-wrap > label {\n", + " grid-column: 1;\n", + " vertical-align: top;\n", + "}\n", + "\n", + ".xr-preview {\n", + " color: var(--xr-font-color3);\n", + "}\n", + "\n", + ".xr-array-preview,\n", + ".xr-array-data {\n", + " padding: 0 5px !important;\n", + " grid-column: 2;\n", + "}\n", + "\n", + ".xr-array-data,\n", + ".xr-array-in:checked ~ .xr-array-preview {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-array-in:checked ~ .xr-array-data,\n", + ".xr-array-preview {\n", + " display: inline-block;\n", + "}\n", + "\n", + ".xr-dim-list {\n", + " display: inline-block !important;\n", + " list-style: none;\n", + " padding: 0 !important;\n", + " margin: 0;\n", + "}\n", + "\n", + ".xr-dim-list li {\n", + " display: inline-block;\n", + " padding: 0;\n", + " margin: 0;\n", + "}\n", + "\n", + ".xr-dim-list:before {\n", + " content: '(';\n", + "}\n", + "\n", + ".xr-dim-list:after {\n", + " content: ')';\n", + "}\n", + "\n", + ".xr-dim-list li:not(:last-child):after {\n", + " content: ',';\n", + " padding-right: 5px;\n", + "}\n", + "\n", + ".xr-has-index {\n", + " font-weight: bold;\n", + "}\n", + "\n", + ".xr-var-list,\n", + ".xr-var-item {\n", + " display: contents;\n", + "}\n", + "\n", + ".xr-var-item > div,\n", + ".xr-var-item label,\n", + ".xr-var-item > .xr-var-name span {\n", + " background-color: var(--xr-background-color-row-even);\n", + " margin-bottom: 0;\n", + "}\n", + "\n", + ".xr-var-item > .xr-var-name:hover span {\n", + " padding-right: 5px;\n", + "}\n", + "\n", + ".xr-var-list > li:nth-child(odd) > div,\n", + ".xr-var-list > li:nth-child(odd) > label,\n", + ".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n", + " background-color: var(--xr-background-color-row-odd);\n", + "}\n", + "\n", + ".xr-var-name {\n", + " grid-column: 1;\n", + "}\n", + "\n", + ".xr-var-dims {\n", + " grid-column: 2;\n", + "}\n", + "\n", + ".xr-var-dtype {\n", + " grid-column: 3;\n", + " text-align: right;\n", + " color: var(--xr-font-color2);\n", + "}\n", + "\n", + ".xr-var-preview {\n", + " grid-column: 4;\n", + "}\n", + "\n", + ".xr-var-name,\n", + ".xr-var-dims,\n", + ".xr-var-dtype,\n", + ".xr-preview,\n", + ".xr-attrs dt {\n", + " white-space: nowrap;\n", + " overflow: hidden;\n", + " text-overflow: ellipsis;\n", + " padding-right: 10px;\n", + "}\n", + "\n", + ".xr-var-name:hover,\n", + ".xr-var-dims:hover,\n", + ".xr-var-dtype:hover,\n", + ".xr-attrs dt:hover {\n", + " overflow: visible;\n", + " width: auto;\n", + " z-index: 1;\n", + "}\n", + "\n", + ".xr-var-attrs,\n", + ".xr-var-data {\n", + " display: none;\n", + " background-color: var(--xr-background-color) !important;\n", + " padding-bottom: 5px !important;\n", + "}\n", + "\n", + ".xr-var-attrs-in:checked ~ .xr-var-attrs,\n", + ".xr-var-data-in:checked ~ .xr-var-data {\n", + " display: block;\n", + "}\n", + "\n", + ".xr-var-data > table {\n", + " float: right;\n", + "}\n", + "\n", + ".xr-var-name span,\n", + ".xr-var-data,\n", + ".xr-attrs {\n", + " padding-left: 25px !important;\n", + "}\n", + "\n", + ".xr-attrs,\n", + ".xr-var-attrs,\n", + ".xr-var-data {\n", + " grid-column: 1 / -1;\n", + "}\n", + "\n", + "dl.xr-attrs {\n", + " padding: 0;\n", + " margin: 0;\n", + " display: grid;\n", + " grid-template-columns: 125px auto;\n", + "}\n", + "\n", + ".xr-attrs dt, dd {\n", + " padding: 0;\n", + " margin: 0;\n", + " float: left;\n", + " padding-right: 10px;\n", + " width: auto;\n", + "}\n", + "\n", + ".xr-attrs dt {\n", + " font-weight: normal;\n", + " grid-column: 1;\n", + "}\n", + "\n", + ".xr-attrs dt:hover span {\n", + " display: inline-block;\n", + " background: var(--xr-background-color);\n", + " padding-right: 10px;\n", + "}\n", + "\n", + ".xr-attrs dd {\n", + " grid-column: 2;\n", + " white-space: pre-wrap;\n", + " word-break: break-all;\n", + "}\n", + "\n", + ".xr-icon-database,\n", + ".xr-icon-file-text2 {\n", + " display: inline-block;\n", + " vertical-align: middle;\n", + " width: 1em;\n", + " height: 1.5em !important;\n", + " stroke-width: 0;\n", + " stroke: currentColor;\n", + " fill: currentColor;\n", + "}\n", + "</style><pre class='xr-text-repr-fallback'><xarray.DataArray 'SCS_UTC1_ADQ/ADC/1:network.digitizers.channel_1_C.raw.samples' (trainId: 3066, samplesId: 600000)>\n", + "array([[1515, 1500, 1507, ..., 1505, 1498, 1500],\n", + " [1500, 1502, 1498, ..., 1504, 1490, 1499],\n", + " [1503, 1508, 1507, ..., 1512, 1500, 1496],\n", + " ...,\n", + " [1502, 1515, 1517, ..., 1503, 1498, 1509],\n", + " [1512, 1511, 1513, ..., 1506, 1504, 1506],\n", + " [1499, 1502, 1508, ..., 1508, 1502, 1500]], dtype=int16)\n", + "Coordinates:\n", + " * trainId (trainId) uint64 520069541 520069542 ... 520072605 520072606\n", + "Dimensions without coordinates: samplesId</pre><div class='xr-wrap' hidden><div class='xr-header'><div class='xr-obj-type'>xarray.DataArray</div><div class='xr-array-name'>'SCS_UTC1_ADQ/ADC/1:network.digitizers.channel_1_C.raw.samples'</div><ul class='xr-dim-list'><li><span class='xr-has-index'>trainId</span>: 3066</li><li><span>samplesId</span>: 600000</li></ul></div><ul class='xr-sections'><li class='xr-section-item'><div class='xr-array-wrap'><input id='section-797922ee-1be5-4715-99a3-b1e48d2a750d' class='xr-array-in' type='checkbox' checked><label for='section-797922ee-1be5-4715-99a3-b1e48d2a750d' title='Show/hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-array-preview xr-preview'><span>1515 1500 1507 1506 1497 1505 1510 ... 1506 1508 1513 1508 1502 1500</span></div><div class='xr-array-data'><pre>array([[1515, 1500, 1507, ..., 1505, 1498, 1500],\n", + " [1500, 1502, 1498, ..., 1504, 1490, 1499],\n", + " [1503, 1508, 1507, ..., 1512, 1500, 1496],\n", + " ...,\n", + " [1502, 1515, 1517, ..., 1503, 1498, 1509],\n", + " [1512, 1511, 1513, ..., 1506, 1504, 1506],\n", + " [1499, 1502, 1508, ..., 1508, 1502, 1500]], dtype=int16)</pre></div></div></li><li class='xr-section-item'><input id='section-8a9e5391-7fe8-4d6a-9deb-c98f7b93332a' class='xr-section-summary-in' type='checkbox' checked><label for='section-8a9e5391-7fe8-4d6a-9deb-c98f7b93332a' class='xr-section-summary' >Coordinates: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>trainId</span></div><div class='xr-var-dims'>(trainId)</div><div class='xr-var-dtype'>uint64</div><div class='xr-var-preview xr-preview'>520069541 520069542 ... 520072606</div><input id='attrs-9435069b-6d74-409c-aed3-ac5294cce5f7' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-9435069b-6d74-409c-aed3-ac5294cce5f7' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-10417c8c-1a86-44b8-9e3b-d79d616b5eff' class='xr-var-data-in' type='checkbox'><label for='data-10417c8c-1a86-44b8-9e3b-d79d616b5eff' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([520069541, 520069542, 520069543, ..., 520072604, 520072605, 520072606],\n", + " dtype=uint64)</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-4020eff5-2cf5-4308-9874-0461d72a2239' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-4020eff5-2cf5-4308-9874-0461d72a2239' class='xr-section-summary' title='Expand/collapse section'>Attributes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'></dl></div></li></ul></div></div>" + ], + "text/plain": [ + "<xarray.DataArray 'SCS_UTC1_ADQ/ADC/1:network.digitizers.channel_1_C.raw.samples' (trainId: 3066, samplesId: 600000)>\n", + "array([[1515, 1500, 1507, ..., 1505, 1498, 1500],\n", + " [1500, 1502, 1498, ..., 1504, 1490, 1499],\n", + " [1503, 1508, 1507, ..., 1512, 1500, 1496],\n", + " ...,\n", + " [1502, 1515, 1517, ..., 1503, 1498, 1509],\n", + " [1512, 1511, 1513, ..., 1506, 1504, 1506],\n", + " [1499, 1502, 1508, ..., 1508, 1502, 1500]], dtype=int16)\n", + "Coordinates:\n", + " * trainId (trainId) uint64 520069541 520069542 ... 520072605 520072606\n", + "Dimensions without coordinates: samplesId" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "raw_traces = run.get_array(*tb.mnemonics['MCP2raw'].values())\n", + "raw_traces" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `raw_traces` `DataArray` contains the digitizer raw traces generated by the MCP 2 of the TIM detector. The array has dimensions `trainId` and `samplesId` (the latter given by `tb.mnemonics['MCP2raw']['dim']`). Quick visual inspection of the trace of the first train can be performed using the built-in plotting function of `xarray`:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x2ae2a8e23f60>]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "raw_traces.isel(trainId=0).plot()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "xfel", + "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": 2 +} diff --git a/doc/bunch_pattern_decoding.rst b/doc/bunch_pattern_decoding.rst index f1812e4..38dc708 100644 --- a/doc/bunch_pattern_decoding.rst +++ b/doc/bunch_pattern_decoding.rst @@ -1,3 +1,6 @@ +The bunch pattern table is an array of 2700 values per train (the maximum number of pulses at 4.5 MHz provided by the machine) and contains information on how the pulses are distributed among SASE 1, 2, 3, and the various lasers at European XFEL. +The data stored in the bunch pattern table (mnemonic *bunchPatternTable*) can be extracted using the wrappers to the `euxfel_bunch_pattern <https://pypi.org/project/euxfel-bunch-pattern/>`_ package as follows: + .. code:: ipython3 import toolbox_scs as tb @@ -6,29 +9,17 @@ proposalNB = 2511 runNB = 176 -**option 1** - -This method uses function we implemented. - -.. code:: ipython3 + run, data = tb.load(proposalNB, runNB, "bunchPatternTable") + ppl_mask = tbm.is_ppl(data.bunchPatternTable) - fields = ["bunchPatternTable"] - run = tb.load(fields, runNB, proposalNB) - bpt = run['bunchPatternTable'] +ppl_mask is a boolean DataArray of dimensions trainId x 2700, where True values indicate where a laser pulse from the PP laser was triggered. - bpt_dec = tbm.extractBunchPattern( - run['bunchPatternTable'],'scs_ppl') +.. note:: + The position of the PP laser pulses with respect to that of the SASE 3 pulses is arbitrary. The PP laser pattern always starts at pulse Id 0, while that of SASE 3 can vary, depending on the machine parameters. - -**option 2** - -This method uses function from the euxfel_bunch_pattern package. +From this mask, one can obtain the number of pulses per train by summing along the 'pulse_slot' dimension: .. code:: ipython3 + ppl_npulses = ppl_mask.sum(dim='pulse_slot') - run = tb.load_run(proposalNB, runNB) - mnemonic = tb.mnemonics["bunchPatternTable"] - bpt = run.get_array(*mnemonic.values()) - - bpt_is_laser = tbm.is_ppl(bpt) diff --git a/doc/conf.py b/doc/conf.py index a48fe7a..4d0032b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -43,12 +43,17 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.coverage', 'sphinx.ext.napoleon', - 'autoapi.extension', + # Comment out autoapi to be able to run nbsphinx + # 'autoapi.extension', 'sphinx_rtd_theme', + 'nbsphinx' ] autoapi_dirs = ['../src/toolbox_scs'] autoapi_ignore = ['*/deprecated/*'] +# Don't add .txt suffix to source files: +html_sourcelink_suffix = '' + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/doc/howtos.rst b/doc/howtos.rst index aac8797..e74759b 100644 --- a/doc/howtos.rst +++ b/doc/howtos.rst @@ -4,7 +4,8 @@ top --- -* :doc:`load run and data <load>`. +.. * :doc:`load run and data <load>`. +* :doc:`load data in memory <Loading_data_in_memory>`. misc ---- @@ -12,15 +13,23 @@ misc * :doc:`bunch pattern decoding <bunch_pattern_decoding>`. -detectors (dssc) ----------------- +detectors +--------- +DSSC +++++ Most of the functions within toolbox_scs.detectors can be accessed directly. This is useful during development, or when working in a non-standardized way, which is often neccessary during data evaluation. For frequent routines there is the possibility to use dssc objects that guarantee consistent data structure, and reduce the amount of recurring code within the notebook. * bin data using toolbox_scs.tbdet -> *to be documented*. * :doc:`bin data using the DSSCBinner <dssc/DSSCBinner>`. * post processing, data analysis -> *to be documented* +Point detectors ++++++++++++++++ +Detectors that produce one point per pulse, or 0D detectors, are all handled in a similar way. Such detectors are, for instance, the X-ray Gas Monitor (XGM), the Transmitted Intensity Monitor (TIM), the electron Bunch Arrival Monitor (BAM) or the photo diodes monitoring the PP laser. + +* :doc:`extract data from point detectors <point_detectors/point_detectors>`. + routines -------- diff --git a/doc/load.rst b/doc/load.rst index 37265ea..6e2df26 100644 --- a/doc/load.rst +++ b/doc/load.rst @@ -1,3 +1,5 @@ +Loading data in memory is performed as follows: + **Option 1**: .. code:: python3 @@ -13,9 +15,9 @@ proposalNr = 2565 runNr = 19 - run_data = tb.load(fields, runNr, proposalNr) + run, data = tb.load(proposalNr, runNr, fields) -run_data is an xarray dataArray. It has an attribute called 'run' containing the underlying extra_data dataCollection. +run is an extra_data dataCollection and data is an xarray Dataset containing all variables listed in fields. For convinience, data also contains the variable bunchPatternTable, which is used by other functions of the ToolBox. All variables are aligned by train Id. **Option 2**: @@ -28,7 +30,7 @@ run_data is an xarray dataArray. It has an attribute called 'run' containing the proposalNr = 2565 runNr = 19 - run = tb.load_run(proposalNr, runNr) - run_data = run.get_array(*mnemonic.values()) + run, _ = tb.load(proposalNr, runNr) + data = run.get_array(*mnemonic.values()) -run is an extra_data dataCollection and run_data an xarray dataArray for a single data source. +run is an extra_data dataCollection and data an xarray dataArray for a single data source. diff --git a/doc/point_detectors/point_detectors.rst b/doc/point_detectors/point_detectors.rst new file mode 100644 index 0000000..bdf6855 --- /dev/null +++ b/doc/point_detectors/point_detectors.rst @@ -0,0 +1 @@ +blablabla \ No newline at end of file diff --git a/doc/requirements.txt b/doc/requirements.txt index 2ef5a2b..c2718b3 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,4 +1,5 @@ sphinx sphinx_rtd_theme autoapi -sphinx-autoapi \ No newline at end of file +sphinx-autoapi +nbsphinx \ No newline at end of file diff --git a/notebook_examples/Knife edge scan and fluence calculation.ipynb b/notebook_examples/Knife edge scan and fluence calculation.ipynb index 158e436..ea8d110 100644 --- a/notebook_examples/Knife edge scan and fluence calculation.ipynb +++ b/notebook_examples/Knife edge scan and fluence calculation.ipynb @@ -41,1753 +41,129 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#Load ToolBox package\n", - "#!git clone https://git.xfel.eu/gitlab/SCS/ToolBox.git" - ] - }, - { - "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#%cd ~/Notebooks\n", "import numpy as np\n", "%matplotlib notebook\n", "import matplotlib.pyplot as plt\n", - "import matplotlib.cm as cm\n", - "import matplotlib.colors as colors\n", "\n", "import matplotlib as mpl\n", "mpl.rcParams['font.size'] = 12.0\n", "mpl.rcParams['savefig.dpi'] = 100\n", "mpl.rcParams['figure.dpi'] = 100\n", "\n", - "from extra_data import RunDirectory, by_index\n", - "import xarray as xr\n", "import toolbox_scs as tb\n", "import toolbox_scs.detectors as tbdet\n", - "from toolbox_scs.routines.knife_edge import knife_edge\n", + "import toolbox_scs.routines as tbr\n", "\n", - "from scipy.stats import binned_statistic\n", - "from scipy.signal import find_peaks\n" + "import logging\n", + "logging.basicConfig(level=logging.WARNING)\n", + "log_root = logging.getLogger(__name__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# X-ray beam profile and fluence" + "# Optical laser beam profile and fluence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Knife-edge measurement" + "## Knife-edge measurement (OL)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Load runs with horizontal and vertical scans" + "### Load scanning motor and laser photodiode data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The laser used in these knife-edge scans was the SCS backup laser, for which there was no bunch pattern table, so, whenever a function needs the bunch pattern as input argument, we set it to **'None'**. If the PP laser is used, then the corresponding bunch pattern key is **'scs_ppl'**." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "<xarray.Dataset>\n", - "Dimensions: (XGMbunchId: 1000, apdId: 400, bunchId: 1000, trainId: 613)\n", - "Coordinates:\n", - " * trainId (trainId) uint64 566589937 566589938 ... 566590549\n", - "Dimensions without coordinates: XGMbunchId, apdId, bunchId\n", - "Data variables:\n", - " sase1 (trainId, bunchId) uint64 320 324 328 332 336 ... 0 0 0 0\n", - " npulses_sase1 (trainId) int64 15 15 15 15 15 15 15 ... 15 15 15 15 15 15\n", - " sase3 (trainId, bunchId) uint64 322 338 354 370 386 ... 0 0 0 0\n", - " npulses_sase3 (trainId) int64 25 25 25 25 25 25 25 ... 25 25 25 25 25 25\n", - " MCP2apd (trainId, apdId) float64 1.898 54.88 ... 19.33 -32.31\n", - " scannerX (trainId) float64 18.5 18.5 18.5 18.5 ... 17.5 17.5 17.5\n", - " SCS_SA3 (trainId, XGMbunchId) float32 4954.09 2332.2 ... 1.0 1.0\n", - " SCS_photonFlux (trainId) float32 1.1874738 1.1874738 ... 1.1305579\n", - " SCS_XGM (trainId, XGMbunchId) float32 34.03499 4954.09 ... 1.0 1.0\n", - " XTD10_XGM (trainId, XGMbunchId) float32 1.2124572 3506.015 ... 1.0\n", - " XTD10_photonFlux (trainId) float32 2381.053 2381.053 ... 2322.0618\n", - "Attributes:\n", - " run: <extra_data.reader.DataCollection object at 0x2b87a3ec6b38>\n", - " runFolder: /gpfs/exfel/exp/SCS/201931/p900094/raw/r0687\n" - ] - } - ], + "outputs": [], "source": [ "proposal = 900094\n", - "fields = [\"MCP2apd\", \"scannerX\", \"SCS_SA3\", \"SCS_photonFlux\", \"SCS_XGM\", \"XTD10_XGM\", \"XTD10_photonFlux\"]\n", - "runNB = 687\n", - "runX = tb.load(fields, runNB, proposal)\n", - "\n", - "fields = [\"MCP2apd\", \"scannerY\", \"SCS_SA3\", \"SCS_photonFlux\", \"SCS_XGM\", \"XTD10_XGM\", \"XTD10_photonFlux\"]\n", - "runNB = 688\n", - "runY = tb.load(fields, runNB, proposal)\n", + "runNB = 384\n", + "fields = [\"FastADC4raw\", \"scannerX\"]\n", + "runX, dsX = tb.load(proposal, runNB, fields, laser_bp='None')\n", "\n", - "print(runX)" + "fields = [\"FastADC4raw\", \"scannerY\"]\n", + "runNB = 385\n", + "runY, dsY = tb.load(proposal, runNB, fields, laser_bp='None')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Clean up and align XGM and MCP (TIM) data, normalize X-ray transmission using XGM" + "### Check diode traces and region of integration for peak calculations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using **'show_all=True'** displays the entire trace and all integration regions. We can then zoom and pan in the interactive figure." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "nrunX = tbdet.matchXgmTimPulseId(runX)\n", - "nrunY = tbdet.matchXgmTimPulseId(runY)\n", - "nrunX['Tr'] = -nrunX['MCP2apd'] / nrunX['SCS_SA3']\n", - "nrunY['Tr'] = -nrunY['MCP2apd'] / nrunY['SCS_SA3']" + "paramsX = tbdet.check_peak_params(runX, 'FastADC4raw', show_all=True, bunchPattern='None')\n", + "print(paramsX)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Fit scan to erfc function and plot" + "using the default **'show_all=False'** parameter only shows the first and last pulses of the trace" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fitting function: a*erfc(np.sqrt(2)*(x-x0)/w0) + b\n", - "w0 = (177.9 +/- 0.6) um\n", - "x0 = (17.953 +/- 0.000) mm\n", - "a = 6.956484e-01 +/- 5.093211e-04 \n", - "b = 3.562530e-03 +/- 7.279907e-04 \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 / 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,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sbG0bduWJ554gszMzEoYfe2jvPn6/PPPqVu3Li4uLhw+fJikpCT69OnDbbfdRnR0dLnnXbBgAYZhEBsbW+Kxxx57jI8//riyXkKtoarmqixGjhyJYRikp6df58hrJ1U9X1OmTOHBBx8kKytLhbeKUOFVqpWrEahu3brRoEGDCsmPk5MThmFw33338dprr7Fw4ULc3d156KGH+Pvf/67/yF8jVTVfALGxsTRp0qTIYrdXXnml4CtE5eopb75OnjzJu+++W+T9vv/++yv0H7KjoyOGYZCamlrisZYtW/L6669XxvBrFVU1V6Vx+vRpHnzwQdq0aXOdo669VOV8HT9+nDvvvBNPT08AFd4qQoVXqVYqKlBZWVnceuut/Oc//6nQee3s7Ar+kcnOzi7YHxMTg2EYjBo16nqGXWupqvkC2L9/P926dWP48OGsXLmSqVOnct999/HWW2+Rk5NznSOvnZQ3X9nZ2fTp04dvvvmGgIAA5syZw4svvkjDhg05cOBAuec1/X6dPHmyxGNt2rShefPmlfUSag1VNVfFuXTpEp06daJ+/frEx8dX0uhrH1U5X19//TXNmzfn0qVLgApvVaHCq1QrFRWoOXPmYBgGy5Ytq9B5TRGonj17lnjsiSeeoF27dtcy3FpPVc3XmTNneOihh5g6dWqR/Rs3bsQwDNzd3a91yLWa8uarU6dOdOnSpci+06dPc++99/LZZ5+Ve16N8FY+VTVXxenTpw+GYeDr63s9w631VNV8xcTEUKdOHSIjIwv2qfBWDSq8SrVSUYF69913ufvuuyu88GzhwoUYhsHw4cNLPNaqVStatGhxLcOt9VTVfPn4+GAYBvv37y/x2F133UWPHj2uZbi1nrLmKyUlpSDHvTgfffQRjz76aLnn1Rzeyqeq5sqcsWPHYhgGkyZNut7h1nqqar7atGnD22+/zeHDhws20w1mUFAQR48ercyXUatR4VWqlYoIVHp6Orfccgvfffddhc+bnJyMYRh89dVXJR5r1KgR77333rUMt9ZTVfPl4OCAYRglylnl5+dz++23X/NK9NpOWfMVHR1dZvWLDz74gIceeqjc8yYkJJRbpcHOzu66x17bqKq5MuHq6ophGAwaNKgyhlvrqar5aty4cblNfO6+++7KfBm1GhVepVqpiECZFqBFRESU+nheXh5JSUklFqI1b96cu+66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\" width=\"700\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fitting function: a*erfc(-np.sqrt(2)*(x-x0)/w0) + b\n", - "w0 = (114.6 +/- 0.5) um\n", - "x0 = (13.328 +/- 0.000) mm\n", - "a = 6.919488e-01 +/- 4.776092e-04 \n", - "b = 1.138866e-03 +/- 6.013901e-04 \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 / 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,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Dg7O9v569OiBppnOoq1SpYrFJ80zZ86gaRqTJk3K9v5yE2vZ7o8//kDTNAYOHJip8qdOnaJYsWIWZ4XnJTJjv82bN7Nu3TomTpxInTp1MjUGcN68eWn2cnTu3BlnZ2fD90f13IPcs58l9P/t2rVrMyx78+ZNXFxceO6557K1L2tgTdtB/rrugfXsVxCvfbNnz6ZYsWIG0ZoVwauP97127ZrZb40aNaJWrVqG74UKFaJ3795m5SIiItA0jRUrVmShRfkPEbz5kMyKtsWLF2NnZ2cy/jE7nDhxwmws0aPa02Et2w0fPhxN0zh48GCm1+nYsSP29vZmbqTyElntIT99+jSOjo5MmzYt3XLSw2uZzNovNePGjTP7z2bEN998g6ZpXLx4MUv7shbWsp1OfrrugfXsV9CufXFxcbi4uDB8+HBDnvTw2gYRvPmQzFy4wsPDsbe35/3338/xxIB///3X7In9UR3LZi3bVatWLcu9ZV5eXmiaZjYhJi+R1ZsmQP369U0u2paQMbxpkxn7GTNnzhzs7OzMXBplRFBQEJqmceTIkSytZy2sYTtj8tN1D6xnv4J27fv+++957LHHOHr0KDExMcTExLBjxw40TeO7774jJiYm3YmhMob34SGCNx+S0YVr7969FC9enAYNGvDff//leH9RUVFomsbo0aMNeZ6enhZnK+vDAPLqbGVr2G7v3r1omoaPj0+W1mvXrh2Ojo5m497yEtm5adauXduiSDDm1q1b6XppMO7VeFTPPcg9++msXLmSwoUL065duyyfR4MGDULTNC5fvpyl9axFbtsuNfnpugfWsV9BvPZ16dLFMO45rRQZGZnmdqOjo9G0tL00GNvyo48+suiloUePHuKlARG8+ZL0LlzHjh2jTJky1KhRg7///jvd7Rw/fpzz588bvsfFxZn9YR48eECHDh3QNM0kmot+YTN+ZZOQkEC1atV47bXXstmy3Ce3bGdMv3790DSN06dPW/z9+vXrZnm//fYbRYsWpXXr1hk3woakZb/ExESLNtu3bx+FCxemc+fOJvmW7Ne8eXMqVKjA7du3DXl6z8X69esNeY/quQe5a79t27bh6OjIW2+9le6Nz9L5d+nSJR577DFq1qyZhdZYl9yyXUG47kHunns6BfHad+jQIVasWGGSQkND0TSNrl27smLFCm7dugWoKGzHjx83e6h8/vnnqVWrlsmQjmHDhmFnZ8exY8cMeYsXL0bTTP3w3rhxg9KlS9OhQ4dcaPWjhQjefMS0adPw9fWld+/eaJrGhx9+iK+vL76+vty6dYvbt29TuXJlChUqxNixY80i2Ri7JgLQNA03NzfD9y1btlC+fHkGDhxIUFAQEyZMoGHDhmiaRs+ePc3q4+7ubuiVCw0NpUGDBhQpUoRt27bltimyTG7bTicpKQkXF5d0XwO+9dZbtGzZ0hDRbcCAATg5OeHs7GxycctLZGS/2NhYw/iyiRMnEhISQp8+fXBycuLxxx83iwJkyX6HDh3CwcHBJNKao6MjzZo1M6vPo3TuQe7b79y5czg7O1OsWDGCgoLMzl/jYQpdu3alUaNGjBgxgrCwML777jvKlCmDvb09W7ZssZJFMk9u2y4/X/fAOv9dKLjXPkukNYZXz+/SpYtJ/po1a7Czs6NJkyaEhYXRr18/ChUqRI8ePUzKJSUl8frrr1OiRAlGjhxJUFAQNWrUoGTJkpw4ceKhtvtRRARvPsLV1TXNVyb62KH0Xquk/pOlvnCdPXsWd3d3nn76aRwdHXFycuKVV14hJCTEYmjd+Ph4PD09KV++PA4ODtStWzfPDprPbdvpbNiwAU1LP1DFlClTqFevHo8//jhFihShQoUKfPrppybRsPIaGdnv7t279O/fn5o1a1KqVCmKFi2Kq6sr3bt3JyYmxmx7adlvx44dNGjQAEdHR5544gn69Olj0uOr8yide5D79tP9m6aVvL29DWUXLlzIm2++yRNPPEGRIkUoW7Ysbdu2NenJzEvktu3y83UPrPffLajXPktkVfACrFixgtq1a+Pg4EClSpUs+oEG+Pvvv+nevTtlypTByckJNze3R8KPsTUQwSsIgiAIgiDka0TwCoIgCIIgCPkaEbyCIAiCIAhCvkYEryAIgiAIgpCvEcErCIIgCIIg5GtE8AqCIAiCIAj5GhG8giAIgiAIQr5GBK8gCIIgCIKQrxHBKwiCIAiCIORrRPAKgiAIgiAI+RoRvIIgCEKaeHt7o2mZu1XMmTMn3ZCquUXq0N9Lly616v4zwtnZ2VC3Pn362Lo6glAgEcErCIJgBTw8PChatChRUVFmvyUmJvLSSy/h6urKP//8Y4PapY0lwevn58eKFSvMytpa8Pbs2ZP58+dz/vx5q+4/I5YsWcL8+fNF8AqCDRHBKwiCYAViY2MpX748DRs25MGDBya/jRs3Dk3TWLt2rY1qlzaJiYnEx8eb5BUvXpwuXbqYlU1KSiI+Pt6sfbmNLnjnzJlj1f1mFRG8gmA7RPAKgiDkMvHx8dy/f58lS5agaRqhoaGG386fP0/x4sVp3769DWuYNdISvLZCBK8gCBkhglcQhFzn9u3b9O/fH1dXV+zt7XniiSdo2rQphw4dMim3d+9eWrRoQenSpXFycuKll15i8uTJht+PHDlCly5deOaZZ3BwcMDFxYVu3brx119/mWxHfw1/6tQpunTpgrOzM6VKlaJr1678+++/JmV1EbJixQpq1KiBvb091atXZ/369WbtuHTpEt26daNcuXKGcrNmzTIps2XLFjRNY9GiRQwdOpSKFStiZ2dHbGwsAC1btuSxxx7j2rVrALRu3ZrSpUtz5cqVDO2o13XBggX873//w8HBgZdffplt27aZlT18+DDNmzenZMmSFC9enCZNmrBnzx6TMvfu3WPEiBFUq1YNBwcHHn/8cRo2bEh4eLiZLY3rkDrp4jetIQ1BQUFUr14de3t7KlSowJdffmmwh46bmxs1atTg6NGjNG7cmGLFilGxYkX8/f0ztEt6glev/x9//MEnn3xCqVKlKFu2LMOGDePBgwdcuHCB1q1bU7JkSVxcXJgwYYLJ+vrxXLJkCSNGjKBixYqUKFGCdu3acevWLRISEujfvz9PPPEExYsXp2vXriQkJFispwheQbAdIngFQch1Pv74Y+zt7fn666+ZOXMm/v7+tGrVigULFhjKhIeHY29vj6urK97e3kyfPp1+/frRtGlTQ5kJEybQqFEjfHx8CAsLo3///hQrVox69eqZvEbXRU6dOnX48MMPCQ4O5osvvkDTNAYPHmxSN03TqFWrFhUqVMDX15fJkydTpUoVnJycTIT01atXqVSpEpUrV8bHx4fp06fTunVrNE1j0qRJhnK6QKpevTq1a9cmICCAMWPGGIT2uXPnKF68OB9//DErV65E0zRCQkIyZUdN03jxxRcpW7YsPj4++Pv74+rqSrFixUzGBkdHR1O8eHFDm8aOHWt4SNi7d6+h3HfffYednR09evRgxowZTJw4kU6dOjF27FgzW+rMnz8fBwcHGjVqxPz585k/fz67d+8GLAteff2mTZsybdo0vvrqKwoXLkzdunW5d++eoZyb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\" width=\"700\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.00017787613670375985 0.00011464211799492675\n", - "X-FWHM [um]: 209.43314612133952\n", - "Y-FWHM [um]: 134.9807787296284\n" - ] - } - ], + "outputs": [], "source": [ - "w0_x = knife_edge(nrunX, axisKey='scannerX', signalKey='Tr', plot=True)[0]*1e-3\n", - "w0_y = knife_edge(nrunY, axisKey='scannerY', signalKey='Tr', plot=True)[0]*1e-3\n", - "print(w0_x, w0_y)\n", + "tbdet.check_peak_params(runX, 'FastADC4raw', bunchPattern='None')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot intensity vs. knife-edge positions, fit with erfc function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "w0_x = tbr.knife_edge(dsX, axisKey='scannerX', plot=True)[0]*1e-3\n", + "w0_y = tbr.knife_edge(dsY, axisKey='scannerY', plot=True)[0]*1e-3\n", "\n", "print('X-FWHM [um]:', w0_x * np.sqrt(2*np.log(2))*1e6)\n", "print('Y-FWHM [um]:', w0_y * np.sqrt(2*np.log(2))*1e6)" @@ -1797,4161 +173,122 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Fluence calculation" + "## Fluence calculation (OL)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Load run of interest, clean up XGM data" + "### OL power measurement " ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "proposal = 900094\n", - "fields = [\"SCS_SA3\", \"SCS_XGM\", \"SCS_photonFlux\", \"XTD10_XGM\", \"XTD10_photonFlux\"]\n", - "runNB = 647\n", - "run = tb.load(fields, runNB, proposal)\n", - "nrun = tbdet.matchXgmTimPulseId(run)" + "#measurement performed in Exp Hutch before in-coupling window\n", + "rel_powers = np.array([100, 75, 50, 25, 15, 12, 10, 8, 6, 4, 2, 1, 0.75, 0.5, 0.25, 0.1, 0])\n", + "powers = np.array([505, 384, 258, 130, 81, 67, 56.5, 45.8, 35.6, 24.1, 14.1, 9.3, 8.0, 6.5, 4.8, 4.1, 1.0])*1e-3 #in W\n", + "\n", + "rep_rate = 10\n", + "npulses = 336" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Calibrate XGM fast data using photon flux and plot" + "### Fluence vs. laser power" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "8.341872\n", - "Pulse energy [J]: 4.498510461663136e-05\n", - "Fluence [mJ/cm^2]: 140.43875422560828\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 / 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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdfVxUdf7///cMF8OAqSMoopIKXsaSpaVpmYqueJFaGdWKXZuJrlkbGJsZmkkf1i7J1pDKzdJq65ZdbLcu9LuGqJu2bW0prq4tIaSt5iq4CgrD8/dHy/k5zgUzODPn/T7neb/dzs2dw+G8zsxxO48mziBARERERKYi9D4AIiIiIgovBiARERGRyTAAiYiIiEyGAUhERERkMgxAIiIiIpNhABIRERGZDAOQiIiIyGQYgEREREQmwwAkIiIiMhkGIBEREZHJMACJiIiITIYBSERERGQyDEAiIiIik2EAEhEREZkMA5CIiIjIZBiARERERCbDACQiIiIyGQYgERERkckwAImIiIhMhgFIRETSKywsxJAhQ9CuXTt06dIFWVlZqKys1PuwiJTFACQiIullZmbiD3/4A3bv3o2//e1vGDt2LAYMGIDGxka9D41ISQxAItJFZWUlhBC47bbb9D4U6axZswZCCG256aab9D4k6fzrX/+CEAJ///vftXV79uxxed169uyp3wESSY4BSERB0xJ1vpZjx465bMsAdNcSgNOmTUNBQQHeeuutkM0SQqB///5ev/7FF19ACIHnnnsuZMfQFl999RWEEKiurtbWHTlyBAUFBSgoKECHDh0YgEQ+MACJKGhaoi41NVW7EJ+71NfXu2zLAHTXEoBr1qwJ+azWAvDhhx+GEAIHDhwI+bH4q6mpCWPHjsWkSZO8btOzZ08GIJEPDEAiCpqWqMvMzPR7WwagO5kCMD09HYMHDw75cfirubkZs2bNQt++fXH48GGv2zEAiXxjABJR0JxvAPoKn82bN0MIgYKCArevlZWV4ZprrkF8fDyio6PRp08fLFq0CCdPnvS6jy+++ALjxo1Du3bt0L59e1x77bU+7yotKyvDtGnT0KVLF0RHR6NHjx647rrrUF5e3ubj8cbf12Hbtm0YPXo02rVrh4SEBOTk5ODUqVMAgD/96U+44oorEBsbiy5duiAvL8/jDRO+ArDl5+yWLl0a8OsR7OMEfo6/OXPmoFevXq2+I8kAJPKNAUhEQaNHAP7+97+HxWKBw+HArbfeitzcXIwePRpCCIwYMQKnT59228ekSZNgt9sxadIkPPDAA8jIyND+03XLf6I+2zPPPAOLxYLY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2O12VFVVaes2btzodmGqqalBVFQU5s2bp61rbm7GyJEj0aNHDzQ1NYXuyZjYtm3b3C78+/btg81mQ3Z2traO51E9TU1NGDRoEPr376+t43lUy0033YSMjAyMGjXKLQAnTpyIpKQk1NbWautKS0shhMAnn3yirduxYweEEFixYoW2rr6+HqmpqRg+fHjon4TBMACJzuIrALt06YKsrCy39f369cPYsWO1x88//zyEENi9e7fLduvXr4cQgv+mGmaDBw/G4MGDtcc8j2q65pprkJiYqD3meVRHWVkZIiIi8M0337gFYG1tLSIjI5GXl+fyPadPn0a7du1w1113aevy8vIQERHhEooAUFhYCCEEDhw4ENonYjAMQKKzeAvAmpoaCCFQVFTk9j0zZ85Ep06dtMezZs1CXFwcmpubXbbbv38/hBAoLi4OybGTu+bmZnTv3h3jx48HwPOokv/+9784cuQI9u/fj6eeegoRERGYMWMGAJ5HlTQ1NeHiiy/GPffcAwBuAbh161YIIfDmm2+6fe9VV13l8i9v48aNw8CBA92227RpE4QQHn9OlLxjABKdxVsAtqxfu3at2/fk5eVBCIGGhgYAwOTJk5GSkuK23cmTJyGEQH5+fkiOndy9+uqrEELgpZdeAsDzqJJ77rkHQggIIWC1WnHDDTfgP//5DwCeR5WsXLkSHTp00G7OOTcA33rrLQghsGXLFrfvzcrKQteuXbXHaWlpyMjIcNtu9+7dEELghRdeCMEzMC4GINFZvAXgli1bvP5b6uLFiyGEwLFjxwAAGRkZHv8t1el0QgiBBQsWhOTYydWePXvQvn17DB8+XPs5L55HdezZswcbN27EK6+8gsmTJ+O6667Djz/+CIDnURU//fQTOnXqhCeeeEJbd24Arl27FkII7Nixw+37b7nlFnTo0EF7nJKSgokTJ7pt991330EIgaeffjrIz8DYGIBEZ+E7gMZw6NAhpKSkIDk5GT/88IO2nudRXb/85S9x+eWXo7m5medREXPmzEGfPn1cbs7iO4DyYAASnSVYPwMYGxvLnznSyfHjx3HJJZegU6dObj/4z/OorpKSEggh8I9//IPnUQH79u2D1WpFcXExKisrtWXYsGHo168fKisrcfToUf4MoI4YgERn8XUXcOfOnb3edXj2v5WuXLnS412H69at8/pvuhQc9fX1GDly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QgiP+z5by528VVVVLutfeeUVCCG0j4P7y1/+AovFgj//+c9us/292eOKK65Aamqqz20YgAbHADSJYAZgsP6hzAAkkpJZAvDsWGpqasIVV1yBbt264cSJEy7bewvAHj16eAzAcyOsJQA3b97s87j69u0LIQQaGhpc1n/00UcQQuDdd98FAIwcORJXX301KisrtWXFihXar4w9NyA9ycrKgsPh8LkNA9DgGICKO9+wYwAS0TnMGIDA/x9qjz/+uMt6h8OBBQsWuKw7ffo0IiIighqAN998M4QQ+O6771zWv/TSSxBCYNu2bQB+fufR24c7CyHQoUOHVl+DIUOGoF+/fj63YQAaHANQcQxAIgoyswYgAAwdOhSJiYkuz/2yyy7DpZde6rLdc889ByFEUANww4YNEELgoYce0tY5nU5cddVV6NSpk/bO4CeffIINGza4LPPnz4cQAk888QT+9Kc/ad/v6eNnPvzwQwghWv28QQagwTEAFccAJKIgM3MAvvXWW24fBfPCCy9ACIHrr78eq1atwpw5c9C7d28kJCQENQCbm5sxduxYWCwWzJ49G88//zx++ctfQgih3e0b6HPq06cPsrKyUFRUhBdeeAGzZ89GZGQkkpOT8eOPP/rcJwPQ4BiAimMAElGQmTkAnU4nUlNTkZqaqn1ostPpxIMPPqh9sHNmZib279/v9SaQtgYg8POHPy9YsABdu3ZFdHQ00tPT8dprr7X5OS1atAiXXHIJOnTogKioKFx44YXIyclpNf4ABqDhMQAVxwAkoiAz+u8CJv8wAA2OAag4BiARBRkDkAAGoOExABXHACSiIGMAEsAANDwGoOJkDsDWtmMAEkmJAUgAA9DwGICKUzkA6+qA2tqf/yQiaTAACWAAGh4DUHEqByARSYkBSAAD0PAYgIpjABJRkDEACWAAGh4DUHEMQCIKMgYgAQxAw2MAKk7lAHzySaCg4Oc/iUgaLRf+U6dO6X0opKNTp04xAI2MASgxPd6NC+dM3gVMJKWmpibs2bMHR44c0ftQSEdHjhzBnj17tN+Ici4GoOIYgBJjABKRTg4ePIiKigrU1NSgrq4Op06dQn19PReDL6dOnUJdXR1qampQUVGBgwcPev07wgBUHANQYgxAItJJc3Mzjh07hr1796KiooKLyZa9e/fi2LFjaG5u9vp3hAGoOAagxBiARKSz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\" width=\"640\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "print(nrun['SCS_photonFlux'].mean().values)\n", - "f_xgm = tbdet.calibrateXGMs(run)\n", - "\n", - "pulse_energy = nrun['SCS_SA3'].mean().values*f_xgm[1]*1e-6 #average energy in J\n", - "nrun['pulse_energy'] = nrun['SCS_SA3']*f_xgm[1]*1e-6\n", - "nrun['fluence'] = 2*nrun['pulse_energy']/(np.pi*w0_x*w0_y)\n", - "print('Pulse energy [J]:',pulse_energy)\n", - "F0 = 2*pulse_energy/(np.pi*w0_x*w0_y)\n", - "print('Fluence [mJ/cm^2]:', F0*1e-1)\n", + "pulse_energies = powers/(rep_rate*npulses)\n", + "print(pulse_energies*1e6)\n", + "fluences = 2*pulse_energies*1e3/(np.pi*w0_x*w0_y*1e4)\n", + "print(fluences)\n", + "plt.figure()\n", + "plt.plot(rel_powers, fluences, 'o-', ms=4)\n", + "plt.grid()\n", + "plt.ylabel('Peak fluence [mJ/cm$^2$]')\n", + "plt.xlabel('Laser power [%]')\n", "\n", + "e_fit = np.polyfit(rel_powers, pulse_energies*1e6, 1)\n", "plt.figure()\n", - "plt.hist(nrun['pulse_energy'].values.flatten()*1e6, bins=50, rwidth=0.7, color='orange', label='Run 645')\n", - "plt.axvline(pulse_energy*1e6, color='r', lw=2, ls='--')\n", - "plt.xlabel('Pulse energy [$\\mu$J]', size=14)\n", - "plt.ylabel('Number of pulses', size=14)\n", - "#plt.xlim(0,50)\n", + "plt.plot(rel_powers, pulse_energies*1e6, 'o-', \n", + " ms=4, label='E[$\\mu$J] = {:.3f} x power [%] + {:.3f}'.format(e_fit[0], e_fit[1]))\n", + "plt.grid()\n", + "plt.ylabel('Pulse energy [$\\mu$J]')\n", + "plt.xlabel('Laser power [%]')\n", + "plt.plot(rel_powers,rel_powers*e_fit[0]+ e_fit[1])\n", "plt.legend()\n", - "ax = plt.gca()\n", - "plt.twiny()\n", - "plt.xlim(np.array(ax.get_xlim())*2e-6/(np.pi*w0_x*w0_y)*1e-1)\n", - "plt.xlabel('Fluence [mJ/cm$^2$]', labelpad=10, size=14)\n", - "plt.tight_layout()" + "print(e_fit)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Optical laser beam profile and fluence" + "# X-ray beam profile and fluence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Knife-edge measurement (OL)" + "## Knife-edge measurement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Load runs" + "### Load runs with horizontal and vertical scans, normalize the transmitted signal by XGM" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "<xarray.Dataset>\n", - "Dimensions: (bunchId: 1000, fadc_samplesId: 100000, trainId: 767)\n", - "Coordinates:\n", - " * trainId (trainId) uint64 512717212 512717213 ... 512717978 512717979\n", - "Dimensions without coordinates: bunchId, fadc_samplesId\n", - "Data variables:\n", - " sase1 (trainId, bunchId) uint64 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", - " npulses_sase1 (trainId) int64 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0\n", - " sase3 (trainId, bunchId) uint64 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0\n", - " npulses_sase3 (trainId) int64 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0\n", - " FastADC4raw (trainId, fadc_samplesId) uint16 33080 33093 ... 33048 33055\n", - " scannerX (trainId) float64 18.0 18.0 18.0 18.0 ... 19.5 19.5 19.5 19.5\n", - "Attributes:\n", - " run: <extra_data.reader.DataCollection object at 0x2b8825a20d68>\n", - " runFolder: /gpfs/exfel/exp/SCS/201931/p900094/raw/r0384\n" - ] - } - ], + "outputs": [], "source": [ "proposal = 900094\n", - "fields = [\"FastADC4raw\", \"scannerX\"]\n", - "runNB = 384\n", - "runX = tb.load(fields, runNB, proposal, validate=False, display=False)\n", - "print(runX)\n", + "fields = [\"MCP2apd\", \"scannerX\", \"SCS_SA3\"]\n", + "runNB = 687\n", + "runX, dsX = tb.load(proposal, runNB, fields)\n", + "dsX['Tr'] = -dsX['MCP2peaks'] / dsX['SCS_SA3']\n", "\n", - "fields = [\"FastADC4raw\", \"scannerY\"]\n", - "runNB = 385\n", - "runY = tb.load(fields, runNB, proposal, validate=False, display=False)" + "fields = [\"MCP2apd\", \"scannerY\", \"SCS_SA3\"]\n", + "runNB = 688\n", + "runY, dsY = tb.load(proposal, runNB, fields)\n", + "dsY['Tr'] = -dsY['MCP2peaks'] / dsY['SCS_SA3']\n", + "\n", + "dsY" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Plot diode traces" + "### Fit scan to erfc function and plot" ] }, { "cell_type": "code", - "execution_count": 9, - "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,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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 0x2b8826018a20>]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plt.figure()\n", - "plt.plot(runY['FastADC4raw'][0])\n", - "plt.plot(runX['FastADC4raw'][0]-20000)" - ] - }, - { - "cell_type": "markdown", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "### Integrate peaks, plot intensity vs. knife-edge positions, fit with erfc function" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": false - }, - "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,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\" width=\"640\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fitting function: a*erfc(np.sqrt(2)*(x-x0)/w0) + b\n", - "w0 = (133.0 +/- 0.1) um\n", - "x0 = (18.758 +/- 0.000) mm\n", - "a = 2.440091e+05 +/- 3.786296e+01 \n", - "b = 8.093633e+03 +/- 5.257618e+01 \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 / 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,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X3+xZMkSwsLC+PPPP/P9jDNnzpCYmFiocrF+505pyB2JvpjLCbxRUVEYhsGePXs8dqwn583mutzAW9xzeN944w2XeeEX07x5c1q2bOlW//zzz3PDDTe41OUG3gtHcl955RUqVqzo1kazZs247bbbCvz8AgPvsb0QHsKn3ezYbQ42/7ebuZKDiJQaCrziQlMaCh94x44d67U5vLGxsZQvX56nn36azMzC31H+ww8/YBgGK1asoGzZss7lpCIiIrj33nsZPnw4tWvXdmkzNTWVsmXLkpBwfsvVZs2auW0IkcsT81Fzb1r78ccfC/w+lxN4J0yYgGEYfPvttx47tnfv3vmujBAREVHsqzR4si+evGnt6quvdrkxDcz54tWrV+fZZ591qS/2wHs2HcY9wq/9WmC3OYjuvJQzXxf9plARCVwKvOJCN60VPvBOmzYNwzD44YcfPN6HRx55hNatW3PmzJkivS93U4HHHnvMZRRw8uTJNGjQgOuuu47hw4e7vOf7778nNDTUpa5bt268/fbb+X6GJ+bw5s43ff/99wv8PgUFsiNHjrjVnT17lrvvvpvg4GCXG+KKcuxff/1FfHy8SxjbsmULhuG69m1GRgY33HADDzzwQIHfwdOK0pf8vktehV2WrHv37gX26ciRIxiGwXPPPedSn7sld3h4uEt9sQdegMktyBlahfnnlijb3rujGYRFpFRQ4BUXCryFD7xbt27FMAz+8Y9/MGfOHBYuXOixZclSUlKKtENe3vfljq5OnjzZWT979mwMw6Bs2bJu84HXr19PvXr1XOoGDhyIzWa7rL4X1u23386LL76Y72uF2QUxdy7ysGHDiImJYcSIEdx8880YhsF7773n0l5Rjs39878wpLVr146goCD69OlDVFQUDz30EEFBQZdcLgsgKSnJuXTdpUphfoYK25eLfZfCnF84v/HEpeZ0506nqFy5Ml26dGHixIm8+OKLhIWFYRgGbdq0yfemtWINvGMfhvAQ4vo8jd3m4IMuH5N1OK7ANkWk5FDgFRcKvIUPvAAjRoygdu3aWK1Wr01vKIrs7GwsFguVKlVy+TNcvHgxhmHw/PPPu72nqCO8njJu3DgqVaqU781QhdkFceHChbRo0YKaNWsSFBREaGgoLVq0YMmSJW7tFeXYi4XE9PR0evfuTa1atShfvjz33XcfX375ZaG+qyeX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DMPg008/veTnfPHFF1gsFh577DGio6Pp3r07VquVzp07e+FbXZniOCfLli2jbNmy/Otf/2LChAnY7XYee+wxDMNg6NChXvpml6+4fk7yeuqpp6hYsaJfXpSL63ycOHGCxo0bU61aNQYMGMD777/Pu+++y/9v7+6joirzOID/hsEBYXhL3hRwMs+K78NW+JIiGeXqali6ptEaUG2mJUibnlrcBeGcMjQyEUi2dE/kS5umi2db09Vejkcz11NWm2UpuZpKrOJbIQh89w/PvctlXgDhjszw/Zwz5+gzlzvP/c2dZ75z57l3Jk+ejHPnzumwZdfPVTWZNm0avL29MXfuXPz5z3/GkiVLEB4ejoCAAHz//fc6bNn1a2tNFi1aBBHBb37zG5SWlmL+/Pnw9vbGhAkT2vQ47jK+uqIenjq2dnQfaa4rj62uxMDbzVy5cgWnT58GABw4cMDhi+0Xv/gF4uPj0dTUpLZduHABZrMZycnJrT7O4MGDYbVaNUccsrOzYTAYcPjw4Y5vSCdyRU2OHTtm8+bc1NSEu+66Cz4+Ptf1qV1PrtpPFNu3b4fJZMLixYu75KDsqnrMnTsXwcHBOHbsWKf1XS+uqMnJkychInjmmWc07bt374aIoLCwsOMb0onaUpNTp07B29sbs2fP1rQXFRVBRFBRUdHq47jL+OqKenji2NoZ+4iiq4+trsTA2405e5OKiIjA5MmTbdojIyMxc+ZMp+v997//DRFBcXGxpv2HH36AiCA/P79D/daTXjVxRDn69fnnn1/X37uC3jWpr69HbGwsFi5ciLVr13b5QVmvetTU1MDX1xeLFi0CANTV1bnNtTb1qsnhw4chIli2bJnd9tLS0g71W0+OarJ582aICP7+979r2qurqyEiSElJcbpedx1f9aqHI+48tnZWTdxtbNUbA2835uxNaubMmTAajVi5ciUqKytx+PBhzJs3Dz179sTevXudrvfNN9+EiGD//v0290VHR2PatGmdtQmdTq+aOPKHP/wBIoJTp051sOf60bsmBQUFCA8Px4ULF9xiUNarHtu2bYOIoKysDNOnT4fRaITBYMAdd9yBTz/9VKet6Rx61aS+vh7R0dGIjIxERUUFTpw4gf379yMxMRH9+vVDTU2NTlvUcY5qsn79eogIdu/erWn/6aefICKIjY11ul53HV/1qocj7jy2dlZN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\" width=\"700\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fitting function: a*erfc(-np.sqrt(2)*(x-x0)/w0) + b\n", - "w0 = (314.9 +/- 0.6) um\n", - "x0 = (12.092 +/- 0.000) mm\n", - "a = 2.480674e+05 +/- 1.685863e+02 \n", - "b = -8.370131e+03 +/- 1.847908e+02 \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 / 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,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\" width=\"700\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "X-FWHM [um]: 156.5707204032264\n", - "Y-FWHM [um]: 370.80865951724894\n" - ] - } - ], - "source": [ - "runX['FastADC4peaks'] = tbdet.autoFindFastAdcPeaks(runX, channel=4, plot=True)\n", - "runY['FastADC4peaks'] = tbdet.autoFindFastAdcPeaks(runY, channel=4)\n", - "\n", - "w0_x = knife_edge(runX, axisKey='scannerX', plot=True)[0]*1e-3\n", - "w0_y = knife_edge(runY, axisKey='scannerY', plot=True)[0]*1e-3\n", + "w0_x = tbr.knife_edge(dsX, axisKey='scannerX', signalKey='Tr', plot=True)[0]*1e-3\n", + "w0_y = tbr.knife_edge(dsY, axisKey='scannerY', signalKey='Tr', plot=True)[0]*1e-3\n", + "print(w0_x, w0_y)\n", "\n", "print('X-FWHM [um]:', w0_x * np.sqrt(2*np.log(2))*1e6)\n", "print('Y-FWHM [um]:', w0_y * np.sqrt(2*np.log(2))*1e6)" @@ -5961,1663 +298,63 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Fluence calculation (OL)" + "## Fluence calculation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### OL power measurement " + "### Load XGM data" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "#measurement performed in Exp Hutch before in-coupling window\n", - "rel_powers = np.array([100, 75, 50, 25, 15, 12, 10, 8, 6, 4, 2, 1, 0.75, 0.5, 0.25, 0.1, 0])\n", - "powers = np.array([505, 384, 258, 130, 81, 67, 56.5, 45.8, 35.6, 24.1, 14.1, 9.3, 8.0, 6.5, 4.8, 4.1, 1.0])*1e-3 #in W\n", - "\n", - "rep_rate = 10\n", - "npulses = 336" + "proposal = 900094\n", + "runNB = 647\n", + "run, ds = tb.load(proposal, runNB, 'SCS_SA3')\n", + "ds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Fluence vs. laser power" + "### Calibrate XGM fast data using photon flux and plot" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[150.29761905 114.28571429 76.78571429 38.69047619 24.10714286\n", - " 19.94047619 16.81547619 13.63095238 10.5952381 7.17261905\n", - " 4.19642857 2.76785714 2.38095238 1.93452381 1.42857143\n", - " 1.2202381 0.29761905]\n", - "[228.46899057 173.7269156 116.72277142 58.81379955 36.64552126\n", - " 30.31172746 25.56138211 20.720554 16.1059328 10.90317361\n", - " 6.37903518 4.20744874 3.61931074 2.94068998 2.17158645\n", - " 1.85489676 0.45241384]\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 / 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,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\" width=\"640\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('<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,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\" width=\"640\">" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1.49838084 1.33228895]\n" - ] - } - ], + "outputs": [], "source": [ - "pulse_energies = powers/(rep_rate*npulses)\n", - "print(pulse_energies*1e6)\n", - "fluences = 2*pulse_energies*1e3/(np.pi*w0_x*w0_y*1e4)\n", - "print(fluences)\n", - "plt.figure()\n", - "plt.plot(rel_powers, fluences, 'o-', ms=4)\n", - "plt.grid()\n", - "plt.ylabel('Peak fluence [mJ/cm$^2$]')\n", - "plt.xlabel('Laser power [%]')\n", + "f_scs = tbdet.calibrate_xgm(run, ds, plot=True)\n", + "f_xtd10 = tbdet.calibrate_xgm(run, ds, xgm='SCS')\n", + "\n", + "pulse_energy = ds['SCS_SA3'].mean().values*f_scs*1e-6 #average energy in J\n", + "ds['pulse_energy'] = ds['SCS_SA3']*f_scs*1e-6\n", + "ds['fluence'] = 2*ds['pulse_energy']/(np.pi*w0_x*w0_y)\n", + "print('Pulse energy [J]:',pulse_energy)\n", + "F0 = 2*pulse_energy/(np.pi*w0_x*w0_y)\n", + "print('Fluence [mJ/cm^2]:', F0*1e-1)\n", "\n", - "e_fit = np.polyfit(rel_powers, pulse_energies*1e6, 1)\n", "plt.figure()\n", - "plt.plot(rel_powers, pulse_energies*1e6, 'o-', \n", - " ms=4, label='E[$\\mu$J] = {:.3f} x power [%] + {:.3f}'.format(e_fit[0], e_fit[1]))\n", - "plt.grid()\n", - "plt.ylabel('Pulse energy [$\\mu$J]')\n", - "plt.xlabel('Laser power [%]')\n", - "plt.plot(rel_powers,rel_powers*e_fit[0]+ e_fit[1])\n", + "plt.hist(ds['pulse_energy'].values.flatten()*1e6, bins=50, rwidth=0.7, color='orange', label='Run 645')\n", + "plt.axvline(pulse_energy*1e6, color='r', lw=2, ls='--')\n", + "plt.xlabel('Pulse energy [$\\mu$J]', size=14)\n", + "plt.ylabel('Number of pulses', size=14)\n", + "#plt.xlim(0,50)\n", "plt.legend()\n", - "print(e_fit)" + "ax = plt.gca()\n", + "plt.twiny()\n", + "plt.xlim(np.array(ax.get_xlim())*2e-6/(np.pi*w0_x*w0_y)*1e-1)\n", + "plt.xlabel('Fluence [mJ/cm$^2$]', labelpad=10, size=14)\n", + "plt.tight_layout()" ] }, { diff --git a/notebook_examples/XAS and XMCD energy shift investigation.ipynb b/notebook_examples/XAS and XMCD energy shift investigation.ipynb new file mode 100644 index 0000000..31a296b --- /dev/null +++ b/notebook_examples/XAS and XMCD energy shift investigation.ipynb @@ -0,0 +1,343 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook shows an example of X-ray absorption spectroscopy (XAS) and X-ray magnetic circular dichroism (XMCD) experiment." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Import toolbox_scs and subpackages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "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 toolbox_scs as tb\n", + "import toolbox_scs.detectors as tbdet\n", + "import toolbox_scs.routines as tbr\n", + "import extra_data as ed\n", + "import xarray as xr\n", + "\n", + "import logging\n", + "logging.basicConfig(level=logging.INFO)\n", + "log_root = logging.getLogger(__name__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load data, extract pulse-resolved signals from detectors\n", + "\n", + "Here, we use the ToolBox mnemonics to get the arrays: MCP1apd is the pulse-resolved peak-integrated TIM data from MCP 1, SCS_SA3 is the XGM data for SASE 3 pulses in SCS hutch, nrj is the monochromator energy in eV and magnet is the current applied to the magnet in A.\n", + "\n", + "The function get_all_detectors() takes care of aligning the pulse-resolved data (TIM and XGM) according to the sase 3 bunch pattern." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "runNB = 491\n", + "proposalNB = 900094\n", + "mcp = 'MCP1apd'\n", + "fields = [mcp, 'SCS_SA3', 'nrj', 'magnet']\n", + "run, ds = tb.load(proposalNB, runNB, fields)\n", + "mcp = mcp.replace('apd', 'peaks')\n", + "ds\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Split positive and negative magnetic fields, calculate XAS and XMCD spectra\n", + "\n", + "Here we first define the monochromator energy bins, and apply the xas() subroutine to subsets of the data. The subsets correspond to positive magnet current and negative magnet current. The xas() routine returns (among other quantities) the binned energy and the absorption, which are then plotted for both positive and negative magnet currents." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nrj_bins_edges = np.linspace(704, 712, 31)\n", + "pxas = tbr.xas(ds.where(ds['magnet'] > 2, drop=True), bins=nrj_bins_edges, plot=False, Itkey=mcp)\n", + "nxas = tbr.xas(ds.where(ds['magnet'] < -2, drop=True), bins=nrj_bins_edges, plot=False, Itkey=mcp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.plot(pxas['nrj'], pxas['muA'])\n", + "plt.plot(nxas['nrj'], nxas['muA'])\n", + "plt.ylabel('$\\mu_A$')\n", + "plt.xlabel('Energy [eV]')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now calculate the XMCD using the positive and negative data returned by xas() routine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res = tbr.xasxmcd(pxas, nxas)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.plot(res['nrj'], res['muXAS'])\n", + "plt.ylabel('$\\mu_A$')\n", + "plt.xlabel('Energy [eV]')\n", + "plt.twinx()\n", + "plt.plot(res['nrj'], -res['muXMCD'], c='C1')\n", + "plt.ylabel('$\\mu_{XMCD}$')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Only 2000 first train" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "subds = ds.isel({'trainId':slice(1600)})\n", + "\n", + "pxas2 = tbr.xas(subds.where(subds['magnet'] > 2, drop=True), bins=nrj_bins_edges, plot=False, Itkey=mcp)\n", + "nxas2 = tbr.xas(subds.where(subds['magnet'] < -2, drop=True), bins=nrj_bins_edges, plot=False, Itkey=mcp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.plot(subds['nrj'])\n", + "plt.ylabel('energy [eV]')\n", + "plt.xlabel('train number')\n", + "plt.twinx()\n", + "plt.plot(subds['magnet'], c='C1')\n", + "plt.ylabel('magnet current [A]')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.errorbar(pxas['nrj'], pxas['muA'], pxas['sterrA'], label='pos all trains')\n", + "plt.errorbar(pxas2['nrj'], pxas2['muA'], pxas2['sterrA'], c='C0', ls='--', label='pos first 2000 trains')\n", + "\n", + "plt.errorbar(nxas['nrj'], nxas['muA'], nxas['sterrA'], label='neg all trains')\n", + "plt.errorbar(nxas2['nrj'], nxas2['muA'], nxas['sterrA'], c='C1', ls='--', label='neg first 2000 trains')\n", + "plt.legend()\n", + "plt.ylabel('$\\mu_A$')\n", + "plt.xlabel('Energy [eV]')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res2 = tbr.xasxmcd(pxas2, nxas2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.plot(res['nrj'], res['muXAS'])\n", + "plt.plot(res2['nrj'], res2['muXAS'], ls='--', c='C0')\n", + "plt.ylabel('$\\mu_A$')\n", + "plt.xlabel('Energy [eV]')\n", + "plt.twinx()\n", + "plt.plot(res['nrj'], -res['muXMCD'], c='C1')\n", + "plt.plot(res2['nrj'], -res2['muXMCD'], ls='--', c='C1')\n", + "plt.ylabel('$\\mu_{XMCD}$')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mono up or down" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.signal import savgol_filter\n", + "\n", + "dE = np.gradient(savgol_filter(ds['nrj'], 9, 1))\n", + "mono_turn = dE > 0\n", + "\n", + "plt.figure()\n", + "plt.plot(1e3*dE)\n", + "plt.ylabel('Delta energy (meV)')\n", + "plt.twinx()\n", + "plt.plot(mono_turn, ls='', marker='.', c='C1')\n", + "plt.ylabel('mono going up')\n", + "plt.title(f'run {runNB} p{proposalNB}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds['mono_turn'] = xr.DataArray(np.gradient(savgol_filter(ds['nrj'], 9, 1))>0, dims=['trainId'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "subds = ds#.isel({'trainId':slice(1600)})\n", + "\n", + "Eshift = 0.05\n", + "shift_subds = subds\n", + "shift_subds['nrj'] = subds['nrj'] + Eshift\n", + "pxas3a = tbr.xas(shift_subds.where((subds['magnet'] > 2)*subds['mono_turn'], drop=True),\n", + " bins=nrj_bins_edges, plot=False, Itkey=mcp)\n", + "nxas3a = tbr.xas(shift_subds.where((subds['magnet'] < -2)*subds['mono_turn'], drop=True),\n", + " bins=nrj_bins_edges, plot=False, Itkey=mcp)\n", + "\n", + "shift_subds['nrj'] = subds['nrj'] - Eshift\n", + "pxas3b = tbr.xas(shift_subds.where((subds['magnet'] > 2)*np.logical_not(subds['mono_turn']), drop=True),\n", + " bins=nrj_bins_edges, plot=False, Itkey=mcp)\n", + "nxas3b = tbr.xas(shift_subds.where((subds['magnet'] < -2)*np.logical_not(subds['mono_turn']), drop=True),\n", + " bins=nrj_bins_edges, plot=False, Itkey=mcp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "#plt.errorbar(pxas['nrj'], pxas['muA'], pxas['sterrA'])\n", + "plt.errorbar(pxas3a['nrj'], pxas3a['muA'], pxas3a['sterrA'], c='C0', ls='-', label='+H, mono up')\n", + "plt.errorbar(pxas3b['nrj'], pxas3b['muA'], pxas3b['sterrA'], c='C0', ls='--', \n", + " label=f'+H, mono down, dE = {-1e3*Eshift} meV')\n", + "\n", + "#plt.errorbar(nxas['nrj'], nxas['muA'], nxas['sterrA'])\n", + "plt.errorbar(nxas3a['nrj'], nxas3a['muA'], nxas3a['sterrA'], c='C1', ls='-', label='-H, mono up')\n", + "plt.errorbar(nxas3b['nrj'], nxas3b['muA'], nxas3b['sterrA'], c='C1', ls='--', \n", + " label=f'-H, mono down, dE = {-1e3*Eshift} meV')\n", + "\n", + "plt.xlabel('Energy (eV)')\n", + "plt.ylabel('XAS (arb. units)')\n", + "plt.title(f'run {runNB} p{proposalNB}')\n", + "plt.xlim([707, 709])\n", + "plt.ylim([3, 4.5])\n", + "plt.legend()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.title(f'run {runNB} p{proposalNB}')\n", + "plt.xlabel('Energy (eV)')\n", + "plt.ylabel('XAS (mono up) - XAS (mono down) (arb. units)')\n", + "plt.plot(pxas3a['nrj'], pxas3a['muA'] - pxas3b['muA'])\n", + "plt.plot(nxas3a['nrj'], nxas3a['muA'] - nxas3b['muA'])\n", + "plt.ylim([-0.1, 0.18])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "xfel", + "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": 2 +} diff --git a/notebook_examples/tim-normalization.ipynb b/notebook_examples/tim-normalization.ipynb index ac51581..2f19d89 100644 --- a/notebook_examples/tim-normalization.ipynb +++ b/notebook_examples/tim-normalization.ipynb @@ -74,7 +74,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.044 s\n" + "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0048 s\n" ] } ], @@ -134,8 +134,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0023 s\n", - "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0021 s\n" + "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0031 s\n", + "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0027 s\n" ] } ], @@ -174,6 +174,7 @@ "name": "stderr", "output_type": "stream", "text": [ + "INFO:toolbox_scs.detectors.digitizers:Extracting ADQ412 peaks from ['MCP2apd', 'MCP1apd', 'MCP3apd'].\n", "INFO:toolbox_scs.detectors.dssc_misc:loaded formatted tim data.\n", "INFO:toolbox_scs.detectors.dssc:binned tim data according to dssc binners.\n" ] @@ -193,6 +194,7 @@ "name": "stderr", "output_type": "stream", "text": [ + "INFO:toolbox_scs.detectors.xgm:Extracting XGM data from ['SCS_SA3'].\n", "INFO:toolbox_scs.detectors.dssc_misc:loaded formatted xgm data.\n", "INFO:toolbox_scs.detectors.dssc:binned xgm data according to dssc binners.\n" ] @@ -211,7 +213,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43da66390>]" + "[<matplotlib.lines.Line2D at 0x2ba157986860>]" ] }, "execution_count": 10, @@ -245,7 +247,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43dca0898>]" + "[<matplotlib.lines.Line2D at 0x2ba1571a5e80>]" ] }, "execution_count": 11, @@ -254,7 +256,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAD4CAYAAAAAczaOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO3deXiMVxvH8e9JMtkjEUIIse+7ppYWVUXR2rpYiip9q6q8VLWWVnel2lqqraIUpdUWrdhp7bskRGwhBEmQiET2dea8f8y0pfa3SSbJ3J/rmsvk2eY+ht88OXOe8yitNUIIIWyDnbULEEIIUXAk9IUQwoZI6AshhA2R0BdCCBsioS+EEDbEwdoF3Enp0qV15cqVrV2GEEIUKcHBwfFaa59brSvUoV+5cmWCgoKsXYYQQhQpSqnzt1sn3TtCCGFDJPSFEMKGSOgLIYQNkdAXQggbIqEvhBA2REJfCCFsiIS+EELYkEI9Tl8IIWyK1pBwFiJ3mH8OGJTnLyGhL4QQ1qI1JJ6Dczshciec2wUpF83rKjST0BdCiKJIa01qVi7Jmbmkx0Vid34XLjF78Irdh2vGJQBSHUpyxq0JR316c8iuAYaSNZicD7VI6AshRD5KTUvli69nUS1pHy3tjlHD7goAV7UHW0112Gd6nL2musQY/SlhZ6CENuDh7EB9h/z5ylVCXwgh8prWEBMMh5diH/IzE0ypZDqXIL5UAMd9W5BVoRX2vnWo5+JESxcD7zg7YLC3+8ch8udWthL6QgiRV5IvwZFlcPgHiD9Frp0z63IC0I2e45mn+lDBzv6uhziVeIoFRxegUExunfcdPBL6QgjblhQDgSPAzQdK1wCfWlC6JnhXBXvD3ffPyYTwdXB4KZzZAtoE/i258uhndPmjFFUqlOPHp1qAnbrjYUJiQ5h/dD47onfg4uBCn9p90Fqj1J33u18S+kII27ZtsnmIpHsZ81n6n+wczMFfuubfD5+aUKoGOHlATIg56I8uh8wkKFEBWr8OjfqS5VmZQbP3kG2fwYzejbG/TeBrrdkZs5Nvw77lUNwhSjqVZHjj4fSp3QdPJ898aa6EvhDCdl09Y+6KaTYEOk+BrBSIPw3xp8yPK+Hmn09tAFPu3/s5e0HmNXBwhjrdoPFzUOURsDP3y09dc5yjMcnMHfAA5b1cbnrZXFMuG85tYMHRBZxOPE05t3KMazaOp2o8hYvDzdvnJQl9IYTt2jYZHJyg9Wjzz04e4NfU/LieMcc8nv5KOBcvBbM4bi/K3ZcK/q0o71UNPw8/KhgzcbVzZevJOObviuT5lpXoWM/3hsNk5GbwW8RvLDq2iJjUGKp7VefjVh/TqUonDHb30JWUByT0hRC2KfY4hC2HVqPMXTt3Ym8g06si38X8zoKLazBpE/ZJCWQcCr5hM09HL5JTPChTrTQe5Rrxc/hx/Nz9KONahq1RW1l6YikJmQk08mnEuGbjaFOhDXaqYGfDkdAXQtimrZPMZ/YP/feOm2mt2RK1hU8PfkpMagwdK3VkTMAYfN18ScxKJCYlhpjUGKJSolkSdAij8TJepeP5MXwpOaacG47V2q81LzZ4kaZlmub5F7T3SkJfCGF7Lh6Ck2ug7Xhw9b7tZpFJkUw5MIU9F/dQ3as633b8lublmv+13tvZG29nbxr4NOCrrRGcP1WOT55uQO8H/TFpE3HpccSkxnAx9SI1S9aklnetgmjdHUnoCyFsz5ZJ4FISWgy75eq0nDTmhM7h+xPf42LvwtgHx9K7du/b9rsHn09g2uZTPNmwHL0CKgJgp+zwdfPF182XB8o+kG9NuV8S+kII23JhH0Rshvbvg3OJG1ZprVlzdg3Tg6dzJeMKPav3ZGTTkZRyKXXbwyVl5PDfHw9T3suZj59qYLVum3sloS+EKFaiEtL59VAMGTlGsnNN5BhNZOeayDaayMk1MfzCm/jalWT08cakHNtLjtGEAupXSSU8ZzHHE49Qv1R9Zjw6g4Y+De/4Wlprxq88QmxyJr8MbUkJ54IZgfNvSOgLIYoFrTXLg6N5L/AYadlGDPYKR3s7DA525j/t7WhBGDUyQ5nh9gKXTbFgn4w2JJNkOs2p2D1ooyt++nm6+TxLZQ+/u77mjweiWBd2mbGdatPEv2QBtPLfU/k1qU9eCAgI0EFBQdYuQwhRyCWmZTPh1yNsOHGGBpU0A1p5ou1TuJJxhSvpV4jPiOdKxhXi40+SgJHcf3TBOCgHnqj8FN453VhzOJGzV9JwcrCjQ92yPNXUj9Y1fG6aEO1UbApdZ+2iWRVvFg1qht1dplkoSEqpYK11wC3XSegLIQo7rTVJWUlcTr/M5bTLxKbF/vU8PD6KiIRoTHbXUHbGG/ZTKEo6l8THxYfSJvCJDsan6mOUqvIoPi4++Lj6UNqlND4uPjg7OP/1Wkeik1gZEk1g6EUS03Mo7e5It0Z+PNXUj3rlS5CVa6Lbl7tISMtm3cjWlPFwtsZfy21J6Ashiqx5R+YxL2weGbkZNyy3Vw44qZIkp7riZl+aDjVrUb+sv3nEjKsvpV1K4+3ibR5xYzLB3DaQlQrDD97bRGpAdq6J7aeusDIkmj9OxJFtNFGzrDtlPJzZFRHPosHNeKSmT340+1+5U+hLn74QotD6/fzvfHHoC1r7taZFuRZ/DYFMSXXj/d+iOBWbxsCWlRjXuQ4ujneYtvhEIFwOg55z7znwARwtXTwd6pblWno2a45c4tdDMeyKiOflR6oWysC/GznTF0IUSmeTztJ3TV+qe1Xnu07f4WjviMmkWbA7kqkbwinhYuDTZxvyaK27TKFgMsLXLc3Ph+2Fe5jT/m6upmbh7eZYaIdnypm+EKJISctJY9TWUTg7OPN5289xtHfkUlIGY34JZXfEVTrULcuUpxpQyt3p7gcL+wXiw+HZRXkS+MC9vW4hJaEvhChUtNZM3D2R88nnmddhHr5uvqw9cokJv4aRnWti8lMN6PNgxXs7yzbmmGfS9G1gngJZSOgLIQqXhccWsvn8Zl5/4HWalWvGtE3hfLElgkYVvZjRuzFVSrvd+8EOLTFPifzcz3/NdW/rJPSFEIXG/kv7mREyg46VOjKw3kA2HL3MF1sieOaBCkx+qsFNY+XvKCcTdnwKFR6EGh3zr+giRkJfCFEoXE67zBvb36Byicp88PAHRManMeaXUBpV9GJSz/r3F/gAwQshOQZ6fA2F9AtXa7jr36JSylkpdUApFaqUOqaUet+yfKFSKlIpddjyaGxZrpRSXyilIpRSR5RSTa871kCl1GnLY2D+NUsIUZRkG7MZvW002aZspj86HaWdeGVJCAZ7xdf9muLkcJ9fwGanwc7PoHJr820MxV/u5Uw/C2intU5VShmAXUqp9ZZ1b2itl/9j+85ADcujOTAbaK6U8gbeBQIADQQrpQK11ol50RAhRNE1+cBkwuLDmN52OlVKVGHUT4c5FZfCokHN8LvFPWbv6sBcSLsCvZfIWf4/3PVMX5ulWn40WB53GtzfHVhs2W8f4KWUKgc8DmzWWidYgn4z0OnflS+EKOp+Pf0ry08tZ3D9wbSv1J7v951n1eGLjG5fkzb/z8VPmUmweyZU7wD+LfK+4CLunjrJlFL2SqnDQBzm4N5vWTXJ0oUzXSn158BVPyDqut2jLctut/yfrzVEKRWklAq6cuXKfTZHCFGUHLt6jI/2fUTzcs0Z0WQEIRcS+XDNcR6rXYZXH61+fwdLiYWtk2FWAGRcg3Zv5U/RRdw9hb7W2qi1bgxUAJoppeoD44HawIOANzA2LwrSWs/VWgdorQN8fIreJc5CiHtzLfMao7eOxtvFm6ltpnIt3ciwJSH4ejozrVfje5+1MiYEVg6B6fVg+xQo3xgGBkL5JvnbgCLqvkbvaK2vKaW2Ap201p9ZFmcppb4Dxlh+jgEqXrdbBcuyGKDtP5Zv+z9qFkIUcUaTkTd3vMmVjCss7rwYT8eSDPh+P4np2ax45SE8Xe8yP44xB46vgv1zIPoAOLpDwGBoNgRK3+dvCDbmrqGvlPIBciyB7wJ0AD5RSpXTWl9S5sviegBHLbsEAsOVUsswf5GbZNluI/CxUurPOw10xPzbghDCxnx1+Cv2XtrLuy3fpX7p+kzdcJI9Z64y9ZmG1PfzvP2OafHmoZgH50PKRShZBTpNgcbPgfMd9hN/uZcz/XLAIqWUPebuoJ+11muUUlssHwgKOAwMtWy/DugCRADpwCAArXWCUupD4KBluw+01gl51xQhRFGw5cIW5oXN46kaT/FMzWfYdOwyX287Q99mFf+6qfhNLh0xn9WH/QLGLKj6KDw53XzRlVxpe19klk0hRIG5lHqJp1c/TUWPiizuvJhLibl0nbWLyqXd+GVoS5wN/xiPnxAJG8bDqfVgcIVGfaDZy1CmtnUaUETILJtCCKszmoyM2zkOo8nIp20+xWR0YOiS/dhbLsC6IfBzMs3DLndNA2UP7SbCgy+CS9G4D21hJqEvhCgQ34Z9S0hcCJNaTaKiR0Ve/yWU8NgUvnvhQSp6u/694enNsO4NSIyEej2h4yTwvPtNysW9kdAXQuS70CuhzA6dTefKnelatStL919gZUgMo9rXoO2fN0G5FgUbxsHJNVCqOgz4Faq1s27hxZCEvhAiX6VmpzJ2x1jKupbl7ZZvExqdxAerj/NITR/+264G5GbD3i/NM2JqDY+9Ay2Hg0PRvVFJYSahL4TIVx/v/5hLaZdY2GkhkbEmBi88iI+HEzN6N8bu3HZYOwaunobaT0KnyeDlb+2SizUJfSFEvllzdg2rz65mWKNhpFyrwNAl+yjl7sjSXv6UXDcEjv1qHmvfbznU6GDtcm2ChL4QIl9Ep0Tz0b6PaFKmCWX1EwxeeJCaZdz4qXEoHj8MMF9V23Y8PDwKDM7WLtdmSOgLIfJcrimXcTvHoVA0dh7G6J/C6OqfzXSnWThs22OeAbPLp+Bdxdql2hwJfSFEnptzZA6hV0J5uMQovtgYzwf+hxlwbTYKBd2/gsb9ZJ57K5HQF0LkqZDYEOYemUs5+1YE73dmfZmvqRO323wXqx5fyxe1ViahL4TIM8nZyYzdMQ6DqRT+4SVZ5T4e5/QseHwyNB8q8+QUAhL6Qog8obVm4s73uZwWy5BoH0YYvoIyTaDnHPCpZe3yhIWEvhAiTywOW86W6E0MSsziVWOIeWRO69fB/i5z44sCJaEvhPjXdpwKYWbwRwRkZfISHtj9Zxn4NbV2WeIWJPSFEP/K0QObmHH4NVwcNG+W6ohHj8/A4GLtssRtyLcqQoj/W9gf3/Lbvpc57WTHa9VfpM6zX0ngF3Jypi+EuC85xhx2xuxk+d6ZHEiPIMvTna7+T/JMm9etXZq4BxL6Qoi7MmkTwbHBrD27ls3nN5OcnUxJo5GW6e70fPwzHq3e2tolinskoS+EuCWtNScTTrIuch3rItcRlx6Hi4MLrXQJel6OICm7OU2HLaF8qRLWLlXcBwl9IcQNolKiWHd2HWsj1xKZFImDnQOt/FrxRtPXaLrnJ8qcCeRH+660GvYN5Uu5W7tccZ8k9IUQf1l2chlTDkzBqI0ElA1gQN0BdPDvgJedgbQl/XG7sIWv7PvxxNCpVJTAL5Ik9IUQ5Jpy+eTAJywLX8YjFR7h7RZv4+vma16ZnkDmwq44Xz7ER3ZD6Tt0IpV9JPCLKgl9IWxccnYyY7aNYe+lvQyqN4iRTUdib2dvWXmR7EU9sbsawVi70Qx5eRTVJPCLNAl9IWzYheQLDN8ynKiUKD546AN61uj598qrZ8hd2I3clHhGqgm89p+XqFnWw3rFijwhoS+EjTp4+SCvbXsNhWJuh7k86Pvg3ysvhWJc3JPUjBxe5l0m/qcfdcvLKJ3iQK7IFcIGrTi1giGbhlDKuRQ/dPnhxsCP3Inpuy7EZ9rRX3/AuMF9qe/nab1iRZ6SM30hbIjRZGRa8DQWH1/Mw+Uf5tNHPsXD8boum7gT6KXPcMHkwyDjeD4d3Jkm/iWtV7DIcxL6QtiI1OxUxu4cy47oHfSr048xAWNwsLsuAkxG0pcPI8dooF/uW3w+qCMBlb2tV7DIFxL6QtiAmNQYhv8xnMikSCa2mEivWr1uWB+XksneHz6me1wIb6kRfPJ8B1pULWWlakV+ktAXopg7FHeIUVtHkWPKYXb72bQs3/KvdZk5RubviuTXrftYpb7hjGdz3hz6Dp6ujlasWOQnCX0hiiGTNhF0OYhVZ1axPnI95d3LM6vdLKp4VgHM8+qsC7vM5PUniE5MZ3XJxbjk2lNt0DyQwC/WJPSFKEaiUqJYfWY1gWcCiUmNwd3gTo/qPRjZdCSeTuYROEeir/HhmuMcPJdIbV8PNj0WR83d+6HTFChZycotEPlNQl+IIi49J51N5zexKmIVQbFBKBQtyrVgRJMRtPNvh4uD+aYmscmZTN0QzoqQaEq7OzL5qQb0quuK/dcvgN8D0GyIdRsiCoSEvhBF0J/z26+KWMWm85vIyM3A38OfEU1G0K1at7/nzQEyso3M23mW2dvOYDRphj5SjVcfrYaHswFWvgyZSdBtFvw59YIo1iT0hShCUrJTWHJ8CavOrCImNQY3gxtdqnShe/XuNPZpjFLqr21NJs2q0Bg+3RDOxaRMOtf3ZXznOviXcjVvEPE7HFkGbd6AsvWs1CJR0CT0hSgiTNrEGzveYE/MHpqVa8arjV+lfaX2f3XfXG93RDwfrzvBsYvJ1PcrwbTejW8cgpmVCqtfg1I1oPWYAmyFsLa7hr5SyhnYAThZtl+utX5XKVUFWAaUAoKBAVrrbKWUE7AYeAC4CvTWWp+zHGs88CJgBP6rtd6Y900Sonj64cQP7I7ZzYTmE+hbu+8ttwm/nMLk9SfYFn4FPy8XZvZpTNeG5bGzUzduuPVjSLoAg9aDwbkAqheFxb2c6WcB7bTWqUopA7BLKbUeGA1M11ovU0p9gznMZ1v+TNRaV1dK9QE+AXorpeoCfYB6QHngd6VUTa21MR/aJUSxEp4QzrTgaTxStjl9MjTkZoPD30MrLydlMn3zKX4JjsLdyYEJXWrzfMvKOBtu0U8fHQz7Z0PAi1DpoQJshSgM7hr6WmsNpFp+NFgeGmgHPGdZvgh4D3Pod7c8B1gOfKnMHY3dgWVa6ywgUikVATQD9uZFQ4QorjJzMxm7YywlDG68f3Ifat8vsHs6PPE5qeUfYs72M8zbeRajSTPo4SoMf7Q6Jd1uM9Y+NxsCR4C7L7R/t2AbIgqFe+rTV0rZY+7CqQ58BZwBrmmtcy2bRAN+lud+QBSA1jpXKZWEuQvID9h33WGv3+f61xoCDAHw9/e/z+YIUfx8HvQ5Z5LO8E2yiVKZqdDlM/TeL1GLurJLtWJZRl86NKrHm4/XoqK3650PtmcmxB2DPj+Cs8ycaYvuKfQtXTCNlVJewK9A7fwqSGs9F5gLEBAQoPPrdYQoCrZHbWdZ+DL6Z5h4OD0N/fwqNif6Mi3Hn065yxjmsJoOHoexr/I2eDa488GunILtU6FuD6jdpWAaIAqd+5pPX2t9DdgKtAS8lFJ/fmhUAGIsz2OAigCW9Z6Yv9D9a/kt9hFC/EN8Rjzv7HqLmrmaUUnpXO7xC8+vz2LI98HkKCfqPTcFw4j92FdqARvGwdy2cGH/rQ9mMsHqkWBwgc5TC7QdonC5a+grpXwsZ/gopVyADsAJzOH/jGWzgcAqy/NAy89Y1m+xfC8QCPRRSjlZRv7UAA7kVUOEKE5M2sTbW0eTlnWNT65lsKbBbB5dcpWQ84m817UuG0e1oUPdsqhS1aDfcuj1PWQkwIKOsOpVSIu/8YAhC+HCHug4CTzKWqVNonC4l+6dcsAiS7++HfCz1nqNUuo4sEwp9RFwCJhv2X4+8L3li9oEzCN20FofU0r9DBwHcoFXZeSOELf2w8EZ7L5yiPHJ2Uy3e5+1O4y0r1OGD7rXp7zXP8blKwV1u0G1drBjKuz9Ck6sMX9R2/QFSL0Mm9+FKm2gSX+rtEcUHsp8El44BQQE6KCgIGuXIUSBCj+zkb47X6d5ppGzUSO56lKd97vVo0sD3xuuuL2tuJOwbgyc2wnlm4KjG0QfhGF7wbtq/jdAWJ1SKlhrHXCrdXJFrhCFSOalUN7cOhoPBSejh9KsyUNM6FIHT1fDvR+kTG0YuBrClsPGCZAWBx0+kMAXgIS+EIVG0rlQpq/pxVkPR6ol9mLsoP60rPZ/3r1KKWj4LNTsCJE7oJaM1hFmEvpCWJnWmq07tpGxbzArfN1p7NiGea9OuPXVtPfL2RPqdP33xxHFhoS+EFZ08VoG3/z0GwNi32BQBS8qu/oz/6npONrLNMcif0joC2EleyLimbl0BV+bPmRseU8yDU7M6PAFjvZyu0KRfyT0hShgWmu+232OFes38KPjJH4tU4L9zna8/eCbVPOqZu3yRDEnoS9EAcrMMTLh1zCOHtrHQtfJhHiWYGYJJ9r6taJXrV7WLk/YAAl9IfJZek46kUmRHLx4nHn795CZfQqv6ud43ME84VkZJ2/ef+j9exuDL8S/JKEvRB66lHqJQ3GHiLgW8dcjOiUajeUiSAd7apFDjVxN9fr9qeHXkkY+jfB0khkvRcGQ0BciD5xNOsv8sPmsPbsWozZir+ypXKIydUvVpZJjG/44YkcjJxeWGGfhpEzwwlrwqWXtsoUNktAX4l84lXiKeUfmsfHcRpzsnehbuy89qvegimcVtLbnvcDjrD9wgWer5vBJ8jjsyIWBEvjCeiT0hfg/HIs/xpwjc9gatRVXB1cG1x/MgLoDKOVivoI2LjmTV5YGEXw+kQktXXjpzJsoY5Z5eoQydaxcvbBlEvpC3ElMMDh7QSnzUMrDcYf55sg37I7ZjYejB680eoV+dfrd0Cd/6EIiQ5cEk5yRy4IeZWm3dxBkp5oD37e+tVoiBCChL8TtJZ6DbzugtZEDFRow19OdA+kxlHQqycimI+lTqw/uju5/ba615qeDUbyz6hhlPZ0IfL4yNdb2gqwkeD4QyjW0XluEsJDQF+J29n7FHhdnZvvX5nDWFXySr/JGcirPlKqKq9HNfDcqi6T0HCb8GsbasEu0ql6aL5/0xeun7pCRCM//BuUbW7EhQvxNQl+IW8hOvsS0sytZWrYU5RwceKvxW/T0rIvT8VUQ9gv8NhQcnKFWZ076dOKlPV5cSjUxtlNthjRxxX7RE+a7Vw34FfwesHZzhPiL3ERFiH+ISonijTX9OZadwIDKTzCq1Qc3zoejNUQfxBj6E1mHl+Oae41k3Mmt1RXvB3rCprchKQYGrAT/FtZriLBZchMVIe7R7+d/553dEyErhRkGfx57ZMrNGynFWee6jDrXk+OpbZhQO5bn3fbjcCoQwn8Eg6v5vrUS+KIQktAXAsgx5vB58OcsPbGU+s5l+TQmnAoD5t20ndaan4OieC/wOE4GO77s34xO9csBQyA7DU5vgpKVoXyTAm+DEPdCQl/YvOiUaN7Y/gZHrx6lf+3nGL3vRwy+D9x0pn4tPZvxK8NYf/QyD1UrxbRejfH1dP57A0c3qNezgKsX4v5I6Aub9seFP5i4eyJomNF2Bo+lJEHieej4sfmWgxZ7IuIZ/XMoV9OyGN+5Ni+1roqdnUyQJooeCX1hk3KMOUwLnsaSE0uoV6oenz7yKRXdK8DctlCq+l/3lM3ONfH55nDm7jhLlVJuzHv+YRpUkMnRRNEloS9sTkxqDG9sf4Ow+DD61enH6AdG42jviD67DXXpMCebTWL7zkjCY1MIPp/I+avp9G3mz8Qn6+DqKP9lRNEm/4KFTdlyYQtv734bk8nEy7Xfwz2nKe+uCudUbAqvXX6HmnjRfYcfWZykbAknapb14K0udehYz9fapQuRJyT0RbGntWbPxT3MPjyX0PgQVHYFUi705bMwZ+A4Xq4GOnhfoZUKJaTmSL5v+Qg1y7rj5Sr3qhXFj4S+KLaMJiObL2xmQdgCTiScwKC9yI1/ki7+T1Onoze1fD2oVdYDHw8n1MohkOxO056jwcXL2qULkW8k9EWxk23MJvBMIN8d/Y4LKReoXKIyD5V4hY37/Zj6dFN6PVjxxh2uXYCjK6DFKxL4otiT0BfFRlpOGstPLWfxscXEZcRRt1RdprWdBmn1eGnxIXoHVLw58AH2fm0entnilYIvWogCJqEviryEzAR+OPEDP578keTsZJr7NuejVh/RolwLohIyePK7ndT3K8H73evdvHN6AoQsggbPgmeFgi9eiAImoS+KrKsZV5kXNo8Vp1aQaczkMf/HeLH+izTwaQBAZo6RoUuCAZjd7wGcDfY3H+TgfMhJh4dGFGTpQliNhL4ocowmI8tPLWfmoZlk5GTQpWoXXqz/IlW9qt6w3TurjnL8UjILXgigorfrzQfKyYD930CNjlD2Fr8FCFEMSeiLIuVo/FE+2vcRx64eo7lvcyY0G0fVktVv2u6ngxf4OSiaEe2q06522Vsf7PAPkB4PD4/M56qFKDzsrF2AEPciKSuJj/Z9xHNrnyM2PZapbaYyz6UOVb962Dx/fWbyX9sejUli4qpjtK5RmlHta976gCYj7JllvsFJpYcLqBVCWJ+EvijUtNasilhFt9+68cupX+hXpx+BPQLpfP4IassH4F0N9nwJsx6Awz9wLS2ToUuCKe3myMw+TbC/3aRoJ9dAYqT5LF/JxGnCdkj3jii0TiWeYtK+SYTEhdDIpxFzOsyhdslasPVj2DEVGvWF7l/BpVBY/yb89gpXHWdSJr0/E4f0x9vtNlfUag27ZoB3Vaj9ZME2Sggrk9AXhU5aThpfH/6apSeW4uHowfsPvU+P6j2wQ8Ef78Ou6dCkP3T9Auzswa8pDN7EpmVf0Dh8Oisd3oZDJ8H7XXAvc/MLnN8NF0Pgyenm/YWwIRL6otDYcSqO+YdWcTp3KSm5V3m6xtOMajoKL2cv89n55onmfvgHBsET08Du797JnWeu8nJYDXrV/4EpPhtR+76G44HQdhw0GwL2hr9faPdMcPMx/6YghI25a5++UqqiUmqrUuq4UuqYUmqkZfl7SqkYpdRhy6PLdfuMV0pFKKXClVKPX7e8k2VZhFJqXP40SRRFa4/E8PL6cahHzp8AABjCSURBVIRkfsG1VEcyzw/j5NHHWX4wgcgrqbBhvDnwH3zJcob+9z/dmGsZ/PfHQ9Qs48G7zzZHdfwAhu2Dis1h4wSY/TCc2WLeOPaY+ZaGzV8Gg4uVWiuE9dzLmX4u8LrWOkQp5QEEK6U2W9ZN11p/dv3GSqm6QB+gHlAe+F0p9ecQiq+ADkA0cFApFai1Pp4XDRFF16+HLjBh5zs4eAUzoPYg2pUdwNbwq/xxIo5Ja49h2PgmVRw2c7Bsb6g7nqYa7C3fvWblGhm2NIQco2Z2/6Z/z3dfujr0Xw6nNsKGcfB9T3P/vckIBjcIeNF6DRbCiu4a+lrrS8Aly/MUpdQJwO8Ou3QHlmmts4BIpVQE0MyyLkJrfRZAKbXMsq2Evg37Oeg87+yZiMHzEP+pP5SRD7wKQEBlH97oUJPUlf/F/ehm1no8w6jo7uTM2UdJVwOP1i5D+zpl2Xk6ntCoa3zTvylVfdxvfoGaj0PVtrDva9j+KeSkQfNXwNW7QNspRGFxX336SqnKQBNgP/AwMFwp9TwQhPm3gUTMHwj7rtstmr8/JKL+sbz5LV5jCDAEwN/f/37KE0XM0v2RfLj/HQyeh3m5wTCGN71uwjOTCVb/F/ej30Or0Tzx2Du0ycplx6l4/jgRy5aTcawMiQFgSJuqdKpf7vYv5OAErV6Dhn3g8FIIGJzPLROi8Lrn0FdKuQMrgFFa62Sl1GzgQ0Bb/vwc+Nf/m7TWc4G5AAEBAfrfHk8UTgv3nGFK0LsYPEMZ1mg4rzR++e+VJiOsehVCf4Q2b8KjE0ApPJwNPNGwHE80LEeu0UTIhWtExKXSK+AeJ0orUQ7ajMmfBglRRNxT6CulDJgDf6nWeiWA1jr2uvXzgDWWH2OA6+evrWBZxh2WCxsyd8dpph1+D4PnEYY3HsnLjf7z90pjLvw2FMJ+gbYToO3YWx7Dwd6OZlW8aVZFummEuB/3MnpHAfOBE1rradctv/736Z7AUcvzQKCPUspJKVUFqAEcAA4CNZRSVZRSjpi/7A3Mm2aIouKLLSeZFvouBs8jjGzy2j8CPwdW/scc+I+9c9vAF0L8/+7lTP9hYAAQppQ6bFk2AeirlGqMuXvnHPAygNb6mFLqZ8xf0OYCr2qtjQBKqeHARsAeWKC1PpaHbRGFmNaa6b+fYO7JDzGUOMropq8zqMELf2+QEAm/DYMLe6DDh/Dwf61WqxDFmdK68HabBwQE6KCgIGuXIf4lrTVTNhxlUcQkDCWOMSbgDQbWe/7PleabmGyYYL46tsun0KiPdQsWoohTSgVrrQNutU6uyBX5SmvNB2vC+PH8JAwljvNmwFgG1OtvXplyGQJHmC+WqtIGun8NXre4naEQIs9I6It8YzJp3gk8zIroyRg8TjCh2QT61rFMfXB0Jawdbb6RSeep5itt7WTSVyHym4S+yBcRcalMXh/GnpRpOHic5K3mb9Gndh/zPWnXjYGjK8xz2ff4BnxuM+e9ECLPSeiLPHXhajoz/jjFqrDjuPgtw8EjkndavMOztZ6F05th1XDz3aoefdt8wZS9/BMUoiDJ/ziRJy4lZTBrSwQ/H4zCweMYXjVWYmdn5L2HpvCE3yOweiQELwSfOtDvZyjXyNolC2GTJPTFv3IlJYuvt0WwdP8FNNnUbbCNyOzfqe5dl6ltplIp8SJ88zAknoeH/guPvgUGZ2uXLYTNktAX/5dr6dnM2XGWhbvPkW008XhjzQWHBUSmnGVQvUGMqNodw44ZEPQdePnDoHVQ6SFrly2EzZPQF/clJTOH+bsimb8zktTsXLo2LEeN6kdYeHIWHtqDOQ++zUPh22BdM0DBg/+B9u+Ck4e1SxdCIKEv7sP3e8/x+eZTXEvPoVM9X158pAyLI6Yy9/g2WpduxIcpuZT6+WVwcDbfrarlcPC80yzcQoiCJqEv7kprzYzfTzPzj9O0ql6asZ1qk2EfzridL5CYmcBYVZp+B1ejnDzNs1g2Hwpupa1dthDiFiT0xR1prZm++RRfbIng2Qcq8GHPOsw9Mptvw+ZTSdvz5cUo6hhSoP175rtROZewdslCiDuQ0Be3pbXm802n+HJrBL0DKvJqe09e/K0bR9JieDollTdz3HBtPxma9Jf7zQpRREjoi1vSWjN1Yzizt52hz4MVCKh9hGd/m4q9ychnWY483moSNHgW7A3WLlUIcR8k9MVNzLNinmTO9rM89aAHSSVm837QbppnZvJB09GUDxhinhFTCFHkSOiLG2itmbz+JHN3nKFt02j2Z39P9sVUxscn0Kf1e9g1e8naJQoh/gUJffEXrTUfrT3Bgr1h1Gq4ieCMAzRy8WVS1EkqBbwMEvhCFHkS+gL4c97743x/ZA2lagVyxZjBa/5PMHDHHOxrdoaOH1q7RCFEHpDQF2iteWvVAVZe+AqXCoeoWrIOk2oNpMYvL4FvQ3h6nvThC1FMSOjbOK01Q1csZde12Th6pvJyw6EMqdIVw/zHwcUL+i4DRzdrlymEyCMS+jYsJSuVvivf4nz2FrycKzC301zqeVSC7zpDVjIM3gglylm7TCFEHpLQt1EhsSG8snEMaaZ46rl1Z1HPt3G2M8CyfhB7FPr+BL71rV2mECKPSejbmFxTLnOPzOWb0G8wZpekU9kP+Kxrd5RSsGE8nFoPXT6Dmh2tXaoQIh9I6NuQqJQoxu8cT+iVUHKuNeHJCsP4tGtzc+AfmAf7vobmr8jQTCGKMQl9G6C1Zs3ZNUzaPwmjCTJj+vCIX0em9HjAHPinNsH6N6FmZ3h8krXLFULkIwn9Yi45O5mP9n3E+sj11CjRgKOhT1K/TCVm9W2Kg70dXA6D5YOgbH14+lsZmilEMSehX4yFxIYwfud4YtNj6VvjJZZtrkkFd2fmD3wQF0d7SL4EP/QGpxLw3E/g5G7tkoUQ+czO2gWIvJdryuXLQ18yaOMg7JQd01rPY832ejg5OLBocDO83Rwh7Sr80AsyrpkDv0R5a5cthCgAcqZfzEQlRzFu1ziOXDlCt2rdeLXhGAYvCCM5M5dlQ1pQ0dsVrp6Bpc9A8kXovQTKNbR22UKIAiKhX0xorQk8E8jH+z/GXtnzaZtPebRiBwYuOEBEXCoLBzWjvp8nnN8Ly54DpWDgaqjYzNqlCyEKkIR+EZdjzGH9ufUsPLaQ04mnaVqmKVNaT6Gsqy8jlh1i39kEZvRuTKsapeHoCvh1KHj5Q79fwLuqtcsXQhQwCf0iKjU7lRWnV7D4+GLi0uOo7lWdjx7+iCerPomdsuPDNSdYe+QS4zvXpkfj8rBrOvz+Hvi3hD4/gKu3tZsghLACCf0iJi49jiUnlvBL+C+k5qTSzLcZ77V8j1Z+rcxj7oF5O86yYHckLzxUmSGt/GHNKAheCPWfhu5fg8HZuo0QQliNhH4RcebaGRYeW8ias2swaRMdKnVgUL1B1Ctd74btVh2OYdK6EzzRoBzvdKiA+qE3nPkDWr8Oj74NdjJgSwhbJqFfiGmtCYoNYuGxheyI3oGzvTPP1nyWAXUHUNGj4k3b746IZ8wvoTSv4s3nnUpjt7ALxJ2Arl/AAwOt0AIhRGEjoV9IhSeE8/7e9wmLD6OkU0mGNR5Gn1p9KOlc8qZtk9JzWLL/PF9vjaBqaXe+fdwJ54UdISsV+v0M1dtboQVCiMJIQr8Q2hOzh9e2vYa7wZ2JLSbSrVo3nB1u7oe/eC2DBbsi+fHABdKyjbSp6cOMpnF4/NAXnD1h8AaZHlkIcYO7hr5SqiKwGCgLaGCu1nqmUsob+AmoDJwDemmtE5X528SZQBcgHXhBax1iOdZA4G3LoT/SWi/K2+YUfasiVvHenveo6lWVrx/7mrJuZW/a5uTlZOZuP0tg6EU00LVhOYa0qUbdiytg1etQti4897NcZSuEuMm9nOnnAq9rrUOUUh5AsFJqM/AC8IfWeopSahwwDhgLdAZqWB7NgdlAc8uHxLtAAOYPj2ClVKDWOjGvG1UUaa2ZFzaPWYdm0aJcC6a3nY67o/sN6/eevcrcHWfZFn4FV0d7nm9ZmcGtKlMh7QRs7geRO6B6B3j2O3DysGJrhBCF1V1DX2t9CbhkeZ6ilDoB+AHdgbaWzRYB2zCHfndgsdZaA/uUUl5KqXKWbTdrrRMALB8cnYAf87A9RVKuKZdJ+yex/NRyulbtyvsPvY/B3gCA0aTZcPQyc3ac4Uh0EqXdHRnTsSb9W1TCK/UsbHwJTq4B11Lw+GRoNgTspddOCHFr95UOSqnKQBNgP1DW8oEAcBlz9w+YPxCirtst2rLsdsv/+RpDgCEA/v7+91NekZSek86bO95ke/R2XmrwEiOajEApRY7RxLKDUXy78yznr6ZTpbQbH/dswFNN/XBOi4FNoyD0RzC4QdsJ0HKYnN0LIe7qnkNfKeUOrABGaa2T/7wQCEBrrZVSOi8K0lrPBeYCBAQE5MkxC6urGVcZ/sdwjiccZ2KLifSq1QuAzBwjrywJZmv4FRpX9GJ859p0qOuLfXo8/P4WBM0HFLQYBq1Gg1sp6zZECFFk3FPoK6UMmAN/qdZ6pWVxrFKqnNb6kqX7Js6yPAa4fhB5BcuyGP7uDvpz+bb/v/Si7XzyeYZuHkp8RjwzH51J24ptAUjPzmXI4mB2n4lnUs/6PNfMH5WVAtsnw96vICcdGveDtuPAs4J1GyGEKHLuZfSOAuYDJ7TW065bFQgMBKZY/lx13fLhSqllmL/ITbJ8MGwEPlZK/TnQvCMwPm+aUbSEXgllxB8jAJj/+Hwa+pinNk7NymXwwoMEnUvg02ca8UzD0uag3/k5ZCRA3R7Q7m0oXcOa5QshirB7OdN/GBgAhCmlDluWTcAc9j8rpV4EzgO9LOvWYR6uGYF5yOYgAK11glLqQ+CgZbsP/vxS15ZsubCFsTvG4uPqwzftv8G/hPl7i6SMHF747gBHopOY0acJ3UqcgVkdITkGqrWDx96B8k2sXL0QoqhT5kE2hVNAQIAOCgqydhl55qeTP/HxgY+pV6oeXz72Jd7O5pkuE9OyeX7BAU5eTmZW36Z0Yg/8+jKUrAJPfAZV2li5ciFEUaKUCtZaB9xqnYztKyBzQufw5eEvaVuhLZ+0+QRXgysA8alZ9P92P2fj05gz4AHaXfsVNowzT4Hc9wdwuXnaBSGE+H9J6BeApSeW8uXhL+lWrRvvP/Q+Dnbmv/a45Eye+3Y/0YnpzH++Ka3PfwW7Z0KdrvDUtzIFshAiz0no57PVZ1Yz5cAU2lVsd0PgX7yWwXPz9nElJYtFA5vQ/Mg7cGQZPPgf6DwV7OytXLkQojiS0M9H26K2MXH3RJr7NmfqI1P/CvyohHT6zttnnh3z+fo02TvMPOd9u7eh9Rjz/WuFECIfSOjnk4OXD/L6ttep412Hme1m4mTvBEBkfBrPzdtHeraRn/pVpe4f/eByGHT7EpoOsHLVQojiTkI/Hxy7eowRW0ZQ0aMis9vPxs3gBsDp2BSe+3Y/JpNmeW9faqx/FlIuQ98foebjVq5aCGELJPTz2Nmks7yy+RU8HT2Z02EOmFwJPp/AqdhUPtsYjp2d4teervivfgpMRhi4Gio+aO2yhRA2QkI/DxhNmpjEDA5Gn+GzsBFkm4x4J71Cl2lHuJqW/dd2FUq68Ev7dMqtet48X07/lXJ1rRCiQEno/58CQy+y8dhlzsSlcjY+jRydjGulb1AOaRjiXsXgVYYOdd2p5uNOtTJuVPNxp2JUIHaBw8GnDvRfDh6+1m6GEMLGSOjfp/TsXCb+dowVIdH4eblQ29eDFtXd2J02h4TsFD5v8xVtKzW/cafsNNg2BfZ8Yb66tvcS8+0MhRCigEno34fTsSkMWxpCxJVU/vtYDUY+VoMcUxZDfx9KfNZ5ZrabSZsK1wW+1nAiEDZMgORoaPo8dPkMHJys1wghhE2T0L9HK0OieevXo7g62rN4cDNa1/Ahx5TDmO1jCIkNYUrrKbSpcN0cOVfPwLo3zOPvy9aHp7+FSi2t1wAhhEBC/64yc4y8u+oYPwVF0ayKN7P6NqFsCWdM2sTE3RPZHr2dt5u/TZeqXcw7ZKfDrmnm6RQcnKHTJ+arbOUWhkKIQkCS6A7OXEnl1aUhnLycwvBHqzOqfQ0c7O1IykpiyoEprD27lhFNRtC7dm9zV074Olg/DpIuQMPe0OED+bJWCFGoSOjfxqrDMYxfGYazwZ5Fg5vxSE0ftNasPrOaz4I+IykriWGNhvFSg5cgIRLWj4XTG80jc15YC5VbWbsJQghxEwn9f8jMMfLBmuP8sP8CD1YuyRd9m1DO04WzSWeZtG8SBy4foGHphszpMIfaHpVg+yewcxrYG6DjR9B8qPm5EEIUQhL61zkXn8awpSEcv5TM0EeqMaZjTXJ1NrMOzWLB0QW4OLgwscVEnqnWA7vwtfB9b0g8B/WfNgd+ifLWboIQQtyRhL7FmiMXGbciDAd7xYIXAmhXuyy7YnYxad8kolOj6Vq1K6/X7k+pY4GwpiGkXILSNeH5VVC1rbXLF0KIe2LzoZ+Yls27gccIDL1IU38vZj3XFINjCq9ve51N5zdRuURl5jccSbPTO2BLK9BGqN4enpwONTrKvPdCiCKlWIa+0WQkKDYILycvvJ298XLywnCLfvbNx2MZvzKMpIxsXu9Qk5faVGZFxM/MOjSLXFMOI0q34IXIwziGvm6+bWHLYRAwGLyrWqFVQgjx7xXL0L+WdY3/bPrPDcvcDe6UdC5JSaeSuBtKcC5OcS5OUbq0N6MeqEOVUqd5fsNbnEg4wcMGb96KjqZixM/g9wD0mA31eoLBxUotEkKIvKG01tau4bYCAgJ0UFDQfe+Xbcwm9EooiZmJXMu6RmJmIolZiSRmJnI2IY7wK5cwqlQMhgyM/D0Lpo+2Y2xcLB2zNarBMxDwIvg1zcsmCSFEvlNKBWutA261rlie6TvaO/Kg741z1Kdk5vDRmhMcDIqiZll3Pn+mEQ04RUbIIhLDV3MtN53K7hVxbT0RGj9n7s4RQohipliG/j/tOh3Pm8tDuZycyRsPefCy50Ecfnsdrp7GxeCKS90elG/SD/wfAjs7a5crhBD5pliHflpWLpPXn+CXfRE853WMUVUP4HloJ2iTOeBbjYK63cHJw9qlCiFEgSi2ob/vTDzf/rySNumbOOy2D5fMFEipAK1fh0Z9oVQ1a5cohBAFrliG/vkzJ/Fa9Azf2kVhcnTCrk5XaNIPqjwi4+qFEDatWIZ+pcrVuVyuKtlNRuHY6Blw8bJ2SUIIUSgUy9DH3gHfVwKtXYUQQhQ6MlRFCCFsiIS+EELYEAl9IYSwIRL6QghhQyT0hRDChkjoCyGEDZHQF0IIGyKhL4QQNqRQz6evlLoCnP8XhygNxOdROUWFrbXZ1toL0mZb8W/aXElr7XOrFYU69P8tpVTQ7W4kUFzZWpttrb0gbbYV+dVm6d4RQggbIqEvhBA2pLiH/lxrF2AFttZmW2svSJttRb60uVj36QshhLhRcT/TF0IIcR0JfSGEsCHFMvSVUp2UUuFKqQil1Dhr11MQlFLnlFJhSqnDSqkga9eTH5RSC5RScUqpo9ct81ZKbVZKnbb8WdKaNea127T5PaVUjOW9PqyU6mLNGvOaUqqiUmqrUuq4UuqYUmqkZXmxfK/v0N58eZ+LXZ++UsoeOAV0AKKBg0BfrfVxqxaWz5RS54AArXWxvYBFKdUGSAUWa63rW5ZNBRK01lMsH/AltdZjrVlnXrpNm98DUrXWn1mztvyilCoHlNNahyilPIBgoAfwAsXwvb5De3uRD+9zcTzTbwZEaK3Paq2zgWVAdyvXJPKA1noHkPCPxd2BRZbnizD/Zyk2btPmYk1rfUlrHWJ5ngKcAPwopu/1HdqbL4pj6PsBUdf9HE0+/gUWIhrYpJQKVkoNsXYxBais1vqS5flloKw1iylAw5VSRyzdP8Wim+NWlFKVgSbAfmzgvf5HeyEf3ufiGPq2qpXWuinQGXjV0i1gU7S5r7J49Vfe2mygGtAYuAR8bt1y8odSyh1YAYzSWidfv644vte3aG++vM/FMfRjgIrX/VzBsqxY01rHWP6MA37F3M1lC2ItfaJ/9o3GWbmefKe1jtVaG7XWJmAexfC9VkoZMAfgUq31SsviYvte36q9+fU+F8fQPwjUUEpVUUo5An2AQCvXlK+UUm6WL4BQSrkBHYGjd96r2AgEBlqeDwRWWbGWAvFn8Fn0pJi910opBcwHTmitp123qli+17drb369z8Vu9A6AZWjTDMAeWKC1nmTlkvKVUqoq5rN7AAfgh+LYZqXUj0BbzFPOxgLvAr8BPwP+mKfh7qW1LjZffN6mzW0x/8qvgXPAy9f1dRd5SqlWwE4gDDBZFk/A3M9d7N7rO7S3L/nwPhfL0BdCCHFrxbF7RwghxG1I6AshhA2R0BdCCBsioS+EEDZEQl8IIWyIhL4QQtgQCX0hhLAh/wPNry/TAiwtXgAAAABJRU5ErkJggg==\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] @@ -279,7 +281,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43d942160>]" + "[<matplotlib.lines.Line2D at 0x2ba157b3f780>]" ] }, "execution_count": 12, @@ -312,7 +314,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43d97c128>]" + "[<matplotlib.lines.Line2D at 0x2ba1571da9b0>]" ] }, "execution_count": 13, @@ -345,7 +347,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43d90beb8>]" + "[<matplotlib.lines.Line2D at 0x2ba1579bee10>]" ] }, "execution_count": 14, @@ -377,7 +379,7 @@ { "data": { "text/plain": [ - "[<matplotlib.lines.Line2D at 0x2ad43d807c50>]" + "[<matplotlib.lines.Line2D at 0x2ba157513438>]" ] }, "execution_count": 15, @@ -409,56 +411,6 @@ "source": [ "# this is how the correlation should look like ideally (run from last week)" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# how to access the raw mcp data" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:extra_data.read_machinery:Found proposal dir '/gpfs/exfel/exp/SCS/202002/p002719' in 0.0023 s\n" - ] - } - ], - "source": [ - "run_obj = ed.open_run(2719, 194)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mcp4 = run_obj.get_array(*tb.mnemonics['MCP4raw'].values())\n", - "# other mnemonics: MCP1raw, MCP2raw, MCP3raw" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.plot(mcp4[0,:])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/src/toolbox_scs/__init__.py b/src/toolbox_scs/__init__.py index fede7d9..47d2252 100644 --- a/src/toolbox_scs/__init__.py +++ b/src/toolbox_scs/__init__.py @@ -1,5 +1,4 @@ -from .load import (load, concatenateRuns, get_array, - load_run, run_by_path) +from .load import (load, concatenateRuns, get_array, run_by_path) from .constants import mnemonics @@ -8,7 +7,6 @@ __all__ = ( "load", "concatenateRuns", "get_array", - "load_run", "run_by_path", # Classes # Variables diff --git a/src/toolbox_scs/constants.py b/src/toolbox_scs/constants.py index d0e98b8..72eee76 100644 --- a/src/toolbox_scs/constants.py +++ b/src/toolbox_scs/constants.py @@ -1,395 +1,399 @@ mnemonics = { # Machine - "sase3": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'sase3.pulseIds.value', - 'dim':['bunchId']}, - "sase2": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'sase2.pulseIds.value', - 'dim':['bunchId']}, - "sase1": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'sase1.pulseIds.value', - 'dim':['bunchId']}, - "maindump": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'maindump.pulseIds.value', - 'dim':['bunchId']}, - "bunchpattern": {'source':'SCS_RR_UTC/TSYS/TIMESERVER', - 'key':'readBunchPatternTable.value', - 'dim':None}, - "bunchPatternTable": {'source':'SCS_RR_UTC/TSYS/TIMESERVER', - 'key':'bunchPatternTable.value', - 'dim':['pulse_slot']}, - "npulses_sase3": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'sase3.nPulses.value', - 'dim':None}, - "npulses_sase1": {'source':'SCS_RR_UTC/MDL/BUNCH_DECODER', - 'key':'sase1.nPulses.value', - 'dim':None}, + "sase3": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'sase3.pulseIds.value', + 'dim': ['bunchId']}, + "sase2": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'sase2.pulseIds.value', + 'dim': ['bunchId']}, + "sase1": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'sase1.pulseIds.value', + 'dim': ['bunchId']}, + "maindump": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'maindump.pulseIds.value', + 'dim': ['bunchId']}, + "bunchpattern": {'source': 'SCS_RR_UTC/TSYS/TIMESERVER', + 'key': 'readBunchPatternTable.value', + 'dim': None}, + "bunchPatternTable": {'source': 'SCS_RR_UTC/TSYS/TIMESERVER', + 'key': 'bunchPatternTable.value', + 'dim': ['pulse_slot']}, + "npulses_sase3": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'sase3.nPulses.value', + 'dim': None}, + "npulses_sase1": {'source': 'SCS_RR_UTC/MDL/BUNCH_DECODER', + 'key': 'sase1.nPulses.value', + 'dim': None}, + "bunchPatternTable_SA3": { + 'source': 'SA3_BR_UTC/TSYS/TIMESERVER:outputBunchPattern', + 'key': 'data.bunchPatternTable', + 'dim': ['pulse_slot']}, + + # Bunch Arrival Monitors + "BAM414": {'source': 'SCS_ILH_LAS/DOOCS/BAM_414_B2:output', + 'key': 'data.lowChargeArrivalTime', + 'dim': ['BAMbunchId']}, + "BAM1932M": {'source': 'SCS_ILH_LAS/DOOCS/BAM_1932M_TL:output', + 'key': 'data.lowChargeArrivalTime', + 'dim': ['BAMbunchId']}, + "BAM1932S": {'source': 'SCS_ILH_LAS/DOOCS/BAM_1932S_TL:output', + 'key': 'data.lowChargeArrivalTime', + 'dim': ['BAMbunchId']}, - #Bunch Arrival Monitors - "BAM5": {'source':'SCS_ILH_LAS/DOOCS/BAM_414_B2:output', - 'key':'data.lowChargeArrivalTime', - 'dim':['BAMbunchId']}, - "BAM6": {'source':'SCS_ILH_LAS/DOOCS/BAM_1932M_TL:output', - 'key':'data.lowChargeArrivalTime', - 'dim':['BAMbunchId']}, - "BAM7": {'source':'SCS_ILH_LAS/DOOCS/BAM_1932S_TL:output', - 'key':'data.lowChargeArrivalTime', - 'dim':['BAMbunchId']}, - # SA3 - "nrj": {'source':'SA3_XTD10_MONO/MDL/PHOTON_ENERGY', - 'key':'actualEnergy.value', - 'dim':None}, + "nrj": {'source': 'SA3_XTD10_MONO/MDL/PHOTON_ENERGY', + 'key': 'actualEnergy.value', + 'dim': None}, "M2BEND": {'source': 'SA3_XTD10_MIRR-2/MOTOR/BENDER', 'key': 'actualPosition.value', - 'dim':None}, - "VSLIT": {'source':'SA3_XTD10_VSLIT/MDL/BLADE', - 'key':'actualGap.value', - 'dim':None}, - "ESLIT": {'source':'SCS_XTD10_ESLIT/MDL/MAIN', - 'key':'actualGap.value', - 'dim':None}, - "HSLIT": {'source':'SCS_XTD10_HSLIT/MDL/BLADE', - 'key':'actualGap.value', - 'dim':None}, - "transmission": {'source':'SA3_XTD10_GATT/MDL/GATT_TRANSMISSION_MONITOR', - 'key':'Estimated_Tr.value', - 'dim':None}, - "GATT_pressure": {'source':'P_GATT', - 'key':'value.value', - 'dim':None}, - "navitar": {'source':'SCS_XTD10_IMGES/CAM/BEAMVIEW_NAVITAR:daqOutput', - 'key':'data.image.pixels', - 'dim':['x','y']}, - "UND": {'source':'SA3_XTD10_UND/DOOCS/PHOTON_ENERGY', - 'key':'actualPosition.value', - 'dim':None}, - #DPS imagers - "DPS2CAM2": {'source':'SCS_BLU_DPS-2/CAM/IMAGER2CAMERA:daqOutput', - 'key':'data.image.pixels', - 'dim':['dps2cam2_y', 'dps2cam2_x']}, + 'dim': None}, + "VSLIT": {'source': 'SA3_XTD10_VSLIT/MDL/BLADE', + 'key': 'actualGap.value', + 'dim': None}, + "ESLIT": {'source': 'SCS_XTD10_ESLIT/MDL/MAIN', + 'key': 'actualGap.value', + 'dim': None}, + "HSLIT": {'source': 'SCS_XTD10_HSLIT/MDL/BLADE', + 'key': 'actualGap.value', + 'dim': None}, + "transmission": {'source': 'SA3_XTD10_GATT/MDL/GATT_TRANSMISSION_MONITOR', + 'key': 'Estimated_Tr.value', + 'dim': None}, + "GATT_pressure": {'source': 'P_GATT', + 'key': 'value.value', + 'dim': None}, + "navitar": {'source': 'SCS_XTD10_IMGES/CAM/BEAMVIEW_NAVITAR:daqOutput', + 'key': 'data.image.pixels', + 'dim': ['x', 'y']}, + "UND": {'source': 'SA3_XTD10_UND/DOOCS/PHOTON_ENERGY', + 'key': 'actualPosition.value', + 'dim': None}, + # DPS imagers + "DPS2CAM2": {'source': 'SCS_BLU_DPS-2/CAM/IMAGER2CAMERA:daqOutput', + 'key': 'data.image.pixels', + 'dim': ['dps2cam2_y', 'dps2cam2_x']}, # XTD10 XGM - ## keithley - "XTD10_photonFlux": {'source':'SA3_XTD10_XGM/XGM/DOOCS', - 'key':'pulseEnergy.photonFlux.value', - 'dim':None}, - "XTD10_photonFlux_sigma": {'source':'SA3_XTD10_XGM/XGM/DOOCS', - 'key':'pulseEnergy.photonFluxSigma.value', - 'dim':None}, - ## ADC - "XTD10_XGM": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensityTD', - 'dim':['XGMbunchId']}, - "XTD10_XGM_sigma": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensitySigmaTD', - 'dim':['XGMbunchId']}, - "XTD10_SA3": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa3TD', - 'dim':['XGMbunchId']}, - "XTD10_SA3_sigma": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa3SigmaTD', - 'dim':['XGMbunchId']}, - "XTD10_SA1": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa1TD', - 'dim':['XGMbunchId']}, - "XTD10_SA1_sigma": {'source':'SA3_XTD10_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa1SigmaTD', - 'dim':['XGMbunchId']}, - ## low pass averaged ADC - "XTD10_slowTrain": {'source':'SA3_XTD10_XGM/XGM/DOOCS', - 'key':'controlData.slowTrain.value', - 'dim':None}, - "XTD10_slowTrain_SA1": {'source':'SA3_XTD10_XGM/XGM/DOOCS', - 'key':'controlData.slowTrainSa1.value', - 'dim':None}, - "XTD10_slowTrain_SA3": {'source':'SA3_XTD10_XGM/XGM/DOOCS', - 'key':'controlData.slowTrainSa3.value', - 'dim':None}, + # keithley + "XTD10_photonFlux": {'source': 'SA3_XTD10_XGM/XGM/DOOCS', + 'key': 'pulseEnergy.photonFlux.value', + 'dim': None}, + "XTD10_photonFlux_sigma": {'source': 'SA3_XTD10_XGM/XGM/DOOCS', + 'key': 'pulseEnergy.photonFluxSigma.value', + 'dim': None}, + # ADC + "XTD10_XGM": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensityTD', + 'dim': ['XGMbunchId']}, + "XTD10_XGM_sigma": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySigmaTD', + 'dim': ['XGMbunchId']}, + "XTD10_SA3": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa3TD', + 'dim': ['XGMbunchId']}, + "XTD10_SA3_sigma": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa3SigmaTD', + 'dim': ['XGMbunchId']}, + "XTD10_SA1": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa1TD', + 'dim': ['XGMbunchId']}, + "XTD10_SA1_sigma": {'source': 'SA3_XTD10_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa1SigmaTD', + 'dim': ['XGMbunchId']}, + # low pass averaged ADC + "XTD10_slowTrain": {'source': 'SA3_XTD10_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrain.value', + 'dim': None}, + "XTD10_slowTrain_SA1": {'source': 'SA3_XTD10_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrainSa1.value', + 'dim': None}, + "XTD10_slowTrain_SA3": {'source': 'SA3_XTD10_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrainSa3.value', + 'dim': None}, # SCS XGM - ## keithley - "SCS_photonFlux": {'source':'SCS_BLU_XGM/XGM/DOOCS', - 'key':'pulseEnergy.photonFlux.value', - 'dim':None}, - "SCS_photonFlux_sigma": {'source':'SCS_BLU_XGM/XGM/DOOCS', - 'key':'pulseEnergy.photonFluxSigma.value', - 'dim':None}, - ## ADC - "SCS_XGM": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensityTD', - 'dim':['XGMbunchId']}, - "SCS_XGM_sigma": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensitySigmaTD', - 'dim':['XGMbunchId']}, - "SCS_SA1": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa1TD', - 'dim':['XGMbunchId']}, - "SCS_SA1_sigma": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa1SigmaTD', - 'dim':['XGMbunchId']}, - "SCS_SA3": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa3TD', - 'dim':['XGMbunchId']}, - "SCS_SA3_sigma": {'source':'SCS_BLU_XGM/XGM/DOOCS:output', - 'key':'data.intensitySa3SigmaTD', - 'dim':['XGMbunchId']}, - ## low pass averaged ADC - "SCS_slowTrain": {'source':'SCS_BLU_XGM/XGM/DOOCS', - 'key':'controlData.slowTrain.value', - 'dim':None}, - "SCS_slowTrain_SA1": {'source':'SCS_BLU_XGM/XGM/DOOCS', - 'key':'controlData.slowTrainSa1.value', - 'dim':None}, - "SCS_slowTrain_SA3": {'source':'SCS_BLU_XGM/XGM/DOOCS', - 'key':'controlData.slowTrainSa3.value', - 'dim':None}, + # keithley + "SCS_photonFlux": {'source': 'SCS_BLU_XGM/XGM/DOOCS', + 'key': 'pulseEnergy.photonFlux.value', + 'dim': None}, + "SCS_photonFlux_sigma": {'source': 'SCS_BLU_XGM/XGM/DOOCS', + 'key': 'pulseEnergy.photonFluxSigma.value', + 'dim': None}, + # ADC + "SCS_XGM": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensityTD', + 'dim': ['XGMbunchId']}, + "SCS_XGM_sigma": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySigmaTD', + 'dim': ['XGMbunchId']}, + "SCS_SA1": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa1TD', + 'dim': ['XGMbunchId']}, + "SCS_SA1_sigma": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa1SigmaTD', + 'dim': ['XGMbunchId']}, + "SCS_SA3": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa3TD', + 'dim': ['XGMbunchId']}, + "SCS_SA3_sigma": {'source': 'SCS_BLU_XGM/XGM/DOOCS:output', + 'key': 'data.intensitySa3SigmaTD', + 'dim': ['XGMbunchId']}, + # low pass averaged ADC + "SCS_slowTrain": {'source': 'SCS_BLU_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrain.value', + 'dim': None}, + "SCS_slowTrain_SA1": {'source': 'SCS_BLU_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrainSa1.value', + 'dim': None}, + "SCS_slowTrain_SA3": {'source': 'SCS_BLU_XGM/XGM/DOOCS', + 'key': 'controlData.slowTrainSa3.value', + 'dim': None}, # KBS - "HFM_CAPB": {'source':'SCS_KBS_HFM/ASENS/CAPB', - 'key':'value.value', - 'dim':None}, - "HFM_CAPF": {'source':'SCS_KBS_HFM/ASENS/CAPF', - 'key':'value.value', - 'dim':None}, - "HFM_CAPM": {'source':'SCS_KBS_HFM/ASENS/CAPM', - 'key':'value.value', - 'dim':None}, - "HFM_BENDERB": {'source':'SCS_KBS_HFM/MOTOR/BENDERB', - 'key':'encoderPosition.value', - 'dim':None}, - "HFM_BENDERF": {'source':'SCS_KBS_HFM/MOTOR/BENDERF', - 'key':'encoderPosition.value', - 'dim':None}, - "VFM_CAPB": {'source':'SCS_KBS_VFM/ASENS/CAPB', - 'key':'value.value', - 'dim':None}, - "VFM_CAPF": {'source':'SCS_KBS_VFM/ASENS/CAPF', - 'key':'value.value', - 'dim':None}, - "VFM_CAPM": {'source':'SCS_KBS_VFM/ASENS/CAPM', - 'key':'value.value', - 'dim':None}, - "VFM_BENDERB": {'source':'SCS_KBS_VFM/MOTOR/BENDERB', - 'key':'encoderPosition.value', - 'dim':None}, - "VFM_BENDERF": {'source':'SCS_KBS_VFM/MOTOR/BENDERF', - 'key':'encoderPosition.value', - 'dim':None}, - + "HFM_CAPB": {'source': 'SCS_KBS_HFM/ASENS/CAPB', + 'key': 'value.value', + 'dim': None}, + "HFM_CAPF": {'source': 'SCS_KBS_HFM/ASENS/CAPF', + 'key': 'value.value', + 'dim': None}, + "HFM_CAPM": {'source': 'SCS_KBS_HFM/ASENS/CAPM', + 'key': 'value.value', + 'dim': None}, + "HFM_BENDERB": {'source': 'SCS_KBS_HFM/MOTOR/BENDERB', + 'key': 'encoderPosition.value', + 'dim': None}, + "HFM_BENDERF": {'source': 'SCS_KBS_HFM/MOTOR/BENDERF', + 'key': 'encoderPosition.value', + 'dim': None}, + "VFM_CAPB": {'source': 'SCS_KBS_VFM/ASENS/CAPB', + 'key': 'value.value', + 'dim': None}, + "VFM_CAPF": {'source': 'SCS_KBS_VFM/ASENS/CAPF', + 'key': 'value.value', + 'dim': None}, + "VFM_CAPM": {'source': 'SCS_KBS_VFM/ASENS/CAPM', + 'key': 'value.value', + 'dim': None}, + "VFM_BENDERB": {'source': 'SCS_KBS_VFM/MOTOR/BENDERB', + 'key': 'encoderPosition.value', + 'dim': None}, + "VFM_BENDERF": {'source': 'SCS_KBS_VFM/MOTOR/BENDERF', + 'key': 'encoderPosition.value', + 'dim': None}, + # AFS LASER - "AFS_PhaseShifter": {'source':'SCS_ILH_LAS/PHASESHIFTER/DOOCS', - 'key':'actualPosition.value', - 'dim':None}, - "AFS_DelayLine": {'source':'SCS_ILH_LAS/MOTOR/LT3', - 'key':'actualPosition.value', - 'dim':None}, - "AFS_HalfWP": {'source':'SCS_ILH_LAS/MOTOR/ROT_OPA_BWP1', - 'key':'actualPosition.value', - 'dim':None}, - "AFS_FocusLens": {'source':'SCS_ILH_LAS/MOTOR/LT_SPARE1', - 'key':'actualPosition.value', - 'dim':None}, + "AFS_PhaseShifter": {'source': 'SCS_ILH_LAS/PHASESHIFTER/DOOCS', + 'key': 'actualPosition.value', + 'dim': None}, + "AFS_DelayLine": {'source': 'SCS_ILH_LAS/MOTOR/LT3', + 'key': 'actualPosition.value', + 'dim': None}, + "AFS_HalfWP": {'source': 'SCS_ILH_LAS/MOTOR/ROT_OPA_BWP1', + 'key': 'actualPosition.value', + 'dim': None}, + "AFS_FocusLens": {'source': 'SCS_ILH_LAS/MOTOR/LT_SPARE1', + 'key': 'actualPosition.value', + 'dim': None}, # 2nd lens of telescope - "AFS_TeleLens": {'source':'SCS_ILH_LAS/MOTOR/LT2', - 'key':'actualPosition.value', - 'dim':None}, + "AFS_TeleLens": {'source': 'SCS_ILH_LAS/MOTOR/LT2', + 'key': 'actualPosition.value', + 'dim': None}, # PP LASER 800 nm path - "PP800_PhaseShifter": {'source':'SCS_ILH_LAS/DOOCS/PP800_PHASESHIFTER', - 'key':'actualPosition.value', - 'dim':None}, - "PP800_SynchDelayLine": {'source':'SCS_ILH_LAS/DOOCS/PPL_OPT_DELAY', - 'key':'actualPosition.value', - 'dim':None}, - "PP800_DelayLine": {'source':'SCS_ILH_LAS/MOTOR/LT3', - 'key':'actualPosition.value', - 'dim':None}, - "PP800_HalfWP": {'source':'SCS_ILH_LAS/MOTOR/ROT8WP1', - 'key':'actualPosition.value', - 'dim':None}, - "PP800_FocusLens": {'source':'SCS_ILH_LAS/MOTOR/LT_SPARE1', - 'key':'actualPosition.value', - 'dim':None}, + "PP800_PhaseShifter": {'source': 'SCS_ILH_LAS/DOOCS/PP800_PHASESHIFTER', + 'key': 'actualPosition.value', + 'dim': None}, + "PP800_SynchDelayLine": {'source': 'SCS_ILH_LAS/DOOCS/PPL_OPT_DELAY', + 'key': 'actualPosition.value', + 'dim': None}, + "PP800_DelayLine": {'source': 'SCS_ILH_LAS/MOTOR/LT3', + 'key': 'actualPosition.value', + 'dim': None}, + "PP800_HalfWP": {'source': 'SCS_ILH_LAS/MOTOR/ROT8WP1', + 'key': 'actualPosition.value', + 'dim': None}, + "PP800_FocusLens": {'source': 'SCS_ILH_LAS/MOTOR/LT_SPARE1', + 'key': 'actualPosition.value', + 'dim': None}, # 1st lens of telescope (setup of August 2019) - "PP800_TeleLens": {'source':'SCS_ILH_LAS/MOTOR/LT7', - 'key':'actualPosition.value', - 'dim':None}, - "ILH_8CAM1": {'source':'SCS_ILH_LAS/CAM/8CAM1:daqOutput', - 'key':'data.image.pixels', - 'dim':['8cam1_y', '8cam1_x']}, + "PP800_TeleLens": {'source': 'SCS_ILH_LAS/MOTOR/LT7', + 'key': 'actualPosition.value', + 'dim': None}, + "ILH_8CAM1": {'source': 'SCS_ILH_LAS/CAM/8CAM1:daqOutput', + 'key': 'data.image.pixels', + 'dim': ['8cam1_y', '8cam1_x']}, + + # GPC + "GPC_EOS_DelayLine": {'source': 'SCS_CDIDET_GRD/MOTOR/IMAGER', + 'key': 'actualPosition.value', + 'dim': None}, + "GPC_X": {'source': 'SCS_GPC_MOV/MOTOR/X', + 'key': 'actualPosition.value', + 'dim': None}, + "GPC_Y": {'source': 'SCS_GPC_MOV/MOTOR/Y', + 'key': 'actualPosition.value', + 'dim': None}, + "GPC_THETA": {'source': 'SCS_GPC_MOV/MOTOR/THETA', + 'key': 'actualPosition.value', + 'dim': None}, + "GPC_THETAMAG": {'source': 'SCS_GPC_MOV/MOTOR/THETAMAG', + 'key': 'actualPosition.value', + 'dim': None}, - # GPC - "GPC_EOS_DelayLine": {'source':'SCS_CDIDET_GRD/MOTOR/IMAGER', - 'key':'actualPosition.value', - 'dim':None}, - "GPC_X": {'source':'SCS_GPC_MOV/MOTOR/X', - 'key':'actualPosition.value', - 'dim':None}, - "GPC_Y": {'source':'SCS_GPC_MOV/MOTOR/Y', - 'key':'actualPosition.value', - 'dim':None}, - "GPC_THETA": {'source':'SCS_GPC_MOV/MOTOR/THETA', - 'key':'actualPosition.value', - 'dim':None}, - "GPC_THETAMAG": {'source':'SCS_GPC_MOV/MOTOR/THETAMAG', - 'key':'actualPosition.value', - 'dim':None}, - # FFT - "scannerX": {'source':'SCS_CDIFFT_SAM/LMOTOR/SCANNERX', - 'key':'actualPosition.value', - 'dim':None}, - "scannerY": {'source':'SCS_CDIFFT_SAM/MOTOR/SCANNERY', - 'key':'actualPosition.value', - 'dim':None}, - "scannerY_enc": {'source':'SCS_CDIFFT_SAM/ENC/SCANNERY', - 'key':'value.value', - 'dim':None}, - "SAM-Z": {'source':'SCS_CDIFFT_MOV/ENC/SAM_Z', - 'key':'value.value', - 'dim':None}, - "magnet": {'source':'SCS_CDIFFT_MAG/ASENS/CURRENT', - 'key':'value.value', - 'dim':None}, - "magnet_old": {'source':'SCS_CDIFFT_MAG/SUPPLY/CURRENT', - 'key':'actualCurrent.value', - 'dim':None}, - - "Vertical_FDM": {'source':'SCS_CDIFFT_LDM/CAM/CAMERA1A:daqOutput', - 'key':'data.image.pixels', - 'dim':['vfdm_y', 'vfdm_x']}, + "scannerX": {'source': 'SCS_CDIFFT_SAM/LMOTOR/SCANNERX', + 'key': 'actualPosition.value', + 'dim': None}, + "scannerY": {'source': 'SCS_CDIFFT_SAM/MOTOR/SCANNERY', + 'key': 'actualPosition.value', + 'dim': None}, + "scannerY_enc": {'source': 'SCS_CDIFFT_SAM/ENC/SCANNERY', + 'key': 'value.value', + 'dim': None}, + "SAM-Z": {'source': 'SCS_CDIFFT_MOV/ENC/SAM_Z', + 'key': 'value.value', + 'dim': None}, + "magnet": {'source': 'SCS_CDIFFT_MAG/ASENS/CURRENT', + 'key': 'value.value', + 'dim': None}, + "magnet_old": {'source': 'SCS_CDIFFT_MAG/SUPPLY/CURRENT', + 'key': 'actualCurrent.value', + 'dim': None}, + "Vertical_FDM": {'source': 'SCS_CDIFFT_LDM/CAM/CAMERA1A:daqOutput', + 'key': 'data.image.pixels', + 'dim': ['vfdm_y', 'vfdm_x']}, # FastCCD, if in raw folder, raw images # if in proc folder, dark substracted and relative gain corrected - "fastccd": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.pixels', - 'dim':['x', 'y']}, + "fastccd": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.pixels', + 'dim': ['x', 'y']}, # FastCCD with common mode correction - "fastccd_cm": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.pixels_cm', - 'dim':['x', 'y']}, + "fastccd_cm": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.pixels_cm', + 'dim': ['x', 'y']}, # FastCCD charge split correction in very low photon count regime - "fastccd_classified": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.pixels_classified', - 'dim':['x', 'y']}, + "fastccd_classified": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.pixels_classified', + 'dim': ['x', 'y']}, # FastCCD event multiplicity from the charge split correction: # 0: no events # 100, 101: single events # 200-203: charge split into two pixels in four different orientations # 300-303: charge split into three pixels in four different orientations # 400-403: charge split into four pixels in four different orientations - # 1000: charge in more than four neighboring pixels. Cannot be produced by a single photon alone. - "fastccd_patterns": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.patterns', - 'dim':['x', 'y']}, + # 1000: charge in more than four neighboring pixels. Cannot be produced + # by a single photon alone. + "fastccd_patterns": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.patterns', + 'dim': ['x', 'y']}, # FastCCD gain map, 0 high gain, 1 medium gain, 2 low gain - "fastccd_gain": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.gain', - 'dim':['x', 'y']}, + "fastccd_gain": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.gain', + 'dim': ['x', 'y']}, # FastCCD mask, bad pixel map to be ignored if > 0 - "fastccd_mask": {'source':'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', - 'key':'data.image.mask', - 'dim':['x', 'y']}, + "fastccd_mask": {'source': 'SCS_CDIDET_FCCD2M/DAQ/FCCD:daqOutput', + 'key': 'data.image.mask', + 'dim': ['x', 'y']}, # TIM - "MCP1apd": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_D.apd.pulseIntegral', - 'dim':['apdId']}, - "MCP1raw": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_D.raw.samples', - 'dim':['samplesId']}, - "MCP2apd": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_C.apd.pulseIntegral', - 'dim':['apdId']}, - "MCP2raw": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_C.raw.samples', - 'dim':['samplesId']}, - "MCP3apd": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_B.apd.pulseIntegral', - 'dim':['apdId']}, - "MCP3raw": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_B.raw.samples', - 'dim':['samplesId']}, - "MCP4apd": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_A.apd.pulseIntegral', - 'dim':['apdId']}, - "MCP4raw": {'source':'SCS_UTC1_ADQ/ADC/1:network', - 'key':'digitizers.channel_1_A.raw.samples', + "MCP1apd": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_D.apd.pulseIntegral', + 'dim': ['apdId']}, + "MCP1raw": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_D.raw.samples', + 'dim': ['samplesId']}, + "MCP2apd": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_C.apd.pulseIntegral', + 'dim': ['apdId']}, + "MCP2raw": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_C.raw.samples', + 'dim': ['samplesId']}, + "MCP3apd": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_B.apd.pulseIntegral', + 'dim': ['apdId']}, + "MCP3raw": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_B.raw.samples', + 'dim': ['samplesId']}, + "MCP4apd": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_A.apd.pulseIntegral', + 'dim': ['apdId']}, + "MCP4raw": {'source': 'SCS_UTC1_ADQ/ADC/1:network', + 'key': 'digitizers.channel_1_A.raw.samples', 'dim': ['samplesId']}, # FastADC - "FastADC0peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_0.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC0raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_0.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC1peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_1.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC1raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_1.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC2peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_2.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC2raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_2.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC3peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_3.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC3raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_3.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC4peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_4.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC4raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_4.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC5peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_5.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC5raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_5.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC6peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_6.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC6raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_6.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC7peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_7.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC7raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_7.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC8peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_8.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC8raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_8.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, - "FastADC9peaks": {'source':'SCS_UTC1_MCP/ADC/1:channel_9.output', - 'key':'data.peaks', - 'dim':['peakId']}, - "FastADC9raw": {'source':'SCS_UTC1_MCP/ADC/1:channel_9.output', - 'key':'data.rawData', - 'dim':['fadc_samplesId']}, + "FastADC0peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_0.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC0raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_0.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC1peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_1.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC1raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_1.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC2peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_2.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC2raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_2.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC3peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_3.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC3raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_3.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC4peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_4.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC4raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_4.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC5peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_5.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC5raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_5.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC6peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_6.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC6raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_6.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC7peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_7.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC7raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_7.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC8peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_8.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC8raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_8.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, + "FastADC9peaks": {'source': 'SCS_UTC1_MCP/ADC/1:channel_9.output', + 'key': 'data.peaks', + 'dim': ['peakId']}, + "FastADC9raw": {'source': 'SCS_UTC1_MCP/ADC/1:channel_9.output', + 'key': 'data.rawData', + 'dim': ['fadc_samplesId']}, # KARABACON - "KARABACON": {'source':'SCS_DAQ_SCAN/MDL/KARABACON', - 'key': 'actualStep.value', - 'dim': None}, - - #GOTTHARD - "Gotthard1": {'source':'SCS_PAM_XOX/DET/GOTTHARD_RECEIVER1:daqOutput', - 'key': 'data.adc', - 'dim': ['gott_pId','pixelId']}, - "Gotthard2": {'source':'SCS_PAM_XOX/DET/GOTTHARD_RECEIVER2:daqOutput', - 'key': 'data.adc', - 'dim': ['gott_pId','pixelId']} + "KARABACON": {'source': 'SCS_DAQ_SCAN/MDL/KARABACON', + 'key': 'actualStep.value', + 'dim': None}, + + # GOTTHARD + "Gotthard1": {'source': 'SCS_PAM_XOX/DET/GOTTHARD_RECEIVER1:daqOutput', + 'key': 'data.adc', + 'dim': ['gott_pId', 'pixelId']}, + "Gotthard2": {'source': 'SCS_PAM_XOX/DET/GOTTHARD_RECEIVER2:daqOutput', + 'key': 'data.adc', + 'dim': ['gott_pId', 'pixelId']} } diff --git a/src/toolbox_scs/detectors/__init__.py b/src/toolbox_scs/detectors/__init__.py index 65809f4..9b899f1 100644 --- a/src/toolbox_scs/detectors/__init__.py +++ b/src/toolbox_scs/detectors/__init__.py @@ -1,8 +1,9 @@ from .xgm import ( - load_xgm, cleanXGMdata, matchXgmTimPulseId, calibrateXGMs, - autoFindFastAdcPeaks) -from .tim import ( - load_TIM,) + get_xgm, calibrate_xgm) +from .digitizers import ( + get_peaks, get_tim_peaks, get_laser_peaks, get_digitizer_peaks, + check_peak_params) +from .bam_detectors import get_bam from .dssc_data import ( save_xarray, load_xarray, get_data_formatted, save_attributes_h5) from .dssc_misc import ( @@ -12,25 +13,30 @@ from .dssc_processing import ( process_dssc_data) from .dssc import ( DSSCBinner, DSSCFormatter) -from .azimuthal_integrator import AzimuthalIntegrator, AzimuthalIntegratorDSSC +from .azimuthal_integrator import ( + AzimuthalIntegrator, AzimuthalIntegratorDSSC) __all__ = ( # Functions - "load_xgm", - "cleanXGMdata", - "load_TIM", - "matchXgmTimPulseId", - "load_dssc_info", - "create_dssc_bins", - "calc_xgm_frame_indices", - "get_xgm_formatted", - "process_dssc_data", + "get_xgm", + "calibrate_xgm", + "get_peaks", + "get_tim_peaks", + "get_laser_peaks", + "get_digitizer_peaks", + "check_peak_params", + "get_bam", "save_xarray", "load_xarray", "get_data_formatted", "save_attributes_h5", + "load_dssc_info", + "create_dssc_bins", "quickmask_DSSC_ASIC", + "get_xgm_formatted", "load_mask", + "calc_xgm_frame_indices", + "process_dssc_data", # Classes "DSSCBinner", "DSSCFormatter", @@ -58,8 +64,9 @@ clean_ns = [ 'dssc_plot', 'azimuthal_integrator', 'FastCCD', - 'tim', 'xgm', + 'digitizers', + 'bam_detectors' ] diff --git a/src/toolbox_scs/detectors/bam_detectors.py b/src/toolbox_scs/detectors/bam_detectors.py new file mode 100644 index 0000000..4b0d77f --- /dev/null +++ b/src/toolbox_scs/detectors/bam_detectors.py @@ -0,0 +1,109 @@ +""" Beam Arrival Monitor related sub-routines + + Copyright (2021) SCS Team. + + (contributions preferrably comply with pep8 code structure + guidelines.) +""" + +import logging + +import numpy as np +import xarray as xr + +from ..constants import mnemonics as _mnemonics +from ..misc.bunch_pattern_external import is_pulse_at +import toolbox_scs.load as tbload + + +log = logging.getLogger(__name__) + + +def get_bam(run, mnemonics=None, merge_with=None, bunchPattern='sase3'): + """ + Load beam arrival monitor (BAM) data and align their pulse ID + according to the bunch pattern. Sources can be loaded on the fly + via the mnemonics argument, or processed from an existing data set + (merge_with). + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonics: str or list of str + mnemonics for BAM, e.g. "BAM1932M" or ["BAM414", "BAM1932M"]. + If None, defaults to "BAM1932M" in case no merge_with dataset + is provided. + merge_with: xarray Dataset + If provided, the resulting Dataset will be merged with this + one. The BAM variables of merge_with (if any) will also be + selected, aligned and merged. + bunchPattern: str + 'sase1' or 'sase3' or 'scs_ppl', bunch pattern + used to extract peaks. The pulse ID dimension will be named + 'sa1_pId', 'sa3_pId' or 'ol_pId', respectively. + Returns + ------- + xarray Dataset with pulse-resolved BAM variables aligned, + merged with Dataset *merge_with* if provided. + + Example + ------- + >>> import toolbox_scs as tb + >>> import toolbox_scs.detectors as tbdet + >>> run, _ = tb.load(2711, 303) + >>> bam = tbdet.get_bam(run) + + """ + # get the list of mnemonics to process + mnemonics = tbload.mnemonics_to_process(mnemonics, merge_with, 'BAM') + + if len(mnemonics) == 0: + log.info('No array with unaligned BAM data to extract. Skipping.') + return merge_with + else: + log.info(f'Extracting BAM data from {mnemonics}.') + + # Prepare the dataset of non-BAM data to merge with + if bool(merge_with): + mw_ds = merge_with.drop(mnemonics, errors='ignore') + else: + mw_ds = xr.Dataset() + + # extract the XFEL pulses: slice(0,5400,2) + roi = np.s_[:5400:2] + ds = xr.Dataset() + for m in mnemonics: + if bool(merge_with) and m in merge_with: + val = merge_with[m].isel({_mnemonics[m]['dim'][0]: roi}) + log.debug(f'Using {m} from merge_with dataset.') + else: + val = run.get_array(*_mnemonics[m].values(), roi=roi, name=m) + log.debug(f'Loading {m} from DataCollection.') + val[_mnemonics[m]['dim'][0]] = np.arange(2700) + ds = ds.merge(val, join='inner') + + # check if bunch pattern table exists + if bool(merge_with) and 'bunchPatternTable' in merge_with: + bpt = merge_with['bunchPatternTable'] + log.debug('Using bpt from merge_with dataset.') + elif _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + log.debug('Loaded bpt from extra_data run.') + else: + bpt = None + + # align the pulse Id + if bpt is not None and len(ds.variables) > 0: + dim_names = {'sase3': 'sa3_pId', 'sase1': 'sa1_pId', + 'scs_ppl': 'ol_pId'} + mask = is_pulse_at(bpt, bunchPattern) + mask = mask.rename({'pulse_slot': dim_names[bunchPattern]}) + ds = ds.rename({_mnemonics['BAM1932M']['dim'][0]: + dim_names[bunchPattern]}) + ds = ds.where(mask, drop=True) + + # merge with non-BAM dataset + ds = mw_ds.merge(ds, join='inner') + + return ds diff --git a/src/toolbox_scs/detectors/digitizers.py b/src/toolbox_scs/detectors/digitizers.py new file mode 100644 index 0000000..d412cbf --- /dev/null +++ b/src/toolbox_scs/detectors/digitizers.py @@ -0,0 +1,1053 @@ +""" Digitizers related sub-routines + + Copyright (2021) SCS Team. + + (contributions preferrably comply with pep8 code structure + guidelines.) +""" + +import logging + +import numpy as np +import xarray as xr +import matplotlib.pyplot as plt +from scipy.signal import find_peaks + +from ..constants import mnemonics as _mnemonics +from ..misc.bunch_pattern_external import is_pulse_at +from ..util.exceptions import ToolBoxValueError +import toolbox_scs.load as tbload + +log = logging.getLogger(__name__) + + +def peaks_from_raw_trace(traces, pulseStart, pulseStop, baseStart, baseStop, + period, npulses, extra_dim): + """ + Computes peaks from raw digitizer traces by trapezoidal integration. + + Parameters + ---------- + traces: xarray DataArray or numpy array containing raw traces. If + numpy array is provided, the second dimension is that of the samples. + pulseStart: int or list or 1D-numpy array + trace index of integration start. If 1d array, each value is the start + of one peak. The period and npulses parameters are ignored. + pulseStop: int + trace index of integration stop. + baseStart: int + trace index of background start. + baseStop: int + trace index of background stop. + period: int + number of samples between two peaks. Ignored if intstart is a 1D-array. + npulses: int + number of pulses. Ignored if intstart is a 1D-array. + extra_dim: str + Name given to the dimension along the peaks. + + Returns + ------- + xarray DataArray + """ + + assert len(traces.shape) == 2 + + if isinstance(traces, xr.DataArray): + ntid = traces.sizes['trainId'] + coords = traces.coords + traces = traces.values + if traces.shape[0] != ntid: + traces = traces.T + else: + coords = None + + if hasattr(pulseStart, '__len__'): + pulseStart = np.array(pulseStart) + pulses = pulseStart - pulseStart[0] + pulseStart = pulseStart[0] + else: + pulses = range(0, npulses*period, period) + + results = xr.DataArray(np.empty((traces.shape[0], len(pulses))), + coords=coords, + dims=['trainId', extra_dim]) + + for i, p in enumerate(pulses): + a = pulseStart + p + b = pulseStop + p + bkga = baseStart + p + bkgb = baseStop + p + if b > traces.shape[1]: + break + bg = np.outer(np.median(traces[:, bkga:bkgb], axis=1), + np.ones(b-a)) + results[:, i] = np.trapz(traces[:, a:b] - bg, axis=1) + return results + + +def peaks_from_apd(array, params, digitizer, bpt, bunchPattern): + """ + Extract peak-integrated data according to the bunch pattern. + + Parameters + ---------- + array: xarray DataArray + 2D array containing peak-integrated data + params: dict + peak-integration parameters of the digitizer + digitizer: str + digitizer type, one of {'FastADC', 'ADQ412'} + bpt: xarray DataArray + bunch pattern table + bunchPattern: str + one of {'sase1', 'sase3', 'scs_ppl'}, used to select pulses and + assign name of the pulse id dimension. + + Returns + ------- + xarray DataArray with pulse id coordinates. + """ + if params['enable'] == 0 or (array == 1.).all(): + raise ValueError('The digitizer did not record integrated peaks. ' + 'Consider using raw traces from the same channel ' + 'for peak integration.') + if digitizer == 'FastADC': + min_distance = 24 + if digitizer == 'ADQ412': + min_distance = 440 + period = params['period'] + if period % min_distance != 0: + log.warning(f'Warning: the pulse period ({period} samples) of ' + 'digitizer is not a multiple of the pulse separation at ' + f'4.5 MHz ({min_distance} samples). Pulse id assignment ' + 'is likely to fail.') + stride = int(period/min_distance) + npulses_apd = params['npulses'] + dim_names = {'sase3': 'sa3_pId', 'sase1': 'sa1_pId', 'scs_ppl': 'ol_pId'} + pulse_dim = dim_names[bunchPattern] + arr_dim = [dim for dim in array.dims if dim != 'trainId'][0] + if npulses_apd > array.sizes[arr_dim]: + log.warning(f'The digitizer was set to record {npulses_apd} pulses ' + f'but the array length is only {array.sizes[arr_dim]}.') + npulses_apd = array.sizes[arr_dim] + mask = is_pulse_at(bpt, bunchPattern).rename({'pulse_slot': pulse_dim}) + mask = mask.sel(trainId=array.trainId) + mask = mask.assign_coords({pulse_dim: np.arange(2700)}) + pid = np.sort(np.unique(np.where(mask)[1])) + npulses_bpt = len(pid) + apd_coords = np.arange(pid[0], pid[0] + stride*npulses_apd, stride) + noalign = False + if len(np.intersect1d(apd_coords, pid, assume_unique=True)) < npulses_bpt: + log.warning('Not all pulses were recorded. The digitizer ' + 'was set to record pulse ids ' + f'{apd_coords[apd_coords<2700]} but the bunch pattern for' + f' {bunchPattern} is {pid}. Skipping pulse ID alignment.') + noalign = True + array = array.isel({arr_dim: slice(0, npulses_apd)}) + array = array.where(array != 1.) + if noalign: + return array + array = array.rename( + {arr_dim: pulse_dim}).assign_coords({pulse_dim: apd_coords}) + array, mask = xr.align(array, mask, join='inner') + array = array.where(mask, drop=True) + return array + + +def get_peaks(run, + data=None, + source=None, + key=None, + digitizer='ADQ412', + useRaw=True, + autoFind=True, + integParams=None, + bunchPattern='sase3', + bpt=None, + extra_dim=None, + indices=None, + ): + """ + Extract peaks from one source (channel) of a digitizer. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data + data: xarray DataArray or str + array containing the raw traces or peak-integrated values from the + digitizer. If str, must be one of the ToolBox mnemonics. If None, + the data is loaded via the source and key arguments. + source: str + Name of digitizer source, e.g. 'SCS_UTC1_ADQ/ADC/1:network'. Only + required if data is a DataArray or None. + key: str + Key for digitizer data, e.g. 'digitizers.channel_1_A.raw.samples'. + Only required if data is a DataArray or is None. + digitizer: string + name of digitizer, e.g. 'FastADC' or 'ADQ412'. Used to determine + the sampling rate. + useRaw: bool + If True, extract peaks from raw traces. If False, uses the APD (or + peaks) data from the digitizer. + autoFind: bool + If True, finds integration parameters by inspecting the average raw + trace. Only valid if useRaw is True. + integParams: dict + dictionnary containing the integration parameters for raw trace + integration: 'pulseStart', 'pulseStop', 'baseStart', 'baseStop', + 'period', 'npulses'. Not used if autoFind is True. All keys are + required when bunch pattern is missing. + bunchPattern: string or dict + match the peaks to the bunch pattern: 'sase1', 'sase3', 'scs_ppl'. + This will dictate the name of the pulse ID coordinates: 'sa1_pId', + 'sa3_pId' or 'scs_ppl'. Alternatively, a dict with source, key and + pattern can be provided, e.g. {'source':'SCS_RR_UTC/TSYS/TIMESERVER', + 'key':'bunchPatternTable.value', 'pattern':'sase3'} + bpt: xarray DataArray + bunch pattern table + extra_dim: str + Name given to the dimension along the peaks. If None, the name is given + according to the bunchPattern. + indices: array, slice + indices from the peak-integrated data to retrieve. Only required + when bunch pattern is missing and useRaw is False. + + Returns + ------- + xarray.DataArray containing digitizer peaks with pulse coordinates + """ + if data is None and (source is None or key is None): + raise ValueError('At least data or source + key arguments ' + 'are required.') + # Load data + arr = None + if data is None: + log.debug(f'Loading array from DataCollection with {source}, {key}') + arr = run.get_array(source, key) + if isinstance(data, str): + log.debug(f'Loading array from mnemonic {data}') + arr = run.get_array(*_mnemonics[data].values()) + source = _mnemonics[data]['source'] + key = _mnemonics[data]['key'] + if arr is None: + log.debug('Using array provided in data argument.') + if source is None or key is None: + raise ValueError('source and/or key arguments missing.') + arr = data + dim = [d for d in arr.dims if d != 'trainId'][0] + + # Load bunch pattern table + if bpt is None and bunchPattern != 'None': + if isinstance(bunchPattern, dict): + bpt = run.get_array(bunchPattern['source'], bunchPattern['key'], + extra_dims=['pulse_slot']) + pattern = bunchPattern['pattern'] + if _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + pattern = bunchPattern + else: + pattern = bunchPattern + if bunchPattern == 'None': + bpt = None + # 1. Peak-integrated data from digitizer + if useRaw is False: + # 1.1 No bunch pattern provided + if bpt is None: + log.info('Missing bunch pattern info.') + if indices is None: + raise TypeError('indices argument must be provided ' + 'when bunch pattern info is missing.') + if extra_dim is None: + extra_dim = 'pulseId' + return arr.isel({dim: indices}).rename({dim: extra_dim}) + + # 1.2 Bunch pattern is provided + peak_params = channel_peak_params(run, source, key) + log.debug(f'Digitizer peak integration parameters: {peak_params}') + return peaks_from_apd(arr, peak_params, digitizer, bpt, bunchPattern) + + # 2. Use raw data from digitizer + # minimum pulse period @ 4.5MHz, according to digitizer type + min_distance = 1 + if digitizer == 'FastADC': + min_distance = 24 + if digitizer == 'ADQ412': + min_distance = 440 + if autoFind: + trace = arr.isel(trainId=slice(0, 300)).mean(dim='trainId') + try: + integParams = find_integ_params(trace, min_distance=min_distance) + except ValueError as err: + log.warning(f'{err}, trying with average over all trains.') + trace = arr.mean(dim='trainId') + integParams = find_integ_params(trace, min_distance=min_distance) + log.debug(f'Auto find peaks result: {integParams}') + + # 2.1. No bunch pattern provided + if bpt is None: + log.info('Missing bunch pattern info.') + required_keys = ['pulseStart', 'pulseStop', 'baseStart', + 'baseStop', 'period', 'npulses'] + if integParams is None or not all(name in integParams + for name in required_keys): + raise TypeError('All keys of integParams argument ' + f'{required_keys} are required when ' + 'bunch pattern info is missing.') + log.debug(f'Retrieving {integParams["npulses"]} pulses.') + if extra_dim is None: + extra_dim = 'pulseId' + return peaks_from_raw_trace(arr, integParams['pulseStart'], + integParams['pulseStop'], + integParams['baseStart'], + integParams['baseStop'], + integParams['period'], + integParams['npulses'], + extra_dim=extra_dim) + + # 2.2 Bunch pattern is provided + # load mask and extract pulse Id: + dim_names = {'sase3': 'sa3_pId', 'sase1': 'sa1_pId', 'scs_ppl': 'ol_pId'} + extra_dim = dim_names[pattern] + valid_tid = np.intersect1d(arr.trainId, bpt.trainId, assume_unique=True) + mask = is_pulse_at(bpt.sel(trainId=valid_tid), pattern) + mask = mask.rename({'pulse_slot': extra_dim}) + mask = mask.assign_coords({extra_dim: np.arange(2700)}) + mask_on = mask.where(mask, drop=True).fillna(False).astype(bool) + if not (mask_on == mask_on[0]).all().values: + log.info(f'Bunch pattern of {pattern} changed during the run.') + pid = mask_on.coords[extra_dim] + npulses = len(pid) + log.debug(f'Bunch pattern: {npulses} pulses for {pattern}.') + if npulses == 1: + period_bpt = 0 + else: + period_bpt = np.min(np.diff(pid)) + if autoFind and period_bpt*min_distance != integParams['period']: + log.warning('The period from the bunch pattern is different than ' + 'that found by the peak-finding algorithm. Either ' + 'the algorithm failed or the bunch pattern source ' + f'({bunchPattern}) is not correct.') + # create array of sample indices for peak integration + sample_id = (pid-pid[0])*min_distance + # override auto find parameters + if isinstance(integParams['pulseStart'], (int, np.integer)): + integParams['pulseStart'] = integParams['pulseStart'] + sample_id + # select trains containing pulses + valid_arr = arr.sel(trainId=mask_on.trainId) + peaks = peaks_from_raw_trace(valid_arr, integParams['pulseStart'], + integParams['pulseStop'], + integParams['baseStart'], + integParams['baseStop'], + integParams['period'], + integParams['npulses'], + extra_dim) + peaks = peaks.where(mask_on, drop=True) + return peaks.assign_coords({extra_dim: pid}) + + +def channel_peak_params(run, source, key=None, digitizer=None, + channel=None, board=None): + """ + Extract peak-integration parameters used by a channel of the digitizer. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + source: str + ToolBox mnemonic of a digitizer data, e.g. "MCP2apd" or + "FastADC4peaks", or name of digitizer source, e.g. + 'SCS_UTC1_ADQ/ADC/1:network'. + key: str + optional, used in combination of source (if source is not a ToolBox + mnemonics) instead of digitizer, channel and board. + digitizer: {"FastADC", "ADQ412"} str + Type of digitizer. If None, inferred from the source mnemonic. + channel: int or str + The digitizer channel for which to retrieve the parameters. If None, + inferred from the source mnemonic. + board: int + Board of the ADQ412. If None, inferred from the source mnemonic. + + Returns + ------- + dict with peak integration parameters. + """ + if source in _mnemonics: + m = _mnemonics[source] + source = m['source'] + key = m['key'] + if key is not None: + if 'network' in source: + digitizer = 'ADQ412' + ch_to_int = {'A': 0, 'B': 1, 'C': 2, 'D': 3} + k = key.split('.')[1].split('_') + channel = ch_to_int[k[2]] + board = k[1] + else: + digitizer = 'FastADC' + channel = int(source.split(':')[1].split('.')[0].split('_')[1]) + if digitizer is None: + raise ValueError('digitizer argument is missing.') + if channel is None: + raise ValueError('channel argument is missing.') + if isinstance(channel, str): + ch_to_int = {'A': 0, 'B': 1, 'C': 2, 'D': 3} + channel = ch_to_int[channel] + if board is None and digitizer == 'ADQ412': + raise ValueError('board argument is missing.') + keys = None + if digitizer == 'ADQ412': + baseKey = f'board{board}.apd.channel_{channel}.' + keys = ['baseStart', 'baseStop', 'pulseStart', + 'pulseStop', 'initialDelay', 'upperLimit', + 'enable'] + keys = {k: baseKey + k + '.value' for k in keys} + keys['npulses'] = f'board{board}.apd.numberOfPulses.value' + if digitizer == 'FastADC': + if ":" in source: + baseKey = source.split(':')[1].split('.')[0]+'.' + else: + baseKey = f'channel_{channel}.' + keys = ['baseStart', 'baseStop', 'initialDelay', + 'peakSamples', 'numPulses', 'pulsePeriod', + 'enablePeakComputation'] + keys = {k: baseKey + k + '.value' for k in keys} + if ":" in source: + source = source.split(':')[0] + tid, data = run.select(source).train_from_index(0) + result = [data[source][k] for k in keys.values()] + result = dict(zip(keys.keys(), result)) + if digitizer == 'ADQ412': + result['period'] = result.pop('upperLimit') - \ + result.pop('initialDelay') + if digitizer == 'FastADC': + result['period'] = result.pop('pulsePeriod') + result['npulses'] = result.pop('numPulses') + result['pulseStart'] = result['initialDelay'] + result['pulseStop'] = result.pop('initialDelay') + \ + result.pop('peakSamples') + result['enable'] = result.pop('enablePeakComputation') + + return result + + +def find_integ_params(trace, min_distance=1, height=None, width=1): + """ + Find integration parameters for peak integration of a raw + digitizer trace. Based on scipy find_peaks(). + + Parameters + ---------- + trace: numpy array or xarray DataArray + The digitier raw trace used to find peaks + min_distance: int + minimum number of samples between two peaks + height: int + minimum threshold for peak determination + width: int + minimum width of peak + + Returns + ------- + dict with keys 'pulseStart', 'pulseStop', 'baseStart', 'baseStop', + 'period', 'npulses' and values in number of samples. + """ + if isinstance(trace, xr.DataArray): + trace = trace.values + bl = np.median(trace) + trace_no_bl = trace - bl + if np.max(trace_no_bl) < np.abs(np.min(trace_no_bl)): + trace_no_bl *= -1 + trace = bl + trace_no_bl + if height is None: + height = trace_no_bl.max()/20 + centers, peaks = find_peaks(trace_no_bl, distance=min_distance, + height=height, width=width) + npulses = len(centers) + if npulses == 0: + raise ValueError('Could not automatically find peaks.') + elif npulses == 1: + period = 0 + else: + period = np.median(np.diff(centers)).astype(int) + intstart = np.round(peaks['left_ips'][0] + - 0.5*np.mean(peaks['widths'])).astype(int) + intstop = np.round(peaks['right_ips'][0] + + 0.7*np.mean(peaks['widths'])).astype(int) + bkgstop = intstart - int(0.5*np.mean(peaks['widths'])) + bkgstart = np.max([bkgstop - min_distance/2, 0]).astype(int) + intstart = max(0, intstart) + intstop = max(1, intstop) + bkgstart = max(0, bkgstart) + bkgstop = max(1, bkgstop) + result = {'pulseStart': intstart, 'pulseStop': intstop, + 'baseStart': bkgstart, 'baseStop': bkgstop, + 'period': period, 'npulses': npulses} + return result + + +def get_peak_params(run, mnemonic, raw_trace=None, ntrains=200): + """ + Get the peak region and baseline region of a raw digitizer trace used + to compute the peak integration. These regions are either those of the + digitizer peak-integration settings or those determined in get_tim_peaks + or get_fast_adc_peaks when the inputs are raw traces. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonic: str + ToolBox mnemonic of the digitizer data, e.g. 'MCP2apd'. + raw_trace: optional, 1D numpy array or xarray DataArray + Raw trace to display. If None, the average raw trace over + ntrains of the corresponding channel is loaded (this can + be time-consuming). + ntrains: optional, int + Only used if raw_trace is None. Number of trains used to + calculate the average raw trace of the corresponding channel. + """ + if mnemonic not in _mnemonics: + raise ToolBoxValueError("mnemonic must be a ToolBox mnemonics") + if "raw" not in mnemonic: + mnemo_raw = mnemonic.replace('peaks', 'raw').replace('apd', 'raw') + params = channel_peak_params(run, mnemonic) + if 'enable' in params and params['enable'] == 0: + log.warning('The digitizer did not record peak-integrated data.') + title = 'Digitizer peak params' + else: + mnemo_raw = mnemonic + min_distance = 24 if "FastADC" in mnemonic else 440 + title = 'Auto-find peak params' + if raw_trace is None: + sel = run.select_trains(np.s_[:ntrains]) + raw_trace = sel.get_array(*_mnemonics[mnemo_raw].values()) + raw_trace = raw_trace.mean(dim='trainId') + params = find_integ_params(raw_trace, min_distance=min_distance) + log.debug(f'{title} for {mnemonic}: {params}') + return params + + +def check_peak_params(run, mnemonic, raw_trace=None, ntrains=200, params=None, + plot=True, show_all=False, bunchPattern='sase3'): + """ + Checks and plots the peak parameters (pulse window and baseline window + of a raw digitizer trace) used to compute the peak integration. These + parameters are either set by the digitizer peak-integration settings, + or are determined by a peak finding algorithm (used in get_tim_peaks + or get_fast_adc_peaks) when the inputs are raw traces. The parameters + can also be provided manually for visual inspection. The plot either + shows the first and last pulse of the trace or the entire trace. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonic: str + ToolBox mnemonic of the digitizer data, e.g. 'MCP2apd'. + raw_trace: optional, 1D numpy array or xarray DataArray + Raw trace to display. If None, the average raw trace over + ntrains of the corresponding channel is loaded (this can + be time-consuming). + ntrains: optional, int + Only used if raw_trace is None. Number of trains used to + calculate the average raw trace of the corresponding channel. + plot: bool + If True, displays the raw trace and peak integration regions. + show_all: bool + If True, displays the entire raw trace and all peak integration + regions (this can be time-consuming). + If False, shows the first and last pulse according to the bunchPattern. + bunchPattern: optional, str + Only used if plot is True. Checks the bunch pattern against + the digitizer peak parameters and shows potential mismatch. + + Returns + ------- + dictionnary of peak integration parameters + """ + if "raw" in mnemonic: + mnemo_raw = mnemonic + title = 'Auto-find peak params' + else: + mnemo_raw = mnemonic.replace('peaks', 'raw').replace('apd', 'raw') + title = 'Digitizer peak params' + if raw_trace is None: + sel = run.select_trains(np.s_[:ntrains]) + raw_trace = sel.get_array(*_mnemonics[mnemo_raw].values()) + raw_trace = raw_trace.mean(dim='trainId') + if params is None: + params = get_peak_params(run, mnemonic, raw_trace) + if 'enable' in params and params['enable'] == 0: + log.warning('The digitizer did not record peak-integrated data.') + if not plot: + return params + min_distance = 24 if "FastADC" in mnemonic else 440 + if _mnemonics['bunchPatternTable']['source'] in sel.all_sources \ + and bunchPattern != 'None': + sel = run.select_trains(np.s_[:ntrains]) + bp_params = {} + bpt = sel.get_array(*_mnemonics['bunchPatternTable'].values()) + mask = is_pulse_at(bpt, bunchPattern) + pid = np.sort(np.unique(np.where(mask)[1])) + bp_params['npulses'] = len(pid) + if bp_params['npulses'] == 1: + bp_params['period'] = 0 + else: + bp_params['period'] = np.diff(pid)[0] * min_distance + print(f'bunch pattern {bunchPattern}: {bp_params["npulses"]} pulses,' + f' {bp_params["period"]} samples between two pulses') + else: + bp_params = None + print(f'{title}: {params["npulses"]} pulses, {params["period"]}' + ' samples between two pulses') + fig, ax = plotPeakIntegrationWindow(raw_trace, params, bp_params, show_all) + ax[0].set_ylabel(mnemo_raw) + fig.suptitle(title, size=12) + return params + + +def plotPeakIntegrationWindow(raw_trace, params, bp_params, show_all=False): + if show_all: + fig, ax = plt.subplots(figsize=(6, 3), constrained_layout=True) + n = params['npulses'] + p = params['period'] + for i in range(n): + lbl = 'baseline' if i == 0 else None + lp = 'peak' if i == 0 else None + ax.axvline(params['baseStart'] + i*p, ls='--', color='k') + ax.axvline(params['baseStop'] + i*p, ls='--', color='k') + ax.axvspan(params['baseStart'] + i*p, params['baseStop'] + i*p, + alpha=0.5, color='grey', label=lbl) + ax.axvline(params['pulseStart'] + i*p, ls='--', color='r') + ax.axvline(params['pulseStop'] + i*p, ls='--', color='r') + ax.axvspan(params['pulseStart'] + i*p, params['pulseStop'] + i*p, + alpha=0.2, color='r', label=lp) + ax.plot(raw_trace, color='C0', label='raw trace') + ax.legend(fontsize=8) + return fig, [ax] + + if bp_params is not None: + npulses = bp_params['npulses'] + period = bp_params['period'] + else: + npulses = params['npulses'] + period = params['period'] + xmin = np.max([0, params['baseStart']-100]) + xmax = np.min([params['pulseStop']+100, raw_trace.size]) + fig, ax = plt.subplots(1, 2, figsize=(6, 3), constrained_layout=True) + ax[0].axvline(params['baseStart'], ls='--', color='k') + ax[0].axvline(params['baseStop'], ls='--', color='k') + ax[0].axvspan(params['baseStart'], params['baseStop'], + alpha=0.5, color='grey', label='baseline') + ax[0].axvline(params['pulseStart'], ls='--', color='r') + ax[0].axvline(params['pulseStop'], ls='--', color='r') + ax[0].axvspan(params['pulseStart'], params['pulseStop'], + alpha=0.2, color='r', label='peak') + ax[0].plot(np.arange(xmin, xmax), raw_trace[xmin:xmax], color='C0', + label='1st pulse') + ax[0].legend(fontsize=8) + ax[0].set_xlim(xmin, xmax) + ax[0].set_xlabel('digitizer samples') + ax[0].set_title('First pulse', size=10) + + xmin2 = xmin + (npulses-1) * period + xmax2 = xmax + (npulses-1) * period + p = params['period'] + lbl = 'baseline' + lp = 'peak' + for i in range(params['npulses']): + mi = params['baseStart'] + i*p + if not xmin2 < mi < xmax2: + continue + ax[1].axvline(params['baseStart'] + i*p, ls='--', color='k') + ax[1].axvline(params['baseStop'] + i*p, ls='--', color='k') + ax[1].axvspan(params['baseStart'] + i*p, params['baseStop'] + i*p, + alpha=0.5, color='grey', label=lbl) + ax[1].axvline(params['pulseStart'] + i*p, ls='--', color='r') + ax[1].axvline(params['pulseStop'] + i*p, ls='--', color='r') + ax[1].axvspan(params['pulseStart'] + i*p, params['pulseStop'] + i*p, + alpha=0.2, color='r', label=lp) + lbl = None + lp = None + if xmax2 < raw_trace.size: + ax[1].plot(np.arange(xmin2, xmax2), raw_trace[xmin2:xmax2], color='C0', + label='last pulse') + else: + log.warning('The digitizer raw trace is too short to contain ' + + 'all the pulses.') + ax[1].legend(fontsize=8) + ax[1].set_xlabel('digitizer samples') + ax[1].set_xlim(xmin2, xmax2) + ax[1].set_title('Last pulse', size=10) + return fig, ax + + +def get_tim_peaks(run, mnemonics=None, merge_with=None, + bunchPattern='sase3', integParams=None, + keepAllSase=False): + """ + Automatically computes TIM peaks. Sources can be loaded on the + fly via the mnemonics argument, or processed from an existing data + set (merge_with). The bunch pattern table is used to assign the + pulse id coordinates. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonics: str or list of str + mnemonics for TIM, e.g. "MCP2apd" or ["MCP2apd", "MCP3raw"]. + If None, defaults to "MCP2apd" in case no merge_with dataset + is provided. + merge_with: xarray Dataset + If provided, the resulting Dataset will be merged with this + one. The TIM variables of merge_with (if any) will also be + computed and merged. + bunchPattern: str + 'sase1' or 'sase3' or 'scs_ppl', bunch pattern + used to extract peaks. The pulse ID dimension will be named + 'sa1_pId', 'sa3_pId' or 'ol_pId', respectively. + integParams: dict + dictionnary for raw trace integration, e.g. + {'pulseStart':100, 'pulsestop':200, 'baseStart':50, + 'baseStop':99, 'period':24, 'npulses':500}. + If None, integration parameters are computed automatically. + keepAllSase: bool + Only relevant in case of sase-dedicated trains. If True, all + trains are kept, else only those of the bunchPattern are kept. + + Returns + ------- + xarray Dataset with all TIM variables substituted by + the peak caclulated values (e.g. "MCP2raw" becomes + "MCP2peaks"), merged with Dataset *merge_with* if provided. + """ + return get_digitizer_peaks(run, mnemonics, 'ADQ412', merge_with, + bunchPattern, integParams, + keepAllSase) + + +def get_laser_peaks(run, mnemonics=None, merge_with=None, + bunchPattern='scs_ppl', integParams=None): + """ + Extracts laser photodiode signal (peak intensity) from Fast ADC + digitizer. Sources can be loaded on the fly via the mnemonics + argument, and/or processed from an existing data set (merge_with). + The PP laser bunch pattern is used to assign the pulse idcoordinates. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonics: str or list of str + mnemonics for FastADC corresponding to laser signal, e.g. + "FastADC2peaks" or ["FastADC2raw", "FastADC3peaks"]. If None, + defaults to "MCP2apd" in case no merge_with dataset is provided. + merge_with: xarray Dataset + If provided, the resulting Dataset will be merged with this + one. The FastADC variables of merge_with (if any) will also be + computed and merged. + bunchPattern: str + 'sase1' or 'sase3' or 'scs_ppl', bunch pattern + used to extract peaks. + integParams: dict + dictionnary for raw trace integration, e.g. + {'pulseStart':100, 'pulsestop':200, 'baseStart':50, + 'baseStop':99, 'period':24, 'npulses':500}. + If None, integration parameters are computed + automatically. + + Returns + ------- + xarray Dataset with all Fast ADC variables substituted by + the peak caclulated values (e.g. "FastADC2raw" becomes + "FastADC2peaks"). + """ + return get_digitizer_peaks(run, mnemonics, 'FastADC', merge_with, + bunchPattern, integParams, False) + + +def get_digitizer_peaks(run, mnemonics, digitizer, merge_with=None, + bunchPattern='sase3', integParams=None, + keepAllSase=False): + """ + Automatically computes digitizer peaks. Sources can be loaded on the + fly via the mnemonics argument, or processed from an existing data set + (merge_with). The bunch pattern table is used to assign the pulse + id coordinates. + + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonics: str or list of str + mnemonics for FastADC or TIM, e.g. "FastADC2raw" or ["MCP2raw", + "MCP3apd"]. If None and no merge_with dataset is provided, + defaults to "MCP2apd" if digitizer is ADQ412 or + "FastADC5raw" if digitizer is FastADC. + digitizer: str + value in {'FastADC', 'ADQ412'} + merge_with: xarray Dataset + If provided, the resulting Dataset will be merged with this + one. The FastADC variables of merge_with (if any) will also be + computed and merged. + bunchPattern: str + 'sase1' or 'sase3' or 'scs_ppl', bunch pattern + used to extract peaks. + integParams: dict + dictionnary for raw trace integration, e.g. + {'pulseStart':100, 'pulsestop':200, 'baseStart':50, + 'baseStop':99, 'period':24, 'npulses':500}. + If None, integration parameters are computed automatically. + keepAllSase: bool + Only relevant in case of sase-dedicated trains. If True, all + trains are kept, else only those of the bunchPattern are kept. + + Returns + ------- + xarray Dataset with all Fast ADC variables substituted by + the peak caclulated values (e.g. "FastADC2raw" becomes + "FastADC2peaks"). + """ + # get the list of mnemonics to process + def to_processed_name(name): + return name.replace('raw', 'peaks').replace('apd', 'peaks') + mnemonics = tbload.mnemonics_to_process(mnemonics, merge_with, + digitizer, to_processed_name) + + if len(mnemonics) == 0: + log.info(f'No array with unaligned {digitizer} peaks to extract. ' + 'Skipping.') + return merge_with + else: + log.info(f'Extracting {digitizer} peaks from {mnemonics}.') + + # check if bunch pattern table exists + if bool(merge_with) and 'bunchPatternTable' in merge_with: + bpt = merge_with['bunchPatternTable'] + log.debug('Using bpt from merge_with dataset.') + elif _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + log.debug('Loaded bpt from DataCollection.') + else: + bpt = None + + # iterate over mnemonics and merge arrays in dataset + if bool(merge_with): + mw_ds = merge_with.drop(mnemonics, errors='ignore') + else: + mw_ds = xr.Dataset() + autoFind = True if integParams is None else False + names = [] + vals = [] + for k in mnemonics: + useRaw = True if 'raw' in k else False + m = _mnemonics[k] + if bool(merge_with) and k in merge_with: + data = merge_with[k] + else: + data = None + peaks = get_peaks(run, data, + source=m['source'], + key=m['key'], + digitizer=digitizer, + useRaw=useRaw, + autoFind=autoFind, + integParams=integParams, + bunchPattern=bunchPattern, + bpt=bpt) + name = to_processed_name(k) + names.append(name) + vals.append(peaks) + join = 'outer' if keepAllSase else 'inner' + aligned_vals = xr.align(*vals, join=join) + ds = xr.Dataset(dict(zip(names, aligned_vals))) + ds = mw_ds.merge(ds, join=join) + return ds + + +def calibrateTIM(data, rollingWindow=200, mcp=1, plot=False, use_apd=True, intstart=None, + intstop=None, bkgstart=None, bkgstop=None, t_offset=None, npulses_apd=None): + ''' Calibrate TIM signal (Peak-integrated signal) to the slow ion signal of SCS_XGM + (photocurrent read by Keithley, channel 'pulseEnergy.photonFlux.value'). + The aim is to find F so that E_tim_peak[uJ] = F x TIM_peak. For this, we want to + match the SASE3-only average TIM pulse peak per train (TIM_avg) to the slow XGM + signal E_slow. + Since E_slow is the average energy per pulse over all SASE1 and SASE3 + pulses (N1 and N3), we first extract the relative contribution C of the SASE3 pulses + by looking at the pulse-resolved signals of the SA3_XGM in the tunnel. + There, the signal of SASE1 is usually strong enough to be above noise level. + Let TIM_avg be the average of the TIM pulses (SASE3 only). + The calibration factor is then defined as: F = E_slow * C * (N1+N3) / ( N3 * TIM_avg ). + If N3 changes during the run, we locate the indices for which N3 is maximum and define + a window where to apply calibration (indices start/stop). + + Warning: the calibration does not include the transmission by the KB mirrors! + + Inputs: + data: xarray Dataset + rollingWindow: length of running average to calculate TIM_avg + mcp: MCP channel + plot: boolean. If True, plot calibration results. + use_apd: boolean. If False, the TIM pulse peaks are extract from raw traces using + getTIMapd + intstart: trace index of integration start + intstop: trace index of integration stop + bkgstart: trace index of background start + bkgstop: trace index of background stop + t_offset: index separation between two pulses + npulses_apd: number of pulses + + Output: + F: float, TIM calibration factor. + + ''' + start = 0 + stop = None + npulses = data['npulses_sase3'] + ntrains = npulses.shape[0] + if not np.all(npulses == npulses[0]): + start = np.argmax(npulses.values) + stop = ntrains + np.argmax(npulses.values[::-1]) - 1 + if stop - start < rollingWindow: + print('not enough consecutive data points with the largest number of pulses per train') + start += rollingWindow + stop = np.min((ntrains, stop+rollingWindow)) + filteredTIM = getTIMapd(data, mcp, use_apd, intstart, intstop, bkgstart, bkgstop, t_offset, npulses_apd) + sa3contrib = saseContribution(data, 'sase3', 'XTD10_XGM') + avgFast = filteredTIM.mean(axis=1).rolling(trainId=rollingWindow).mean() + ratio = ((data['npulses_sase3']+data['npulses_sase1']) * + data['SCS_photonFlux'] * sa3contrib) / (avgFast*data['npulses_sase3']) + F = float(ratio[start:stop].median().values) + + if plot: + fig = plt.figure(figsize=(8,5)) + ax = plt.subplot(211) + ax.set_title('E[uJ] = {:2e} x TIM (MCP{})'.format(F, mcp)) + ax.plot(data['SCS_photonFlux'], label='SCS XGM slow (all SASE)', color='C0') + slow_avg_sase3 = data['SCS_photonFlux']*(data['npulses_sase1'] + +data['npulses_sase3'])*sa3contrib/data['npulses_sase3'] + ax.plot(slow_avg_sase3, label='SCS XGM slow (SASE3 only)', color='C1') + ax.plot(avgFast*F, label='Calibrated TIM rolling avg', color='C2') + ax.legend(loc='upper left', fontsize=8) + ax.set_ylabel('Energy [$\mu$J]', size=10) + ax.plot(filteredTIM.mean(axis=1)*F, label='Calibrated TIM train avg', alpha=0.2, color='C9') + ax.legend(loc='best', fontsize=8, ncol=2) + plt.xlabel('train in run') + + ax = plt.subplot(234) + xgm_fast = selectSASEinXGM(data) + ax.scatter(filteredTIM, xgm_fast, s=5, alpha=0.1, rasterized=True) + fit, cov = np.polyfit(filteredTIM.values.flatten(),xgm_fast.values.flatten(),1, cov=True) + y=np.poly1d(fit) + x=np.linspace(filteredTIM.min(), filteredTIM.max(), 10) + ax.plot(x, y(x), lw=2, color='r') + ax.set_ylabel('Raw HAMP [$\mu$J]', size=10) + ax.set_xlabel('TIM (MCP{}) signal'.format(mcp), size=10) + ax.annotate(s='y(x) = F x + A\n'+ + 'F = %.3e\n$\Delta$F/F = %.2e\n'%(fit[0],np.abs(np.sqrt(cov[0,0])/fit[0]))+ + 'A = %.3e'%fit[1], + xy=(0.5,0.6), xycoords='axes fraction', fontsize=10, color='r') + print('TIM calibration factor: %e'%(F)) + + ax = plt.subplot(235) + ax.hist(filteredTIM.values.flatten()*F, bins=50, rwidth=0.8) + ax.set_ylabel('number of pulses', size=10) + ax.set_xlabel('Pulse energy MCP{} [uJ]'.format(mcp), size=10) + ax.set_yscale('log') + + ax = plt.subplot(236) + if not use_apd: + pulseStart = intstart + pulseStop = intstop + else: + pulseStart = data.attrs['run'].get_array( + 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.pulseStart.value')[0].values + pulseStop = data.attrs['run'].get_array( + 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.pulseStop.value')[0].values + + if 'MCP{}raw'.format(mcp) not in data: + tid, data = data.attrs['run'].train_from_index(0) + trace = data['SCS_UTC1_ADQ/ADC/1:network']['digitizers.channel_1_D.raw.samples'] + print('no raw data for MCP{}. Loading trace from MCP1'.format(mcp)) + label_trace='MCP1 Voltage [V]' + else: + trace = data['MCP{}raw'.format(mcp)][0] + label_trace='MCP{} Voltage [V]'.format(mcp) + ax.plot(trace[:pulseStop+25], 'o-', ms=2, label='trace') + ax.axvspan(pulseStart, pulseStop, color='C2', alpha=0.2, label='APD region') + ax.axvline(pulseStart, color='gray', ls='--') + ax.axvline(pulseStop, color='gray', ls='--') + ax.set_xlim(pulseStart - 25, pulseStop + 25) + ax.set_ylabel(label_trace, size=10) + ax.set_xlabel('sample #', size=10) + ax.legend(fontsize=8) + plt.tight_layout() + + return F + + +''' TIM calibration table + Dict with key= photon energy and value= array of polynomial coefficients for each MCP (1,2,3). + The polynomials correspond to a fit of the logarithm of the calibration factor as a function + of MCP voltage. If P is a polynomial and V the MCP voltage, the calibration factor (in microjoule + per APD signal) is given by -exp(P(V)). + This table was generated from the calibration of March 2019, proposal 900074, semester 201930, + runs 69 - 111 (Ni edge): https://in.xfel.eu/elog/SCS+Beamline/2323 + runs 113 - 153 (Co edge): https://in.xfel.eu/elog/SCS+Beamline/2334 + runs 163 - 208 (Fe edge): https://in.xfel.eu/elog/SCS+Beamline/2349 +''' +tim_calibration_table = { + 705.5: np.array([ + [-6.85344690e-12, 5.00931986e-08, -1.27206912e-04, 1.15596821e-01, -3.15215367e+01], + [ 1.25613942e-11, -5.41566381e-08, 8.28161004e-05, -7.27230153e-02, 3.10984925e+01], + [ 1.14094964e-12, 7.72658935e-09, -4.27504907e-05, 4.07253378e-02, -7.00773062e+00]]), + 779: np.array([ + [ 4.57610777e-12, -2.33282497e-08, 4.65978738e-05, -6.43305156e-02, 3.73958623e+01], + [ 2.96325102e-11, -1.61393276e-07, 3.32600044e-04, -3.28468195e-01, 1.28328844e+02], + [ 1.14521506e-11, -5.81980336e-08, 1.12518434e-04, -1.19072484e-01, 5.37601559e+01]]), + 851: np.array([ + [ 3.15774215e-11, -1.71452934e-07, 3.50316512e-04, -3.40098861e-01, 1.31064501e+02], + [5.36341958e-11, -2.92533156e-07, 6.00574534e-04, -5.71083140e-01, 2.10547161e+02], + [ 3.69445588e-11, -1.97731342e-07, 3.98203522e-04, -3.78338599e-01, 1.41894119e+02]]) +} + + +def timFactorFromTable(voltage, photonEnergy, mcp=1): + ''' Returns an energy calibration factor for TIM integrated peak signal (APD) + according to calibration from March 2019, proposal 900074, semester 201930, + runs 69 - 111 (Ni edge): https://in.xfel.eu/elog/SCS+Beamline/2323 + runs 113 - 153 (Co edge): https://in.xfel.eu/elog/SCS+Beamline/2334 + runs 163 - 208 (Fe edge): https://in.xfel.eu/elog/SCS+Beamline/2349 + Uses the tim_calibration_table declared above. + + Inputs: + voltage: MCP voltage in volts. + photonEnergy: FEL photon energy in eV. Calibration factor is linearly + interpolated between the known values from the calibration table. + mcp: MCP channel (1, 2, or 3). + + Output: + f: calibration factor in microjoule per APD signal + ''' + energies = np.sort([key for key in tim_calibration_table]) + if photonEnergy not in energies: + if photonEnergy > energies.max(): + photonEnergy = energies.max() + elif photonEnergy < energies.min(): + photonEnergy = energies.min() + else: + idx = np.searchsorted(energies, photonEnergy) - 1 + polyA = np.poly1d(tim_calibration_table[energies[idx]][mcp-1]) + polyB = np.poly1d(tim_calibration_table[energies[idx+1]][mcp-1]) + fA = -np.exp(polyA(voltage)) + fB = -np.exp(polyB(voltage)) + f = fA + (fB-fA)/(energies[idx+1]-energies[idx])*(photonEnergy - energies[idx]) + return f + poly = np.poly1d(tim_calibration_table[photonEnergy][mcp-1]) + f = -np.exp(poly(voltage)) + return f diff --git a/src/toolbox_scs/detectors/dssc.py b/src/toolbox_scs/detectors/dssc.py index 48535ab..aaa80bf 100644 --- a/src/toolbox_scs/detectors/dssc.py +++ b/src/toolbox_scs/detectors/dssc.py @@ -19,7 +19,7 @@ import joblib import numpy as np import xarray as xr -from ..load import load_run +import toolbox_scs as tb from ..util.exceptions import ToolBoxValueError, ToolBoxFileError from .dssc_data import ( save_xarray, load_xarray, save_attributes_h5, @@ -84,7 +84,7 @@ class DSSCBinner: self.proposal = proposal_nr self.runnr = run_nr self.info = load_dssc_info(proposal_nr, run_nr) - self.run = load_run(proposal_nr, run_nr) + self.run, _ = tb.load(proposal_nr, run_nr) self.binners = {} for b in binners: self.add_binner(b, binners[b]) diff --git a/src/toolbox_scs/detectors/dssc_misc.py b/src/toolbox_scs/detectors/dssc_misc.py index 9b7010b..96f5254 100644 --- a/src/toolbox_scs/detectors/dssc_misc.py +++ b/src/toolbox_scs/detectors/dssc_misc.py @@ -11,9 +11,8 @@ from imageio import imread import extra_data as ed -from ..constants import mnemonics as _mnemonics -from ..misc.bunch_pattern_external import is_sase_3 - +from .xgm import get_xgm +from .digitizers import get_tim_peaks log = logging.getLogger(__name__) @@ -95,15 +94,6 @@ def create_dssc_bins(name, coordinates, bins): 'trainId, x, or y') -def _bunch_pattern_sase3(run_obj): - log.debug('load sase3 bunch pattern info') - bpt = run_obj.get_array(*_mnemonics["bunchPatternTable"].values()) - is_sase3 = is_sase_3(bpt.values[0]) - ind_sase3 = np.where(is_sase3 == 1)[0] - n_pulses = len(ind_sase3) - return is_sase3, ind_sase3, n_pulses - - def get_xgm_formatted(run_obj, xgm_name, dssc_frame_coords): """ Load the xgm data and define coordinates along the pulse dimension. @@ -123,27 +113,16 @@ def get_xgm_formatted(run_obj, xgm_name, dssc_frame_coords): xgm data with coordinate 'pulse'. """ log.debug('load raw xgm data') - xgm_raw = run_obj.get_array(*_mnemonics[xgm_name].values()) - - log.debug('create formatted xarray.dataArray') - _, ind_sase3, n_pulses = _bunch_pattern_sase3(run_obj) - coords = {'trainId': xgm_raw.trainId.values} - shape = (len(xgm_raw.trainId.values), n_pulses) - xgm_formatted = xr.DataArray(np.zeros(shape, dtype=np.float64), - coords=coords, - dims=['trainId', 'pulse']) - for i in range(len(xgm_formatted.trainId)): - xgm_formatted[i, :] = xgm_raw[i, 0:n_pulses].values - + xgm = get_xgm(run_obj, xgm_name)[xgm_name] + pulse_dim = [d for d in xgm.dims if d != 'trainId'][0] + xgm = xgm.rename({pulse_dim: 'pulse'}) if type(dssc_frame_coords) == int: - dssc_frame_coords = np.linspace(0, - (n_pulses-1)*dssc_frame_coords, - n_pulses, - dtype=np.uint64) + dssc_frame_coords = np.arange(xgm.sizes['pulse']*dssc_frame_coords, + step=dssc_frame_coords, dtype=np.uint64) - xgm_formatted['pulse'] = dssc_frame_coords + xgm['pulse'] = dssc_frame_coords log.info('loaded formatted xgm data.') - return xgm_formatted + return xgm def get_tim_formatted(run_obj, tim_names, dssc_frame_coords): @@ -161,40 +140,22 @@ def get_tim_formatted(run_obj, tim_names, dssc_frame_coords): Returns ------- - xgm: xarray.DataArray - xgm data with coordinate 'pulse'. + tim: xarray.DataArray + tim data with coordinate 'pulse'. """ log.debug('load tim data') - data = [] - for name in tim_names: - data.append(run_obj.get_array(*_mnemonics[name].values())) - tim_raw = xr.zeros_like(data[0]) - for d in data: - tim_raw -= d - tim_raw /= len(data) - - log.debug('calculate pulse indices in raw data') - _, ind_sase3, n_pulses = _bunch_pattern_sase3(run_obj) - ind_pulse_tim = ((np.array(ind_sase3)-ind_sase3[0])/4).astype(np.int64) - - log.debug('create formatted xarray.dataArray') - coords = {'trainId': tim_raw.trainId.values} - shape = (len(tim_raw.trainId.values), n_pulses) - tim_formatted = xr.DataArray(np.zeros(shape, dtype=np.float64), - coords=coords, - dims=['trainId', 'pulse']) - for i in range(len(tim_formatted.trainId)): - tim_formatted[i, :] = np.take(tim_raw[i, :].values, ind_pulse_tim) - + tim = get_tim_peaks(run_obj, tim_names) + # average over all tim sources + tim = -tim.to_array().mean(dim='variable') + pulse_dim = [d for d in tim.dims if d != 'trainId'][0] + tim = tim.rename({pulse_dim: 'pulse'}) if type(dssc_frame_coords) == int: - dssc_frame_coords = np.linspace(0, - (n_pulses-1)*dssc_frame_coords, - n_pulses, - dtype=np.uint64) + dssc_frame_coords = np.arange(tim.sizes['pulse']*dssc_frame_coords, + step=dssc_frame_coords, dtype=np.uint64) - tim_formatted['pulse'] = dssc_frame_coords + tim['pulse'] = dssc_frame_coords log.info('loaded formatted tim data.') - return tim_formatted + return tim def quickmask_DSSC_ASIC(poslist): diff --git a/src/toolbox_scs/detectors/tim.py b/src/toolbox_scs/detectors/tim.py deleted file mode 100644 index b7ec771..0000000 --- a/src/toolbox_scs/detectors/tim.py +++ /dev/null @@ -1,54 +0,0 @@ -""" Tim related sub-routines - - Copyright (2019) SCS Team. - contributions preferrably comply with pep8 code structure - guidelines. -""" - -import logging - -import xarray as xr - -from .xgm import matchXgmTimPulseId -from ..constants import mnemonics as _mnemonics - - - -log = logging.getLogger(__name__) - - -def load_TIM(run, apd='MCP2apd'): - """ - Load TIM traces and match them to SASE3 pulses. - - Parameters - ---------- - run: extra_data.DataCollection, extra_data.RunDirectory - - Returns - ------- - timdata : xarray.DataArray - xarray DataArray containing the tim data - - Example - ------- - >>> import toolbox_scs as tb - >>> import toolbox_scs.detectors as tbdet - >>> run = tb.run_by_proposal(2212, 235) - >>> data = tbdet.load_TIM(run) - """ - - fields = ["sase1", "sase3", "npulses_sase3", - "npulses_sase1", apd, "SCS_SA3", "nrj"] - timdata = xr.Dataset() - - for f in fields: - m = _mnemonics[f] - timdata[f] = run.get_array(m['source'], - m['key'], - extra_dims=m['dim']) - - timdata.attrs['run'] = run - timdata = matchXgmTimPulseId(timdata) - - return timdata.rename({'sa3_pId': 'pulse'})[apd] \ No newline at end of file diff --git a/src/toolbox_scs/detectors/xgm.py b/src/toolbox_scs/detectors/xgm.py index cb77bde..bed5941 100644 --- a/src/toolbox_scs/detectors/xgm.py +++ b/src/toolbox_scs/detectors/xgm.py @@ -1,8 +1,8 @@ """ XGM related sub-routines Copyright (2019) SCS Team. - - (contributions preferrably comply with pep8 code structure + + (contributions preferrably comply with pep8 code structure guidelines.) """ @@ -11,1075 +11,267 @@ import logging import numpy as np import xarray as xr import matplotlib.pyplot as plt -from scipy.signal import find_peaks -import extra_data as ed from ..constants import mnemonics as _mnemonics +from ..misc.bunch_pattern_external import is_sase_1, is_sase_3 +import toolbox_scs.load as tbload log = logging.getLogger(__name__) -def load_xgm(run, xgm_mnemonic='SCS_SA3'): +def get_xgm(run, mnemonics=None, merge_with=None, keepAllSase=False, + indices=slice(0, None)): """ - Loads XGM data from karabo_data.DataCollection + Load and/or computes XGM data. Sources can be loaded on the + fly via the key argument, or processed from an existing data set + (merge_with). The bunch pattern table is used to assign the pulse + id coordinates. Parameters ---------- - run: karabo_data.DataCollection - + run: extra_data.DataCollection + DataCollection containing the digitizer data. + mnemonics: str or list of str + mnemonics for XGM, e.g. "SCS_SA3" or ["XTD10_XGM", "SCS_XGM"]. + If None, defaults to "SCS_SA3" in case no merge_with dataset + is provided. + merge_with: xarray Dataset + If provided, the resulting Dataset will be merged with this + one. The XGM variables of merge_with (if any) will also be + computed and merged. + keepAllSase: bool + Only relevant in case of sase-dedicated trains. If True, all + trains are kept, else only those of the bunchPattern are kept. + indices: slice, list, 1D array + Pulse indices of the XGM array in case bunch pattern is missing. Returns ------- - xgm : xarray.DataArray - xarray DataArray containing the xgm data + xarray Dataset with pulse-resolved XGM variables aligned, + merged with Dataset *merge_with* if provided. Example ------- >>> import toolbox_scs as tb >>> import toolbox_scs.detectors as tbdet - >>> run = tb.run_by_proposal(2212, 235) - >>> xgm_data = tbdet.load_xgm(run) - """ - nbunches = run.get_array(*_mnemonics['sase3'].values()) - nbunches = np.unique(nbunches) - if len(nbunches) == 1: - nbunches = nbunches[0] - else: - log.info('change of pulse pattern in sase3 during the run.') - nbunches = max(nbunches) - - log.info(f'maximum number of bunches per train in sase3: {nbunches}') - xgm = run.get_array(*_mnemonics[xgm_mnemonic].values(), - roi=ed.by_index[:nbunches]) - return xgm - - -def cleanXGMdata(data, npulses=None, sase3First=True): - ''' Cleans the XGM data arrays obtained from load() function. - The XGM "TD" data arrays have arbitrary size of 1000 and default value 1.0 - when there is no pulse. This function sorts the SASE 1 and SASE 3 pulses. - For DAQ runs after April 2019, sase-resolved arrays can be used. For older runs, - the function selectSASEinXGM is used to extract sase-resolved pulses. - Inputs: - data: xarray Dataset containing XGM TD arrays. - npulses: number of pulses, needed if pulse pattern not available. - sase3First: bool, needed if pulse pattern not available. - - Output: - xarray Dataset containing sase- and pulse-resolved XGM data, with - dimension names 'sa1_pId' and 'sa3_pId' - ''' - dropList = [] - mergeList = [] - load_sa1 = True - if 'sase3' in data: - if np.all(data['npulses_sase1'].where(data['npulses_sase3'] !=0, - drop=True) == 0): - print('Dedicated trains, skip loading SASE 1 data.') - load_sa1 = False - npulses_sa1 = None - else: - print('Missing bunch pattern info!') - if npulses is None: - raise TypeError('npulses argument is required when bunch pattern ' + - 'info is missing.') - #pulse-resolved signals from XGMs - keys = ["XTD10_XGM", "XTD10_SA3", "XTD10_SA1", - "XTD10_XGM_sigma", "XTD10_SA3_sigma", "XTD10_SA1_sigma", - "SCS_XGM", "SCS_SA3", "SCS_SA1", - "SCS_XGM_sigma", "SCS_SA3_sigma", "SCS_SA1_sigma"] - - for whichXgm in ['SCS', 'XTD10']: - load_sa1 = True - if (f"{whichXgm}_SA3" not in data and f"{whichXgm}_XGM" in data): - #no SASE-resolved arrays available - if not 'sase3' in data: - npulses_xgm = data[f'{whichXgm}_XGM'].where(data[f'{whichXgm}_XGM'], drop=True).shape[1] - npulses_sa1 = npulses_xgm - npulses - if npulses_sa1==0: - load_sa1 = False - if npulses_sa1 < 0: - raise ValueError(f'npulses = {npulses} is larger than the total number' - +f' of pulses per train = {npulses_xgm}') - sa3 = selectSASEinXGM(data, xgm=f'{whichXgm}_XGM', sase='sase3', npulses=npulses, - sase3First=sase3First).rename({'XGMbunchId':'sa3_pId'}).rename(f"{whichXgm}_SA3") - mergeList.append(sa3) - if f"{whichXgm}_XGM_sigma" in data: - sa3_sigma = selectSASEinXGM(data, xgm=f'{whichXgm}_XGM_sigma', sase='sase3', npulses=npulses, - sase3First=sase3First).rename({'XGMbunchId':'sa3_pId'}).rename(f"{whichXgm}_SA3_sigma") - mergeList.append(sa3_sigma) - dropList.append(f'{whichXgm}_XGM_sigma') - if load_sa1: - sa1 = selectSASEinXGM(data, xgm=f'{whichXgm}_XGM', sase='sase1', - npulses=npulses_sa1, sase3First=sase3First).rename( - {'XGMbunchId':'sa1_pId'}).rename(f"{whichXgm}_SA1") - mergeList.append(sa1) - if f"{whichXgm}_XGM_sigma" in data: - sa1_sigma = selectSASEinXGM(data, xgm=f'{whichXgm}_XGM_sigma', sase='sase1', npulses=npulses_sa1, - sase3First=sase3First).rename({'XGMbunchId':'sa1_pId'}).rename(f"{whichXgm}_SA1_sigma") - mergeList.append(sa1_sigma) - dropList.append(f'{whichXgm}_XGM') - keys.remove(f'{whichXgm}_XGM') - - for key in keys: - if key not in data: - continue - if "sa3" in key.lower(): - sase = 'sa3_' - elif "sa1" in key.lower(): - sase = 'sa1_' - if not load_sa1: - dropList.append(key) - continue - else: - dropList.append(key) - continue - res = data[key].where(data[key] != 1.0, drop=True).rename( - {'XGMbunchId':'{}pId'.format(sase)}).rename(key) - res = res.assign_coords( - {f'{sase}pId':np.arange(res[f'{sase}pId'].shape[0])}) - - dropList.append(key) - mergeList.append(res) - mergeList.append(data.drop(dropList)) - subset = xr.merge(mergeList, join='inner') - for k in data.attrs.keys(): - subset.attrs[k] = data.attrs[k] - return subset + >>> run, _ = tb.load(2212, 213) + >>> xgm = tbdet.get_xgm(run) + """ + # get the list of mnemonics to process + mnemonics = tbload.mnemonics_to_process(mnemonics, merge_with, 'XGM') -def selectSASEinXGM(data, sase='sase3', xgm='SCS_XGM', sase3First=True, npulses=None): - ''' Given an array containing both SASE1 and SASE3 data, extracts SASE1- - or SASE3-only XGM data. The function tracks the changes of bunch patterns - in sase 1 and sase 3 and applies a mask to the XGM array to extract the - relevant pulses. This way, all complicated patterns are accounted for. - - Inputs: - data: xarray Dataset containing xgm data - sase: key of sase to select: {'sase1', 'sase3'} - xgm: key of xgm to select: {'XTD10_XGM[_sigma]', 'SCS_XGM[_sigma]'} - sase3First: bool, optional. Used in case no bunch pattern was recorded - npulses: int, optional. Required in case no bunch pattern was recorded. - - Output: - DataArray that has all trainIds that contain a lasing - train in sase, with dimension equal to the maximum number of pulses of - that sase in the run. The missing values, in case of change of number of pulses, - are filled with NaNs. - ''' - #1. case where bunch pattern is missing: - if sase not in data: - print('Retrieving {} SASE {} pulses assuming that '.format(npulses, sase[4]) - +'SASE {} pulses come first.'.format('3' if sase3First else '1')) - #in older version of DAQ, non-data numbers were filled with 0.0. - xgmData = data[xgm].where(data[xgm]!=0.0, drop=True) - xgmData = xgmData.fillna(0.0).where(xgmData!=1.0, drop=True) - if (sase3First and sase=='sase3') or (not sase3First and sase=='sase1'): - return xgmData[:,:npulses].assign_coords(XGMbunchId=np.arange(npulses)) - else: - if xr.ufuncs.isnan(xgmData).any(): - raise Exception('The number of pulses changed during the run. ' - 'This is not supported yet.') - else: - start=xgmData.shape[1]-npulses - return xgmData[:,start:start+npulses].assign_coords(XGMbunchId=np.arange(npulses)) - - #2. case where bunch pattern is provided - #2.1 Merge sase1 and sase3 bunch patterns to get indices of all pulses - xgm_arr = data[xgm].where(data[xgm] != 1., drop=True) - sa3 = data['sase3'].where(data['sase3'] > 1, drop=True) - sa3_val=np.unique(sa3) - sa3_val = sa3_val[~np.isnan(sa3_val)] - sa1 = data['sase1'].where(data['sase1'] > 1, drop=True) - sa1_val=np.unique(sa1) - sa1_val = sa1_val[~np.isnan(sa1_val)] - sa_all = xr.concat([sa1, sa3], dim='bunchId').rename('sa_all') - sa_all = xr.DataArray(np.sort(sa_all)[:,:xgm_arr['XGMbunchId'].shape[0]], - dims=['trainId', 'bunchId'], - coords={'trainId':data.trainId}, - name='sase_all') - if sase=='sase3': - idxListSase = np.unique(sa3) - newName = xgm.split('_')[0] + '_SA3' + if len(mnemonics) == 0: + log.info('No array with unaligned XGM peaks to extract. Skipping.') + return merge_with else: - idxListSase = np.unique(sa1) - newName = xgm.split('_')[0] + '_SA1' - - #2.2 track the changes of pulse patterns and the indices at which they occured (invAll) - idxListAll, invAll = np.unique(sa_all.fillna(-1), axis=0, return_inverse=True) - - #2.3 define a mask, loop over the different patterns and update the mask for each pattern - mask = xr.DataArray(np.zeros((data.dims['trainId'], sa_all['bunchId'].shape[0]), dtype=bool), - dims=['trainId', 'XGMbunchId'], - coords={'trainId':data.trainId, - 'XGMbunchId':sa_all['bunchId'].values}, - name='mask') + log.info(f'Extracting XGM data from {mnemonics}.') - big_sase = [] - for i,idxXGM in enumerate(idxListAll): - mask.values = np.zeros(mask.shape, dtype=bool) - idxXGM = np.isin(idxXGM, idxListSase) - idxTid = invAll==i - mask[idxTid, idxXGM] = True - sa_arr = xgm_arr.where(mask, drop=True) - if sa_arr.trainId.size > 0: - sa_arr = sa_arr.assign_coords(XGMbunchId=np.arange(sa_arr.XGMbunchId.size)) - big_sase.append(sa_arr) - if len(big_sase) > 0: - da_sase = xr.concat(big_sase, dim='trainId').rename(newName) + # Prepare the dataset of non-XGM data to merge with + if bool(merge_with): + ds = merge_with.drop(mnemonics, errors='ignore') else: - da_sase = xr.DataArray([], dims=['trainId'], name=newName) - return da_sase - -def saseContribution(data, sase='sase1', xgm='XTD10_XGM'): - ''' Calculate the relative contribution of SASE 1 or SASE 3 pulses - for each train in the run. Supports fresh bunch, dedicated trains - and pulse on demand modes. - - Inputs: - data: xarray Dataset containing xgm data - sase: key of sase for which the contribution is computed: {'sase1', 'sase3'} - xgm: key of xgm to select: {'XTD10_XGM', 'SCS_XGM'} - - Output: - 1D DataArray equal to sum(sase)/sum(sase1+sase3) - - ''' - xgm_sa1 = selectSASEinXGM(data, 'sase1', xgm=xgm) - xgm_sa3 = selectSASEinXGM(data, 'sase3', xgm=xgm) - #Fill missing train ids with 0 - r = xr.align(*[xgm_sa1, xgm_sa3], join='outer', exclude=['XGMbunchId']) - xgm_sa1 = r[0].fillna(0) - xgm_sa3 = r[1].fillna(0) - - contrib = xgm_sa1.sum(axis=1)/(xgm_sa1.sum(axis=1) + xgm_sa3.sum(axis=1)) - if sase=='sase1': - return contrib + ds = xr.Dataset() + + # check if bunch pattern table exists + if bool(merge_with) and 'bunchPatternTable' in merge_with: + bpt = merge_with['bunchPatternTable'] + log.debug('Using bpt from merge_with dataset.') + elif _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + log.debug('Loaded bpt from DataCollection.') else: - return 1 - contrib - -def calibrateXGMs(data, allPulses=False, plot=False, display=False): - ''' Calibrate the fast (pulse-resolved) signals of the XTD10 and SCS XGM - (read in intensityTD property) to the respective slow ion signal - (photocurrent read by Keithley, key 'pulseEnergy.photonFlux.value'). - If the sase-resolved averaged signals ("slowTrain", introduced in May - 2019) are recorded, the calibration is defined as the mean ratio - between the photonFlux and the slowTrain signal. Otherwise, the - averaged fast signals are computed using a rolling average. - - Inputs: - data: xarray Dataset - allPulses: if True, uses "XTD10_XGM" and "SCS_XGM" arrays and - computes the relative contributions of SASE1 and SASE3 to - photonFlux. This should be more accurate in cases where the - number of SASE1 pulses is large and/or the SASE1 pulse - intensity cannot be neglected. - plot: bool, plot the calibration output - display: bool, displays info if True + bpt = None - Output: - ndarray with [XTD10 calibration factor, SCS calibration factor] - ''' - if allPulses: - return calibrateXGMsFromAllPulses(data, plot) - hasSlowTrain=[True,True] - results = np.array([np.nan, np.nan], dtype=float) - slowTrainData = [] - for i,whichXgm in enumerate(['XTD10', 'SCS']): - #1. Try to load fast data averages (in DAQ since May 2019) - if f'{whichXgm}_slowTrain' in data: - if display: - print(f'Using fast data averages (slowTrain) for {whichXgm}') - slowTrainData.append(data[f'{whichXgm}_slowTrain']) + # Load the arrays, assign pulse ID and merge + for m in mnemonics: + if bool(merge_with) and m in merge_with: + arr = merge_with[m] + log.debug(f'Using {m} from merge_with dataset.') else: - mnemo = _mnemonics[f'{whichXgm}_slowTrain'] - if mnemo['key'] in data.attrs['run'].keys_for_source(mnemo['source']): - if display: - print(f'Using fast data averages (slowTrain) for {whichXgm}') - slowTrainData.append(data.attrs['run'].get_array(mnemo['source'], mnemo['key'])) - #2. Calculate fast data average from fast data - else: - if display: - print(f'No averages of fast data (slowTrain) available for {whichXgm}.'+ - ' Attempting calibration from fast data.') - if f'{whichXgm}_SA3' in data: - if display: - print(f'Calculating slowTrain from SA3 for {whichXgm}') - slowTrainData.append(data[f'{whichXgm}_SA3'].rolling(trainId=200 - ).mean().mean(axis=1)) - elif f'{whichXgm}_XGM' in data: - sa3 = selectSASEinXGM(data, xgm=f'{whichXgm}_XGM') - slowTrainData.append(sa3.rolling(trainId=200).mean().mean(axis=1)) - else: - hasSlowTrain[i]=False - if hasSlowTrain[i]: - results[i] = np.mean(data[f'{whichXgm}_photonFlux']/slowTrainData[i]) - if display: - print(f'Calibration factor {whichXgm} XGM: {results[i]}') - if plot: - plt.figure(figsize=(8,4)) - plt.subplot(211) - plt.plot(data['XTD10_photonFlux'], label='XTD10 photon flux') - plt.plot(slowTrainData[0]*results[0], label='calibrated XTD10 fast signal') - plt.ylabel(r'Energy [$\mu$J]') - plt.legend(fontsize=8, loc='upper left') - plt.twinx() - plt.plot(slowTrainData[0], label='uncalibrated XTD10 fast signal', color='C4') - plt.ylabel(r'Uncalibrated energy') - plt.legend(fontsize=8, loc='upper right') - plt.subplot(212) - plt.plot(data['SCS_photonFlux'], label='SCS photon flux') - plt.plot(slowTrainData[1]*results[1], label='calibrated SCS fast signal') - plt.ylabel(r'Energy [$\mu$J]') - plt.xlabel('train Id') - plt.legend(fontsize=8, loc='upper left') - plt.twinx() - plt.plot(slowTrainData[1], label='uncalibrated SCS fast signal', color='C4') - plt.ylabel(r'Uncalibrated energy') - plt.legend(fontsize=8, loc='upper right') - plt.tight_layout() - return results - -def calibrateXGMsFromAllPulses(data, plot=False): - ''' Calibrate the fast (pulse-resolved) signals of the XTD10 and SCS XGM - (read in intensityTD property) to the respective slow ion signal - (photocurrent read by Keithley, channel 'pulseEnergy.photonFlux.value'). - One has to take into account the possible signal created by SASE1 pulses. In the - tunnel, this signal is usually large enough to be read by the XGM and the relative - contribution C of SASE3 pulses to the overall signal is computed. - In the tunnel, the calibration F is defined as: - F = E_slow / E_fast_avg, where - E_fast_avg is the rolling average (with window rollingWindow) of the fast signal. - In SCS XGM, the signal from SASE1 is usually in the noise, so we calculate the - average over the pulse-resolved signal of SASE3 pulses only and calibrate it to the - slow signal modulated by the SASE3 contribution: - F = (N1+N3) * E_avg * C/(N3 * E_fast_avg_sase3), where N1 and N3 are the number - of pulses in SASE1 and SASE3, E_fast_avg_sase3 is the rolling average (with window - rollingWindow) of the SASE3-only fast signal. - - Inputs: - data: xarray Dataset - rollingWindow: length of running average to calculate E_fast_avg - plot: boolean, plot the calibration output - - Output: - factors: numpy ndarray of shape 1 x 2 containing - [XTD10 calibration factor, SCS calibration factor] - ''' - XTD10_factor = np.nan - SCS_factor = np.nan - noSCS = noXTD10 = False - if 'SCS_XGM' not in data: - print('no SCS XGM data. Skipping calibration for SCS XGM') - noSCS = True - if 'XTD10_XGM' not in data: - print('no XTD10 XGM data. Skipping calibration for XTD10 XGM') - noXTD10 = True - if noSCS and noXTD10: - return np.array([XTD10_factor, SCS_factor]) - if not noSCS and noXTD10: - print('XTD10 data is needed to calibrate SCS XGM.') - return np.array([XTD10_factor, SCS_factor]) - start = 0 - stop = None - npulses = data['npulses_sase3'] - ntrains = npulses.shape[0] - rollingWindow=200 - # First, in case of change in number of pulses, locate a region where - # the number of pulses is maximum. - if not np.all(npulses == npulses[0]): - print('Warning: Number of pulses per train changed during the run!') - start = np.argmax(npulses.values) - stop = ntrains + np.argmax(npulses.values[::-1]) - 1 - if stop - start < rollingWindow: - print('not enough consecutive data points with the largest number of pulses per train') - start += rollingWindow - stop = np.min((ntrains, stop+rollingWindow)) - - # Calculate SASE3 slow data - sa3contrib = saseContribution(data, 'sase3', 'XTD10_XGM') - SA3_SLOW = data['XTD10_photonFlux']*(data['npulses_sase3']+data['npulses_sase1'])*sa3contrib/data['npulses_sase3'] - SA1_SLOW = data['XTD10_photonFlux']*(data['npulses_sase3']+data['npulses_sase1'])*(1-sa3contrib)/data['npulses_sase1'] - - # Calibrate XTD10 XGM with all signal from SASE1 and SASE3 - if not noXTD10: - xgm_avg = selectSASEinXGM(data, 'sase3', 'XTD10_XGM').mean(axis=1) - rolling_sa3_xgm = xgm_avg.rolling(trainId=rollingWindow).mean() - ratio = SA3_SLOW/rolling_sa3_xgm - XTD10_factor = ratio[start:stop].mean().values - print('calibration factor XTD10 XGM: %f'%XTD10_factor) - - # Calibrate SCS XGM with SASE3-only contribution - if not noSCS: - SCS_SLOW = data['SCS_photonFlux']*(data['npulses_sase3']+data['npulses_sase1'])*sa3contrib/data['npulses_sase3'] - scs_sase3_fast = selectSASEinXGM(data, 'sase3', 'SCS_XGM').mean(axis=1) - meanFast = scs_sase3_fast.rolling(trainId=rollingWindow).mean() - ratio = SCS_SLOW/meanFast - SCS_factor = ratio[start:stop].median().values - print('calibration factor SCS XGM: %f'%SCS_factor) - - if plot: - if noSCS ^ noXTD10: - plt.figure(figsize=(8,4)) - else: - plt.figure(figsize=(8,8)) - plt.subplot(211) - plt.title('E[uJ] = %.2f x IntensityTD' %(XTD10_factor)) - plt.plot(SA3_SLOW, label='SA3 slow', color='C1') - plt.plot(rolling_sa3_xgm*XTD10_factor, - label='SA3 fast signal rolling avg', color='C4') - plt.plot(xgm_avg*XTD10_factor, label='SA3 fast signal train avg', alpha=0.2, color='C4') - plt.ylabel('Energy [uJ]') - plt.xlabel('train in run') - plt.legend(loc='upper left', fontsize=10) - plt.twinx() - plt.plot(SA1_SLOW, label='SA1 slow', alpha=0.2, color='C2') - plt.ylabel('SA1 slow signal [uJ]') - plt.legend(loc='lower right', fontsize=10) - - plt.subplot(212) - plt.title('E[uJ] = %.2g x HAMP' %SCS_factor) - plt.plot(SCS_SLOW, label='SCS slow', color='C1') - plt.plot(meanFast*SCS_factor, label='SCS HAMP rolling avg', color='C2') - plt.ylabel('Energy [uJ]') - plt.xlabel('train in run') - plt.plot(scs_sase3_fast*SCS_factor, label='SCS HAMP train avg', alpha=0.2, color='C2') - plt.legend(loc='upper left', fontsize=10) - plt.tight_layout() - - return np.array([XTD10_factor, SCS_factor]) - - -# TIM -def mcpPeaks(data, intstart, intstop, bkgstart, bkgstop, mcp=1, t_offset=None, npulses=None): - ''' Computes peak integration from raw MCP traces. - - Inputs: - data: xarray Dataset containing MCP raw traces (e.g. 'MCP1raw') - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - mcp: MCP channel number - t_offset: index separation between two pulses. Needed if bunch - pattern info is not available. If None, checks the pulse - pattern and determine the t_offset assuming mininum pulse - separation of 220 ns and digitizer resolution of 2 GHz. - npulses: number of pulses. If None, takes the maximum number of - pulses according to the bunch pattern (field 'npulses_sase3') - - Output: - results: DataArray with dims trainId x max(sase3 pulses) - - ''' - keyraw = 'MCP{}raw'.format(mcp) - if keyraw not in data: - raise ValueError("Source not found: {}!".format(keyraw)) - if npulses is None: - npulses = int(data['npulses_sase3'].max().values) - if t_offset is None: - sa3 = data['sase3'].where(data['sase3']>1) - if npulses > 1: - #Calculate the number of pulses between two lasing pulses (step) - step = sa3.where(data['npulses_sase3']>1, drop=True)[0,:2].values - step = int(step[1] - step[0]) - #multiply by elementary samples length (220 ns @ 2 GHz = 440) - t_offset = 440 * step - else: - t_offset = 1 - results = xr.DataArray(np.zeros((data.trainId.shape[0], npulses)), coords=data[keyraw].coords, - dims=['trainId', 'MCP{}fromRaw'.format(mcp)]) - for i in range(npulses): - a = intstart + t_offset*i - b = intstop + t_offset*i - bkga = bkgstart + t_offset*i - bkgb = bkgstop + t_offset*i - if b > data.dims['samplesId']: - break - bg = np.outer(np.median(data[keyraw][:,bkga:bkgb], axis=1), np.ones(b-a)) - results[:,i] = np.trapz(data[keyraw][:,a:b] - bg, axis=1) - return results - - -def getTIMapd(data, mcp=1, use_apd=True, intstart=None, intstop=None, - bkgstart=None, bkgstop=None, t_offset=None, npulses=None, - stride=1): - ''' Extract peak-integrated data from TIM where pulses are from SASE3 only. - If use_apd is False it calculates integration from raw traces. - The missing values, in case of change of number of pulses, are filled - with NaNs. If no bunch pattern info is available, the function assumes - that SASE 3 comes first and that the number of pulses is fixed in both - SASE 1 and 3. - - Inputs: - data: xarray Dataset containing MCP raw traces (e.g. 'MCP1raw') - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - t_offset: number of ADC samples between two pulses - mcp: MCP channel number - npulses: int, optional. Number of pulses to compute. Required if - no bunch pattern info is available. - stride: int, optional. Used to select pulses in the APD array if - no bunch pattern info is available. - Output: - tim: DataArray of shape trainId only for SASE3 pulses x N - with N=max(number of pulses per train) - ''' - #1. case where no bunch pattern is available: - if 'sase3' not in data: - print('Missing bunch pattern info!\n') - if npulses is None: - raise TypeError('npulses argument is required when bunch pattern ' + - 'info is missing.') - print('Retrieving {} SASE 3 pulses assuming that '.format(npulses) + - 'SASE 3 pulses come first.') - if use_apd: - tim = data[f'MCP{mcp}apd'][:,:npulses:stride] + arr = run.get_array(*_mnemonics[m].values(), name=m) + log.debug(f'Loading {m} from DataCollection.') + if bpt is not None: + arr = align_xgm_array(arr, bpt) else: - tim = mcpPeaks(data, intstart, intstop, bkgstart, bkgstop, mcp=mcp, - t_offset=t_offset, npulses=npulses) - return tim - - #2. If bunch pattern available, define a mask that corresponds to the SASE 3 pulses - sa3 = data['sase3'].where(data['sase3']>1, drop=True) - sa3 -= sa3[0,0] - #2.1 case where apd is used: - if use_apd: - pulseId = 'apdId' - pulseIdDim = data.dims['apdId'] - initialDelay = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.initialDelay.value')[0].values - upperLimit = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.upperLimit.value')[0].values - #440 = samples between two pulses @4.5 MHz with ADQ412 digitizer: - period = int((upperLimit - initialDelay)/440) - #display some warnings if apd parameters do not match pulse pattern: - period_from_bunch_pattern = int(np.nanmin(np.diff(sa3))) - if period > period_from_bunch_pattern: - print(f'Warning: apd parameter was set to record 1 pulse out of {period} @ 4.5 MHz ' + - f'but XFEL delivered 1 pulse out of {period_from_bunch_pattern}.') - maxPulses = data['npulses_sase3'].max().values - if period*pulseIdDim < period_from_bunch_pattern*(maxPulses-1): - print(f'Warning: Number of pulses and/or rep. rate in apd parameters were set ' + - f'too low ({pulseIdDim})to record the {maxPulses} SASE 3 pulses') - peaks = data[f'MCP{mcp}apd'] - - #2.2 case where integration is performed on raw trace: - else: - pulseId = f'MCP{mcp}fromRaw' - pulseIdDim = int(np.max(sa3).values) + 1 - period = int(np.nanmin(np.diff(sa3))) - peaks = mcpPeaks(data, intstart, intstop, bkgstart, bkgstop, mcp=mcp, t_offset=period*440, - npulses=pulseIdDim) - - sa3 = sa3/period - #2.3 track the changes of pulse patterns and the indices at which they occured (invAll) - idxList, inv = np.unique(sa3, axis=0, return_inverse=True) - mask = xr.DataArray(np.zeros((data.dims['trainId'], pulseIdDim), dtype=bool), - dims=['trainId', pulseId], - coords={'trainId':data.trainId, - pulseId:np.arange(pulseIdDim)}) - mask = mask.sel(trainId=sa3.trainId) - for i,idxApd in enumerate(idxList): - idxApd = idxApd[idxApd>=0].astype(int) - idxTid = inv==i - mask[idxTid, idxApd] = True + arr = arr.where(arr != 1., drop=True).sel(XGMbunchId=indices) + ds = ds.merge(arr, join='inner') + return ds - peaks = peaks.where(mask, drop=True) - peaks = peaks.assign_coords({pulseId:np.arange(peaks[pulseId].shape[0])}) - return peaks +def align_xgm_array(xgm_arr, bpt): + """ + Assigns pulse ID coordinates to a pulse-resolved XGM array, according to + the bunch pattern table. If the arrays contains both SASE 1 and SASE 3 + data, it is split in two arrays. -def calibrateTIM(data, rollingWindow=200, mcp=1, plot=False, use_apd=True, intstart=None, - intstop=None, bkgstart=None, bkgstop=None, t_offset=None, npulses_apd=None): - ''' Calibrate TIM signal (Peak-integrated signal) to the slow ion signal of SCS_XGM - (photocurrent read by Keithley, channel 'pulseEnergy.photonFlux.value'). - The aim is to find F so that E_tim_peak[uJ] = F x TIM_peak. For this, we want to - match the SASE3-only average TIM pulse peak per train (TIM_avg) to the slow XGM - signal E_slow. - Since E_slow is the average energy per pulse over all SASE1 and SASE3 - pulses (N1 and N3), we first extract the relative contribution C of the SASE3 pulses - by looking at the pulse-resolved signals of the SA3_XGM in the tunnel. - There, the signal of SASE1 is usually strong enough to be above noise level. - Let TIM_avg be the average of the TIM pulses (SASE3 only). - The calibration factor is then defined as: F = E_slow * C * (N1+N3) / ( N3 * TIM_avg ). - If N3 changes during the run, we locate the indices for which N3 is maximum and define - a window where to apply calibration (indices start/stop). - - Warning: the calibration does not include the transmission by the KB mirrors! - - Inputs: - data: xarray Dataset - rollingWindow: length of running average to calculate TIM_avg - mcp: MCP channel - plot: boolean. If True, plot calibration results. - use_apd: boolean. If False, the TIM pulse peaks are extract from raw traces using - getTIMapd - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - t_offset: index separation between two pulses - npulses_apd: number of pulses - - Output: - F: float, TIM calibration factor. - - ''' - start = 0 - stop = None - npulses = data['npulses_sase3'] - ntrains = npulses.shape[0] - if not np.all(npulses == npulses[0]): - start = np.argmax(npulses.values) - stop = ntrains + np.argmax(npulses.values[::-1]) - 1 - if stop - start < rollingWindow: - print('not enough consecutive data points with the largest number of pulses per train') - start += rollingWindow - stop = np.min((ntrains, stop+rollingWindow)) - filteredTIM = getTIMapd(data, mcp, use_apd, intstart, intstop, bkgstart, bkgstop, t_offset, npulses_apd) - sa3contrib = saseContribution(data, 'sase3', 'XTD10_XGM') - avgFast = filteredTIM.mean(axis=1).rolling(trainId=rollingWindow).mean() - ratio = ((data['npulses_sase3']+data['npulses_sase1']) * - data['SCS_photonFlux'] * sa3contrib) / (avgFast*data['npulses_sase3']) - F = float(ratio[start:stop].median().values) + Parameters + ---------- + xgm_arr: xarray DataArray + array containing pulse-resolved XGM data, with dims ['trainId', + 'XGMbunchId'] + bpt: xarray DataArray + bunch pattern table - if plot: - fig = plt.figure(figsize=(8,5)) - ax = plt.subplot(211) - ax.set_title('E[uJ] = {:2e} x TIM (MCP{})'.format(F, mcp)) - ax.plot(data['SCS_photonFlux'], label='SCS XGM slow (all SASE)', color='C0') - slow_avg_sase3 = data['SCS_photonFlux']*(data['npulses_sase1'] - +data['npulses_sase3'])*sa3contrib/data['npulses_sase3'] - ax.plot(slow_avg_sase3, label='SCS XGM slow (SASE3 only)', color='C1') - ax.plot(avgFast*F, label='Calibrated TIM rolling avg', color='C2') - ax.legend(loc='upper left', fontsize=8) - ax.set_ylabel('Energy [$\mu$J]', size=10) - ax.plot(filteredTIM.mean(axis=1)*F, label='Calibrated TIM train avg', alpha=0.2, color='C9') - ax.legend(loc='best', fontsize=8, ncol=2) - plt.xlabel('train in run') - - ax = plt.subplot(234) - xgm_fast = selectSASEinXGM(data) - ax.scatter(filteredTIM, xgm_fast, s=5, alpha=0.1, rasterized=True) - fit, cov = np.polyfit(filteredTIM.values.flatten(),xgm_fast.values.flatten(),1, cov=True) - y=np.poly1d(fit) - x=np.linspace(filteredTIM.min(), filteredTIM.max(), 10) - ax.plot(x, y(x), lw=2, color='r') - ax.set_ylabel('Raw HAMP [$\mu$J]', size=10) - ax.set_xlabel('TIM (MCP{}) signal'.format(mcp), size=10) - ax.annotate(s='y(x) = F x + A\n'+ - 'F = %.3e\n$\Delta$F/F = %.2e\n'%(fit[0],np.abs(np.sqrt(cov[0,0])/fit[0]))+ - 'A = %.3e'%fit[1], - xy=(0.5,0.6), xycoords='axes fraction', fontsize=10, color='r') - print('TIM calibration factor: %e'%(F)) - - ax = plt.subplot(235) - ax.hist(filteredTIM.values.flatten()*F, bins=50, rwidth=0.8) - ax.set_ylabel('number of pulses', size=10) - ax.set_xlabel('Pulse energy MCP{} [uJ]'.format(mcp), size=10) - ax.set_yscale('log') - - ax = plt.subplot(236) - if not use_apd: - pulseStart = intstart - pulseStop = intstop - else: - pulseStart = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.pulseStart.value')[0].values - pulseStop = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', 'board1.apd.channel_0.pulseStop.value')[0].values - - if 'MCP{}raw'.format(mcp) not in data: - tid, data = data.attrs['run'].train_from_index(0) - trace = data['SCS_UTC1_ADQ/ADC/1:network']['digitizers.channel_1_D.raw.samples'] - print('no raw data for MCP{}. Loading trace from MCP1'.format(mcp)) - label_trace='MCP1 Voltage [V]' + Returns + ------- + xarray Dataset with pulse ID coordinates. For SASE 1 data, the coordinates + name is sa1_pId, for SASE 3 data, the coordinates name is sa3_pId. + """ + key = xgm_arr.name + compute_sa1 = False + compute_sa3 = False + valid_tid = np.intersect1d(xgm_arr.trainId, bpt.trainId, + assume_unique=True) + # get the relevant masks for SASE 1 and/or SASE3 + if "SA1" in key or "SA3" in key: + if "SA1" in key: + mask = is_sase_1(bpt.sel(trainId=valid_tid)) + compute_sa1 = True else: - trace = data['MCP{}raw'.format(mcp)][0] - label_trace='MCP{} Voltage [V]'.format(mcp) - ax.plot(trace[:pulseStop+25], 'o-', ms=2, label='trace') - ax.axvspan(pulseStart, pulseStop, color='C2', alpha=0.2, label='APD region') - ax.axvline(pulseStart, color='gray', ls='--') - ax.axvline(pulseStop, color='gray', ls='--') - ax.set_xlim(pulseStart - 25, pulseStop + 25) - ax.set_ylabel(label_trace, size=10) - ax.set_xlabel('sample #', size=10) - ax.legend(fontsize=8) - plt.tight_layout() - - return F - + mask = is_sase_3(bpt.sel(trainId=valid_tid)) + compute_sa3 = True + tid = mask.where(mask.sum(dim='pulse_slot') > 0, drop=True).trainId + mask = mask.sel(trainId=tid) + mask_sa1 = mask.rename({'pulse_slot': 'sa1_pId'}) + mask_sa3 = mask.rename({'pulse_slot': 'sa3_pId'}) + if "XGM" in key: + compute_sa1 = True + compute_sa3 = True + mask_sa1 = is_sase_1(bpt.sel(trainId=valid_tid)) + mask_sa3 = is_sase_3(bpt.sel(trainId=valid_tid)) + mask = xr.ufuncs.logical_or(mask_sa1, mask_sa3) + tid = mask.where(mask.sum(dim='pulse_slot') > 0, + drop=True).trainId + mask_sa1 = mask_sa1.sel(trainId=tid).rename({'pulse_slot': 'sa1_pId'}) + mask_sa3 = mask_sa3.sel(trainId=tid).rename({'pulse_slot': 'sa3_pId'}) + mask = mask.sel(trainId=tid) + + npulses_max = mask.sum(dim='pulse_slot').max().values + xgm_arr = xgm_arr.sel(trainId=tid).isel( + XGMbunchId=slice(0, npulses_max)) + # In rare cases, some xgm data is corrupted: trainId is valid but values + # are inf / NaN. We set them to -1 to avoid size mismatch between xgm and + # bpt. Before returning we will drop them. + xgm_arr = xgm_arr.where(np.isfinite(xgm_arr)).fillna(-1.) + # pad the xgm array to match the bpt dims, flatten and + # reorder xgm array to match the indices of the mask + xgm_flat = np.hstack((xgm_arr.fillna(1.), + np.ones((xgm_arr.sizes['trainId'], + 2700-npulses_max)))).flatten() + xgm_flat_arg = np.argwhere(xgm_flat != 1.) + mask_flat = mask.values.flatten() + mask_flat_arg = np.argwhere(mask_flat) + if(xgm_flat_arg.shape != mask_flat_arg.shape): + log.warning(f'{key}: XGM data and bunch pattern do not match.') + new_xgm_flat = np.ones(xgm_flat.shape) + new_xgm_flat[mask_flat_arg] = xgm_flat[xgm_flat_arg] + new_xgm = new_xgm_flat.reshape((xgm_arr.sizes['trainId'], 2700)) + # create a dataset with new_xgm array masked by SASE 1 or SASE 3 + xgm_dict = {} + if compute_sa1: + sa1_xgm = xr.DataArray(new_xgm, dims=['trainId', 'sa1_pId'], + coords={'trainId': xgm_arr.trainId, + 'sa1_pId': np.arange(2700)}, + name=key.replace('XGM', 'SA1')) + sa1_xgm = sa1_xgm.where(mask_sa1, drop=True) + sa1_xgm = sa1_xgm.where(sa1_xgm != -1., drop=True) + # remove potential corrupted data: + xgm_dict[sa1_xgm.name] = sa1_xgm + if compute_sa3: + sa3_xgm = xr.DataArray(new_xgm, dims=['trainId', 'sa3_pId'], + coords={'trainId': xgm_arr.trainId, + 'sa3_pId': np.arange(2700)}, + name=key.replace('XGM', 'SA3')) + sa3_xgm = sa3_xgm.where(mask_sa3, drop=True) + # remove potential corrupted data: + sa3_xgm = sa3_xgm.where(sa3_xgm != -1., drop=True) + xgm_dict[sa3_xgm.name] = sa3_xgm + ds = xr.Dataset(xgm_dict) + return ds + + +def calibrate_xgm(run, data, xgm='SCS', plot=False): + """ + Calculates the calibration factor F between the photon flux (slow signal) + and the fast signal (pulse-resolved) of the sase 3 pulses. The calibrated + fast signal is equal to the uncalibrated one multiplied by F. -''' TIM calibration table - Dict with key= photon energy and value= array of polynomial coefficients for each MCP (1,2,3). - The polynomials correspond to a fit of the logarithm of the calibration factor as a function - of MCP voltage. If P is a polynomial and V the MCP voltage, the calibration factor (in microjoule - per APD signal) is given by -exp(P(V)). - This table was generated from the calibration of March 2019, proposal 900074, semester 201930, - runs 69 - 111 (Ni edge): https://in.xfel.eu/elog/SCS+Beamline/2323 - runs 113 - 153 (Co edge): https://in.xfel.eu/elog/SCS+Beamline/2334 - runs 163 - 208 (Fe edge): https://in.xfel.eu/elog/SCS+Beamline/2349 -''' -tim_calibration_table = { - 705.5: np.array([ - [-6.85344690e-12, 5.00931986e-08, -1.27206912e-04, 1.15596821e-01, -3.15215367e+01], - [ 1.25613942e-11, -5.41566381e-08, 8.28161004e-05, -7.27230153e-02, 3.10984925e+01], - [ 1.14094964e-12, 7.72658935e-09, -4.27504907e-05, 4.07253378e-02, -7.00773062e+00]]), - 779: np.array([ - [ 4.57610777e-12, -2.33282497e-08, 4.65978738e-05, -6.43305156e-02, 3.73958623e+01], - [ 2.96325102e-11, -1.61393276e-07, 3.32600044e-04, -3.28468195e-01, 1.28328844e+02], - [ 1.14521506e-11, -5.81980336e-08, 1.12518434e-04, -1.19072484e-01, 5.37601559e+01]]), - 851: np.array([ - [ 3.15774215e-11, -1.71452934e-07, 3.50316512e-04, -3.40098861e-01, 1.31064501e+02], - [5.36341958e-11, -2.92533156e-07, 6.00574534e-04, -5.71083140e-01, 2.10547161e+02], - [ 3.69445588e-11, -1.97731342e-07, 3.98203522e-04, -3.78338599e-01, 1.41894119e+02]]) -} + Parameters + ---------- + run: extra_data.DataCollection + DataCollection containing the digitizer data. + data: xarray Dataset + dataset containing the pulse-resolved sase 3 signal, e.g. 'SCS_SA3' + xgm: str + one in {'XTD10', 'SCS'} + plot: bool + If True, shows a plot of the photon flux, averaged fast signal and + calibrated fast signal. -def timFactorFromTable(voltage, photonEnergy, mcp=1): - ''' Returns an energy calibration factor for TIM integrated peak signal (APD) - according to calibration from March 2019, proposal 900074, semester 201930, - runs 69 - 111 (Ni edge): https://in.xfel.eu/elog/SCS+Beamline/2323 - runs 113 - 153 (Co edge): https://in.xfel.eu/elog/SCS+Beamline/2334 - runs 163 - 208 (Fe edge): https://in.xfel.eu/elog/SCS+Beamline/2349 - Uses the tim_calibration_table declared above. - - Inputs: - voltage: MCP voltage in volts. - photonEnergy: FEL photon energy in eV. Calibration factor is linearly - interpolated between the known values from the calibration table. - mcp: MCP channel (1, 2, or 3). - - Output: - f: calibration factor in microjoule per APD signal - ''' - energies = np.sort([key for key in tim_calibration_table]) - if photonEnergy not in energies: - if photonEnergy > energies.max(): - photonEnergy = energies.max() - elif photonEnergy < energies.min(): - photonEnergy = energies.min() - else: - idx = np.searchsorted(energies, photonEnergy) - 1 - polyA = np.poly1d(tim_calibration_table[energies[idx]][mcp-1]) - polyB = np.poly1d(tim_calibration_table[energies[idx+1]][mcp-1]) - fA = -np.exp(polyA(voltage)) - fB = -np.exp(polyB(voltage)) - f = fA + (fB-fA)/(energies[idx+1]-energies[idx])*(photonEnergy - energies[idx]) - return f - poly = np.poly1d(tim_calibration_table[photonEnergy][mcp-1]) - f = -np.exp(poly(voltage)) - return f + Returns + ------- + F: float + calibration factor F defined as: + calibrated XGM [microJ] = F * fast XGM array ('SCS_SA3' or 'XTD10_SA3') + Example + ------- + >>> import toolbox_scs as tb + >>> import toolbox_scs.detectors as tbdet + >>> run, data = tb.load(900074, 69, ['SCS_XGM']) + >>> ds = tbdet.get_xgm(run, merge_with=data) + >>> F = tbdet.calibrate_xgm(run, ds, plot=True) + >>> # Add calibrated XGM to the dataset: + >>> ds['SCS_SA3_uJ'] = F * ds['SCS_SA3'] + """ -def checkTimApdWindow(data, mcp=1, use_apd=True, intstart=None, intstop=None): - ''' Plot the first and last pulses in MCP trace together with - the window of integration to check if the pulse integration - is properly calculated. If the number of pulses changed during - the run, it selects a train where the number of pulses was - maximum. - - Inputs: - data: xarray Dataset - mcp: MCP channel (1, 2, 3 or 4) - use_apd: if True, gets the APD parameters from the digitizer - device. If False, uses intstart and intstop as boundaries - and uses the bunch pattern to determine the separation - between two pulses. - intstart: trace index of integration start of the first pulse - intstop: trace index of integration stop of the first pulse - - Output: - Plot - ''' - mcpToChannel={1:'D', 2:'C', 3:'B', 4:'A'} - apdChannels={1:3, 2:2, 3:1, 4:0} - npulses_max = data['npulses_sase3'].max().values - tid = data['npulses_sase3'].where(data['npulses_sase3'] == npulses_max, - drop=True).trainId.values - if 'MCP{}raw'.format(mcp) not in data: - print('no raw data for MCP{}. Loading average trace from MCP{}'.format(mcp, mcp)) - trace = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1:network', - 'digitizers.channel_1_{}.raw.samples'.format(mcpToChannel[mcp]) - ).sel({'trainId':tid}).mean(dim='trainId') + if 'bunchPatternTable' in data: + bpt = data['bunchPatternTable'] + log.debug('Using bpt from provided dataset.') + elif _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + elif _mnemonics['bunchPatternTable_SA3']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable_SA3'].values()) else: - trace = data['MCP{}raw'.format(mcp)].sel({'trainId':tid}).mean(dim='trainId') - if use_apd: - pulseStart = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', - 'board1.apd.channel_{}.pulseStart.value'.format(apdChannels[mcp]))[0].values - pulseStop = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', - 'board1.apd.channel_{}.pulseStop.value'.format(apdChannels[mcp]))[0].values - initialDelay = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', - 'board1.apd.channel_{}.initialDelay.value'.format(apdChannels[mcp]))[0].values - upperLimit = data.attrs['run'].get_array( - 'SCS_UTC1_ADQ/ADC/1', - 'board1.apd.channel_{}.upperLimit.value'.format(apdChannels[mcp]))[0].values + raise ValueError('Bunch pattern missing. Cannot calibrate XGM.') + mask_sa3 = is_sase_3(bpt.sel(trainId=data.trainId)) + npulses_sa3 = np.unique(mask_sa3.sum(dim='pulse_slot')) + if len(npulses_sa3) == 1: + npulses_sa3 = npulses_sa3[0] else: - pulseStart = intstart - pulseStop = intstop - if npulses_max > 1: - sa3 = data['sase3'].where(data['sase3']>1) - step = sa3.where(data['npulses_sase3']>1, drop=True)[0,:2].values - step = int(step[1] - step[0]) - nsamples = 440 * step + log.warning('change of pulse pattern in sase3 during the run.') + npulses_sa3 = max(npulses_sa3) + mask_sa1 = is_sase_1(bpt.sel(trainId=data.trainId)) + npulses_sa1 = np.unique(mask_sa1.sum(dim='pulse_slot')) + if len(npulses_sa1) == 1: + npulses_sa1 = npulses_sa1[0] else: - nsamples = 0 + log.warning('change of pulse pattern in sase1 during the run.') + npulses_sa1 = max(npulses_sa1) - fig, ax = plt.subplots(figsize=(5,3)) - ax.plot(trace[:pulseStop+25], color='C1', label='first pulse') - ax.axvspan(pulseStart, pulseStop, color='k', alpha=0.1, label='APD region') - ax.axvline(pulseStart, color='gray', ls='--') - ax.axvline(pulseStop, color='gray', ls='--') - ax.set_xlim(pulseStart-25, pulseStop+25) - ax.locator_params(axis='x', nbins=4) - ax.set_ylabel('MCP{} Voltage [V]'.format(mcp)) - ax.set_xlabel('First pulse sample #') - if npulses_max > 1: - pulseStart = pulseStart + nsamples*(npulses_max-1) - pulseStop = pulseStop + nsamples*(npulses_max-1) - ax2 = ax.twiny() - ax2.plot(range(pulseStart-25,pulseStop+25), trace[pulseStart-25:pulseStop+25], - color='C4', label='last pulse') - ax2.locator_params(axis='x', nbins=4) - ax2.set_xlabel('Last pulse sample #') - lines, labels = ax.get_legend_handles_labels() - lines2, labels2 = ax2.get_legend_handles_labels() - ax2.legend(lines + lines2, labels + labels2, loc=0) + pflux_key = f'{xgm}_photonFlux' + if pflux_key in data: + pflux = data[pflux_key] else: - ax.legend(loc='lower left') - plt.tight_layout() - -def matchXgmTimPulseId(data, use_apd=True, intstart=None, intstop=None, - bkgstart=None, bkgstop=None, t_offset=None, - npulses=None, sase3First=True, stride=1): - ''' Function to match XGM pulse Id with TIM pulse Id. - Inputs: - data: xarray Dataset containing XGM and TIM data - use_apd: bool. If True, uses the digitizer APD ('MCP[1,2,3,4]apd'). - If False, peak integration is performed from raw traces. - All following parameters are needed in this case. - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - t_offset: index separation between two pulses - npulses: number of pulses to compute. Required if no bunch - pattern info is available - sase3First: bool, needed if bunch pattern is missing. - stride: int, used to select pulses in the TIM APD array if - no bunch pattern info is available. - - Output: - xr DataSet containing XGM and TIM signals with the share d - dimension 'sa3_pId'. Raw traces, raw XGM and raw APD are dropped. - ''' - - dropList = [] - mergeList = [] - ndata = cleanXGMdata(data, npulses, sase3First) - for mcp in range(1,5): - if 'MCP{}apd'.format(mcp) in data or 'MCP{}raw'.format(mcp) in data: - MCPapd = getTIMapd(data, mcp=mcp, use_apd=use_apd, intstart=intstart, - intstop=intstop,bkgstart=bkgstart, bkgstop=bkgstop, - t_offset=t_offset, npulses=npulses, - stride=stride).rename('MCP{}apd'.format(mcp)) - if use_apd: - MCPapd = MCPapd.rename({'apdId':'sa3_pId'}) - else: - MCPapd = MCPapd.rename({'MCP{}fromRaw'.format(mcp):'sa3_pId'}) - mergeList.append(MCPapd) - if 'MCP{}raw'.format(mcp) in ndata: - dropList.append('MCP{}raw'.format(mcp)) - if 'MCP{}apd'.format(mcp) in data: - dropList.append('MCP{}apd'.format(mcp)) - mergeList.append(ndata.drop(dropList)) - subset = xr.merge(mergeList, join='inner') - for k in ndata.attrs.keys(): - subset.attrs[k] = ndata.attrs[k] - return subset - - -# Fast ADC -def fastAdcPeaks(data, channel, intstart, intstop, bkgstart, bkgstop, - period=None, npulses=None, source='scs_ppl', - usePeakValue=False, peakType='pos'): - ''' Computes peak integration from raw FastADC traces. - - Inputs: - data: xarray Dataset containing FastADC raw traces (e.g. 'FastADC1raw') - channel: FastADC channel number - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - period: number of samples between two pulses. Needed if bunch - pattern info is not available. If None, checks the pulse - pattern and determine the period assuming a resolution of - 9.23 ns per sample which leads to 24 samples between - two bunches @ 4.5 MHz. - npulses: number of pulses. If None, takes the maximum number of - pulses according to the bunch patter (field 'npulses_sase3') - source: str, nature of the pulses, 'sase[1,2 or 3]', or 'scs_ppl', - or any name. Used to give name to the peak Id dimension. - usePeakValue: bool, if True takes the peak value of the signal, - otherwise integrates over integration region. - peakType: str, 'pos' or 'neg'. Used if usePeakValue is True to - indicate if min or max value should be extracted. - - - Output: - results: DataArray with dims trainId x max(sase3 pulses) - - ''' - keyraw = 'FastADC{}raw'.format(channel) - if keyraw not in data: - raise ValueError("Source not found: {}!".format(keyraw)) - if npulses is None or period is None: - indices, npulses_bp, mask = tb.extractBunchPattern(runDir=data.attrs['run'], - key=source) - if npulses is None: - npulses = int(npulses_bp.max().values) - if period is None: - indices = indices_bp.where(indices_bp>1) - if npulses > 1: - #Calculate the number of pulses between two lasing pulses (step) - step = indices.where(npulses_bp>1, drop=True)[0,:2].values - step = int(step[1] - step[0]) - #multiply by elementary pulse length (221.5 ns / 9.23 ns = 24 samples) - period = 24 * step - else: - period = 1 - pulseId = source - if source=='scs_ppl': - pulseId = 'ol_pId' - if 'sase' in source: - pulseId = f'sa{source[4]}_pId' - results = xr.DataArray(np.empty((data.trainId.shape[0], npulses)), coords=data[keyraw].coords, - dims=['trainId', pulseId]) - for i in range(npulses): - a = intstart + period*i - b = intstop + period*i - bkga = bkgstart + period*i - bkgb = bkgstop + period*i - bg = np.outer(np.median(data[keyraw][:,bkga:bkgb], axis=1), np.ones(b-a)) - if usePeakValue: - if peakType=='pos': - val = np.max(data[keyraw][:,a:b] - bg, axis=1) - if peakType=='neg': - val = np.min(data[keyraw][:,a:b] - bg, axis=1) - else: - val = np.trapz(data[keyraw][:,a:b] - bg, axis=1) - results[:,i] = val - return results - -def autoFindFastAdcPeaks(data, channel=5, window='large', usePeakValue=False, - source='scs_ppl', display=False, plot=False): - ''' Automatically finds peaks in channel of Fast ADC trace, a minimum width of 4 - samples. The find_peaks function and determination of the peak integration - region and baseline subtraction is optimized for typical photodiode signals - of the SCS instrument (ILH, FFT reflectometer, FFT diag stage). - Inputs: - data: xarray Dataset containing Fast ADC traces - key: data key of the array of traces - window: 'small' or 'large': defines the width of the integration region - centered on the peak. - usePeakValue: bool, if True takes the peak value of the signal, - otherwise integrates over integration region. - display: bool, displays info on the pulses found - plot: bool, plots regions of integration of the first pulse in the trace - Output: - peaks: DataArray of the integrated peaks - ''' - - key = f'FastADC{channel}raw' - if key not in data: - raise ValueError(f'{key} not found in data set') - #average over the 100 first traces to get at least one train with signal - trace = data[key].isel(trainId=slice(0,100)).mean(dim='trainId').values - if plot: - trace_plot = np.copy(trace) - #subtract baseline and check if peaks are positive or negative - bl = np.median(trace) - trace_no_bl = trace - bl - if np.max(trace_no_bl) >= np.abs(np.min(trace_no_bl)): - posNeg = 'positive' - else: - posNeg = 'negative' - trace_no_bl *= -1 - trace = bl + trace_no_bl - threshold = bl + np.max(trace_no_bl) / 2 - #find peaks - centers, peaks = find_peaks(trace, height=threshold, width=(4, None)) - c = centers[0] - w = np.average(peaks['widths']).astype(int) - period = np.median(np.diff(centers)).astype(int) - npulses = centers.shape[0] - if window not in ['small', 'large']: - raise ValueError(f"'window argument should be either 'small' or 'large', not {window}") - if window=='small': - intstart = int(c - w/4) + 1 - intstop = int(c + w/4) + 1 - if window=='large': - intstart = int(peaks['left_ips'][0]) - intstop = int(peaks['right_ips'][0]) + w - bkgstop = int(peaks['left_ips'][0])-5 - bkgstart = bkgstop - 10 - if display: - print(f'Found {npulses} {posNeg} pulses, avg. width={w}, period={period} samples, ' + - f'rep. rate={1e6/(9.230769*period):.3f} kHz') - fAdcPeaks = fastAdcPeaks(data, channel=channel, intstart=intstart, intstop=intstop, - bkgstart=bkgstart, bkgstop=bkgstop, period=period, npulses=npulses, - source=source, usePeakValue=usePeakValue, peakType=posNeg[:3]) + pflux = run.get_array(*_mnemonics[pflux_key].values()) + pflux = pflux.sel(trainId=data.trainId) + pflux_sa3 = (npulses_sa1 + npulses_sa3) * pflux / npulses_sa3 + avg_fast = data[f'{xgm}_SA3'].rolling(trainId=200).mean().mean(axis=1) + calib = np.nanmean(pflux_sa3.values / avg_fast.values) if plot: - plt.figure() - plt.plot(trace_plot, 'o-', ms=3) - for i in range(npulses): - plt.axvline(intstart+i*period, ls='--', color='g') - plt.axvline(intstop+i*period, ls='--', color='r') - plt.axvline(bkgstart+i*period, ls='--', color='lightgrey') - plt.axvline(bkgstop+i*period, ls='--', color='grey') - plt.title(f'Fast ADC {channel} trace') - plt.xlim(bkgstart-10, intstop + 50) - return fAdcPeaks - -def mergeFastAdcPeaks(data, channel, intstart, intstop, bkgstart, bkgstop, - period=None, npulses=None, dim='lasPulseId'): - ''' Calculates the peaks from Fast ADC raw traces with fastAdcPeaks() - and merges the results in Dataset. - Inputs: - data: xr Dataset with 'FastADC[channel]raw' traces - channel: Fast ADC channel - intstart: trace index of integration start - intstop: trace index of integration stop - bkgstart: trace index of background start - bkgstop: trace index of background stop - period: Number of ADC samples between two pulses. Needed - if bunch pattern info is not available. If None, checks the - pulse pattern and determine the period assuming a resolution - of 9.23 ns per sample = 24 samples between two pulses @ 4.5 MHz. - npulses: number of pulses. If None, takes the maximum number of - pulses according to the bunch patter (field 'npulses_sase3') - dim: name of the xr dataset dimension along the peaks - - ''' - peaks = fastAdcPeaks(data, channel=channel, intstart=intstart, intstop=intstop, - bkgstart=bkgstart, bkgstop=bkgstop, period=period, - npulses=npulses) - - key = 'FastADC{}peaks'.format(channel) - if key in data: - s = data.drop(key) - else: - s = data - peaks = peaks.rename(key).rename({'peakId':dim}) - subset = xr.merge([s, peaks], join='inner') - for k in data.attrs.keys(): - subset.attrs[k] = data.attrs[k] - return subset - + plot_xgm_calibration(xgm, pflux, pflux_sa3, avg_fast, calib) + return calib + + +def plot_xgm_calibration(xgm, pflux, pflux_sa3, avg_fast, calib): + plt.figure(figsize=(8, 4)) + plt.plot(pflux, label='photon flux all') + plt.plot(pflux_sa3, label='photon flux SA3') + plt.plot(avg_fast, label='avg pulsed XGM') + plt.plot(avg_fast*calib, label='calibrated avg pulsed XGM') + plt.title(f'calibrated XGM = {xgm}_SA3 * {calib:.3e}') + plt.xlabel('train number') + plt.ylabel(r'Pulse energy [$\mu$J]') + plt.legend() + return diff --git a/src/toolbox_scs/load.py b/src/toolbox_scs/load.py index c973534..19021e7 100644 --- a/src/toolbox_scs/load.py +++ b/src/toolbox_scs/load.py @@ -12,24 +12,30 @@ import logging import numpy as np import xarray as xr - import extra_data as ed -from .misc.bunch_pattern import extractBunchPattern -from .constants import mnemonics as _mnemonics_ld +from .constants import mnemonics as _mnemonics from .util.exceptions import ToolBoxValueError, ToolBoxPathError from .util.data_access import find_run_dir +import toolbox_scs.detectors as tbdet log = logging.getLogger(__name__) -def load(fields, runNB, proposalNB, +def load(proposalNB=None, runNB=None, + fields=None, subFolder='raw', display=False, validate=False, subset=ed.by_index[:], rois={}, - useBPTable=True): + extract_tim=True, + extract_laser=True, + extract_xgm=True, + extract_bam=True, + tim_bp='sase3', + laser_bp='scs_ppl', + ): """ Load a run and extract the data. Output is an xarray with aligned trainIds @@ -37,16 +43,16 @@ def load(fields, runNB, proposalNB, Parameters ---------- - fields: list of strings, list of dictionaries - list of mnemonic strings to load specific data such as "fastccd", - "SCS_XGM", or dictionnaries defining a custom mnemonic such as - {"extra": - {'SCS_CDIFFT_MAG/SUPPLY/CURRENT', - 'actual_current.value', None}} + proposalNB: (str, int) + proposal number e.g. 'p002252' or 2252 runNB: (str, int) run number as integer - proposalNB: (str, int) - of the proposal number e.g. 'p002252' or 2252 + fields: str, list of str, list of dict + list of mnemonics to load specific data such as "fastccd", + "SCS_XGM", or dictionnaries defining a custom mnemonic such as + {"extra": {'source: 'SCS_CDIFFT_MAG/SUPPLY/CURRENT', + 'key': 'actual_current.value', + 'dim': None}} subFolder: (str) sub-folder from which to load the data. Use 'raw' for raw data or 'proc' for processed data. @@ -60,31 +66,49 @@ def load(fields, runNB, proposalNB, rois: dictionary a dictionnary of mnemonics with a list of rois definition and the desired names, for example: - {'fastccd': - {'ref': - {'roi': by_index[730:890, 535:720], - 'dim': ['ref_x', 'ref_y']}, - 'sam': - {'roi':by_index[1050:1210, 535:720], - 'dim': ['sam_x', 'sam_y']}}} - useBPTable: boolean - If True, uses the raw bunch pattern table to extract sase pulse number - and indices in the trains. If false, load the data from BUNCH_DECODER - middle layer device. + {'fastccd': {'ref': {'roi': by_index[730:890, 535:720], + 'dim': ['ref_x', 'ref_y']}, + 'sam': {'roi':by_index[1050:1210, 535:720], + 'dim': ['sam_x', 'sam_y']}}} + extract_tim: bool + If True, extracts the peaks from TIM variables (e.g. 'MCP2raw', + 'MCP3apd') and aligns the pulse Id with the sase3 bunch pattern. + extract_laser: bool + If True, extracts the peaks from FastADC variables (e.g. 'FastADC5raw', + 'FastADC3peaks') and aligns the pulse Id with the PP laser bunch pattern. + extract_xgm: bool + If True, extracts the values from XGM variables (e.g. 'SCS_SA3', + 'XTD10_XGM') and aligns the pulse Id with the sase1 / sase3 bunch pattern. + extract_bam: bool + If True, extracts the values from BAM variables (e.g. 'BAM1932M') + and aligns the pulse Id with the sase3 bunch pattern. + tim_bp: str + bunch pattern used to extract the TIM pulses. Ignored if extract_tim=False. + laser_bp: str + bunch pattern used to extract the TIM pulses. Ignored if extract_tim=False. Returns ------- - res: xarray.DataArray - an xarray DataSet with aligned trainIds + run, data: DataCollection, xarray.DataArray + extra_data DataCollection of the proposal and run number and an + xarray Dataset with aligned trainIds and pulseIds + + Example + ------- + >>> import toolbox_scs as tb + >>> run, data = tb.load(2212, 208, ['SCS_SA3', 'MCP2apd', 'nrj']) + """ try: runFolder = find_run_dir(proposalNB, runNB) except ToolBoxPathError as err: log.error(f"{err.message}") raise - run = ed.RunDirectory(runFolder).select_trains(subset) - + if fields is None: + return run, xr.Dataset() + if isinstance(fields, str): + fields = [fields] if validate: # get_ipython().system('extra-data-validate ' + runFolder) pass @@ -96,25 +120,20 @@ def load(fields, runNB, proposalNB, vals = [] # load pulse pattern info - if useBPTable: - bp_mnemo = _mnemonics_ld['bunchPatternTable'] - if bp_mnemo['source'] not in run.all_sources: - print('Source {} not found in run. Skipping!'.format( - _mnemonics_ld['bunchPatternTable']['source'])) - else: - bp_table = run.get_array(bp_mnemo['source'], bp_mnemo['key'], - extra_dims=bp_mnemo['dim']) - sase1, npulses_sase1, dummy = extractBunchPattern( - bp_table, 'sase1') - sase3, npulses_sase3, dummy = extractBunchPattern( - bp_table, 'sase3') - keys += ["sase1", "npulses_sase1", "sase3", "npulses_sase3"] - vals += [sase1, npulses_sase1, sase3, npulses_sase3] + if _mnemonics['bunchPatternTable']['source'] in run.all_sources: + bpt = run.get_array(*_mnemonics['bunchPatternTable'].values()) + keys.append("bunchPatternTable") + vals.append(bpt) + elif _mnemonics['bunchPatternTable_SA3']['source'] in run.all_sources: + log.info('Did not find SCS bunch pattern table but found the SA3 one.') + bpt = run.get_array(*_mnemonics['bunchPatternTable_SA3'].values()) + keys.append("bunchPatternTable") + vals.append(bpt) else: - fields += ["sase1", "sase3", "npulses_sase3", "npulses_sase1"] - + log.warning('Source {} and {} not found in run. Skipping!'.format( + _mnemonics['bunchPatternTable']['source'], + _mnemonics['bunchPatternTable_SA3']['source'],)) for f in fields: - if type(f) == dict: # extracting mnemomic defined on the spot if len(f.keys()) > 1: @@ -124,73 +143,73 @@ def load(fields, runNB, proposalNB, v = f[k] else: # extracting mnemomic from the table - if f in _mnemonics_ld: - v = _mnemonics_ld[f] + if f in _mnemonics: + v = _mnemonics[f] k = f else: - print('Unknow mnemonic "{}". Skipping!'.format(f)) + print(f'Unknow mnemonic "{f}". Skipping!') continue - if k in keys: continue # already loaded, skip - if display: - print('Loading {}'.format(k)) - + print(f'Loading {k}') if v['source'] not in run.all_sources: - print('Source {} not found in run. Skipping!'.format(v['source'])) + log.warning(f'Source {v["source"]} not found in run. Skipping!') + print(f'Source {v["source"]} not found in run. Skipping!') continue - if k not in rois: # no ROIs selection, we read everything - vals.append(run.get_array(v['source'], v['key'], - extra_dims=v['dim'])) + arr = run.get_array(*v.values()) + if len(arr) == 0: + log.warning(f'Empty array for {f}: {v["source"]}, {v["key"]}. ' + 'Skipping!') + print(f'Empty array for {f}: {v["source"]}, {v["key"]}. ' + 'Skipping!') + continue + vals.append(arr) keys.append(k) else: # ROIs selection, for each ROI we select a region of the data and # save it with new name and dimensions for nk, nv in rois[k].items(): - vals.append(run.get_array(v['source'], v['key'], - extra_dims=nv['dim'], - roi=nv['roi'])) + arr = run.get_array(v['source'], v['key'], + extra_dims=nv['dim'], + roi=nv['roi']) + if len(arr) == 0: + log.warning(f'Empty array for {f}: {v["source"]}, {v["key"]}. ' + 'Skipping!') + print(f'Empty array for {f}: {v["source"]}, {v["key"]}. ' + 'Skipping!') + continue + vals.append(arr) keys.append(nk) - aligned_vals = xr.align(*vals, join='inner') - result = dict(zip(keys, aligned_vals)) - result = xr.Dataset(result) - result.attrs['run'] = run - result.attrs['runFolder'] = runFolder - return result + data = dict(zip(keys, aligned_vals)) + data = xr.Dataset(data) + data.attrs['runFolder'] = runFolder + tim = [k for k in _mnemonics if 'MCP' in k and k in data] + if extract_tim and len(tim) > 0: + data = tbdet.get_tim_peaks(run, mnemonics=tim, merge_with=data, + bunchPattern=tim_bp) -def load_run(proposal, run, **kwargs): - """ - Get run in given proposal + laser = [k for k in _mnemonics if 'FastADC' in k and k in data] + if extract_laser and len(laser) > 0: + data = tbdet.get_laser_peaks(run, mnemonics=laser, merge_with=data, + bunchPattern=laser_bp) - Wraps the extra_data open_run routine, out of convenience for the toolbox - user. More information can be found in the karabo_data documentation. + xgm = ['XTD10_XGM', 'XTD10_XGM_sigma', 'XTD10_SA3', 'XTD10_SA3_sigma', + 'XTD10_SA1', 'XTD10_SA1_sigma', 'SCS_XGM', 'SCS_XGM_sigma', + 'SCS_SA1', 'SCS_SA1_sigma', 'SCS_SA3', 'SCS_SA3_sigma'] + xgm = [k for k in xgm if k in data] + if extract_xgm and len(xgm) > 0: + data = tbdet.get_xgm(run, mnemonics=xgm, merge_with=data) - Parameters - ---------- - proposal: str, int - Proposal number - run: str, int - Run number - - **kwargs - -------- - data: str - default -> 'raw' - include: str - default -> '*' + bam = [k for k in _mnemonics if 'BAM' in k and k in data] + if extract_bam and len(bam) > 0: + data = tbdet.get_bam(run, mnemonics=bam, merge_with=data) - Returns - ------- - run : extra_data.DataCollection - DataCollection object containing information about the specified - run. Data can be loaded using built-in class methods. - """ - return ed.open_run(proposal, run, **kwargs) + return run, data def run_by_path(path): @@ -280,8 +299,8 @@ def get_array(run, mnemonic_key=None, stepsize=None): data = xr.DataArray( np.ones(len(run.train_ids), dtype=np.int16), dims=['trainId'], coords={'trainId': run.train_ids}) - elif mnemonic_key in _mnemonics_ld: - mnem = _mnemonics_ld[mnemonic_key] + elif mnemonic_key in _mnemonics: + mnem = _mnemonics[mnemonic_key] data = run.get_array(*mnem.values()) else: raise ToolBoxValueError("Invalid mnemonic", mnemonic_key) @@ -295,3 +314,79 @@ def get_array(run, mnemonic_key=None, stepsize=None): raise return data + + +def mnemonics_to_process(mnemo_list, merge_with, detector, func=None): + """ + Finds the list of mnemonics, within mnemo_list and merge_with, that + correspond to arrays that are not yet loaded and/or processed by a + detector function. Removes the mnemonics of the already processed + arrays from the list. + + Parameters + ---------- + mnemo_list: str or list of str + ToolBox mnemonics of pulse-resolved detector arrays + merge_with: xarray Dataset + Dataset that may contain non-processed arrays + detector: str + One in {'ADQ412', 'FastADC', 'XGM', 'BAM'} + func: function + function that takes one argument, an unprocessed mnemonic string, + and converts it into a processed one, i.e. from 'MCP2apd' to + 'MCP2peaks'. If None, the function returns the input mnemonic. + + Returns + ------- + mnemonics: list of str + the mnemonics to process + """ + if func is None: + def func(x): + return x + + if detector == 'BAM': + det_mnemos = [m for m in _mnemonics if 'BAM' in m] + default_mnemo = 'BAM1932M' + default_processed = 'BAM1932M' + if detector == 'XGM': + det_mnemos = ['XTD10_XGM', 'XTD10_XGM_sigma', 'XTD10_SA3', + 'XTD10_SA3_sigma', 'XTD10_SA1', 'XTD10_SA1_sigma', + 'SCS_XGM', 'SCS_XGM_sigma', 'SCS_SA1', 'SCS_SA1_sigma', + 'SCS_SA3', 'SCS_SA3_sigma'] + default_mnemo = 'SCS_SA3' + default_processed = 'SCS_SA3' + if detector == 'ADQ412': + det_mnemos = [m for m in _mnemonics if 'MCP' in m] + default_mnemo = 'MCP2apd' + default_processed = 'MCP2peaks' + if detector == 'FastADC': + det_mnemos = [m for m in _mnemonics if 'FastADC' in m] + default_mnemo = 'FastADC5raw' + default_processed = 'FastADC5peaks' + + dig_dims = list(set([_mnemonics[m]['dim'][0] for m in det_mnemos])) + processed_mnemos = list(set([func(m) for m in det_mnemos])) + + # create a list of mnemonics to process from the provided mnemonics and + # merge_with Dataset + mw_mnemos = [] + mw_processed = [] + if bool(merge_with): + mw_mnemos = [m for m in merge_with if m in det_mnemos and + any(dim in merge_with[m].dims for dim in dig_dims)] + mw_processed = [m for m in merge_with if m in processed_mnemos and + any(dim in merge_with[m].dims for dim in dig_dims) + is False] + if mnemo_list is None: + mnemonics = [] + if len(mw_mnemos) == 0 and default_processed not in mw_processed: + mnemonics = [default_mnemo] + else: + mnemonics = [mnemo_list] if isinstance(mnemo_list, str) else mnemo_list + mnemonics = list(set(mnemonics + mw_mnemos)) + for m in mnemonics[:]: + if func(m) in mw_processed: + mnemonics.remove(m) + + return mnemonics diff --git a/src/toolbox_scs/misc/__init__.py b/src/toolbox_scs/misc/__init__.py index 9afb2d9..0f4edde 100644 --- a/src/toolbox_scs/misc/__init__.py +++ b/src/toolbox_scs/misc/__init__.py @@ -1,7 +1,7 @@ -from .bunch_pattern import (extractBunchPattern, pulsePatternInfo, - repRate, sortBAMdata, - ) -from .bunch_pattern_external import is_sase_3, is_sase_1, is_ppl +from .bunch_pattern import (extractBunchPattern, pulsePatternInfo, + repRate) +from .bunch_pattern_external import (is_sase_3, is_sase_1, + is_ppl, is_pulse_at) from .laser_utils import positionToDelay, degToRelPower @@ -14,6 +14,7 @@ __all__ = ( "is_sase_3", "is_sase_1", "is_ppl", + "is_pulse_at", "get_index_ppl", "get_index_sase1", "get_index_sase3", diff --git a/src/toolbox_scs/misc/bunch_pattern.py b/src/toolbox_scs/misc/bunch_pattern.py index 2edf854..3f5939b 100644 --- a/src/toolbox_scs/misc/bunch_pattern.py +++ b/src/toolbox_scs/misc/bunch_pattern.py @@ -212,51 +212,3 @@ def repRate(data=None, runNB=None, proposalNB=None, key='sase3'): return 0 f = 1/((a[0,1] - a[0,0])*12e-3/54.1666667) return f - -def sortBAMdata(data, key='scs_ppl', sa3Offset=0): - ''' Extracts beam arrival monitor data from the raw arrays 'BAM6', 'BAM7', etc... - according to the bunchPatternTable. The BAM arrays contain 7220 values, which - corresponds to FLASH busrt length of 800 us @ 9 MHz. The bunchPatternTable - only has 2700 values, corresponding to XFEL 600 us burst length @ 4.5 MHz. - Hence, the BAM arrays are truncated to 5400 with a stride of 2 and matched - to the bunchPatternTable. If key is one of the sase, the given dimension name - of the bam arrays is 'sa[sase number]_pId', to match other data (XGM, TIM...). - If key is 'scs_ppl', the dimension is named 'ol_pId' - Inputs: - data: xarray Dataset containing BAM arrays - key: str, ['sase1', 'sase2', 'sase3', 'scs_ppl'] - sa3Offset: int, used if key=='scs_ppl'. Offset in number of pulse_id - between the first OL and FEL pulses. An offset of 40 means that - the first laser pulse comes 40 pulse_id later than the FEL on a - grid of 4.5 MHz. Negative values shift the laser pulse before - the FEL one. - Output: - ndata: xarray Dataset with same keys as input data (but new bam arrays) - ''' - a, b, mask = extractBunchPattern(key=key, runDir=data.attrs['run']) - if key == 'scs_ppl': - a3, b3, mask3 = extractBunchPattern(key='sase3', runDir=data.attrs['run']) - firstSa3_pId = a3.where(b3>0, drop=True)[0,0].values.astype(int) - mask = mask.roll(pulse_slot=firstSa3_pId+sa3Offset) - mask = mask.rename({'pulse_slot':'BAMbunchId'}) - ndata = data - dropList = [] - mergeList = [] - for k in data: - if 'BAM' in k: - dropList.append(k) - bam = data[k].isel(BAMbunchId=slice(0,5400,2)) - bam = bam.where(mask, drop=True) - if 'sase' in key: - name = f'sa{key[4]}_pId' - elif key=='scs_ppl': - name = 'ol_pId' - else: - name = 'bam_pId' - bam = bam.rename({'BAMbunchId':name}) - mergeList.append(bam) - mergeList.append(data.drop(dropList)) - ndata = xr.merge(mergeList, join='inner') - for k in data.attrs.keys(): - ndata.attrs[k] = data.attrs[k] - return ndata diff --git a/src/toolbox_scs/misc/bunch_pattern_external.py b/src/toolbox_scs/misc/bunch_pattern_external.py index 0a5ca3b..993b584 100644 --- a/src/toolbox_scs/misc/bunch_pattern_external.py +++ b/src/toolbox_scs/misc/bunch_pattern_external.py @@ -19,7 +19,7 @@ def _convert_data(bpt_dec): bpt_conv = bpt_dec if type(bpt_dec).__module__ == 'xarray.core.dataarray': - bpt_conv = bpt_dec.where(bpt_dec.values == True, other = 0) + bpt_conv = bpt_dec.where(bpt_dec.values == True, other=0) elif type(bpt_dec).__module__ == 'numpy': bpt_conv = bpt_dec.astype(int) else: @@ -30,13 +30,42 @@ def _convert_data(bpt_dec): return bpt_conv +def is_pulse_at(bpt, loc): + """ + Check for prescence of a pulse at the location provided. + + Parameters + ---------- + bpt : numpy array, xarray DataArray + The bunch pattern data. + loc : str + The location where to check: {'sase1', 'sase3', 'scs_ppl'} + + Returns + ------- + boolean : numpy array, xarray DataArray + true if a pulse is present at *loc*. + """ + if loc == 'sase3': + bpt_dec = ebp.is_sase(bpt, 3) + elif loc == 'sase1': + bpt_dec = ebp.is_sase(bpt, 1) + elif loc == 'scs_ppl': + bpt_dec = ebp.is_laser(bpt, laser=PPL_SCS) + else: + raise ValueError(f'loc argument is {loc}, expected "sase1", ' + + '"sase3" or "scs_ppl"') + + return _convert_data(bpt_dec) + + def is_sase_3(bpt): """ Check for prescence of a SASE3 pulse. Parameters ---------- - data : numpy array, xarray DataArray + bpt : numpy array, xarray DataArray The bunch pattern data. Returns @@ -54,7 +83,7 @@ def is_sase_1(bpt): Parameters ---------- - data : numpy array, xarray DataArray + bpt : numpy array, xarray DataArray The bunch pattern data. Returns diff --git a/src/toolbox_scs/routines/XAS.py b/src/toolbox_scs/routines/XAS.py index 0880a0c..1c9ca17 100644 --- a/src/toolbox_scs/routines/XAS.py +++ b/src/toolbox_scs/routines/XAS.py @@ -14,6 +14,7 @@ import matplotlib.gridspec as gridspec import matplotlib.pyplot as plt import re + def absorption(T, Io, fluorescence=False): """ Compute the absorption A = -ln(T/Io) (or A = T/Io for fluorescence) @@ -49,11 +50,11 @@ def absorption(T, Io, fluorescence=False): Io = Io[good] # return type of the structured array fdtype = [('muA', 'f8'), ('sigmaA', 'f8'), ('weights', 'f8'), - ('muT', 'f8'), ('sigmaT', 'f8'), ('muIo', 'f8'), ('sigmaIo', 'f8'), - ('p', 'f8'), ('counts', 'i8')] + ('muT', 'f8'), ('sigmaT', 'f8'), ('muIo', 'f8'), + ('sigmaIo', 'f8'), ('p', 'f8'), ('counts', 'i8')] if counts == 0: return np.array([(np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, - np.NaN, np.NaN, 0)], dtype=fdtype) + np.NaN, np.NaN, 0)], dtype=fdtype) muT = np.mean(T) sigmaT = np.std(T) @@ -62,29 +63,30 @@ def absorption(T, Io, fluorescence=False): sigmaIo = np.std(Io) weights = np.sum(Io) - p = np.corrcoef(T, Io)[0,1] - + p = np.corrcoef(T, Io)[0, 1] + # weighted average of T/Io with Io as weights - muA = muT/muIo - - #Derivation of standard deviation - #1. using biased weighted sample variance: - #sigmaA = np.sqrt(np.average((T/Io - muA)**2, weights=Io)) + muA = muT / muIo + + # Derivation of standard deviation + # 1. using biased weighted sample variance: + # sigmaA = np.sqrt(np.average((T/Io - muA)**2, weights=Io)) - #2. using unbiased weighted sample variance (reliablility weights): + # 2. using unbiased weighted sample variance (reliablility weights): V2 = np.sum(Io**2) sigmaA = np.sqrt(np.sum(Io*(T/Io - muA)**2) / (weights - V2/weights)) - #3. using error propagation for correlated data: - #sigmaA = np.abs(muA)*(np.sqrt((sigmaT/muT)**2 + - # (sigmaIo/muIo)**2 - 2*p*sigmaIo*sigmaT/(muIo*muT))) - + # 3. using error propagation for correlated data: + # sigmaA = np.abs(muA)*(np.sqrt((sigmaT/muT)**2 + + # (sigmaIo/muIo)**2 - 2*p*sigmaIo*sigmaT/(muIo*muT))) + if not fluorescence: - sigmaA = sigmaA/np.abs(muA) + sigmaA = sigmaA / np.abs(muA) muA = -np.log(muA) - + return np.array([(muA, sigmaA, weights, muT, sigmaT, muIo, sigmaIo, - p, counts)], dtype=fdtype) + p, counts)], dtype=fdtype) + def binning(x, data, func, bins=100, bin_length=None): """ General purpose 1-dimension data binning @@ -111,16 +113,17 @@ def binning(x, data, func, bins=100, bin_length=None): bins = np.linspace(bin_start, bin_end, bins) bin_centers = (bins[1:]+bins[:-1])/2 nb_bins = len(bin_centers) - + bin_idx = np.digitize(x, bins) dummy = func([]) res = np.empty((nb_bins), dtype=dummy.dtype) for k in range(nb_bins): - res[k] = func(data[k+1==bin_idx]) + res[k] = func(data[k+1 == bin_idx]) return bins, res -def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3apd', nrjkey='nrj', + +def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3peaks', nrjkey='nrj', Iooffset=0, plot=False, fluorescence=False): """ Compute the XAS spectra from a xarray nrun. @@ -145,21 +148,21 @@ def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3apd', nrjkey='nrj', muIo: the mean of the Io counts: the number of events in each bin """ - - stacked = nrun.stack(dummy_=['trainId','sa3_pId']) + + stacked = nrun.stack(dummy_=['trainId', 'sa3_pId']) Io = stacked[Iokey].values + Iooffset It = stacked[Itkey].values nrj = stacked[nrjkey].values - + names_list = ['nrj', 'Io', 'It'] rundata = np.vstack((nrj, Io, It)) rundata = np.rec.fromarrays(rundata, names=names_list) - + def whichIo(data): """ Select which fields to use as I0 and which to use as I1 """ - + if 'mcp' in Iokey.lower(): Io_sign = -1 else: @@ -170,11 +173,11 @@ def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3apd', nrjkey='nrj', else: It_sign = 1 - if len(data) == 0: return absorption([], [], fluorescence) else: - return absorption(It_sign*data['It'], Io_sign*data['Io'], fluorescence) + return absorption(It_sign*data['It'], Io_sign*data['Io'], + fluorescence) if bins is None: num_bins = 80 @@ -186,16 +189,15 @@ def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3apd', nrjkey='nrj', elif type(bins) == float: energy_limits = [np.min(nrj), np.max(nrj)] bins = np.arange(energy_limits[0], energy_limits[1], bins) - + dummy, nosample = binning(rundata['nrj'], rundata, whichIo, bins) muA = nosample['muA'] - sterrA = nosample['sigmaA']/np.sqrt(nosample['counts']) - + sterrA = nosample['sigmaA'] / np.sqrt(nosample['counts']) + bins_c = 0.5*(bins[1:] + bins[:-1]) - bin_idx = np.digitize(rundata['nrj'], bins) if plot: - f = plt.figure(figsize=(6.5,6)) - gs = gridspec.GridSpec(2,1,height_ratios=[4,1]) + f = plt.figure(figsize=(6.5, 6)) + gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1]) ax1 = plt.subplot(gs[0]) ax1.plot(bins_c, muA, color='C1', label=r'$\sigma$') if fluorescence: @@ -205,25 +207,28 @@ def xas(nrun, bins=None, Iokey='SCS_SA3', Itkey='MCP3apd', nrjkey='nrj', ax1.set_xlabel('Energy (eV)') ax1.legend() ax1_twin = ax1.twinx() - ax1_twin.bar(bins_c, nosample['muIo'], width=0.80*(bins_c[1]-bins_c[0]), - color='C1', alpha=0.2) + ax1_twin.bar(bins_c, nosample['muIo'], + width=0.80*(bins_c[1]-bins_c[0]), color='C1', alpha=0.2) ax1_twin.set_ylabel('Io') try: - proposalNB=int(re.findall(r'p(\d{6})', nrun.attrs['runFolder'])[0]) - runNB=int(re.findall(r'r(\d{4})', nrun.attrs['runFolder'])[0]) + proposalNB = int(re.findall(r'p(\d{6})', + nrun.attrs['runFolder'])[0]) + runNB = int(re.findall(r'r(\d{4})', nrun.attrs['runFolder'])[0]) ax1.set_title(f'run {runNB} p{proposalNB}') except: f.suptitle(nrun.attrs['plot_title']) - + ax2 = plt.subplot(gs[1]) ax2.bar(bins_c, nosample['counts'], width=0.80*(bins_c[1]-bins_c[0]), color='C0', alpha=0.2) ax2.set_xlabel('Energy (eV)') ax2.set_ylabel('counts') plt.tight_layout() - - return {'nrj':bins_c, 'muA':muA, 'sterrA':sterrA, 'sigmaA':nosample['sigmaA'], - 'muIo':nosample['muIo'], 'counts':nosample['counts']} + + return {'nrj': bins_c, 'muA': muA, 'sterrA': sterrA, + 'sigmaA': nosample['sigmaA'], 'muIo': nosample['muIo'], + 'counts': nosample['counts']} + def xasxmcd(dataP, dataN): """ Compute XAS and XMCD from data with both magnetic field direction @@ -237,7 +242,8 @@ def xasxmcd(dataP, dataN): """ assert len(dataP) == len(dataN), "binned datasets must be of same lengths" - assert not np.any(dataP['nrj'] - dataN['nrj']), "Energy points for dataP and dataN should be the same" + assert not np.any(dataP['nrj'] - dataN['nrj']), "Energy points for " \ + "dataP and dataN should be the same" muXAS = dataP['muA'] + dataN['muA'] muXMCD = dataP['muA'] - dataN['muA'] @@ -245,8 +251,9 @@ def xasxmcd(dataP, dataN): # standard error is the same for XAS and XMCD sigma = np.sqrt(dataP['sterrA']**2 + dataN['sterrA']**2) - res = np.empty(len(muXAS), dtype=[('nrj', 'f8'), ('muXAS', 'f8'), ('sigmaXAS', 'f8'), - ('muXMCD', 'f8'), ('sigmaXMCD', 'f8')]) + res = np.empty(len(muXAS), dtype=[('nrj', 'f8'), ('muXAS', 'f8'), + ('sigmaXAS', 'f8'), ('muXMCD', 'f8'), + ('sigmaXMCD', 'f8')]) res['nrj'] = dataP['nrj'] res['muXAS'] = muXAS res['muXMCD'] = muXMCD diff --git a/src/toolbox_scs/routines/__init__.py b/src/toolbox_scs/routines/__init__.py index e69de29..de3ef38 100644 --- a/src/toolbox_scs/routines/__init__.py +++ b/src/toolbox_scs/routines/__init__.py @@ -0,0 +1,29 @@ +from .XAS import ( + xas, xasxmcd) +from .knife_edge import knife_edge + +__all__ = ( + # Functions + "xas", + "xasxmcd", + "knife_edge" +) + +# ----------------------------------------------------------------------------- +# Clean namespace +# -> certain filenames we dont need in the namespace. Especially not those +# that are marked as private by using an underscore (_<filename>.py). +# ----------------------------------------------------------------------------- + +clean_ns = [ + # filenames + 'XAS', + ] + + +for name in dir(): + if name in clean_ns: + del globals()[name] + +del globals()['clean_ns'] +del globals()['name'] diff --git a/src/toolbox_scs/routines/knife_edge.py b/src/toolbox_scs/routines/knife_edge.py index 58e0b2b..191213d 100644 --- a/src/toolbox_scs/routines/knife_edge.py +++ b/src/toolbox_scs/routines/knife_edge.py @@ -1,8 +1,9 @@ """ Toolbox for SCS. - Various utilities function to quickly process data measured at the SCS instruments. + Various utilities function to quickly process data measured + at the SCS instruments. - Copyright (2019) SCS Team. + Copyright (2019-) SCS Team. """ import matplotlib.pyplot as plt import numpy as np @@ -10,47 +11,60 @@ from scipy.special import erfc from scipy.optimize import curve_fit import bisect -def knife_edge(nrun, axisKey='scannerX', signalKey='FastADC4peaks', - axisRange=[None,None], p0=None, full=False, plot=False): - ''' Calculates the beam radius at 1/e^2 from a knife-edge scan by fitting with - erfc function: f(a,b,u) = a*erfc(u)+b or f(a,b,u) = a*erfc(-u)+b where - u = sqrt(2)*(x-x0)/w0 with w0 the beam radius at 1/e^2 and x0 the beam center. - Inputs: - nrun: xarray Dataset containing the detector signal and the motor - position. - axisKey: string, key of the axis against which the knife-edge is - performed. - signalKey: string, key of the detector signal. - axisRange: list of length 2, minimum and maximum values between which to apply - the fit. - p0: list, initial parameters used for the fit: x0, w0, a, b. If None, a beam - radius of 100 um is assumed. - full: bool: If False, returns the beam radius and standard error. If True, - returns the popt, pcov list of parameters and covariance matrix from - curve_fit as well as the fitting function. - plot: bool: If True, plots the data and the result of the fit. - Outputs: - If full is False, ndarray with beam radius at 1/e^2 in mm and standard - error from the fit in mm. If full is True, returns popt and pcov from - curve_fit function. - ''' - def integPowerUp(x, x0, w0, a, b): + +def knife_edge(ds, axisKey='scannerX', + signalKey='FastADC4peaks', + axisRange=[None, None], p0=None, + full=False, plot=False): + """ + Calculates the beam radius at 1/e^2 from a knife-edge scan by + fitting with erfc function: f(a,b,u) = a*erfc(u) + b or + f(a,b,u) = a*erfc(-u) + b where u = sqrt(2)*(x-x0)/w0 with w0 + the beam radius at 1/e^2 and x0 the beam center. + + Parameters + ---------- + ds: xarray Dataset + dataset containing the detector signal and the motor position. + axisKey: str + key of the axis against which the knife-edge is performed. + signalKey: str + key of the detector signal. + axisRange: list of floats + edges of the scanning axis between which to apply the fit. + p0: list of floats, numpy 1D array + initial parameters used for the fit: x0, w0, a, b. If None, a beam + radius of 100 um is assumed. + full: bool + If False, returns the beam radius and standard error. + If True, returns the popt, pcov list of parameters and covariance + matrix from scipy.optimize.curve_fit as well as the fitting function. + plot: bool + If True, plots the data and the result of the fit. + + Returns + ------- + If full is False, ndarray with beam radius at 1/e^2 in mm and standard + error from the fit in mm. If full is True, returns parameters and + covariance matrix from scipy.optimize.curve_fit function. + """ + def stepUp(x, x0, w0, a, b): return a*erfc(-np.sqrt(2)*(x-x0)/w0) + b - def integPowerDown(x, x0, w0, a, b): + def stepDown(x, x0, w0, a, b): return a*erfc(np.sqrt(2)*(x-x0)/w0) + b - #get the number of pulses per train from the signal source: - dim = nrun[signalKey].dims[1] - #duplicate motor position values to match signal shape - #this is much faster than using nrun.stack() - positions = np.repeat(nrun[axisKey].values, - len(nrun[dim])).astype(nrun[signalKey].dtype) - #sort the data to decide which fitting function to use + # get the number of pulses per train from the signal source: + dim = [k for k in ds[signalKey].dims if k != 'trainId'][0] + # duplicate motor position values to match signal shape + # this is faster than using ds.stack() + positions = np.repeat(ds[axisKey].values, + len(ds[dim])).astype(ds[signalKey].dtype) + # sort the data to decide which fitting function to use sortIdx = np.argsort(positions) positions = positions[sortIdx] - intensities = nrun[signalKey].values.flatten()[sortIdx] - + intensities = ds[signalKey].values.flatten()[sortIdx] + if axisRange[0] is None or axisRange[0] < positions[0]: idxMin = 0 else: @@ -65,45 +79,50 @@ def knife_edge(nrun, axisKey='scannerX', signalKey='FastADC4peaks', idxMax = bisect.bisect(positions, axisRange[1]) + 1 pos_sel = positions[idxMin:idxMax] int_sel = intensities[idxMin:idxMax] - - # estimate a linear slope fitting the data to determine which function to fit - slope = np.cov(pos_sel, int_sel)[0][1]/np.var(pos_sel) + no_nan = ~np.isnan(int_sel) + pos_sel = pos_sel[no_nan] + int_sel = int_sel[no_nan] + + # estimate a linear slope fitting the data to determine which function + # to fit + slope = np.cov(pos_sel, int_sel)[0][1]/np.var(pos_sel) if slope < 0: - func = integPowerDown + func = stepDown funcStr = 'a*erfc(np.sqrt(2)*(x-x0)/w0) + b' else: - func = integPowerUp + func = stepUp funcStr = 'a*erfc(-np.sqrt(2)*(x-x0)/w0) + b' if p0 is None: p0 = [np.mean(pos_sel), 0.1, np.max(int_sel)/2, 0] try: popt, pcov = curve_fit(func, pos_sel, int_sel, p0=p0) print('fitting function:', funcStr) - print('w0 = (%.1f +/- %.1f) um'%(popt[1]*1e3, pcov[1,1]**0.5*1e3)) - print('x0 = (%.3f +/- %.3f) mm'%(popt[0], pcov[0,0]**0.5)) - print('a = %e +/- %e '%(popt[2], pcov[2,2]**0.5)) - print('b = %e +/- %e '%(popt[3], pcov[3,3]**0.5)) + print('w0 = (%.1f +/- %.1f) um' % (popt[1]*1e3, pcov[1, 1]**0.5*1e3)) + print('x0 = (%.3f +/- %.3f) mm' % (popt[0], pcov[0, 0]**0.5)) + print('a = %e +/- %e ' % (popt[2], pcov[2, 2]**0.5)) + print('b = %e +/- %e ' % (popt[3], pcov[3, 3]**0.5)) fitSuccess = True - except: - print('Could not fit the data with ercf function.' + + except Exception as e: + print(f'Could not fit the data with erfc function: {e}.' + ' Try adjusting the axisRange and the initial parameters p0') fitSuccess = False - + if plot: - plt.figure(figsize=(7,4)) - plt.scatter(positions, intensities, color='C1', label='exp', s=2, alpha=0.1) + plt.figure(figsize=(7, 4)) + plt.scatter(positions, intensities, color='C1', + label='exp', s=2, alpha=0.1) if fitSuccess: xfit = np.linspace(positions.min(), positions.max(), 1000) yfit = func(xfit, *popt) - plt.plot(xfit, yfit, color='C4', - label=r'fit $\rightarrow$ $w_0=$(%.1f $\pm$ %.1f) $\mu$m'%(popt[1]*1e3, - pcov[1,1]**0.5*1e3)) + plt.plot(xfit, yfit, color='C4', + label=r'fit $\rightarrow$ $w_0=$(%.1f $\pm$ %.1f) $\mu$m' % ( + popt[1]*1e3, pcov[1, 1]**0.5*1e3)) leg = plt.legend() - for lh in leg.legendHandles: + for lh in leg.legendHandles: lh.set_alpha(1) plt.ylabel(signalKey) plt.xlabel(axisKey + ' position [mm]') - plt.title(nrun.attrs['runFolder']) + plt.title(ds.attrs['runFolder']) plt.tight_layout() if full: if fitSuccess: @@ -112,6 +131,6 @@ def knife_edge(nrun, axisKey='scannerX', signalKey='FastADC4peaks', return np.zeros(4), np.zeros(2), None else: if fitSuccess: - return np.array([popt[1], pcov[1,1]**0.5]) + return np.array([popt[1], pcov[1, 1]**0.5]) else: return np.zeros(2) diff --git a/src/toolbox_scs/test/test_top_level.py b/src/toolbox_scs/test/test_top_level.py index 9fd5496..24d74bd 100644 --- a/src/toolbox_scs/test/test_top_level.py +++ b/src/toolbox_scs/test/test_top_level.py @@ -30,7 +30,7 @@ class TestToolbox(unittest.TestCase): @classmethod def setUpClass(cls): log_root.info("Start global setup") - cls._mnentry = 'SCS_RR_UTC/MDL/BUNCH_DECODER' + cls._mnentry = 'SCS_RR_UTC/TSYS/TIMESERVER' cls._ed_run = ed.open_run(2212, 235) log_root.info("Finished global setup, start tests") @@ -46,7 +46,7 @@ class TestToolbox(unittest.TestCase): def test_constant(self): cls = self.__class__ - self.assertEqual(tb.mnemonics['sase3']['source'],cls._mnentry) + self.assertEqual(tb.mnemonics['bunchPatternTable']['source'],cls._mnentry) def test_load(self): fields = ["SCS_XGM"] @@ -55,17 +55,15 @@ class TestToolbox(unittest.TestCase): run_tb = None proposalNB = 2511 runNB = 176 - run_tb = tb.load(fields, runNB, proposalNB, - validate=False, display=False) - self.assertEqual(run_tb['npulses_sase3'].values[0], 42) + run_tb, data = tb.load(proposalNB, runNB, fields) + self.assertEqual(data['bunchPatternTable'].values[0, 0], 2113321) # exception raised run_tb = None proposalNB = 2511 runNB = 1766 with self.assertRaises(ToolBoxPathError) as cm: - run_tb = tb.load(fields, runNB, proposalNB, - validate=False, display=False) + run_tb, data = tb.load(proposalNB, runNB, fields) tb_exception = cm.exception constr_path = f'/gpfs/exfel/exp/SCS/202001/p002511/raw/r{runNB}' exp_msg = f"Invalid path: {constr_path}. " + \ @@ -73,7 +71,7 @@ class TestToolbox(unittest.TestCase): self.assertEqual(tb_exception.message, exp_msg) def test_openrun(self): - run = tb.load_run(2212, 235) + run, _ = tb.load(2212, 235) src = 'SCS_DET_DSSC1M-1/DET/0CH0:xtdf' self.assertTrue(src in run.all_sources) -- GitLab