From d723e3ed99208a86c7867ea0116357a53ea06309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Fiaudrin?= Date: Wed, 3 Jun 2026 09:54:47 +0200 Subject: [PATCH 1/3] Force scale ratio if x and y axis have same unit for 1D and 2D plots --- .../renderer/components/plot/Heatmap2D.tsx | 26 +++++++++++++++++ .../renderer/components/plot/SimplePlotly.tsx | 28 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/frontend/src/renderer/components/plot/Heatmap2D.tsx b/frontend/src/renderer/components/plot/Heatmap2D.tsx index 96bbd390..2139a438 100644 --- a/frontend/src/renderer/components/plot/Heatmap2D.tsx +++ b/frontend/src/renderer/components/plot/Heatmap2D.tsx @@ -58,6 +58,7 @@ export const Heatmap2D = ({ const [y, setY] = useState([]); const [z, setZ] = useState<(number | string)[][]>([]); const plotRef = useRef(null); + const [shouldForceRatio, setShouldForceRatio] = useState(false); const [layoutPlot, setLayoutPlot] = useState>({ autosize: true, scene: { @@ -69,6 +70,8 @@ export const Heatmap2D = ({ exponentformat: 'power', showexponent: 'all', separatethousands: true, + scaleanchor: null, + scaleratio: null, }, yaxis: { exponentformat: 'power', @@ -87,6 +90,29 @@ export const Heatmap2D = ({ const [title, setTitle] = useState(itemDataGrid.title); const layoutPlotWidth = showSliders ? width * 0.8 : width; + /** + * Rule to determine if we have to force ratio + */ + useEffect(() => { + const firstCoordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 0, + )?.unit; + const secondCoordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 1, + )?.unit; + setShouldForceRatio(firstCoordinateUnit === secondCoordinateUnit); + }, [itemDataGrid.coordinates]); + + /** + * Update layout to force ratio are not + */ + useEffect(() => { + const updatedLayoutPlot = structuredClone(layoutPlot); + updatedLayoutPlot.xaxis.scaleanchor = shouldForceRatio ? 'y' : null; + updatedLayoutPlot.xaxis.scaleratio = shouldForceRatio ? 1 : null; + setLayoutPlot(updatedLayoutPlot); + }, [shouldForceRatio]); + /** * Update the editable title when layout title change */ diff --git a/frontend/src/renderer/components/plot/SimplePlotly.tsx b/frontend/src/renderer/components/plot/SimplePlotly.tsx index bb729e87..9ddd1348 100644 --- a/frontend/src/renderer/components/plot/SimplePlotly.tsx +++ b/frontend/src/renderer/components/plot/SimplePlotly.tsx @@ -47,8 +47,11 @@ export const SimplePlotly = ({ const coordsUsedInAxes: 1 | 2 = 1; const { active, updatedConfiguration } = useIbexStore(); const SELECT_AXIS_HEIGHT = 40; // Height of the select axis component + const [shouldForceRatio, setShouldForceRatio] = useState(false); const [layoutPlot, setLayoutPlot] = useState>({ xaxis: { + scaleanchor: null, + scaleratio: null, title: { font: { family: 'Courier New, monospace', @@ -117,6 +120,31 @@ export const SimplePlotly = ({ : width; const customContainerRef = useRef(null); + /** + * Rule to determine if we have to force ratio + */ + useEffect(() => { + const coordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 0, + )?.unit; + const allPlotsHaveSameUnit = itemDataGrid.plot.every( + (plot) => plot.unit === itemDataGrid.plot[0]?.unit, + ); + setShouldForceRatio( + allPlotsHaveSameUnit && coordinateUnit === itemDataGrid.plot[0]?.unit, + ); + }, [itemDataGrid.coordinates]); + + /** + * Update layout to force ratio are not + */ + useEffect(() => { + const updatedLayoutPlot = structuredClone(layoutPlot); + updatedLayoutPlot.xaxis.scaleanchor = shouldForceRatio ? 'y' : null; + updatedLayoutPlot.xaxis.scaleratio = shouldForceRatio ? 1 : null; + setLayoutPlot(updatedLayoutPlot); + }, [shouldForceRatio]); + useEffect(() => { // Check data entries to update axes titles when needed const newDataEntries = [ From 6426e3424a6818019706a7ea7bd73203dcc7aa05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Fiaudrin?= Date: Mon, 8 Jun 2026 16:16:16 +0200 Subject: [PATCH 2/3] Add in visual customization the wanted rule for axis ratios --- .../renderer/components/plot/Heatmap2D.tsx | 29 ++++++++++++----- .../renderer/components/plot/SimplePlotly.tsx | 32 +++++++++++++------ frontend/src/renderer/layout/MainLayout.tsx | 1 + .../customizableElements/CustomizeGlobal.tsx | 16 ++++++++++ frontend/src/renderer/types/plot.ts | 1 + frontend/src/renderer/utils/grid.ts | 1 + frontend/src/renderer/utils/plot.ts | 2 ++ 7 files changed, 64 insertions(+), 18 deletions(-) diff --git a/frontend/src/renderer/components/plot/Heatmap2D.tsx b/frontend/src/renderer/components/plot/Heatmap2D.tsx index 8416cff2..e3e2044f 100644 --- a/frontend/src/renderer/components/plot/Heatmap2D.tsx +++ b/frontend/src/renderer/components/plot/Heatmap2D.tsx @@ -73,12 +73,14 @@ export const Heatmap2D = ({ scaleanchor: null, scaleratio: null, zeroline: false, + showgrid: itemDataGrid.displayGrid, }, yaxis: { exponentformat: 'power', showexponent: 'all', separatethousands: true, zeroline: false, + showgrid: itemDataGrid.displayGrid, }, modebar: { orientation: 'v', @@ -96,14 +98,25 @@ export const Heatmap2D = ({ * Rule to determine if we have to force ratio */ useEffect(() => { - const firstCoordinateUnit = itemDataGrid.coordinates.find( - (c) => c.axeIndex === 0, - )?.unit; - const secondCoordinateUnit = itemDataGrid.coordinates.find( - (c) => c.axeIndex === 1, - )?.unit; - setShouldForceRatio(firstCoordinateUnit === secondCoordinateUnit); - }, [itemDataGrid.coordinates]); + const getShouldForceRatio = () => { + let shoudForceRatioSwitchRule = false; + if (itemDataGrid.xyRatioRule === 'Force') { + shoudForceRatioSwitchRule = true; + } else if (itemDataGrid.xyRatioRule === 'Auto') { + const firstCoordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 0, + )?.unit; + const secondCoordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 1, + )?.unit; + shoudForceRatioSwitchRule = + firstCoordinateUnit === secondCoordinateUnit; + } + setShouldForceRatio(shoudForceRatioSwitchRule); + }; + + getShouldForceRatio(); + }, [itemDataGrid.xyRatioRule, itemDataGrid.coordinates]); /** * Update layout to force ratio are not diff --git a/frontend/src/renderer/components/plot/SimplePlotly.tsx b/frontend/src/renderer/components/plot/SimplePlotly.tsx index 9ddd1348..04dceec8 100644 --- a/frontend/src/renderer/components/plot/SimplePlotly.tsx +++ b/frontend/src/renderer/components/plot/SimplePlotly.tsx @@ -72,6 +72,7 @@ export const SimplePlotly = ({ exponentformat: 'power', showexponent: 'all', separatethousands: true, + showgrid: itemDataGrid.displayGrid, }, yaxis: { title: { @@ -88,12 +89,14 @@ export const SimplePlotly = ({ exponentformat: 'power', showexponent: 'all', separatethousands: true, + showgrid: itemDataGrid.displayGrid, }, yaxis2: { type: (itemDataGrid?.y2AxisData?.type as AxisType) || 'linear', exponentformat: 'power', showexponent: 'all', separatethousands: true, + showgrid: itemDataGrid.displayGrid, }, modebar: { orientation: 'v', @@ -124,16 +127,25 @@ export const SimplePlotly = ({ * Rule to determine if we have to force ratio */ useEffect(() => { - const coordinateUnit = itemDataGrid.coordinates.find( - (c) => c.axeIndex === 0, - )?.unit; - const allPlotsHaveSameUnit = itemDataGrid.plot.every( - (plot) => plot.unit === itemDataGrid.plot[0]?.unit, - ); - setShouldForceRatio( - allPlotsHaveSameUnit && coordinateUnit === itemDataGrid.plot[0]?.unit, - ); - }, [itemDataGrid.coordinates]); + const getShouldForceRatio = () => { + let shoudForceRatioSwitchRule = false; + if (itemDataGrid.xyRatioRule === 'Force') { + shoudForceRatioSwitchRule = true; + } else if (itemDataGrid.xyRatioRule === 'Auto') { + const coordinateUnit = itemDataGrid.coordinates.find( + (c) => c.axeIndex === 0, + )?.unit; + const allPlotsHaveSameUnit = itemDataGrid.plot.every( + (plot) => plot.unit === itemDataGrid.plot[0]?.unit, + ); + shoudForceRatioSwitchRule = + allPlotsHaveSameUnit && coordinateUnit === itemDataGrid.plot[0]?.unit; + } + setShouldForceRatio(shoudForceRatioSwitchRule); + }; + + getShouldForceRatio(); + }, [itemDataGrid.xyRatioRule, itemDataGrid.coordinates]); /** * Update layout to force ratio are not diff --git a/frontend/src/renderer/layout/MainLayout.tsx b/frontend/src/renderer/layout/MainLayout.tsx index 19d80615..8d5cfe3b 100644 --- a/frontend/src/renderer/layout/MainLayout.tsx +++ b/frontend/src/renderer/layout/MainLayout.tsx @@ -102,6 +102,7 @@ export function MainLayout() { isTitleOverwritten: dataGrid.isTitleOverwritten, displayErrorBand: dataGrid.displayErrorBand, displayGrid: dataGrid.displayGrid, + xyRatioRule: dataGrid.xyRatioRule, synchronizedGrids: dataGrid.synchronizedGrids, downsampled_method: dataGrid?.downsampled_method, downsampled_size: dataGrid?.downsampled_size, diff --git a/frontend/src/renderer/pages/visualization/customizableElements/CustomizeGlobal.tsx b/frontend/src/renderer/pages/visualization/customizableElements/CustomizeGlobal.tsx index 22f441cf..957b5d83 100644 --- a/frontend/src/renderer/pages/visualization/customizableElements/CustomizeGlobal.tsx +++ b/frontend/src/renderer/pages/visualization/customizableElements/CustomizeGlobal.tsx @@ -137,6 +137,22 @@ export const CustomizeGlobal = ({ }) } /> + +