diff --git a/docs/_static/thumbnails/estia_advanced_mcstas_reduction_dark.svg b/docs/_static/thumbnails/estia_advanced_mcstas_reduction_dark.svg
new file mode 100644
index 00000000..1afc3dc3
--- /dev/null
+++ b/docs/_static/thumbnails/estia_advanced_mcstas_reduction_dark.svg
@@ -0,0 +1,775 @@
+
+
+
diff --git a/docs/_static/thumbnails/estia_advanced_mcstas_reduction_light.svg b/docs/_static/thumbnails/estia_advanced_mcstas_reduction_light.svg
new file mode 100644
index 00000000..facd4d33
--- /dev/null
+++ b/docs/_static/thumbnails/estia_advanced_mcstas_reduction_light.svg
@@ -0,0 +1,775 @@
+
+
+
diff --git a/docs/_static/thumbnails/estia_mcstas_reduction_dark.svg b/docs/_static/thumbnails/estia_mcstas_reduction_dark.svg
new file mode 100644
index 00000000..5ce44ea6
--- /dev/null
+++ b/docs/_static/thumbnails/estia_mcstas_reduction_dark.svg
@@ -0,0 +1,1482 @@
+
+
+
diff --git a/docs/_static/thumbnails/estia_mcstas_reduction_light.svg b/docs/_static/thumbnails/estia_mcstas_reduction_light.svg
new file mode 100644
index 00000000..96b9f0f4
--- /dev/null
+++ b/docs/_static/thumbnails/estia_mcstas_reduction_light.svg
@@ -0,0 +1,1482 @@
+
+
+
diff --git a/docs/index.md b/docs/index.md
index a5b34110..8a43b807 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -28,23 +28,26 @@
-## Overview
+## Quick links
-This documentation is under construction.
-See the [Amor data reduction](examples/amor) example for a quick start.
+::::{grid} 3
-## Table of contents
+:::{grid-item-card} ESTIA
+:link: user-guide/estia/index.md
-```{toctree}
----
-maxdepth: 2
----
+:::
-user-guide/index
-api-reference/index
-developer/index
-about/index
-```
+:::{grid-item-card} Amor
+:link: user-guide/amor/index.md
+
+:::
+
+::::{grid-item-card} Offspec
+:link: user-guide/offspec/index.md
+
+:::
+
+::::
:::{include} user-guide/installation.md
:heading-offset: 1
@@ -54,3 +57,14 @@ about/index
- If you have questions that are not answered by these documentation pages, ask on [discussions](https://github.com/scipp/essreflectometry/discussions). Please include a self-contained reproducible example if possible.
- Report bugs (including unclear, missing, or wrong documentation!), suggest features or view the source code [on GitHub](https://github.com/scipp/essreflectometry).
+
+```{toctree}
+---
+hidden:
+---
+
+user-guide/index
+api-reference/index
+developer/index
+about/index
+```
diff --git a/docs/user-guide/amor/index.md b/docs/user-guide/amor/index.md
index e379a54a..2c0d7023 100644
--- a/docs/user-guide/amor/index.md
+++ b/docs/user-guide/amor/index.md
@@ -6,4 +6,5 @@ maxdepth: 1
---
amor-reduction
compare-to-eos
+workflow-widget
```
diff --git a/docs/user-guide/amor/gui.ipynb b/docs/user-guide/amor/workflow-widget.ipynb
similarity index 89%
rename from docs/user-guide/amor/gui.ipynb
rename to docs/user-guide/amor/workflow-widget.ipynb
index c3566f08..696313b6 100644
--- a/docs/user-guide/amor/gui.ipynb
+++ b/docs/user-guide/amor/workflow-widget.ipynb
@@ -1,9 +1,17 @@
{
"cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Workflow widget"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
- "id": "0",
+ "id": "1",
"metadata": {},
"outputs": [],
"source": [
@@ -14,7 +22,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "1",
+ "id": "2",
"metadata": {},
"outputs": [],
"source": [
@@ -24,7 +32,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "2",
+ "id": "3",
"metadata": {},
"outputs": [],
"source": [
@@ -34,12 +42,12 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "3",
+ "id": "4",
"metadata": {},
"outputs": [],
"source": [
"gui = AmorBatchReductionGUI()\n",
- "gui.widget\n"
+ "gui.widget"
]
}
],
diff --git a/docs/user-guide/estia/estia-advanced-mcstas-reduction.ipynb b/docs/user-guide/estia/estia-advanced-mcstas-reduction.ipynb
new file mode 100644
index 00000000..f1103e44
--- /dev/null
+++ b/docs/user-guide/estia/estia-advanced-mcstas-reduction.ipynb
@@ -0,0 +1,520 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# ESTIA advanced data reduction\n",
+ "\n",
+ "- Audience: Instrument (data) scientists, instrument users\n",
+ "- Prerequisites: Basic knowledge of [Scipp](https://scipp.github.io/), [Sciline](https://scipp.github.io/sciline/)\n",
+ "\n",
+ "This notebook builds on the [basic ESTIA reduction guide](./estia-mcstas-reduction.rst); you should read that first.\n",
+ "This advanced guide demonstrates how the workflow can be used to make diagnostics plots and options for processing multiple files together.\n",
+ "e the default loader with the `load_mcstas_events` provider.\n",
+ "\n",
+ "The data is available through the ESSreflectometry package but accessing it requires the pooch package.\n",
+ "If you get an error about a missing module pooch, you can install it with `!pip install pooch`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from typing import NewType\n",
+ "\n",
+ "import pandas as pd\n",
+ "import sciline\n",
+ "import scipp as sc\n",
+ "\n",
+ "from ess.estia.data import estia_mcstas_example, estia_mcstas_groundtruth\n",
+ "from ess.estia import EstiaMcStasWorkflow\n",
+ "from ess.reflectometry.types import *\n",
+ "from ess.reflectometry.figures import wavelength_z_figure, wavelength_theta_figure, q_theta_figure"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Process multiple files\n",
+ "\n",
+ "To apply the ESTIA workflow to multiple files, we could simply write a for-loop like this:\n",
+ "```python\n",
+ "results = []\n",
+ "for filename in estia_mcstas_example('Ni/Ti-multilayer'):\n",
+ " wf[Filename[SampleRun]] = filename\n",
+ " results.append(wf.compute(ReflectivityOverQ))\n",
+ "```\n",
+ "However, this would re-load and re-process the reference measurement for every sample file.\n",
+ "Instead, we will use Sciline's [map-reduce](https://scipp.github.io/sciline/user-guide/parameter-tables.html) feature to map the workflow over several files and merge the individual results.\n",
+ "\n",
+ "First, we set up the workflow in almost the same way as in the [basic ESTIA reduction guide](./estia-mcstas-reduction.rst), except that we do *not* set a filename for the sample run."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wf = EstiaMcStasWorkflow()\n",
+ "wf[Filename[ReferenceRun]] = estia_mcstas_example('reference')\n",
+ "\n",
+ "wf[YIndexLimits] = sc.scalar(35), sc.scalar(64)\n",
+ "wf[ZIndexLimits] = sc.scalar(0), sc.scalar(48 * 32)\n",
+ "wf[BeamDivergenceLimits] = sc.scalar(-0.75, unit='deg'), sc.scalar(0.75, unit='deg')\n",
+ "\n",
+ "wf[WavelengthBins] = sc.geomspace('wavelength', 3.5, 12, 2001, unit='angstrom')\n",
+ "wf[QBins] = 1000\n",
+ "\n",
+ "# There is no proton current data in the McStas files, here we just add some fake proton current\n",
+ "# data to make the workflow run.\n",
+ "wf[ProtonCurrent[SampleRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})\n",
+ "wf[ProtonCurrent[ReferenceRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4",
+ "metadata": {},
+ "source": [
+ "## Reflectivity vs. Q\n",
+ "\n",
+ "In this section, we compute the reflectivity as a function of momentum transfer for a number of files with the same sample at different sample rotations.\n",
+ "We will `map` the workflow over the ames for each file and `reduce` the results into a single data group.\n",
+ "\n",
+ "Starting with a parameter table of filenames, we `map` the workflow:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "param_table = pd.DataFrame({\n",
+ " Filename[SampleRun]: estia_mcstas_example('Ni/Ti-multilayer')\n",
+ "}).rename_axis(index='sample_rotation')\n",
+ "\n",
+ "# Make a copy to preserve the original `wf`.\n",
+ "multi_file_workflow = wf.copy()\n",
+ "mapped = multi_file_workflow[ReflectivityOverQ].map(param_table)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6",
+ "metadata": {},
+ "source": [
+ "Then we merge the reflectivity data for all files into a single data group.\n",
+ "We use the sample rotation as key because in this example, each file contains data at a different rotation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def combine_measurements(*measurements: sc.DataArray) -> sc.DataGroup[sc.DataArray]:\n",
+ " return sc.DataGroup({\n",
+ " f\"{da.coords['sample_rotation']:c}\": da for da in measurements\n",
+ " })\n",
+ "\n",
+ "multi_file_workflow[ReflectivityOverQ] = mapped.reduce(\n",
+ " func=combine_measurements\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8",
+ "metadata": {},
+ "source": [
+ "The graph now indicates that everything that depends on `SampleRun` data has been mapped: (Names shown in boxes as opposed to rectangles have been mapped.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "multi_file_workflow.visualize(\n",
+ " ReflectivityOverQ,\n",
+ " graph_attr={\"rankdir\": \"LR\"},\n",
+ " compact=True,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10",
+ "metadata": {},
+ "source": [
+ "We compute the reflectivity for each file and get a data group:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reflectivities = multi_file_workflow.compute(ReflectivityOverQ)\n",
+ "reflectivities"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reflectivities.hist().plot(norm='log', vmin=1e-8)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "13",
+ "metadata": {},
+ "source": [
+ "### Reflectivity vs. Q with custom mask\n",
+ "\n",
+ "The data is very noisy in some $Q$ bins.\n",
+ "We can clean up the plot by removing or masking those bins.\n",
+ "The variance of the reference measurement is a good measure for how noisy the final data will be, so we use that to insert a mask into the reflectivity curve.\n",
+ "This means that we need to request `Reference` to construct the mask.\n",
+ "But since the value of `Reference` is different for each sample run, we need to insert a new step into the workflow and include it in the `map`-operation.\n",
+ "See also [Replacing providers](https://scipp.github.io/sciline/recipes/replacing-providers.html) for a more general guide.\n",
+ "\n",
+ "We define a custom type (`MaskedReflectivityOverQ`) and a provider to apply the mask:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "MaskedReflectivityOverQ = NewType('MaskedReflectivityOverQ', sc.DataArray)\n",
+ "\n",
+ "def mask_noisy_reference(\n",
+ " reflectivity: ReflectivityOverQ,\n",
+ " reference: Reference,\n",
+ ") -> MaskedReflectivityOverQ:\n",
+ " ref = reference.hist(Q=reflectivity.coords['Q'])\n",
+ " return reflectivity.assign_masks(\n",
+ " noisy_reference= sc.stddevs(ref).data > 0.3 * ref.data\n",
+ " )\n",
+ "\n",
+ "wf.insert(mask_noisy_reference)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15",
+ "metadata": {},
+ "source": [
+ "Note that the code above inserts into `wf`, i.e., the unmapped workflow.\n",
+ "Now map-reduce the workflow again but in the new `MaskedReflectivityOverQ` type:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "multi_file_workflow = wf.copy()\n",
+ "param_table = pd.DataFrame({\n",
+ " Filename[SampleRun]: estia_mcstas_example('Ni/Ti-multilayer')\n",
+ "}).rename_axis(index='run')\n",
+ "mapped = multi_file_workflow[MaskedReflectivityOverQ].map(param_table)\n",
+ "multi_file_workflow[MaskedReflectivityOverQ] = mapped.reduce(\n",
+ " func=combine_measurements\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17",
+ "metadata": {},
+ "source": [
+ "The graph is the same as before except that only `MaskedReflectivityOverQ` is available as a final, unmapped type:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "18",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "multi_file_workflow.visualize(\n",
+ " MaskedReflectivityOverQ,\n",
+ " graph_attr={\"rankdir\": \"LR\"},\n",
+ " compact=True,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "19",
+ "metadata": {},
+ "source": [
+ "Compute the results:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reflectivities = multi_file_workflow.compute(MaskedReflectivityOverQ)\n",
+ "reflectivities"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "21",
+ "metadata": {},
+ "source": [
+ "To plot, we histogram and set values in masked bins to NaN to make the plot easier to read:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "histograms = reflectivities.hist().apply(lambda R: R.assign(\n",
+ " sc.where(\n",
+ " R.masks['noisy_reference'],\n",
+ " sc.scalar(float('nan'), unit=R.unit),\n",
+ " R.data\n",
+ " )\n",
+ "))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23",
+ "metadata": {},
+ "source": [
+ "Since this data is from a McStas simulation, we know the true reflectivity of the sample.\n",
+ "We plot it alongside the 'measured' reflectivity for comparison:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ground_truth = estia_mcstas_groundtruth('Ni/Ti-multilayer')\n",
+ "sc.plot({'ground_truth': ground_truth} | dict(histograms), norm='log', vmin=1e-8, c={'ground_truth': 'k'})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25",
+ "metadata": {},
+ "source": [
+ "### Other projections\n",
+ "\n",
+ "ESSreflectometry provides functions for plotting the intensity as a function of different variables.\n",
+ "Note that these plots can also be produced by the workflow directly, see [Draw diagnostics plots with the workflow](#Draw-diagnostics-plots-with-the-workflow).\n",
+ "But here, we make them manually to more easily combine data from all files.\n",
+ "\n",
+ "The plots consume data that is provided by the `Sample` key in the workflow.\n",
+ "We could map-reduce the workflow in that key instead of in `MaskedReflectivityOverQ` to compute `Sample` for each file.\n",
+ "But for simplicity, we use [sciline.compute_mapped](https://scipp.github.io/sciline/generated/functions/sciline.compute_mapped.html#sciline.compute_mapped) to compute the results for all files:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "26",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "results = list(sciline.compute_mapped(multi_file_workflow, Sample))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wavelength_z_figure(results[3], wavelength_bins=400)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "28",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wavelength_theta_figure(\n",
+ " results,\n",
+ " wavelength_bins=200,\n",
+ " theta_bins=200,\n",
+ " q_edges_to_display=[sc.scalar(0.016, unit='1/angstrom'), sc.scalar(0.19, unit='1/angstrom')]\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "29",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "q_theta_figure(results, q_bins=200, theta_bins=200)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30",
+ "metadata": {},
+ "source": [
+ "## Draw diagnostics plots with the workflow\n",
+ "\n",
+ "The ESTIA workflow can produce a number of plots directly to quickly visualize the data in different forms.\n",
+ "Those plots can be combined into a single `ReflectivityDiagnosticsView` or constructed separately.\n",
+ "Here, we use the combined `ReflectivityDiagnosticsView` but you can also request one or more of the individual views (see also the graph below):\n",
+ "- `ReflectivityOverQ`\n",
+ "- `ReflectivityOverZW`\n",
+ "- `WavelengthThetaFigure`\n",
+ "- `WavelengthZIndexFigure`\n",
+ "\n",
+ "These plots correspond to the figures in the [Other projections](#Other-projections) sections above but show only data from a single file.\n",
+ "\n",
+ "We construct the workflow as in the [basic ESTIA reduction guide](./estia-mcstas-reduction.rst) but also add `ThetaBins` for the sample run to control the plots:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "31",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wf = EstiaMcStasWorkflow()\n",
+ "wf[Filename[SampleRun]] = estia_mcstas_example('Ni/Ti-multilayer')[3]\n",
+ "wf[Filename[ReferenceRun]] = estia_mcstas_example('reference')\n",
+ "\n",
+ "wf[YIndexLimits] = sc.scalar(35), sc.scalar(64)\n",
+ "wf[ZIndexLimits] = sc.scalar(0), sc.scalar(48 * 32)\n",
+ "wf[BeamDivergenceLimits] = sc.scalar(-0.75, unit='deg'), sc.scalar(0.75, unit='deg')\n",
+ "\n",
+ "wf[WavelengthBins] = sc.geomspace('wavelength', 3.5, 12, 2001, unit='angstrom')\n",
+ "wf[ThetaBins[SampleRun]] = 200\n",
+ "wf[QBins] = 1000\n",
+ "\n",
+ "# There is no proton current data in the McStas files, here we just add some fake proton current\n",
+ "# data to make the workflow run.\n",
+ "wf[ProtonCurrent[SampleRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})\n",
+ "wf[ProtonCurrent[ReferenceRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "32",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wf.visualize(ReflectivityDiagnosticsView, graph_attr={'rankdir':'LR'})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "33",
+ "metadata": {},
+ "source": [
+ "We request the figure like any other data in the workflow:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "34",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "view = wf.compute(ReflectivityDiagnosticsView)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "35",
+ "metadata": {},
+ "source": [
+ "And finally, we draw it: (this `view` object can be rendered in a Jupyter notebook.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "36",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "view"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.14"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/user-guide/estia/estia-mcstas-reduction.ipynb b/docs/user-guide/estia/estia-mcstas-reduction.ipynb
index 8e670b42..a8838ff9 100644
--- a/docs/user-guide/estia/estia-mcstas-reduction.ipynb
+++ b/docs/user-guide/estia/estia-mcstas-reduction.ipynb
@@ -5,60 +5,83 @@
"id": "0",
"metadata": {},
"source": [
- "# Reduction of ESTIA McStas data"
+ "# Reduction of ESTIA McStas data\n",
+ "\n",
+ "- Audience: Instrument users, beginners\n",
+ "- Prerequisites: Basic knowledge of [Scipp](https://scipp.github.io/)\n",
+ "\n",
+ "This notebook demonstrates the basic reflectometry data reduction workflow for ESTIA with simulated data.\n",
+ "A workflow for data recorded at ESS would be very similar but is not yet available.\n",
+ "The workflow:\n",
+ "\n",
+ "1. Converts the data to momentum transfer $Q$.\n",
+ "2. Normalizes by a reference measurement.\n",
+ "3. Packages the results to be saved to and [ORSO ORT](https://www.reflectometry.org/advanced_and_expert_level/file_format) file.\n",
+ "\n",
+ "The data is available through the ESSreflectometry package but accessing it requires the pooch package.\n",
+ "If you get an error about a missing module pooch, you can install it with `!pip install pooch`."
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": null,
"id": "1",
"metadata": {},
+ "outputs": [],
"source": [
- "This notebook demonstrates how to run the data reduction on the output of McStas simulations of the instrument.\n",
+ "import scipp as sc\n",
"\n",
- "Essentially this looks very similar to how one would do data reduction on real data files from the physical instrument,\n",
- "but we replace the default loader with the `load_mcstas_events` provider."
+ "from ess.estia.data import estia_mcstas_example\n",
+ "from ess.estia import EstiaMcStasWorkflow\n",
+ "from ess.reflectometry.types import *"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Create and configure the workflow\n",
+ "\n",
+ "We begin by creating the ESTIA (McStas) workflow object which is a skeleton for reducing ESTIA data with pre-configured steps:"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "2",
+ "id": "3",
"metadata": {},
"outputs": [],
"source": [
- "#%matplotlib widget\n",
- "import scipp as sc\n",
- "\n",
- "from ess.estia.load import load_mcstas_events\n",
- "from ess.estia.data import estia_mcstas_example, estia_mcstas_groundtruth\n",
- "from ess.estia import EstiaMcStasWorkflow\n",
- "from ess.reflectometry.types import *\n",
- "from ess.reflectometry.figures import wavelength_z_figure, wavelength_theta_figure, q_theta_figure"
+ "wf = EstiaMcStasWorkflow()"
]
},
{
"cell_type": "markdown",
- "id": "3",
+ "id": "4",
"metadata": {},
"source": [
- "The Estia reduction workflow is created and we set parameters such as region of interest, wavelengthbins, and q-bins."
+ "We then need to set the missing parameters which are specific to each experiment (the keys are types defined in [ess.reflectometry.types](../../generated/modules/ess.reflectometry.types.rst))."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "4",
+ "id": "5",
"metadata": {},
"outputs": [],
"source": [
- "\n",
- "wf = EstiaMcStasWorkflow()\n",
- "wf.insert(load_mcstas_events)\n",
+ "# Specify input data files:\n",
+ "# (The choice of 'Ni/Ti-multilayer' file number 3 is arbitrary.)\n",
+ "wf[Filename[SampleRun]] = estia_mcstas_example('Ni/Ti-multilayer')[3]\n",
"wf[Filename[ReferenceRun]] = estia_mcstas_example('reference')\n",
"\n",
- "wf[YIndexLimits] = sc.scalar(35), sc.scalar(64)\n",
+ "# Select a region of interest:\n",
+ "wf[YIndexLimits] = sc.scalar(35), sc.scalar(64)\n",
"wf[ZIndexLimits] = sc.scalar(0), sc.scalar(48 * 32)\n",
"wf[BeamDivergenceLimits] = sc.scalar(-0.75, unit='deg'), sc.scalar(0.75, unit='deg')\n",
+ "\n",
+ "# Configure the binning of intermediate and final results:\n",
"wf[WavelengthBins] = sc.geomspace('wavelength', 3.5, 12, 2001, unit='angstrom')\n",
"wf[QBins] = 1000\n",
"\n",
@@ -69,29 +92,7 @@
" coords={'time': sc.array(dims=('time',), values=[], unit='s')})\n",
"wf[ProtonCurrent[ReferenceRun]] = sc.DataArray(\n",
" sc.array(dims=('time',), values=[]),\n",
- " coords={'time': sc.array(dims=('time',), values=[], unit='s')})\n",
- "\n",
- "\n",
- "def compute_reflectivity_curve_for_mcstas_data(wf, results):\n",
- " R, ref, da = w.compute((ReflectivityOverQ, Reference, ReducibleData[SampleRun])).values()\n",
- " # In the McStas simulation the reference has quite low intensity.\n",
- " # To make the reflectivity curve a bit more clean\n",
- " # we filter out the Q-points where the reference has too large uncertainties.\n",
- " ref = ref.hist(Q=R.coords['Q'])\n",
- " too_large_uncertainty_in_reference = sc.stddevs(ref).data > 0.3 * ref.data\n",
- " R = R.hist()\n",
- " R.data = sc.where(too_large_uncertainty_in_reference, sc.scalar(float('nan'), unit=R.unit), R.data)\n",
- " results[f\"{da.coords['sample_rotation'].value} {da.coords['sample_rotation'].unit}\"] = R\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "5",
- "metadata": {},
- "outputs": [],
- "source": [
- "wf.visualize(graph_attr={'rankdir':\"LR\"})"
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})"
]
},
{
@@ -99,10 +100,9 @@
"id": "6",
"metadata": {},
"source": [
- "## Ni/Ti multilayer sample\n",
- "\n",
- "Below is a comparison between the reflectivity curve obtained using the reduction workflow and the ground truth reflectivity curve that was used in the McStas simulation.\n",
- "The sample was simulated at different sample rotation settings, each settings produces a separate reflectivity curve covering a higher Q-range, and that is the angle in the legend of the figure."
+ "We can visualize the workflow as a graph.\n",
+ "This can help us understand how the data will be reduced.\n",
+ "(`ReflectivityOverQ` is the key of the output data.)"
]
},
{
@@ -112,15 +112,7 @@
"metadata": {},
"outputs": [],
"source": [
- "results = {}\n",
- "for path in estia_mcstas_example('Ni/Ti-multilayer'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " compute_reflectivity_curve_for_mcstas_data(w, results)\n",
- "\n",
- "ground_truth = estia_mcstas_groundtruth('Ni/Ti-multilayer')\n",
- "\n",
- "sc.plot({'ground_truth': ground_truth} | results, norm='log', vmin=1e-8)"
+ "wf.visualize(ReflectivityOverQ, graph_attr={'rankdir': \"LR\"})"
]
},
{
@@ -128,7 +120,12 @@
"id": "8",
"metadata": {},
"source": [
- "Below are a number of figures displaying different projections of the measured intensity distribution."
+ "The workflow is a [Sciline](https://scipp.github.io/sciline/) pipeline.\n",
+ "See the documentation of Sciline for more information and how to modify and extend the workflow.\n",
+ "\n",
+ "## Use the reduction workflow\n",
+ "\n",
+ "We call [wf.compute(targets)](https://scipp.github.io/sciline/generated/classes/sciline.Pipeline.html#sciline.Pipeline.compute) to compute the result:"
]
},
{
@@ -138,21 +135,16 @@
"metadata": {},
"outputs": [],
"source": [
- "results = []\n",
- "for path in estia_mcstas_example('Ni/Ti-multilayer'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " results.append(w.compute(Sample))"
+ "reflectivity = wf.compute(ReflectivityOverQ)"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"id": "10",
"metadata": {},
- "outputs": [],
"source": [
- "wavelength_z_figure(results[3], wavelength_bins=400)"
+ "The reflectivity is still event data.\n",
+ "We can histogram it and plot it:"
]
},
{
@@ -162,25 +154,31 @@
"metadata": {},
"outputs": [],
"source": [
- "wavelength_theta_figure(results, wavelength_bins=400, theta_bins=200, q_edges_to_display=[sc.scalar(0.016, unit='1/angstrom'), sc.scalar(0.19, unit='1/angstrom')])"
+ "reflectivity.hist().plot(norm='log', vmin=1e-8)"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"id": "12",
"metadata": {},
- "outputs": [],
"source": [
- "q_theta_figure(results, q_bins=300, theta_bins=200)"
+ "## Saving to ORSO ORT file\n",
+ "\n",
+ "Ultimately, we want to save the reduced data to a file.\n",
+ "The workflow supports building an [ORSO dataset](https://www.reflectometry.org/orsopy/orsopy.fileio.html#orsopy.fileio.OrsoDataset) from the reduced data: `OrsoIofQDataset`.\n",
+ "We require some additional imports:"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": null,
"id": "13",
"metadata": {},
+ "outputs": [],
"source": [
- "## Ni on Silicon"
+ "from orsopy import fileio\n",
+ "\n",
+ "from ess.reflectometry import orso"
]
},
{
@@ -190,28 +188,17 @@
"metadata": {},
"outputs": [],
"source": [
- "results = {}\n",
- "for path in estia_mcstas_example('Ni-film on silicon'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " compute_reflectivity_curve_for_mcstas_data(w, results)\n",
- "\n",
- "ground_truth = estia_mcstas_groundtruth('Ni-film on silicon')\n",
- "sc.plot({'ground_truth': ground_truth} | results, norm='log', vmin=1e-9)"
+ "wf.visualize(orso.OrsoIofQDataset, graph_attr={'rankdir': \"LR\"})"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"id": "15",
"metadata": {},
- "outputs": [],
"source": [
- "results = []\n",
- "for path in estia_mcstas_example('Ni-film on silicon'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " results.append(w.compute(ReducibleData[SampleRun]))"
+ "We can see from the graph that some nodes are missing (red boxes).\n",
+ "These need to be manually provided as they cannot be deduced from the input.\n",
+ "Further, McStas files do not contain all required metadata, so that needs to be provided manually as well."
]
},
{
@@ -221,17 +208,30 @@
"metadata": {},
"outputs": [],
"source": [
- "wavelength_z_figure(results[3], wavelength_bins=400)"
+ "wf[orso.Beamline] = orso.Beamline(name='ESTIA', facility='ESS')\n",
+ "wf[orso.Measurement] = orso.Measurement(\n",
+ " title='McStas Simulation, Ni/Ti-multilayer',\n",
+ ")\n",
+ "wf[orso.OrsoSample] = orso.OrsoSample(\n",
+ " fileio.data_source.Sample(name='Ni/Ti multilayer')\n",
+ ")\n",
+ "wf[orso.OrsoCreator] = orso.OrsoCreator(\n",
+ " fileio.base.Person(\n",
+ " name='Max Mustermann',\n",
+ " affiliation='European Spallation Source ERIC',\n",
+ " contact='max.mustermann@ess.eu',\n",
+ " )\n",
+ ")\n",
+ "wf[orso.OrsoOwner] = wf[orso.OrsoCreator]"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"id": "17",
"metadata": {},
- "outputs": [],
"source": [
- "wavelength_theta_figure(results, wavelength_bins=400, theta_bins=200, q_edges_to_display=[sc.scalar(0.016, unit='1/angstrom'), sc.scalar(0.19, unit='1/angstrom')])"
+ "Now that we have these additional parameters, we can construct the ORSO dataset:\n",
+ "(Note that this will re-run the reduction procedure to ensure that all data is consistent.)"
]
},
{
@@ -241,7 +241,7 @@
"metadata": {},
"outputs": [],
"source": [
- "q_theta_figure(results, q_bins=300, theta_bins=200)"
+ "dataset = wf.compute(orso.OrsoIofQDataset)"
]
},
{
@@ -249,7 +249,8 @@
"id": "19",
"metadata": {},
"source": [
- "## SiO2 on Silicon"
+ "The `dataset` has not been written to disk yet.\n",
+ "For that, simply call `save`:"
]
},
{
@@ -259,58 +260,17 @@
"metadata": {},
"outputs": [],
"source": [
- "results = {}\n",
- "for path in estia_mcstas_example('Natural SiO2 on silicon'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " compute_reflectivity_curve_for_mcstas_data(w, results)\n",
- "\n",
- "ground_truth = estia_mcstas_groundtruth('Natural SiO2 on silicon')\n",
- "sc.plot({'ground_truth': ground_truth} | results, norm='log', vmin=1e-9)"
+ "dataset.save('estia_reduced_iofq.ort')"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"id": "21",
"metadata": {},
- "outputs": [],
"source": [
- "results = []\n",
- "for path in estia_mcstas_example('Natural SiO2 on silicon'):\n",
- " w = wf.copy()\n",
- " w[Filename[SampleRun]] = path\n",
- " results.append(w.compute(ReducibleData[SampleRun]))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "22",
- "metadata": {},
- "outputs": [],
- "source": [
- "wavelength_z_figure(results[3], wavelength_bins=400)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "23",
- "metadata": {},
- "outputs": [],
- "source": [
- "wavelength_theta_figure(results, wavelength_bins=400, theta_bins=200, q_edges_to_display=[sc.scalar(0.016, unit='1/angstrom')])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "24",
- "metadata": {},
- "outputs": [],
- "source": [
- "q_theta_figure(results, q_bins=300, theta_bins=200)"
+ "---\n",
+ "\n",
+ "Next, consider reading the [ESTIA advanced McStas reduction](./estia-advanced-mcstas-reduction.rst) guide which demonstrates how multiple files can be reduced together and how to make different types of plots."
]
}
],
diff --git a/docs/user-guide/estia/index.md b/docs/user-guide/estia/index.md
index 268892a1..8e102096 100644
--- a/docs/user-guide/estia/index.md
+++ b/docs/user-guide/estia/index.md
@@ -1,8 +1,44 @@
-# Estia
+# ESTIA
+
+## Reduction Workflows
+
+::::{grid} 3
+
+:::{grid-item-card} Reduction of McStas Data
+:link: estia-mcstas-reduction.ipynb
+:text-align: center
+
+```{image} ../../_static/thumbnails/estia_mcstas_reduction_light.svg
+:class: only-light
+:width: 100%
+```
+```{image} ../../_static/thumbnails/estia_mcstas_reduction_dark.svg
+:class: only-dark
+:width: 100%
+```
+:::
+
+:::{grid-item-card} Advanced reduction of McStas Data
+:link: estia-advanced-mcstas-reduction.ipynb
+:text-align: center
+
+```{image} ../../_static/thumbnails/estia_advanced_mcstas_reduction_light.svg
+:class: only-light
+:width: 100%
+```
+```{image} ../../_static/thumbnails/estia_advanced_mcstas_reduction_dark.svg
+:class: only-dark
+:width: 100%
+```
+:::
+
+::::
```{toctree}
---
-maxdepth: 1
+hidden:
---
+
estia-mcstas-reduction
+estia-advanced-mcstas-reduction
```
diff --git a/src/ess/estia/workflow.py b/src/ess/estia/workflow.py
index 99aa93e6..84001d1c 100644
--- a/src/ess/estia/workflow.py
+++ b/src/ess/estia/workflow.py
@@ -27,6 +27,7 @@
mcstas_providers = (
*_general_providers,
*load.providers,
+ load.load_mcstas_events,
)
"""List of providers for setting up a Sciline pipeline for McStas data.
diff --git a/tools/docs/estia-thumbnails.ipynb b/tools/docs/estia-thumbnails.ipynb
new file mode 100644
index 00000000..4b456e66
--- /dev/null
+++ b/tools/docs/estia-thumbnails.ipynb
@@ -0,0 +1,283 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# ESTIA thumbnails\n",
+ "\n",
+ "This notebook generates the thumbnails used in the ESTIA user guide."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from typing import NewType\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "import pandas as pd\n",
+ "import sciline\n",
+ "import scipp as sc\n",
+ "\n",
+ "from ess.estia.data import estia_mcstas_example\n",
+ "from ess.estia import EstiaMcStasWorkflow\n",
+ "from ess.reflectometry.types import *\n",
+ "from ess.reflectometry.figures import q_theta_figure"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wf = EstiaMcStasWorkflow()\n",
+ "wf[Filename[SampleRun]] = estia_mcstas_example('Ni/Ti-multilayer')[3]\n",
+ "wf[Filename[ReferenceRun]] = estia_mcstas_example('reference')\n",
+ "\n",
+ "wf[YIndexLimits] = sc.scalar(35), sc.scalar(64)\n",
+ "wf[ZIndexLimits] = sc.scalar(0), sc.scalar(48 * 32)\n",
+ "wf[BeamDivergenceLimits] = sc.scalar(-0.75, unit='deg'), sc.scalar(0.75, unit='deg')\n",
+ "\n",
+ "wf[WavelengthBins] = sc.geomspace('wavelength', 3.5, 12, 2001, unit='angstrom')\n",
+ "wf[QBins] = 1000\n",
+ "\n",
+ "# There is no proton current data in the McStas files, here we just add some fake proton current\n",
+ "# data to make the workflow run.\n",
+ "wf[ProtonCurrent[SampleRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})\n",
+ "wf[ProtonCurrent[ReferenceRun]] = sc.DataArray(\n",
+ " sc.array(dims=('time',), values=[]),\n",
+ " coords={'time': sc.array(dims=('time',), values=[], unit='s')})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3",
+ "metadata": {},
+ "source": [
+ "## Basic McStas workflow"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reflectivity = wf.compute(ReflectivityOverQ)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def basic_estia_plot(style: str):\n",
+ " with plt.style.context(style):\n",
+ " fig, ax = plt.subplots(layout='constrained', figsize=(3, 2.5))\n",
+ " _ = reflectivity.hist(Q=150).plot(ax=ax, norm='log')\n",
+ " ax.set_xlim((0.13, 0.53))\n",
+ " ax.set_xlabel(r'$Q$ [1/Å]')\n",
+ " ax.set_ylabel(r'$R(Q)$')\n",
+ " return fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = basic_estia_plot('default')\n",
+ "fig.savefig(\n",
+ " \"../../docs/_static/thumbnails/estia_mcstas_reduction_light.svg\",\n",
+ " transparent=True,\n",
+ ")\n",
+ "fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = basic_estia_plot('dark_background')\n",
+ "fig.savefig(\n",
+ " \"../../docs/_static/thumbnails/estia_mcstas_reduction_dark.svg\",\n",
+ " transparent=True,\n",
+ ")\n",
+ "fig"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8",
+ "metadata": {},
+ "source": [
+ "## Advanced McStas workflow"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "MaskedReflectivityOverQ = NewType('MaskedReflectivityOverQ', sc.DataArray)\n",
+ "\n",
+ "def mask_noisy_reference(\n",
+ " reflectivity: ReflectivityOverQ,\n",
+ " reference: Reference,\n",
+ ") -> MaskedReflectivityOverQ:\n",
+ " ref = reference.hist(Q=reflectivity.coords['Q'])\n",
+ " return reflectivity.assign_masks(\n",
+ " noisy_reference= sc.stddevs(ref).data > 0.3 * ref.data\n",
+ " )\n",
+ "\n",
+ "wf.insert(mask_noisy_reference)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "param_table = pd.DataFrame({\n",
+ " Filename[SampleRun]: estia_mcstas_example('Ni/Ti-multilayer')\n",
+ "}).rename_axis(index='sample_rotation')\n",
+ "\n",
+ "# Make a copy to preserve the original `wf`.\n",
+ "multi_file_workflow = wf.copy()\n",
+ "mapped = multi_file_workflow[MaskedReflectivityOverQ].map(param_table)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def combine_measurements(*measurements: sc.DataArray) -> sc.DataGroup[sc.DataArray]:\n",
+ " return sc.DataGroup({\n",
+ " f\"{da.coords['sample_rotation']:c}\": da for da in measurements\n",
+ " })\n",
+ "\n",
+ "multi_file_workflow[MaskedReflectivityOverQ] = mapped.reduce(\n",
+ " func=combine_measurements\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "multi_file_workflow.visualize(\n",
+ " MaskedReflectivityOverQ,\n",
+ " graph_attr={\"rankdir\": \"LR\"},\n",
+ " compact=True,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "samples = list(sciline.compute_mapped(multi_file_workflow, Sample))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def advanced_estia_plot(style: str):\n",
+ " with plt.style.context(style):\n",
+ " fig, ax = plt.subplots(layout='constrained', figsize=(3, 2.5))\n",
+ " _ = q_theta_figure(samples, q_bins=100, theta_bins=100, ax=ax)\n",
+ " ax.set_xlim((0.0, 0.53))\n",
+ " ax.set_ylim((0.0, 0.15))\n",
+ " ax.set_xlabel(r'$Q$ [1/Å]')\n",
+ " ax.set_ylabel(r'$\\theta$ [rad]')\n",
+ " fig.axes[-1].set_ylabel(None)\n",
+ " return fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "15",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = advanced_estia_plot('default')\n",
+ "fig.savefig(\n",
+ " \"../../docs/_static/thumbnails/estia_advanced_mcstas_reduction_light.svg\",\n",
+ " transparent=True,\n",
+ ")\n",
+ "fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = advanced_estia_plot('dark_background')\n",
+ "fig.savefig(\n",
+ " \"../../docs/_static/thumbnails/estia_advanced_mcstas_reduction_dark.svg\",\n",
+ " transparent=True,\n",
+ ")\n",
+ "fig"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}