Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ui): split up and page metrics in eval compare summary section #2672

Merged
merged 13 commits into from
Dec 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const AddEvaluationButton: React.FC<{
);
const expandedRefCols = useMemo(() => new Set<string>(), []);
// Don't query for output here, re-queried in tsDataModelHooksEvaluationComparison.ts
const columns = useMemo(() => ['inputs'], []);
const columns = useMemo(() => ['inputs', 'display_name'], []);
const calls = useCallsForQuery(
props.state.data.entity,
props.state.data.project,
Expand Down Expand Up @@ -137,7 +137,7 @@ const AddEvaluationButton: React.FC<{
return;
}

const filteredOptions = calls.result.filter(call => {
const filteredOptions = evalsNotComparing.filter(call => {
if (
(call.displayName ?? call.spanName)
.toLowerCase()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import {Popover} from '@mui/material';
import {Switch} from '@wandb/weave/components';
import {Button} from '@wandb/weave/components/Button';
import {
DraggableGrow,
DraggableHandle,
} from '@wandb/weave/components/DraggablePopups';
import {TextField} from '@wandb/weave/components/Form/TextField';
import {Tailwind} from '@wandb/weave/components/Tailwind';
import {maybePluralize} from '@wandb/weave/core/util/string';
import classNames from 'classnames';
import React, {useRef, useState} from 'react';

export const MetricsSelector: React.FC<{
setSelectedMetrics: (newModel: Record<string, boolean>) => void;
selectedMetrics: Record<string, boolean> | undefined;
allMetrics: string[];
}> = ({setSelectedMetrics, selectedMetrics, allMetrics}) => {
const [search, setSearch] = useState('');

const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const onClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(anchorEl ? null : ref.current);
setSearch('');
};
const open = Boolean(anchorEl);
const id = open ? 'simple-popper' : undefined;

const filteredCols = search
? allMetrics.filter(col => col.toLowerCase().includes(search.toLowerCase()))
: allMetrics;

const shownMetrics = Object.values(selectedMetrics ?? {}).filter(Boolean);

const numHidden = allMetrics.length - shownMetrics.length;
const buttonSuffix = search ? `(${filteredCols.length})` : 'all';

return (
<>
<span ref={ref}>
<Button
variant="ghost"
icon="column"
tooltip="Manage metrics"
onClick={onClick}
/>
</span>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
slotProps={{
paper: {
sx: {
overflow: 'visible',
},
},
}}
onClose={() => setAnchorEl(null)}
TransitionComponent={DraggableGrow}>
<Tailwind>
<div className="min-w-[360px] p-12">
<DraggableHandle>
<div className="flex items-center pb-8">
<div className="flex-auto text-xl font-semibold">
Manage metrics
</div>
<div className="ml-16 text-moon-500">
{maybePluralize(numHidden, 'hidden column', 's')}
</div>
</div>
</DraggableHandle>
<div className="mb-8">
<TextField
placeholder="Filter columns"
autoFocus
value={search}
onChange={setSearch}
/>
</div>
<div className="max-h-[300px] overflow-auto">
{Array.from(allMetrics).map((metric: string) => {
const value = metric;
const idSwitch = `toggle-vis_${value}`;
const checked = selectedMetrics?.[metric] ?? false;
const label = metric;
const disabled = false;
if (
search &&
!label.toLowerCase().includes(search.toLowerCase())
) {
return null;
}
return (
<div key={value}>
<div
className={classNames(
'flex items-center py-2',
disabled ? 'opacity-40' : ''
)}>
<Switch.Root
id={idSwitch}
size="small"
checked={checked}
onCheckedChange={isOn => {
setSelectedMetrics(
isOn
? {...selectedMetrics, [metric]: true}
: {...selectedMetrics, [metric]: false}
);
}}
disabled={disabled}>
<Switch.Thumb size="small" checked={checked} />
</Switch.Root>
<label
htmlFor={idSwitch}
className={classNames(
'ml-6',
disabled ? '' : 'cursor-pointer'
)}>
{label}
</label>
</div>
</div>
);
})}
</div>
<div className="mt-8 flex items-center">
<Button
size="small"
variant="quiet"
icon="hide-hidden"
disabled={filteredCols.length === 0}
onClick={() => {
const newModel = {...selectedMetrics};
for (const metric of filteredCols) {
newModel[metric] = false;
}
setSelectedMetrics(newModel);
}}>
{`Hide ${buttonSuffix}`}
</Button>
<div className="flex-auto" />
<Button
size="small"
variant="quiet"
icon="show-visible"
disabled={filteredCols.length === 0}
onClick={() => {
const newModel = {...selectedMetrics};
for (const metric of filteredCols) {
newModel[metric] = true;
}
setSelectedMetrics(newModel);
}}>
{`Show ${buttonSuffix}`}
</Button>
</div>
</div>
</Tailwind>
</Popover>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,54 @@ import * as Plotly from 'plotly.js';
import React, {useEffect, useMemo, useRef} from 'react';

import {PLOT_GRID_COLOR} from '../../ecpConstants';
import {RadarPlotData} from './PlotlyRadarPlot';

export const PlotlyBarPlot: React.FC<{
height: number;
data: RadarPlotData;
yRange: [number, number];
plotlyData: Plotly.Data;
}> = props => {
const divRef = useRef<HTMLDivElement>(null);
const plotlyData: Plotly.Data[] = useMemo(() => {
return Object.keys(props.data).map((key, i) => {
const {metrics, name, color} = props.data[key];
return {
type: 'bar',
y: Object.values(metrics),
x: Object.keys(metrics),
name,
marker: {color},
};
});
}, [props.data]);

const plotlyLayout: Partial<Plotly.Layout> = useMemo(() => {
return {
height: props.height - 40,
height: props.height - 30,
showlegend: false,
margin: {
l: 0,
l: 20,
r: 0,
b: 20,
t: 0,
pad: 0,
t: 26,
},
bargap: 0.1,
xaxis: {
automargin: true,
fixedrange: true,
gridcolor: PLOT_GRID_COLOR,
linecolor: PLOT_GRID_COLOR,
showticklabels: false,
},
yaxis: {
fixedrange: true,
range: props.yRange,
gridcolor: PLOT_GRID_COLOR,
linecolor: PLOT_GRID_COLOR,
showticklabels: true,
tickfont: {
size: 10,
},
},
title: {
multiline: true,
text: props.plotlyData.name ?? '',
font: {size: 12},
xref: 'paper',
x: 0.5,
y: 1,
yanchor: 'top',
pad: {t: 2},
},
};
}, [props.height]);
}, [props.height, props.plotlyData, props.yRange]);

const plotlyConfig = useMemo(() => {
return {
displayModeBar: false,
Expand All @@ -57,11 +61,11 @@ export const PlotlyBarPlot: React.FC<{
useEffect(() => {
Plotly.newPlot(
divRef.current as any,
plotlyData,
[props.plotlyData],
plotlyLayout,
plotlyConfig
);
}, [plotlyConfig, plotlyData, plotlyLayout]);
}, [plotlyConfig, props.plotlyData, plotlyLayout]);

return <div ref={divRef}></div>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ export const PlotlyRadarPlot: React.FC<{
}, [props.data]);
const plotlyLayout: Partial<Plotly.Layout> = useMemo(() => {
return {
height: props.height,
height: props.height - 40,
showlegend: false,
margin: {
l: 60,
r: 0,
l: 20,
r: 20,
b: 30,
t: 30,
t: 20,
pad: 0,
},
polar: {
Expand Down
Loading
Loading