Skip to content

Commit 304d0e3

Browse files
authored
Merge pull request #691 from scipp/slicer-instrument-view
New instrument view with better performance
2 parents 808f2f4 + 4223c26 commit 304d0e3

19 files changed

Lines changed: 619 additions & 731 deletions

.buildconfig/ci-linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies:
1616
- mantid==6.15.0
1717
- matplotlib==3.9.4
1818
- mpltoolbox==25.10.0
19-
- plopp==25.11.0
19+
- plopp==26.4.1
2020
- pooch==1.9.0
2121
- pydantic==2.12.4
2222
- pytest==8.3.3

docs/user-guide/instrument-view.ipynb

Lines changed: 115 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,186 +2,210 @@
22
"cells": [
33
{
44
"cell_type": "markdown",
5+
"id": "0",
56
"metadata": {},
67
"source": [
78
"# Instrument view\n",
89
"\n",
9-
"## Overview\n",
10+
"A simple version of the [Mantid instrument view](https://docs.mantidproject.org/nightly/workbench/instrumentviewer.html#instrumentviewer) is available in scippneutron.\n",
1011
"\n",
11-
"A simple version of the Mantid [instrument view](https://www.mantidproject.org/MantidPlot:_Instrument_View) is available in `scippneutron`.\n",
1212
"It currently does not support detector 'picking' and manual drawing of masks,\n",
1313
"nor does it render the actual shape of the detectors (currently it represents them as 2-D squares),\n",
14-
"but basic functionalities such as spatial slicing,\n",
15-
"as well as navigation through the time-of-flight dimension via a slider, are provided."
14+
"but basic functionalities such as spatial slicing, as well as navigation through the time-of-flight dimension via a slider, are provided."
1615
]
1716
},
1817
{
19-
"cell_type": "markdown",
18+
"cell_type": "code",
19+
"execution_count": null,
20+
"id": "1",
2021
"metadata": {},
22+
"outputs": [],
2123
"source": [
22-
"<div class=\"alert alert-info\">\n",
23-
"\n",
24-
"**Note**\n",
25-
"\n",
26-
"The file used in this notebook is from the Mantid [training course data](https://www.mantidproject.org/installation/index#sample-data).\n",
27-
"\n",
28-
"</div>"
24+
"import scipp as sc\n",
25+
"import scippneutron as scn\n",
26+
"from scippneutron import data"
2927
]
3028
},
3129
{
3230
"cell_type": "markdown",
31+
"id": "2",
3332
"metadata": {},
3433
"source": [
35-
"<div class=\"alert alert-warning\">\n",
34+
"## Load the data\n",
3635
"\n",
37-
"**Warning**\n",
38-
" \n",
39-
"While you can interact with the 3D view of the instrument,\n",
40-
"the buttons and sliders will have no effect in the documentation pages,\n",
41-
"as there is no kernel to perform the operations.\n",
42-
"These will only work inside a Jupyter notebook.\n",
43-
"\n",
44-
"</div>"
36+
"We load an example dataset for the Dream (ESS) instrument.\n",
37+
"In each detector bank, the data is organised by `wire`, `strip`, `module`, `segment`, and `counter`."
4538
]
4639
},
4740
{
48-
"cell_type": "markdown",
41+
"cell_type": "code",
42+
"execution_count": null,
43+
"id": "3",
4944
"metadata": {},
45+
"outputs": [],
5046
"source": [
51-
"We load a file containing a `position` coordinate:"
47+
"dg = data.example_dream_data()\n",
48+
"dg"
5249
]
5350
},
5451
{
55-
"cell_type": "code",
56-
"execution_count": null,
57-
"metadata": {},
58-
"outputs": [],
52+
"cell_type": "markdown",
53+
"id": "4",
54+
"metadata": {
55+
"editable": true,
56+
"slideshow": {
57+
"slide_type": ""
58+
},
59+
"tags": []
60+
},
5961
"source": [
60-
"import numpy as np\n",
61-
"import scipp as sc\n",
62-
"import scippneutron as scn\n",
63-
"import scippneutron.data"
62+
"## Full instrument view\n",
63+
"\n",
64+
"We first histogram the data along the time-of-flight (`tof`) dimension,\n",
65+
"making sure the same bins are used for all elements:"
6466
]
6567
},
6668
{
6769
"cell_type": "code",
6870
"execution_count": null,
69-
"metadata": {},
71+
"id": "5",
72+
"metadata": {
73+
"editable": true,
74+
"slideshow": {
75+
"slide_type": ""
76+
},
77+
"tags": []
78+
},
7079
"outputs": [],
7180
"source": [
72-
"sample = scn.data.powder_sample()['data'].hist()\n",
73-
"sample"
81+
"tof_edges = sc.linspace(\"tof\", 1.0e7, 1.0e8, 51, unit=\"ns\", dtype=int)\n",
82+
"histogram = dg.hist(tof=tof_edges)"
7483
]
7584
},
7685
{
7786
"cell_type": "markdown",
78-
"metadata": {},
87+
"id": "6",
88+
"metadata": {
89+
"editable": true,
90+
"slideshow": {
91+
"slide_type": ""
92+
},
93+
"tags": []
94+
},
7995
"source": [
80-
"The `instrument_view` function can now be used to display a 3-D representation:"
96+
"We now use the `instrument_view` function to show the 3D view of the instrument pixels,\n",
97+
"specifying that we wish to have a slider along the `tof` dimension:"
8198
]
8299
},
83100
{
84101
"cell_type": "code",
85102
"execution_count": null,
86-
"metadata": {},
103+
"id": "7",
104+
"metadata": {
105+
"editable": true,
106+
"slideshow": {
107+
"slide_type": ""
108+
},
109+
"tags": []
110+
},
87111
"outputs": [],
88112
"source": [
89-
"scn.instrument_view(sample)"
113+
"full_view = scn.instrument_view(histogram, dim=\"tof\")\n",
114+
"full_view"
90115
]
91116
},
92117
{
93118
"cell_type": "markdown",
94-
"metadata": {},
119+
"id": "8",
120+
"metadata": {
121+
"editable": true,
122+
"slideshow": {
123+
"slide_type": ""
124+
},
125+
"tags": []
126+
},
95127
"source": [
96-
"The <img src='https://upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Font_Awesome_5_solid_cube.svg/240px-Font_Awesome_5_solid_cube.svg.png' width=\"20\"/>\n",
97-
"button in the toolbar activates a tool that lets you can create spatial cuts to slice your data in 3D.\n",
128+
"Note that it is possible to use any dimension for the slider instead of `tof`, such as `wavelength` (if present in the data).\n",
129+
"\n",
130+
"## Displaying individual detector elements\n",
98131
"\n",
99-
"It is possible to customize the figure using the usual arguments, as well as adjusting the pixel size, e.g."
132+
"It is also possible to view a single detector element, selecting e.g. `mantle` from the original data:"
100133
]
101134
},
102135
{
103136
"cell_type": "code",
104137
"execution_count": null,
105-
"metadata": {},
138+
"id": "9",
139+
"metadata": {
140+
"editable": true,
141+
"slideshow": {
142+
"slide_type": ""
143+
},
144+
"tags": []
145+
},
106146
"outputs": [],
107147
"source": [
108-
"scn.instrument_view(\n",
109-
" sample, cmap=\"magma\", vmax=2000.0 * sc.units.counts, norm=\"log\", pixel_size=0.03\n",
110-
")"
148+
"mantle_view = scn.instrument_view(histogram[\"mantle\"], dim=\"tof\")\n",
149+
"mantle_view"
111150
]
112151
},
113152
{
114153
"cell_type": "markdown",
154+
"id": "10",
115155
"metadata": {},
116156
"source": [
117-
"## Displaying additional components\n",
118-
"\n",
119-
"Additional beamline components can be displayed in the instrument view by providing a `dict` of component settings.\n",
120-
"As we can see above, the loaded data array also contains `source_position` and `sample_position` stored as 3-D vector coordinates.\n",
121-
"This is in addition to the `position` coordinate, which defines only the positions of detector pixels.\n",
157+
"The instrument view is designed to be flexible in terms of what it accepts as input.\n",
158+
"This means that you can easily inspect, for example, a single module by using the usual slicing notation for data arrays.\n",
122159
"\n",
123-
"Apart from `position`, the `instrument_view` does not require data arrays to follow a pre-defined naming convention for additional components.\n",
124-
"Instead it relies on the aforementioned `dict` of components, which can be customized, e.g., for a particular beamline.\n",
160+
"The `dim` argument can also be omitted; in this case a reduction `operation` (sum by default) along all non-position dimensions is applied to the data before displaying.\n",
125161
"\n",
126-
"The `dict` key of the component is used as the text label.\n",
127-
"Component settings are given in the form of a dictionary defining, e.g., `color`, `size`, and `type`.\n",
128-
"We can pick from a limited number of `type`s including `cylinder`, `disk` and `box`:"
162+
"Below, we display the first module in the backward end-cap detector, without a `tof` slider:"
129163
]
130164
},
131165
{
132166
"cell_type": "code",
133167
"execution_count": null,
168+
"id": "11",
134169
"metadata": {},
135170
"outputs": [],
136171
"source": [
137-
"sample_settings = {\n",
138-
" 'center': sample.coords['sample_position'],\n",
139-
" 'color': '#000000',\n",
140-
" 'wireframe': True,\n",
141-
" 'size': sc.vector(value=[0.3, 0.3, 0.3], unit=sc.units.m),\n",
142-
" 'type': 'box',\n",
143-
"}\n",
144-
"source_settings = {\n",
145-
" 'center': sample.coords['source_position'],\n",
146-
" 'color': '#FFC133',\n",
147-
" 'size': sc.vector(value=[1000, 2000, 1000], unit=sc.units.mm),\n",
148-
" 'type': 'cylinder',\n",
149-
"}\n",
150-
"scn.instrument_view(\n",
151-
" sample, components={'sample': sample_settings, 'source': source_settings}\n",
152-
")"
172+
"scn.instrument_view(dg[\"endcap_backward\"][\"module\", 0].hist())"
153173
]
154174
},
155175
{
156176
"cell_type": "markdown",
177+
"id": "12",
157178
"metadata": {},
158179
"source": [
159-
"## Defining detector positions\n",
180+
"## Spatial slicing\n",
181+
"\n",
182+
"A tool for selecting parts of the displayed detectors is available by clicking the 'layers' (last) button in the toolbar.\n",
160183
"\n",
161-
"If data comes without pre-defined detector-positions, e.g., when they are not contained in the original file, they can be defined by simply adding a `position` coordinate to a data array:"
184+
"Adding and moving selection regions can help inspect data inside volumetric detectors:"
162185
]
163186
},
164187
{
165188
"cell_type": "code",
166189
"execution_count": null,
190+
"id": "13",
167191
"metadata": {},
168192
"outputs": [],
169193
"source": [
170-
"nx, ny = (10, 10)\n",
171-
"points_x = np.linspace(0, 1, nx)\n",
172-
"points_y = np.linspace(0, 1, ny)\n",
173-
"xv, yv = np.meshgrid(points_x, points_y)\n",
174-
"\n",
175-
"_x = sc.array(dims=['spectrum'], values=xv.ravel())\n",
176-
"_y = sc.array(dims=['spectrum'], values=yv.ravel())\n",
177-
"_z = sc.array(dims=['spectrum'], values=np.zeros(100))\n",
178-
"\n",
179-
"data = sc.arange('spectrum', 100.0, unit='counts')\n",
180-
"da = sc.DataArray(data)\n",
181-
"da.coords['position'] = sc.spatial.as_vectors(_x, _y, _z)\n",
182-
"da.coords['spectrum'] = sc.arange('spectrum', 100)\n",
183-
"\n",
184-
"scn.instrument_view(da, pixel_size=0.1)"
194+
"mantle_view = scn.instrument_view(histogram[\"mantle\"], dim=\"tof\")\n",
195+
"mantle_view"
196+
]
197+
},
198+
{
199+
"cell_type": "code",
200+
"execution_count": null,
201+
"id": "14",
202+
"metadata": {
203+
"nbsphinx": "hidden"
204+
},
205+
"outputs": [],
206+
"source": [
207+
"mantle_view.toolbar['cut3d'].value = True\n",
208+
"mantle_view.bottom_bar.children[0][0]._add_cut('y')"
185209
]
186210
}
187211
],
@@ -201,9 +225,9 @@
201225
"name": "python",
202226
"nbconvert_exporter": "python",
203227
"pygments_lexer": "ipython3",
204-
"version": "3.11.14"
228+
"version": "3.12.12"
205229
}
206230
},
207231
"nbformat": 4,
208-
"nbformat_minor": 4
232+
"nbformat_minor": 5
209233
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ dependencies = [
3737
"lazy_loader>=0.4",
3838
"mpltoolbox>=24.6.0",
3939
"numpy>=1.20",
40-
"plopp>=24.09.1",
40+
"plopp>=26.4.1",
4141
"pydantic>=2",
4242
"scipp>=24.07.0",
4343
"scippnexus>=23.11.0",

0 commit comments

Comments
 (0)