Skip to content

Commit 17e3a27

Browse files
authored
Merge pull request #66 from tiqi-group/12-add-scan-pattern-selection-dropdown-to-replace-scatter-checkbox
12 add scan pattern selection dropdown to replace scatter checkbox
2 parents c50f40a + 831dcc1 commit 17e3a27

File tree

10 files changed

+129
-85
lines changed

10 files changed

+129
-85
lines changed

frontend/src/components/scanInterface/ParameterCard.tsx

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,54 @@ import { useContext, useMemo, useState } from "react";
1313
import { DeviceInfoContext } from "../../contexts/DeviceInfoContext";
1414
import { ParameterDisplayGroupsContext } from "../../contexts/ParameterDisplayGroupsContext";
1515
import { useScanContext } from "../../hooks/useScanContext";
16-
import { ScanParameterInfo } from "../../types/ScanParameterInfo";
16+
import {
17+
ScanParameterInfo,
18+
ScanPattern,
19+
scanPatterns,
20+
} from "../../types/ScanParameterInfo";
1721

1822
const generateScanValues = (
1923
start: number,
2024
stop: number,
2125
points: number,
22-
scatter: boolean,
26+
pattern: ScanPattern,
2327
) => {
24-
const values = Array.from(
25-
{ length: points },
26-
(_, i) => start + (i * (stop - start)) / (points - 1),
27-
);
28-
return scatter ? values.sort(() => Math.random() - 0.5) : values;
28+
const linspace = (n: number) =>
29+
Array.from({ length: n }, (_, i) => start + (i * (stop - start)) / (n - 1));
30+
31+
switch (pattern) {
32+
case "linear":
33+
return linspace(points);
34+
case "scatter":
35+
return linspace(points).sort(() => Math.random() - 0.5);
36+
case "centred": {
37+
const base = linspace(points);
38+
const mid = Math.floor((points - 1) / 2);
39+
const order = [mid];
40+
for (let k = 1; order.length < points; k++) {
41+
if (mid - k >= 0) order.push(mid - k);
42+
if (mid + k < points) order.push(mid + k);
43+
}
44+
return order.map((i) => base[i]);
45+
}
46+
case "forwardReverse": {
47+
const base = linspace(points);
48+
return [...base, ...base.reverse()];
49+
}
50+
}
51+
};
52+
53+
const renderPatternLabel = (pattern: ScanPattern): string => {
54+
switch (pattern) {
55+
case "linear":
56+
return "Linear";
57+
case "scatter":
58+
return "Scatter";
59+
case "centred":
60+
return "Centred";
61+
case "forwardReverse":
62+
return "Forward and reverse";
63+
}
2964
};
3065

