Skip to content

Commit f8f6b39

Browse files
Merge pull request #90 from scipp/refactor-visualizations
Refactor visualizations
2 parents 271ea3a + 53be611 commit f8f6b39

File tree

10 files changed

+839
-179
lines changed

10 files changed

+839
-179
lines changed

docs/api-reference/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@
5252
orso
5353
resolution
5454
types
55+
utils
56+
figures
5557
```

docs/user-guide/amor/amor-reduction.ipynb

Lines changed: 110 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,22 @@
160160
" '611': sc.scalar(5.05, unit='deg'),\n",
161161
"}\n",
162162
"\n",
163-
"results = {}\n",
163+
"reflectivity = {}\n",
164164
"for file, angle in runs.items():\n",
165165
" workflow[Filename[SampleRun]] = amor.data.amor_sample_run(file)\n",
166166
" workflow[SampleRotation[SampleRun]] = angle\n",
167-
" results[file] = workflow.compute(ReflectivityOverQ).hist()\n",
167+
" reflectivity[file] = workflow.compute(ReflectivityOverQ).hist()\n",
168168
"\n",
169-
"sc.plot(results, norm='log', vmin=1e-4)"
169+
"sc.plot(reflectivity, norm='log', vmin=1e-4)"
170+
]
171+
},
172+
{
173+
"cell_type": "markdown",
174+
"metadata": {},
175+
"source": [
176+
"## Scaling the reflectivity curves to overlap\n",
177+
"\n",
178+
"In case we know the curves are have been scaled by different factors (that are constant in Q) it can be useful to scale them so they overlap:"
170179
]
171180
},
172181
{
@@ -176,12 +185,16 @@
176185
"outputs": [],
177186
"source": [
178187
"from ess.reflectometry.tools import scale_reflectivity_curves_to_overlap\n",
179-
"results_scaled = dict(zip(\n",
180-
" results.keys(),\n",
181-
" scale_reflectivity_curves_to_overlap(results.values())[0],\n",
182-
" strict=True\n",
183-
"))\n",
184-
"sc.plot(results_scaled, norm='log', vmin=1e-5)"
188+
"\n",
189+
"scaled_reflectivity_curves, scale_factors = scale_reflectivity_curves_to_overlap(reflectivity.values())\n",
190+
"sc.plot(dict(zip(reflectivity.keys(), scaled_reflectivity_curves, strict=True)), norm='log', vmin=1e-5)"
191+
]
192+
},
193+
{
194+
"cell_type": "markdown",
195+
"metadata": {},
196+
"source": [
197+
"Curves obtained from measurements at different angles can be combined to one common reflectivity curve:"
185198
]
186199
},
187200
{
@@ -191,15 +204,28 @@
191204
"outputs": [],
192205
"source": [
193206
"from ess.reflectometry.tools import combine_curves\n",
194-
"c = combine_curves(results_scaled.values(), workflow.compute(QBins))\n",
195-
"c.plot(norm='log')"
207+
"combined = combine_curves(scaled_reflectivity_curves, workflow.compute(QBins))\n",
208+
"combined.plot(norm='log')"
196209
]
197210
},
198211
{
199212
"cell_type": "markdown",
200213
"metadata": {},
201214
"source": [
202-
"### Additional diagnostics plots"
215+
"## Diagnostic figures"
216+
]
217+
},
218+
{
219+
"cell_type": "markdown",
220+
"metadata": {},
221+
"source": [
222+
"There are some useful visualizations that can be used to troubleshoot the instrument.\n",
223+
"They typically operate on the `ReflectivityData`.\n",
224+
"\n",
225+
"The difference between `ReflectivityData` and `ReflectivityOverQ` is that `ReflectivityData` is not binned in $Q$, but instead has the same shape as the reference.\n",
226+
"\n",
227+
"Essentially it represents a \"reflectivity\" computed in every wavelength-detector coordinate (`z_index`) bin.\n",
228+
"This makes it easier to spot inhomogeneities and diagnose problems."
203229
]
204230
},
205231
{
@@ -208,16 +234,23 @@
208234
"metadata": {},
209235
"outputs": [],
210236
"source": [
211-
"workflow[Filename[SampleRun]] = amor.data.amor_sample_run(608)\n",
212-
"workflow[SampleRotation[SampleRun]] = sc.scalar(0.85, unit='deg')\n",
213-
"workflow.compute(ReflectivityDiagnosticsView)"
237+
"# Start by computing the `ReflectivityData` for each of the files\n",
238+
"diagnostics = {}\n",
239+
"for file, angle in runs.items():\n",
240+
" workflow[Filename[SampleRun]] = amor.data.amor_sample_run(file)\n",
241+
" workflow[SampleRotation[SampleRun]] = angle\n",
242+
" diagnostics[file] = workflow.compute((ReflectivityData, ThetaBins[SampleRun]))\n",
243+
"\n",
244+
"# Scale the results using the scale factors computed earlier\n",
245+
"for key, scale_factor in zip(reflectivity.keys(), scale_factors, strict=True):\n",
246+
" diagnostics[key][ReflectivityData] *= scale_factor"
214247
]
215248
},
216249
{
217250
"cell_type": "markdown",
218251
"metadata": {},
219252
"source": [
220-
"## Make a $(\\lambda, \\theta)$ map\n",
253+
"### Make a $(\\lambda, \\theta)$ map\n",
221254
"A good sanity check is to create a two-dimensional map of the counts in $\\lambda$ and $\\theta$ bins and make sure the triangles converge at the origin."
222255
]
223256
},
@@ -227,7 +260,13 @@
227260
"metadata": {},
228261
"outputs": [],
229262
"source": [
230-
"workflow.compute(WavelengthThetaFigure)"
263+
"from ess.amor.figures import wavelength_theta_figure\n",
264+
"\n",
265+
"wavelength_theta_figure(\n",
266+
" [res[ReflectivityData] for res in diagnostics.values()],\n",
267+
" theta_bins=[res[ThetaBins[SampleRun]] for res in diagnostics.values()],\n",
268+
" q_edges_to_display=(sc.scalar(0.018, unit='1/angstrom'), sc.scalar(0.113, unit='1/angstrom'))\n",
269+
")"
231270
]
232271
},
233272
{
@@ -237,6 +276,60 @@
237276
"This plot can be used to check if the value of the sample rotation angle $\\omega$ is correct. The bright triangles should be pointing back to the origin $\\lambda = \\theta = 0$. In the figure above the black lines are all passing through the origin."
238277
]
239278
},
279+
{
280+
"cell_type": "markdown",
281+
"metadata": {},
282+
"source": [
283+
"### Make a $(Q, \\theta)$ map\n",
284+
"Another good sanity check is to create a two-dimensional map of the counts in $\\lambda$ and $Q$ and make sure the stripes are vertical. If they are not that could indicate that the `ChopperPhase` setting is incorrect."
285+
]
286+
},
287+
{
288+
"cell_type": "code",
289+
"execution_count": null,
290+
"metadata": {},
291+
"outputs": [],
292+
"source": [
293+
"from ess.amor.figures import q_theta_figure\n",
294+
"\n",
295+
"q_theta_figure(\n",
296+
" [res[ReflectivityData] for res in diagnostics.values()],\n",
297+
" theta_bins=[res[ThetaBins[SampleRun]] for res in diagnostics.values()],\n",
298+
" q_bins=workflow.compute(QBins)\n",
299+
")"
300+
]
301+
},
302+
{
303+
"cell_type": "markdown",
304+
"metadata": {},
305+
"source": [
306+
"### Compare the sample measurement to the reference on the detector\n",
307+
"\n",
308+
"Here we compare the raw number of counts on the detector for the sample measurement and the reference respectively.\n",
309+
"\n",
310+
"`z_index` is the $z-$detector coordinate, that is, the detector coordinate in the direction of the scattering angle $\\theta$."
311+
]
312+
},
313+
{
314+
"cell_type": "code",
315+
"execution_count": null,
316+
"metadata": {},
317+
"outputs": [],
318+
"source": [
319+
"from ess.amor.figures import wavelength_z_figure\n",
320+
"\n",
321+
"workflow[Filename[SampleRun]] = amor.data.amor_sample_run('608')\n",
322+
"workflow[SampleRotation[SampleRun]] = runs['608']\n",
323+
"wavelength_z_figure(\n",
324+
" workflow.compute(FootprintCorrectedData[SampleRun]),\n",
325+
" wavelength_bins=workflow.compute(WavelengthBins),\n",
326+
" grid=False\n",
327+
") + wavelength_z_figure(\n",
328+
" reference_result,\n",
329+
" grid=False\n",
330+
")"
331+
]
332+
},
240333
{
241334
"cell_type": "markdown",
242335
"metadata": {},

src/ess/amor/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
SamplePosition,
1717
BeamDivergenceLimits,
1818
)
19-
from . import conversions, load, orso, resolution, utils
19+
from . import conversions, load, orso, resolution, utils, figures
2020
from .instrument_view import instrument_view
2121
from .types import (
2222
AngularResolution,
@@ -44,6 +44,7 @@
4444
*conversions.providers,
4545
*resolution.providers,
4646
*utils.providers,
47+
*figures.providers,
4748
*orso.providers,
4849
)
4950
"""

0 commit comments

Comments
 (0)