From e15b16c0feaca9316d5733b3e611121cdfdecabb Mon Sep 17 00:00:00 2001 From: Tom Kane Date: Fri, 9 Oct 2026 16:15:48 +0000 Subject: [PATCH 1/3] tidy up plane enum --- apps/visr/src/components/tomography/SliceViewer.tsx | 8 +++++++- .../visr/src/components/tomography/TomographyControls.tsx | 2 +- apps/visr/src/components/tomography/TomographyPlots.tsx | 2 +- apps/visr/src/components/tomography/TomographyView.tsx | 2 +- .../src/components/tomography/{PlaneEnum.tsx => plane.ts} | 0 5 files changed, 10 insertions(+), 4 deletions(-) rename apps/visr/src/components/tomography/{PlaneEnum.tsx => plane.ts} (100%) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 0ed5f855..876c1396 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -1,9 +1,15 @@ import { Box } from "@mui/material"; -import { Plane } from "./PlaneEnum"; import { HeatmapPlot } from "@diamondlightsource/davidia"; import ndarray from "ndarray"; import createArrayFromView from "../../utils/createArrayFromView"; +// Not importing Plane in case we move SliceViewer somewhere else as a generic component +export enum Plane { + X, + Y, + Z, +} + interface Props { volumeData: Uint8Array; volumeShape: [number, number, number]; diff --git a/apps/visr/src/components/tomography/TomographyControls.tsx b/apps/visr/src/components/tomography/TomographyControls.tsx index e4bb73dc..cdc2c0ef 100644 --- a/apps/visr/src/components/tomography/TomographyControls.tsx +++ b/apps/visr/src/components/tomography/TomographyControls.tsx @@ -6,7 +6,7 @@ import { Slider, Typography, } from "@mui/material"; -import { Plane } from "./PlaneEnum"; +import { Plane } from "./plane"; interface Props { onSlide: (event: Event, newValue: number | number[]) => void; diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 3e0a6b50..c771d949 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -3,7 +3,7 @@ import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; import { useLayoutEffect, useState } from "react"; import SliceViewer from "./SliceViewer"; import VolumeRenderer from "./VolumeRenderer"; -import { Plane } from "./PlaneEnum"; +import { Plane } from "./plane"; // --------------------------------------------------------------------------- // Types diff --git a/apps/visr/src/components/tomography/TomographyView.tsx b/apps/visr/src/components/tomography/TomographyView.tsx index bbd05410..47b27473 100644 --- a/apps/visr/src/components/tomography/TomographyView.tsx +++ b/apps/visr/src/components/tomography/TomographyView.tsx @@ -2,7 +2,7 @@ import { Box } from "@mui/material"; import { useEffect, useState } from "react"; import TomographyControls from "./TomographyControls"; import { TomographyForm } from "./TomographyForm"; -import { Plane } from "./PlaneEnum"; +import { Plane } from "./plane"; import ControlsDrawer from "../ControlsDrawer"; import TomographyPlots from "./TomographyPlots"; diff --git a/apps/visr/src/components/tomography/PlaneEnum.tsx b/apps/visr/src/components/tomography/plane.ts similarity index 100% rename from apps/visr/src/components/tomography/PlaneEnum.tsx rename to apps/visr/src/components/tomography/plane.ts From 0188a51052904381d972aae109ffe1119621b344 Mon Sep 17 00:00:00 2001 From: Tom Kane Date: Fri, 9 Oct 2026 16:16:56 +0000 Subject: [PATCH 2/3] add route for enz locum data to arrive, and controls to switch to it, plus empty plots --- .../spectroscopy/SpectroscopyControls.tsx | 48 ++++++++++ .../spectroscopy/SpectroscopyPlots.tsx | 90 +++++++++++++++---- .../spectroscopy/SpectroscopyView.tsx | 15 +++- .../src/components/spectroscopy/dataSource.ts | 4 + .../spectroscopy/useSpectroscopyData.ts | 2 +- 5 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 apps/visr/src/components/spectroscopy/SpectroscopyControls.tsx create mode 100644 apps/visr/src/components/spectroscopy/dataSource.ts diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyControls.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyControls.tsx new file mode 100644 index 00000000..c7fe7ff6 --- /dev/null +++ b/apps/visr/src/components/spectroscopy/SpectroscopyControls.tsx @@ -0,0 +1,48 @@ +import { + Box, + FormControlLabel, + Radio, + RadioGroup, + Typography, +} from "@mui/material"; +import { DataSource } from "./dataSource"; + +interface Props { + onSetDataSource: (event: React.ChangeEvent) => void; + dataSource: DataSource; +} + +export default function Controls({ onSetDataSource, dataSource }: Props) { + return ( + + + Plots + + + + + Data Source + + + } + label="Camera" + /> + } + label="Diodes" + /> + + + + ); +} diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index 5c32835e..600c54cb 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -4,6 +4,7 @@ import ndarray from "ndarray"; import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; import { useLayoutEffect, useState, type ComponentProps } from "react"; import { useSpectroscopyData, type RGBColour } from "./useSpectroscopyData"; +import { DataSource } from "./dataSource"; // --------------------------------------------------------------------------- // Helpers: data conversion @@ -72,7 +73,11 @@ async function fetchMap( datapath: string, colour: RGBColour, snake: boolean, -) { + dataSource: DataSource, +): Promise { + // while there is only one data source fake fetch + if (dataSource === DataSource.Diodes) return null; + // add data source string from enum ('camera' or 'diodes') when enz-locum data is available const url = `/api/data/map?filepath=${encodeURIComponent(filepath)}&datapath=${encodeURIComponent(datapath)}&snake=${encodeURIComponent(snake)}`; const resp = await fetch(url); if (!resp.ok) throw new Error(resp.statusText); @@ -80,6 +85,20 @@ async function fetchMap( return toNDT(mapResponse.values, colour); } +const fetchCamera = ( + filepath: string, + datapath: string, + colour: RGBColour, + snake: boolean, +) => fetchMap(filepath, datapath, colour, snake, DataSource.Camera); + +const fetchDiodes = ( + filepath: string, + datapath: string, + colour: RGBColour, + snake: boolean, +) => fetchMap(filepath, datapath, colour, snake, DataSource.Diodes); + // --------------------------------------------------------------------------- // Channel definitions // --------------------------------------------------------------------------- @@ -88,7 +107,7 @@ const CHANNELS = [ { key: "red", label: "Red channel" }, { key: "green", label: "Green channel" }, { key: "blue", label: "Blue channel" }, - //{ key: "gray", label: "Gray channel" }, + //{ key: "gray?", label: "Composite" }, ] as const; type ChannelKey = (typeof CHANNELS)[number]["key"]; @@ -100,15 +119,22 @@ export type SpectroscopyData = Partial>; // --------------------------------------------------------------------------- interface SpectroscopyPlotsProps { + dataSource: DataSource; expanded: boolean; plotAspectRatio: number | "auto" | "equal"; } function SpectroscopyPlots({ + dataSource, expanded, plotAspectRatio, }: SpectroscopyPlotsProps) { - const { data: channels } = useSpectroscopyData(fetchMap); + const { data: cameraChannels } = useSpectroscopyData(fetchCamera); + const { data: diodeChannels } = useSpectroscopyData(fetchDiodes); + + const channels = + dataSource === DataSource.Camera ? cameraChannels : diodeChannels; + const { width, containerRef, mounted } = useContainerWidth(); // ------------------------------------------------------------------------- @@ -143,7 +169,7 @@ function SpectroscopyPlots({ const gridHeight = rowHeight * totalRows; // ------------------------------------------------------------------------- - // Layout: 3x1 collapsed, 2x2 expanded + // Layout: 4x1 collapsed, 2x2 expanded // ------------------------------------------------------------------------- const layout = [ { i: "0", x: 0, y: 0, w: w, h: rowsPerPlot, static: true }, @@ -156,22 +182,36 @@ function SpectroscopyPlots({ h: rowsPerPlot, static: true, }, + { + i: "3", + x: expanded ? 1 : 3, + y: expanded ? rowsPerPlot : 0, + w: w, + h: rowsPerPlot, + static: true, + }, ]; // ------------------------------------------------------------------------- // Views // ------------------------------------------------------------------------- - const views = CHANNELS.map(({ key }) => ( - - )); + const views = [ + ...CHANNELS.map(({ key }) => { + const values = channels[key]; + if (!values) return ; + return ( + + ); + }), + , + ]; - const titles = CHANNELS.map(({ label }) => label); + const titles = [...CHANNELS.map(({ label }) => label), "Composite"]; // ------------------------------------------------------------------------- // Plot cells @@ -216,6 +256,26 @@ function SpectroscopyPlots({ )); + // ------------------------------------------------------------------------- + // Empty plot + // ------------------------------------------------------------------------- + function EmptyPlot({ message }: { message: string }) { + return ( + + + {message} + + + ); + } + // ------------------------------------------------------------------------- // Render // ------------------------------------------------------------------------- @@ -237,7 +297,7 @@ function SpectroscopyPlots({ width={width} style={{ height: gridHeight }} gridConfig={{ - cols: expanded ? 2 : 3, + cols: expanded ? 2 : 4, rowHeight: rowHeight, margin: [0, 0], }} diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx index 137f41fa..3e4450f5 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx @@ -1,5 +1,6 @@ import { Box } from "@mui/material"; import SpectroscopyPlots from "./SpectroscopyPlots"; +import { DataSource } from "./dataSource"; import { useEffect, useState } from "react"; import { useScanEvents } from "../../hooks/scanEvents"; import { useSubmitWorkflow } from "../../hooks/useSubmitWorkflow"; @@ -7,6 +8,7 @@ import { useInstrumentSession } from "../../context/instrumentSession/useInstrum import { visitTextToVisit } from "../../utils/common"; import ControlsDrawer from "../ControlsDrawer"; import { SpectroscopyForm } from "./SpectroscopyForm"; +import SpectroscopyControls from "./SpectroscopyControls"; export type SpectroscopyFormData = { total_number_of_scan_points: number; @@ -26,6 +28,7 @@ const PLOT_ASPECT_RATIO = "equal"; function SpectroscopyView() { const [drawerOpen, setDrawerOpen] = useState(true); + const [dataSource, setDataSource] = useState(DataSource.Camera); // ------------------------------------------------------------------------- // Set off workflow when scan ends @@ -49,6 +52,9 @@ function SpectroscopyView() { } }, [scanEvent, instrumentSession, submitWorkflow]); + const handleSetDataSource = (event: React.ChangeEvent) => + setDataSource(event.target.value as DataSource); + // ------------------------------------------------------------------------- // Render // ------------------------------------------------------------------------- @@ -66,6 +72,7 @@ function SpectroscopyView() { }} > @@ -73,7 +80,13 @@ function SpectroscopyView() { open={drawerOpen} collapsedHeight={DRAWER_COLLAPSED_HEIGHT} onToggle={() => setDrawerOpen(prev => !prev)} - controls={} + controls={[ + , + , + ]} /> ); diff --git a/apps/visr/src/components/spectroscopy/dataSource.ts b/apps/visr/src/components/spectroscopy/dataSource.ts new file mode 100644 index 00000000..fda01b0f --- /dev/null +++ b/apps/visr/src/components/spectroscopy/dataSource.ts @@ -0,0 +1,4 @@ +export enum DataSource { + Camera = "camera", + Diodes = "diodes", +} diff --git a/apps/visr/src/components/spectroscopy/useSpectroscopyData.ts b/apps/visr/src/components/spectroscopy/useSpectroscopyData.ts index 5c6fe7c1..01bfac2a 100644 --- a/apps/visr/src/components/spectroscopy/useSpectroscopyData.ts +++ b/apps/visr/src/components/spectroscopy/useSpectroscopyData.ts @@ -9,7 +9,7 @@ export type FetchMapFunction = ( datapath: string, colour: RGBColour, snake: boolean, -) => Promise; +) => Promise; export interface DataChannels { red: NDT | null; From a06bc08fe81b19e9cc25f3c231aeb554a5b94c48 Mon Sep 17 00:00:00 2001 From: Tom Kane Date: Fri, 9 Oct 2026 17:43:31 +0000 Subject: [PATCH 3/3] stop exporting plane enum from sliceviewer --- apps/visr/src/components/tomography/SliceViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 876c1396..030c29c0 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -4,7 +4,7 @@ import ndarray from "ndarray"; import createArrayFromView from "../../utils/createArrayFromView"; // Not importing Plane in case we move SliceViewer somewhere else as a generic component -export enum Plane { +enum Plane { X, Y, Z,