diff --git a/client/component/package.json b/client/component/package.json index 82612fca..534a19c5 100644 --- a/client/component/package.json +++ b/client/component/package.json @@ -42,17 +42,17 @@ "websocket": "^1.0.35" }, "peerDependencies": { - "@h5web/lib": "^15.0.0", + "@h5web/lib": "^16.0.0", "@react-three/drei": "^9.122.0", "@react-three/fiber": "^8.17.0", "ndarray": "^1.0.19", "react": "^18.3.0", "react-dom": "^18.3.0", "react-toastify": "^11.0.5", - "three": "^0.174.0" + "three": ">=0.182.0" }, "devDependencies": { - "@h5web/lib": "^15.0.0", + "@h5web/lib": "^16.0.0", "@react-three/drei": "^9.122.0", "@react-three/fiber": "^8.18.0", "@types/cwise": "^1.0.6", @@ -63,14 +63,14 @@ "@types/ndarray": "^1.0.14", "@types/react": "^18.3.27", "@types/react-dom": "^18.3.7", - "@types/three": "^0.174.0", + "@types/three": ">=0.182.0", "@types/websocket": "^1.0.10", "d3-random": "^3.0.1", "ndarray": "^1.0.19", "react": "^18.3.1", "react-dom": "^18.3.1", "react-toastify": "^11.0.5", - "three": "^0.174.0", + "three": ">=0.182.0", "typedoc": "^0.28.15", "vite-plugin-dts": "^4.5.4", "vitest": "^4.0.15" diff --git a/client/component/src/ConnectedPlot.tsx b/client/component/src/ConnectedPlot.tsx index 5c465271..ed7ff9f7 100644 --- a/client/component/src/ConnectedPlot.tsx +++ b/client/component/src/ConnectedPlot.tsx @@ -3,7 +3,6 @@ import { decode, encode } from 'messagepack'; import { useCallback, useEffect, useRef, useState } from 'react'; import useWebSocket, { ReadyState } from 'react-use-websocket'; import { toast } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; import type { BatonProps, PlotConfig } from './models'; import AnyPlot from './AnyPlot'; diff --git a/client/component/src/LineConfig.tsx b/client/component/src/LineConfig.tsx index dc5d62ab..69183cef 100644 --- a/client/component/src/LineConfig.tsx +++ b/client/component/src/LineConfig.tsx @@ -69,8 +69,10 @@ function LineConfig(props: LineConfigProps) { key="colour picker" color={colour} onChange={(c: string) => { - currentLineParams.colour = c; - updateLineParams(currentLineKey, currentLineParams); + if (c !== currentLineParams.colour) { + currentLineParams.colour = c; + updateLineParams(currentLineKey, currentLineParams); + } }} /> )} @@ -82,20 +84,39 @@ function LineConfig(props: LineConfigProps) { label="colour" input={currentLineParams.colour ?? ''} updateValue={(c: string) => { - currentLineParams.colour = c; - updateLineParams(currentLineKey, currentLineParams); + if (c !== currentLineParams.colour) { + currentLineParams.colour = c; + updateLineParams(currentLineKey, currentLineParams); + } }} disabled={!hasBaton} /> ); + modeless.push( + + key="line width" + label="line width" + input={currentLineParams.width ?? 1} + updateValue={(p: number) => { + if (p !== currentLineParams.width && p >= 0) { + currentLineParams.width = p; + updateLineParams(currentLineKey, currentLineParams); + } + }} + isValid={(v) => isValidPointSize(v, currentLineParams.lineOn)} + disabled={!hasBaton} + /> + ); modeless.push( key="name" label="name" input={currentLineParams.name} updateValue={(n: string) => { - currentLineParams.name = n; - updateLineParams(currentLineKey, currentLineParams); + if (n !== currentLineParams.name) { + currentLineParams.name = n; + updateLineParams(currentLineKey, currentLineParams); + } }} disabled={!hasBaton} /> @@ -127,8 +148,10 @@ function LineConfig(props: LineConfigProps) { 'calling onGlyphTypeChange with cLine ', currentLineKey ); - currentLineParams.glyphType = v; - updateLineParams(currentLineKey, currentLineParams); + if (v !== currentLineParams.glyphType) { + currentLineParams.glyphType = v; + updateLineParams(currentLineKey, currentLineParams); + } }} hasBaton={hasBaton} /> @@ -139,12 +162,14 @@ function LineConfig(props: LineConfigProps) { label="point size" input={currentLineParams.pointSize ?? 0} updateValue={(p: number) => { - if (p == 0 && currentLineParams.lineOn) { - currentLineParams.pointSize = undefined; - updateLineParams(currentLineKey, currentLineParams); - } else if (p >= 0) { - currentLineParams.pointSize = p; - updateLineParams(currentLineKey, currentLineParams); + if (p !== currentLineParams.pointSize) { + if (p == 0 && currentLineParams.lineOn) { + currentLineParams.pointSize = undefined; + updateLineParams(currentLineKey, currentLineParams); + } else if (p >= 0) { + currentLineParams.pointSize = p; + updateLineParams(currentLineKey, currentLineParams); + } } }} decimalPlaces={2} diff --git a/client/component/src/LinePlot.tsx b/client/component/src/LinePlot.tsx index 527f23d0..b076590d 100644 --- a/client/component/src/LinePlot.tsx +++ b/client/component/src/LinePlot.tsx @@ -55,6 +55,8 @@ interface LineParams { pointSize?: number; /** The type of glyph */ glyphType: GlyphType; + /** The line width */ + width?: number; } /** @@ -118,6 +120,7 @@ function createDataCurve( curveType={curveType} glyphType={p.glyphType ?? GlyphType.Circle} glyphSize={p.pointSize} + width={p.width} visible={visible} /> ); @@ -139,6 +142,7 @@ export function LineVisCanvas(props: Props) { yScaleType, yLabel, mode, + allLineParams, setAllLineParams, currentLineKey, setCurrentLineKey, @@ -206,7 +210,7 @@ export function LineVisCanvas(props: Props) { {lineData.map((d, index) => { - const lp = initLineParams?.get(d.key) ?? d.lineParams; + const lp = allLineParams.get(d.key) ?? d.lineParams; return createDataCurve(d, lp, index); })} {canSelect && ( diff --git a/client/component/src/PlotToolbar.tsx b/client/component/src/PlotToolbar.tsx index aed48643..4a12f218 100644 --- a/client/component/src/PlotToolbar.tsx +++ b/client/component/src/PlotToolbar.tsx @@ -228,7 +228,7 @@ function PlotToolbar(props: PropsWithChildren): React.JSX.Element { bareModals.push( =0.182.0" }, "devDependencies": { "@types/ndarray": "^1.0.14", diff --git a/client/example/src/App.tsx b/client/example/src/App.tsx index 77325aca..bb569fd3 100644 --- a/client/example/src/App.tsx +++ b/client/example/src/App.tsx @@ -77,6 +77,7 @@ class AppMain extends React.Component { key: 'squares', lineParams: { colour: 'purple', + width: 2.4, pointSize: 6, lineOn: true, glyphType: GlyphType.Square, diff --git a/package.json b/package.json index 5ad0daae..c976731c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ }, "version": "1.1.0", "private": true, - "packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a", + "packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a", "scripts": { "preinstall": "npx only-allow pnpm", "start": "pnpm --filter {client/example} start", diff --git a/server/davidia/models/messages.py b/server/davidia/models/messages.py index 6d4f2696..e2a29230 100644 --- a/server/davidia/models/messages.py +++ b/server/davidia/models/messages.py @@ -87,6 +87,7 @@ class LineParams(DvDModel): name: str = "" colour: str | None = None + width: float | None = None line_on: bool = True point_size: int | None = None glyph_type: GlyphType = GlyphType.Circle diff --git a/server/davidia/plot.py b/server/davidia/plot.py index 10f4f123..5f10da67 100644 --- a/server/davidia/plot.py +++ b/server/davidia/plot.py @@ -177,6 +177,7 @@ def _asanyarray(x): else GlyphType[glyph_type] ) colour = global_attribs.pop("colour", None) + width = global_attribs.pop("width", None) point_size = global_attribs.pop("point_size", None) if isinstance(yf, list) and isinstance(yf[0], (list, np.ndarray)): @@ -205,16 +206,18 @@ def _asanyarray(x): for g in glyph_types ] colours = PlotConnection._as_list(colour, n_plots) + widths = PlotConnection._as_list(width, n_plots) point_sizes = PlotConnection._as_list(point_size, n_plots) plot_config = PlotConnection._populate_plot_config(plot_config) lds = [] - for xi, yi, ci, li, ps, gt in zip( - xl, yf, colours, lines_on, point_sizes, glyph_types + for xi, yi, ci, wi, li, ps, gt in zip( + xl, yf, colours, widths, lines_on, point_sizes, glyph_types ): if yi is None: raise ValueError("The y data must not contain None") line_params = LineParams( colour=ci, + width=wi, line_on=li, point_size=ps, glyph_type=gt, @@ -233,6 +236,7 @@ def _asanyarray(x): LineData( line_params=LineParams( colour=colour, + width=width, line_on=line_on, point_size=point_size, glyph_type=glyph_type, diff --git a/server/demos/simple.py b/server/demos/simple.py index 63783379..73394a0e 100644 --- a/server/demos/simple.py +++ b/server/demos/simple.py @@ -41,6 +41,7 @@ def line_demo(p, no_x=False, line_on=False): point_size=8, glyph_type="Circle", colour="red", + width=1.5, ) @@ -50,10 +51,12 @@ def multiline_demo(p, no_x=False, lines=3): x = data yds = None x_label = "index" + width = 2.5 else: x = [4.8, 10, 15.1] yds = data x_label = "x-axis" + width = [1.5 * (i + 1) for i in range(lines)] line( x=x, y=yds, @@ -66,6 +69,7 @@ def multiline_demo(p, no_x=False, lines=3): }, plot_id=f"plot_{p}", line_on=True, + width=width, ) @@ -77,7 +81,7 @@ def append_lines_demo(p, no_x=False): else: x = [[20, 25, 30], [], [20, 25, 30]] yds = data - line(x=x, y=yds, append=True, plot_id=f"plot_{p}", line_on=True) + line(x=x, y=yds, append=True, plot_id=f"plot_{p}", line_on=True, width=[3, 4, 5]) def append_more_lines_demo(p, no_x=False): @@ -88,7 +92,7 @@ def append_more_lines_demo(p, no_x=False): else: x = [[35, 40, 45], [20, 25, 30], []] yds = data - line(x=x, y=yds, append=True, plot_id=f"plot_{p}", line_on=True) + line(x=x, y=yds, append=True, plot_id=f"plot_{p}", line_on=True, width=[6, 5, 4]) def heatmap_demo(p, high=False): diff --git a/storybook/package.json b/storybook/package.json index 34561aea..4707b00c 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -14,20 +14,20 @@ "react": "^18.3.0", "react-dom": "^18.3.0", "react-icons": "^5.5.0", - "three": "^0.174.0" + "three": ">=0.182.0" }, "devDependencies": { - "@storybook/addon-docs": "^9.1.16", - "@storybook/addon-links": "^9.1.16", - "@storybook/react-vite": "^9.1.16", + "@storybook/addon-docs": "^10.1.11", + "@storybook/addon-links": "^10.1.11", + "@storybook/react-vite": "^10.1.11", "@types/ndarray": "^1.0.14", "@types/node": "^20.19.27", "@types/react": "^18.3.27", "@types/react-dom": "^18.3.7", "@types/swagger-ui-react": "^4.19.0", "@types/three": "^0.164.1", - "eslint-plugin-storybook": "^9.1.16", - "storybook": "^9.1.16", + "eslint-plugin-storybook": "^10.1.11", + "storybook": "^10.1.11", "swagger-ui-react": "^5.31.0" }, "eslintConfig": { diff --git a/storybook/stories/LinePlot.stories.tsx b/storybook/stories/LinePlot.stories.tsx index 164db17f..7ed56c97 100644 --- a/storybook/stories/LinePlot.stories.tsx +++ b/storybook/stories/LinePlot.stories.tsx @@ -1,6 +1,7 @@ import ndarray from 'ndarray'; import type { Meta, StoryObj } from '@storybook/react-vite'; import { + GlyphType, LineData, LineParams, LinePlot, @@ -29,7 +30,11 @@ export const Single: Story = { key: 'squares', lineParams: { colour: 'purple', + width: 1, pointSize: 4, + lineOn: true, + glyphType: GlyphType.Circle, + name: 'Single line', } as LineParams, x: ndarray(new Float32Array([1, 2, 3, 4, 6, 10])), xDomain: [1, 10], @@ -56,6 +61,7 @@ export const Multi: Story = { lineParams: { colour: 'red', pointSize: 8, + lineOn: true, } as LineParams, x: ndarray(new Float32Array([10, 12, 13, 16, 19, 20])), xDomain: [10, 20], @@ -68,6 +74,8 @@ export const Multi: Story = { lineParams: { colour: 'green', pointSize: 12, + width: 2, + lineOn: true, } as LineParams, x: ndarray(new Float32Array([10, 12, 13, 16, 19, 20, 22, 25])), xDomain: [10, 25], diff --git a/storybook/stories/ScatterPlot.stories.tsx b/storybook/stories/ScatterPlot.stories.tsx index 0749b71a..2da5fcf7 100644 --- a/storybook/stories/ScatterPlot.stories.tsx +++ b/storybook/stories/ScatterPlot.stories.tsx @@ -1,10 +1,6 @@ import ndarray from 'ndarray'; import type { Meta, StoryObj } from '@storybook/react-vite'; -import { - AxisScaleType, - ScaleType, - ScatterPlot, -} from '@diamondlightsource/davidia'; +import { ScaleType, ScatterPlot } from '@diamondlightsource/davidia'; const meta: Meta = { title: 'Plots/Scatter', @@ -21,8 +17,8 @@ export const Scatter: StoryObj = { title: 'Scatter Plot', xLabel: 'x-axis', yLabel: 'y-axis', - xScale: ScaleType.Linear as AxisScaleType | undefined, - yScale: ScaleType.Linear as AxisScaleType | undefined, + xScale: ScaleType.Linear, + yScale: ScaleType.Linear, }, colourMap: 'Turbo', x: ndarray(new Int32Array([...Array(20).keys()]), [20]), diff --git a/storybook/stories/SurfacePlot.stories.tsx b/storybook/stories/SurfacePlot.stories.tsx index 840e6820..dff95bef 100644 --- a/storybook/stories/SurfacePlot.stories.tsx +++ b/storybook/stories/SurfacePlot.stories.tsx @@ -1,10 +1,6 @@ import ndarray from 'ndarray'; import type { Meta, StoryObj } from '@storybook/react-vite'; -import { - AxisScaleType, - ScaleType, - SurfacePlot, -} from '@diamondlightsource/davidia'; +import { ScaleType, SurfacePlot } from '@diamondlightsource/davidia'; const meta: Meta = { title: 'Plots/Surface', @@ -36,8 +32,8 @@ export const Surface: StoryObj = { title: 'Surface Plot', xLabel: 'x-axis', yLabel: 'y-axis', - xScale: ScaleType.Linear as AxisScaleType | undefined, - yScale: ScaleType.Linear as AxisScaleType | undefined, + xScale: ScaleType.Linear, + yScale: ScaleType.Linear, }, heightValues: values, domain: [-2, 2],