3166
export const ParameterCard = ({
@@ -96,6 +131,8 @@ export const ParameterCard = ({
96131
);
97132
}, [param, parameterDisplayGroups, deviceInfo]);
98133

134+
const pattern = param.generation.pattern ?? "linear";
135+
99136
return (
100137
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
101138
<div
@@ -196,9 +233,7 @@ export const ParameterCard = ({
196233
dispatchScanInfoStateUpdate({
197234
type: "UPDATE_PARAMETER",
198235
index,
199-
payload: {
200-
id: e.target.value,
201-
},
236+
payload: { id: e.target.value },
202237
});
203238
}}
204239
renderValue={(value) => {
@@ -238,7 +273,7 @@ export const ParameterCard = ({
238273
Number(e.target.value),
239274
param.generation.stop,
240275
param.generation.points,
241-
param.generation.scatter,
276+
pattern,
242277
),
243278
},
244279
})
@@ -273,7 +308,7 @@ export const ParameterCard = ({
273308
param.generation.start,
274309
Number(e.target.value),
275310
param.generation.points,
276-
param.generation.scatter,
311+
pattern,
277312
),
278313
},
279314
})
@@ -309,7 +344,7 @@ export const ParameterCard = ({
309344
param.generation.start,
310345
param.generation.stop,
311346
Number(e.target.value),
312-
param.generation.scatter,
347+
pattern,
313348
),
314349
},
315350
})
@@ -324,26 +359,32 @@ export const ParameterCard = ({
324359
}}
325360
/>
326361
</div>
327-
<FormControlLabel
328-
control={
329-
<Checkbox
330-
checked={param.generation.scatter ?? false}
331-
onChange={(e) => {
332-
dispatchScanInfoStateUpdate({
333-
type: "UPDATE_PARAMETER",
334-
index: index!,
335-
payload: {
336-
generation: {
337-
...param.generation,
338-
scatter: e.target.checked,
339-
},
362+
<FormControl fullWidth size="small">
363+
<InputLabel>Scan pattern</InputLabel>
364+
<Select
365+
label="Scan pattern"
366+
value={pattern}
367+
onChange={(e) => {
368+
dispatchScanInfoStateUpdate({
369+
type: "UPDATE_PARAMETER",
370+
index: index!,
371+
payload: {
372+
generation: {
373+
...param.generation,
374+
pattern: e.target.value as ScanPattern,
340375
},
341-
});
342-
}}
343-
/>
344-
}
345-
label="Scatter"
346-
/>
376+
},
377+
});
378+
}}
379+
renderValue={(selected) => renderPatternLabel(selected as ScanPattern)}
380+
>
381+
{scanPatterns.map((pattern) => (
382+
<MenuItem key={pattern} value={pattern}>
383+
{renderPatternLabel(pattern)}
384+
</MenuItem>
385+
))}
386+
</Select>
387+
</FormControl>
347388
</>
348389
) : (
349390
<>

frontend/src/hooks/useScanInfoState.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type ScanInfoAction =
1818
const defaultParameter: ScanParameterInfo = {
1919
id: "",
2020
values: [0, 1],
21-
generation: { start: 0, stop: 1, points: 2, scatter: false },
21+
generation: { start: 0, stop: 1, points: 2, pattern: "linear" },
2222
namespace: "",
2323
deviceNameOrDisplayGroup: "",
2424
};

frontend/src/types/ScanParameterInfo.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
export const scanPatterns = ["linear", "scatter", "centred", "forwardReverse"] as const;
2+
export type ScanPattern = (typeof scanPatterns)[number];
3+
14
export interface ScanParameterInfo {
25
id: string;
36
deviceNameOrDisplayGroup: string;
@@ -7,7 +10,7 @@ export interface ScanParameterInfo {
710
start: number;
811
stop: number;
912
points: number;
10-
scatter: boolean;
13+
pattern: ScanPattern;
1114
};
1215
n_scan_points?: number;
1316
}

frontend/src/utils/windowUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { authority, forwardedProto } from "../socket";
1+
import { forwardedPrefix } from "../socket";
22

33
export function openJobWindow(jobId: string | number, experimentId: string) {
4-
const baseUrl = `${forwardedProto}://${authority}`;
4+
const baseUrl = `${window.location.origin}${forwardedPrefix}`;
55
const url = `${baseUrl}/data/${jobId}`;
66
const storageKey = `jobWindow:${experimentId}`;
77

frontend/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"resolveJsonModule": true,
1515
"isolatedModules": true,
1616
"noEmit": true,
17-
"jsx": "react-jsx"
17+
"jsx": "react-jsx",
18+
"noImplicitReturns": true
1819
},
1920
"include": ["src"]
2021
}

src/icon/server/data_access/repositories/experiment_data_repository.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class ExperimentData:
124124
parameters: dict[str, ParameterValue]
125125
"""Mapping of parameter id to time series (tuple of timestamp str and value)."""
126126

127-
128127
def get_filename_by_job_id(job_id: int) -> str:
129128
"""Return the HDF5 filename for a job.
130129

0 commit comments

Comments
 (0)