diff --git a/frontend/src/renderer/components/plot/Heatmap2D.tsx b/frontend/src/renderer/components/plot/Heatmap2D.tsx index 257bbd2b..abb53323 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,13 +70,17 @@ export const Heatmap2D = ({ exponentformat: 'power', showexponent: 'all', separatethousands: true, + scaleanchor: null, + scaleratio: null, zeroline: false, + showgrid: itemDataGrid.displayGrid, }, yaxis: { exponentformat: 'power', showexponent: 'all', separatethousands: true, zeroline: false, + showgrid: itemDataGrid.displayGrid, }, modebar: { orientation: 'v', @@ -89,6 +94,40 @@ 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 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 && firstCoordinateUnit === secondCoordinateUnit; + } + setShouldForceRatio(shoudForceRatioSwitchRule); + }; + + getShouldForceRatio(); + }, [itemDataGrid.xyRatioRule, itemDataGrid.coordinates]); + + /** + * Update layout to force ratio or 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..5fe9166e 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', @@ -69,6 +72,7 @@ export const SimplePlotly = ({ exponentformat: 'power', showexponent: 'all', separatethousands: true, + showgrid: itemDataGrid.displayGrid, }, yaxis: { title: { @@ -85,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', @@ -117,6 +123,40 @@ export const SimplePlotly = ({ : width; const customContainerRef = useRef(null); + /** + * Rule to determine if we have to force ratio + */ + useEffect(() => { + 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, itemDataGrid.plot]); + + /** + * Update layout to force ratio or 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 = [ 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 = ({ }) } /> + +