From 00e41abdd2ab7e06ed1beec68c029d64ab885f4c Mon Sep 17 00:00:00 2001 From: deep1401 <gandhi0869@gmail.com> Date: Mon, 3 Mar 2025 09:13:06 -0800 Subject: [PATCH] Add Swap Axes logic for line chart --- .../components/Experiment/Eval/Chart.tsx | 119 +++++++++++++----- 1 file changed, 89 insertions(+), 30 deletions(-) diff --git a/src/renderer/components/Experiment/Eval/Chart.tsx b/src/renderer/components/Experiment/Eval/Chart.tsx index 97ba01d4..2de89c99 100644 --- a/src/renderer/components/Experiment/Eval/Chart.tsx +++ b/src/renderer/components/Experiment/Eval/Chart.tsx @@ -1,17 +1,24 @@ -//// filepath: /Users/deep.gandhi/transformerlab-repos/transformerlab-app/src/renderer/components/Experiment/Eval/Chart.tsx import React, { useState } from 'react'; import { ResponsiveLine } from '@nivo/line'; import { ResponsiveBar } from '@nivo/bar'; import { ResponsiveRadar } from '@nivo/radar'; -import { Select, Option, FormControl } from '@mui/joy'; +import { Select, Option, FormControl, Box, Button } from '@mui/joy'; +import { ArrowLeftRight } from 'lucide-react'; + const Chart = ({ metrics, compareChart }) => { const [chartType, setChartType] = useState('bar'); + const [swapAxes, setSwapAxes] = useState(false); + const handleChartTypeChange = (event, newValue) => { setChartType(newValue); }; + const handleSwapAxes = () => { + setSwapAxes(!swapAxes); + }; + if (!metrics || metrics.length === 0) { return <div>No metrics available</div>; } @@ -20,13 +27,42 @@ const Chart = ({ metrics, compareChart }) => { let barData, lineData, radarData; if (compareChart) { - // For compare mode, multiple evaluators/jobs become separate series. - // Use evaluator-job as series key. + // For compare mode, we need to handle the axis swap + const metricTypes = Array.from(new Set(metrics.map(m => m.type))); const seriesKeys = Array.from( new Set(metrics.map(m => `${m.evaluator}-${m.job_id}`)) ); - // For Bar chart: group by metric type. + // For Line chart: handle axis swapping + if (swapAxes && chartType === 'line') { + // Swapped axes: each series is a metric type + const seriesDataMap = {}; + metricTypes.forEach(type => { + seriesDataMap[type] = { id: type, data: [] }; + }); + + metrics.forEach(metric => { + const { type, evaluator, job_id, score } = metric; + const seriesKey = `${evaluator}-${job_id}`; + seriesDataMap[type].data.push({ x: seriesKey, y: score }); + }); + lineData = Object.values(seriesDataMap); + } else { + // Normal mode for line chart: each series is an evaluator-job + const seriesDataMap = {}; + seriesKeys.forEach(series => { + seriesDataMap[series] = { id: series, data: [] }; + }); + + metrics.forEach(metric => { + const { type, evaluator, job_id, score } = metric; + const seriesKey = `${evaluator}-${job_id}`; + seriesDataMap[seriesKey].data.push({ x: type, y: score }); + }); + lineData = Object.values(seriesDataMap); + } + + // Bar chart: data preparation (unchanged) const barDataMap = {}; metrics.forEach(metric => { const { type, evaluator, job_id, score } = metric; @@ -38,19 +74,7 @@ const Chart = ({ metrics, compareChart }) => { }); barData = Object.values(barDataMap); - // For Line chart: each series is an evaluator-job. - const seriesDataMap = {}; - seriesKeys.forEach(series => { - seriesDataMap[series] = { id: series, data: [] }; - }); - metrics.forEach(metric => { - const { type, evaluator, job_id, score } = metric; - const seriesKey = `${evaluator}-${job_id}`; - seriesDataMap[seriesKey].data.push({ x: type, y: score }); - }); - lineData = Object.values(seriesDataMap); - - // For Radar chart: similar to bar, but keys represent evaluator-job score. + // Radar chart: data preparation (unchanged) const radarDataMap = {}; metrics.forEach(metric => { const { type, evaluator, job_id, score } = metric; @@ -62,7 +86,7 @@ const Chart = ({ metrics, compareChart }) => { }); radarData = Object.values(radarDataMap); } else { - // Original logic: assume a single series. + // Original logic for non-compare mode (unchanged) barData = metrics.map(metric => ({ type: metric.type, score: metric.score, @@ -83,13 +107,26 @@ const Chart = ({ metrics, compareChart }) => { return ( <> - <FormControl sx={{ width: 200 }}> - <Select value={chartType} onChange={handleChartTypeChange}> - <Option value="bar">Bar</Option> - <Option value="line">Line</Option> - <Option value="radar">Radar</Option> - </Select> - </FormControl> + <Box sx={{ display: 'flex', gap: 2, mb: 2, alignItems: 'center' }}> + <FormControl sx={{ width: 200 }}> + <Select value={chartType} onChange={handleChartTypeChange}> + <Option value="bar">Bar</Option> + <Option value="line">Line</Option> + <Option value="radar">Radar</Option> + </Select> + </FormControl> + + {compareChart && chartType === 'line' && ( + <Button + variant="outlined" + startDecorator={<ArrowLeftRight size={18} />} + onClick={handleSwapAxes} + > + Swap Axes + </Button> + )} + </Box> + <div style={{ height: 400, width: '100%' }}> {chartType === 'line' && ( <ResponsiveLine @@ -100,7 +137,7 @@ const Chart = ({ metrics, compareChart }) => { type: 'linear', min: 'auto', max: 'auto', - stacked: true, + stacked: false, reverse: false, }} axisTop={null} @@ -108,8 +145,8 @@ const Chart = ({ metrics, compareChart }) => { axisBottom={{ tickSize: 5, tickPadding: 5, - tickRotation: 0, - legend: 'metric', + tickRotation: swapAxes && compareChart ? 45 : 0, + legend: swapAxes && compareChart ? 'experiment' : 'metric', legendOffset: 36, legendPosition: 'middle', }} @@ -121,9 +158,31 @@ const Chart = ({ metrics, compareChart }) => { legendOffset: -40, legendPosition: 'middle', }} + pointSize={10} + pointColor={{ theme: 'background' }} + pointBorderWidth={2} + pointBorderColor={{ from: 'serieColor' }} + legends={[ + { + anchor: 'bottom-right', + direction: 'column', + justify: false, + translateX: 100, + translateY: 0, + itemsSpacing: 0, + itemDirection: 'left-to-right', + itemWidth: 80, + itemHeight: 20, + itemOpacity: 0.75, + symbolSize: 12, + symbolShape: 'circle', + symbolBorderColor: 'rgba(0, 0, 0, .5)', + } + ]} /> )} - {chartType === 'bar' && ( + +{chartType === 'bar' && ( <ResponsiveBar data={barData} keys={ -- GitLab