Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions frontend/src/renderer/components/grid/GridLayoutPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DataGridPlot,
DataPlotly,
GridLayoutPlotProps,
NodeInfoTypeEnum,
URITreeNodeData,
} from '../../../renderer/types';
import { Center, Container, Text } from '@mantine/core';
Expand Down Expand Up @@ -35,7 +36,9 @@ export const GridLayoutPlot = ({
);
const [widthGrid, setWidthGrid] = useState(Math.floor(data.w * colWidth));
const [is3DView, setIs3DView] = useState<boolean>(
data?.selectedPlotMode === 'Heatmap' ? true : false,
data?.selectedPlotMode === 'Heatmap' || data?.selectedPlotMode === 'Contour'
? true
: false,
);
const [active3DTab, setActive3DTab] = useState<string>('0');
const [metadataTabsValue, setMetadataTabsValue] = useState<string>(
Expand Down Expand Up @@ -146,8 +149,8 @@ export const GridLayoutPlot = ({

return {
...plotItem,
x: newXData,
y: newYData,
x: [...newXData],
y: [...newYData],
customdata: customdata,
error_bands: updated_error_bands,
nodeUri: updatedNodeUri,
Expand All @@ -156,8 +159,8 @@ export const GridLayoutPlot = ({
} else {
return {
...plotItem,
x: newXData,
y: newYData,
x: [...newXData],
y: [...newYData],
nodeUri: updatedNodeUri,
path: updatedPath,
};
Expand All @@ -180,6 +183,8 @@ export const GridLayoutPlot = ({
};

useEffect(() => {
let forceToDisplayMetadata = false;

// Rule to force to show metadata when y data is of type string
let isYDataString = false;
for (const plot of data.plot) {
Expand All @@ -190,7 +195,15 @@ export const GridLayoutPlot = ({
}
}
}
setShouldDisplayMetadata(isYDataString);

// Rule to force to show metadata when y data is a geometry
let isGeometry = false;
if (data.is_geometry_node === true) {
isGeometry = true;
}

forceToDisplayMetadata = isYDataString || isGeometry;
setShouldDisplayMetadata(forceToDisplayMetadata);
}, [data.plot.length]);

/**
Expand All @@ -215,7 +228,12 @@ export const GridLayoutPlot = ({
}, [data.plot]);

useEffect(() => {
setIs3DView(data?.selectedPlotMode === 'Heatmap' ? true : false);
setIs3DView(
data?.selectedPlotMode === 'Heatmap' ||
data?.selectedPlotMode === 'Contour'
? true
: false,
);
}, [data.selectedPlotMode]);

/**
Expand Down Expand Up @@ -281,6 +299,7 @@ export const GridLayoutPlot = ({
uri: normalizeIndices(item.nodeUri),
name: item.labelUri,
type: findPlot.dataType,
is_geometry_node: findPlot.is_geometry_node,
}))
: [];

Expand All @@ -295,6 +314,7 @@ export const GridLayoutPlot = ({
name: plot.labelUri,
uri: normalizeIndices(error_band.path),
type: findPlot.dataType,
is_geometry_node: findPlot.is_geometry_node,
};
const exists = checkedNodeURI.some(
(node) =>
Expand All @@ -307,6 +327,28 @@ export const GridLayoutPlot = ({
}
}
}

if (findPlot?.geometries) {
// Check geometries in tree
for (const geometry of findPlot.geometries) {
for (const uriOfGeo of geometry.nodeUris) {
const newCheckedNode = {
name: findPlot.plot[0].labelUri,
uri: normalizeIndices(uriOfGeo),
type: NodeInfoTypeEnum.FLOAT,
is_geometry_node: true,
} as URITreeNodeData;
const exists = checkedNodeURI.some(
(node) =>
node.name === newCheckedNode.name &&
node.uri === newCheckedNode.uri,
);
if (!exists) {
checkedNodeURI.push(newCheckedNode);
}
}
}
}
}

const updatedActive: Configuration = {
Expand Down Expand Up @@ -376,6 +418,7 @@ export const GridLayoutPlot = ({
return (
index.toString() === active3DTab && (
<MetaDataInfos
key={`metadata_${data.i}`}
gridLayoutKey={data.i}
data={plot}
yAxis={plot.yaxis !== '' ? data.y2AxisData : data.yAxisData}
Expand Down
115 changes: 76 additions & 39 deletions frontend/src/renderer/components/grid/HoverButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classes from './HoverButtons.module.css';
import React, { useCallback, useEffect, useRef } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
Group,
Tooltip,
Expand All @@ -8,6 +8,7 @@ import {
Tabs,
Switch,
ScrollArea,
Menu,
} from '@mantine/core';
import {
IconBrandDatabricks,
Expand All @@ -16,14 +17,16 @@ import {
IconEdit,
IconEyeEdit,
IconTrash,
IconTarget,
} from '@tabler/icons-react';
import { useHover } from '@mantine/hooks';
import { Configuration, CustomizedGridType, DataGridPlot } from '../../types';
import {
applyRange,
containsFloat,
fetchErrorBandsInConfig,
} from '../../utils';
Configuration,
CustomizedGridType,
DataGridPlot,
PlotType,
} from '../../types';
import { applyRange, fetchErrorBandsInConfig } from '../../utils';
import { useIbexStore } from '../../stores';

interface HoverButtonsProps {
Expand Down Expand Up @@ -55,9 +58,16 @@ export const HoverButtons = React.memo(
const previousValueDisplayErrorBands = useRef<boolean | undefined>(
undefined,
);
const [plotMode, setPlotMode] = useState<PlotType>(
active.dataPlot.find((dataPlot) => dataPlot.i === data.i)
?.selectedPlotMode,
);
const [plotTypeMenuOpened, setPlotTypeMenuOpened] = useState(false);
const [forcePlotTypeMenuOpened, setForcePlotTypeMenuOpened] =
useState(false);

const heatmapLogo = (
<svg width="50" height="50" viewBox="0 0 50 50">
<svg width="20" height="20" viewBox="0 0 50 50">
<rect x="0" y="0" width="15" height="15" fill="#440154" />
<rect x="17" y="0" width="15" height="15" fill="#31688e" />
<rect x="34" y="0" width="15" height="15" fill="#35b779" />
Expand All @@ -72,6 +82,15 @@ export const HoverButtons = React.memo(
</svg>
);

const modes: {
value: PlotType;
icon?: React.ReactNode;
}[] = [
{ value: '1D' },
{ value: 'Heatmap', icon: heatmapLogo },
{ value: 'Contour', icon: <IconTarget width={22} /> },
];

const updateDisplayErrorBands = useCallback(
(newValue: boolean) => {
const updatedActive = structuredClone(active) as Configuration;
Expand Down Expand Up @@ -157,25 +176,17 @@ export const HoverButtons = React.memo(
updateErrorBands();
}, [data.displayErrorBand]);

const updateSelectedPlotMode = (
is3DView: boolean,
active: Configuration,
) => {
const updateTypeOfPlot = async (wantedType: PlotType) => {
setPlotTypeMenuOpened(false);
setForcePlotTypeMenuOpened(false);
setPlotMode(wantedType);
const updatedDataPlot: DataGridPlot[] = structuredClone(active.dataPlot);
const selectedDataPlot = updatedDataPlot.find(
(dataPlot) => dataPlot.i === data.i,
);
if (selectedDataPlot?.selectedPlotMode) {
selectedDataPlot.selectedPlotMode = is3DView ? 'Heatmap' : '1D';
} else {
selectedDataPlot.selectedPlotMode =
data.coordinates.length >= 2 &&
containsFloat(
data.coordinates.find((coord) => coord.axeIndex === 1)?.data,
)
? 'Heatmap'
: '1D';
}

// Update plot type
selectedDataPlot.selectedPlotMode = wantedType;

const updatedActive: Configuration = {
...active,
Expand Down Expand Up @@ -223,7 +234,10 @@ export const HoverButtons = React.memo(
<div></div>
)}

{hovered || data.isEditing ? (
{hovered ||
data.isEditing ||
plotTypeMenuOpened ||
forcePlotTypeMenuOpened ? (
<Group pos="absolute" right={'1rem'} top={5}>
{!is3DView && data.isEditing && !shouldDisplayMetadata && (
<Switch
Expand All @@ -236,22 +250,45 @@ export const HoverButtons = React.memo(
)}

{data.coordinates.length >= 2 && !shouldDisplayMetadata && (
<Tooltip label="Toggle 1D/Heatmap view">
<ActionIcon
data-testid="toggle-plot-mode-button"
variant="filled"
aria-label="Toggle 1D/Heatmap view"
onClick={() =>
updateSelectedPlotMode(
!(data.selectedPlotMode === 'Heatmap'),
active,
)
}
className={classes.actionButton}
>
{is3DView ? <Text fw="bold">1D</Text> : heatmapLogo}
</ActionIcon>
</Tooltip>
<Menu
opened={plotTypeMenuOpened || forcePlotTypeMenuOpened}
onChange={setPlotTypeMenuOpened}
shadow="md"
width={180}
trigger="click-hover"
>
<Menu.Target>
<Tooltip label="Select plot mode">
<ActionIcon
onClick={() => setForcePlotTypeMenuOpened((o) => !o)}
variant="filled"
aria-label="Select plot mode"
className={classes.actionButton}
>
{modes.find((m) => m.value === plotMode)?.icon || (
<Text fw="bold">{plotMode}</Text>
)}
</ActionIcon>
</Tooltip>
</Menu.Target>

<Menu.Dropdown>
{modes.map((mode) => (
<Menu.Item
key={mode.value}
onClick={() => updateTypeOfPlot(mode.value)}
leftSection={mode.icon}
rightSection={
plotMode === mode.value ? (
<IconCheck size={14} />
) : null
}
>
{mode.value}
</Menu.Item>
))}
</Menu.Dropdown>
</Menu>
)}

{data.coordinates.length && !shouldDisplayMetadata && (
Expand Down
38 changes: 31 additions & 7 deletions frontend/src/renderer/components/plot/Heatmap2D.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface Heatmap2DProps {
height: number;
plotIndex: string;
showSliders: boolean;
forcedPlotType?: 'heatmap' | 'contour';
handleUpdateCoordinate?: (
coordinate: Coordinates,
valueIndex: number,
Expand All @@ -44,6 +45,7 @@ export const Heatmap2D = ({
height,
plotIndex,
showSliders,
forcedPlotType,
handleUpdateCoordinate,
}: Heatmap2DProps) => {
const { active, updatedConfiguration } = useIbexStore();
Expand Down Expand Up @@ -80,6 +82,12 @@ export const Heatmap2D = ({
modebar: {
orientation: 'v',
},
legend: {
x: 1.3,
y: 1,
groupclick: 'togglegroup',
tracegroupgap: 0,
},
});
// Custom hook used for trigger some useEffects to update the layout
usePlotLayout({
Expand Down Expand Up @@ -318,9 +326,13 @@ export const Heatmap2D = ({
coord.axeIndex === (targetAxis === 'y' ? 1 : 0),
).name
}
data={itemDataGrid.coordinates.map(
(coord: Coordinates) => coord.name,
)}
data={(itemDataGrid.geometries.length // In contour plot, allow to transpose only x & y to keep compatibles coordinates with geometries
? itemDataGrid.coordinates.filter(
(coord) =>
coord.axeIndex === 0 || coord.axeIndex === 1,
)
: itemDataGrid.coordinates
).map((coord: Coordinates) => coord.name)}
w={`${width * 0.2}px`}
onChange={(value) =>
value &&
Expand Down Expand Up @@ -417,7 +429,16 @@ export const Heatmap2D = ({
ref={plotRef}
data={[
{
type: 'heatmap',
type: forcedPlotType
? forcedPlotType
: itemDataGrid.selectedPlotMode === 'Heatmap'
? 'heatmap'
: itemDataGrid.selectedPlotMode === 'Contour'
? 'contour'
: 'heatmap',
contours: {
coloring: 'lines',
},
colorscale:
itemDataGrid.plot[parseInt(plotIndex)]?.customPreferences
?.colorscale || 'Viridis',
Expand All @@ -433,10 +454,13 @@ export const Heatmap2D = ({
},
hovertemplate:
'x: %{x}<br>' + 'y: %{y}<br>' + 'z: %{z:,.6g}<extra></extra>',
x: x,
y: y,
z: z,
x: [...x],
y: [...y],
z: z.map((row) => [...row]),
},

// Add geometries in contour type
...(itemDataGrid?.geometries ?? []),
]}
config={{
autosizable: false,
Expand Down
Loading
Loading