Skip to content
Snippets Groups Projects

feat(Vis1D): changes style and adds 2D options

Merged Marcos Pieras requested to merge feat/1DvisWithGPcolors into main
Files
2
import { visualizationColors } from 'config';
import React, { useRef, useEffect, useState } from 'react';
import Plot from 'react-plotly.js';
import { Tooltip, TooltipContent, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
const getCSSVariableHSL = (varName: string) => {
const rootStyles = getComputedStyle(document.documentElement);
const hslValue = rootStyles.getPropertyValue(varName).trim().replace('deg', '');
return `hsl(${hslValue})`;
};
export const plotTypeOptions = ['bar', 'scatter', 'line', 'histogram', 'pie'] as const;
export interface CustomChartPlotlyProps {
data: string[] | number[];
xAxisData: string[] | number[];
plotType: (typeof plotTypeOptions)[number];
title: string;
showAxis: boolean;
yAxisData: string[] | number[];
xAxisLabel?: string;
yAxisLabel?: string;
}
export const getPlotData = (data: (string | number)[], plotType: (typeof plotTypeOptions)[number]): Partial<Plotly.PlotData>[] => {
export const getPlotData = (
xAxisData: (string | number)[],
plotType: (typeof plotTypeOptions)[number],
yAxisData?: (string | number)[],
): Partial<Plotly.PlotData>[] => {
const mainColors = visualizationColors.GPCat.colors[14];
const xValues = data.map((_, index) => index + 1);
const primaryColor = getCSSVariableHSL('--clr-sec--400');
let xValues: (string | number)[] = [];
let yValues: (string | number)[] = [];
if (plotType === 'scatter' || plotType === 'line') {
if (xAxisData.length != 0 && yAxisData && yAxisData.length != 0) {
xValues = xAxisData;
yValues = yAxisData;
} else if (xAxisData.length != 0 && yAxisData && yAxisData.length == 0) {
xValues = xAxisData;
yValues = xAxisData.map((_, index) => index + 1);
} else if (xAxisData.length == 0 && yAxisData && yAxisData.length != 0) {
xValues = yAxisData.map((_, index) => index + 1);
yValues = yAxisData;
} else if (xAxisData.length == 0 && yAxisData && yAxisData.length == 0) {
} else {
}
} else {
xValues = xAxisData;
yValues = xAxisData.map((_, index) => index + 1);
}
switch (plotType) {
case 'bar':
@@ -20,8 +55,9 @@ export const getPlotData = (data: (string | number)[], plotType: (typeof plotTyp
{
type: 'bar',
x: xValues,
y: data,
marker: { color: mainColors },
y: yValues,
marker: { color: primaryColor },
hoverinfo: 'none',
},
];
case 'scatter':
@@ -29,9 +65,10 @@ export const getPlotData = (data: (string | number)[], plotType: (typeof plotTyp
{
type: 'scatter',
x: xValues,
y: data,
y: yValues,
mode: 'markers',
marker: { color: mainColors, size: 12 },
marker: { color: primaryColor, size: 12 },
hoverinfo: 'none',
},
];
case 'line':
@@ -39,17 +76,19 @@ export const getPlotData = (data: (string | number)[], plotType: (typeof plotTyp
{
type: 'scatter',
x: xValues,
y: data,
y: yValues,
mode: 'lines',
line: { color: mainColors },
line: { color: primaryColor },
hoverinfo: 'none',
},
];
case 'histogram':
return [
{
type: 'histogram',
x: data,
marker: { color: mainColors },
x: xAxisData,
marker: { color: primaryColor },
hoverinfo: 'none',
},
];
case 'pie':
@@ -57,18 +96,29 @@ export const getPlotData = (data: (string | number)[], plotType: (typeof plotTyp
{
type: 'pie',
labels: xValues.map(String),
values: data,
values: xAxisData,
marker: { colors: mainColors },
hoverinfo: 'none',
},
];
default:
return [];
}
};
export const CustomChartPlotly: React.FC<CustomChartPlotlyProps> = ({ data, plotType, title }) => {
export const CustomChartPlotly: React.FC<CustomChartPlotlyProps> = ({
xAxisData,
plotType,
title,
showAxis,
yAxisData,
xAxisLabel,
yAxisLabel,
}) => {
const internalRef = useRef<HTMLDivElement>(null);
const [divSize, setDivSize] = useState({ width: 0, height: 0 });
const [hoveredPoint, setHoveredPoint] = useState<{ left: number; top: number; value: number } | null>(null);
useEffect(() => {
const handleResize = () => {
@@ -78,7 +128,7 @@ export const CustomChartPlotly: React.FC<CustomChartPlotlyProps> = ({ data, plot
}
};
handleResize(); // Set initial size
handleResize();
window.addEventListener('resize', handleResize);
if (internalRef.current) {
new ResizeObserver(handleResize).observe(internalRef.current);
@@ -89,28 +139,86 @@ export const CustomChartPlotly: React.FC<CustomChartPlotlyProps> = ({ data, plot
};
}, []);
const handleHover = (event: any) => {
const { points } = event;
if (points.length) {
const point = points[0];
const plotRect = internalRef.current?.getBoundingClientRect(); // Get the plot's bounding box
if (plotRect) {
// Calculate the position of the tooltip
const xIndex = point.xaxis.d2p(point.x); // Convert x value to pixel position
const yIndex = point.yaxis.d2p(point.y); // Convert y value to pixel position
setHoveredPoint({
left: xIndex, // Center tooltip above the point
top: plotRect.top + yIndex, // Position below the point
value: point.y, // Value to display
});
}
}
};
return (
<div className="h-full w-full flex items-center justify-center overflow-hidden" ref={internalRef}>
<div className="h-full w-full flex items-center justify-center overflow-hidden relative" ref={internalRef}>
<Plot
data={getPlotData(data, plotType)}
config={{ responsive: true, displayModeBar: false }}
data={getPlotData(xAxisData, plotType, yAxisData)}
config={{
responsive: true,
scrollZoom: false,
displayModeBar: false,
staticPlot: true,
displaylogo: false,
}}
layout={{
width: divSize.width,
height: divSize.height,
title: title,
dragmode: false,
font: {
family: 'Inter, sans-serif',
size: 16,
color: '#374151',
size: 12,
color: '#374151', // change to gp default color
},
xaxis: {
title: 'Category',
title: showAxis ? (xAxisLabel ? xAxisLabel : '') : '',
showgrid: false,
visible: showAxis,
showline: true,
zeroline: false,
},
yaxis: {
title: 'Value',
title: showAxis ? (yAxisLabel ? yAxisLabel : '') : '',
showgrid: false,
visible: showAxis,
showline: true,
zeroline: false,
},
}}
onHover={handleHover}
onUnhover={() => setHoveredPoint(null)}
/>
{hoveredPoint && (
<div>
<Tooltip open={true} showArrow={true}>
<TooltipTrigger />
<TooltipContent
style={{
position: 'absolute',
left: hoveredPoint.left,
top: hoveredPoint.top,
transform: 'translate(-50%, -100%)',
}}
>
<div>
<strong>Value:</strong> {hoveredPoint.value} <br />
</div>
</TooltipContent>
</Tooltip>
</div>
)}
</div>
);
};
Loading