Skip to content
Merged
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
27 changes: 9 additions & 18 deletions web/libs/editor/src/components/TaskSummary/Aggregation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,15 @@ const resultValue = (result: RawResult) => {
export const AggregationCell = ({
control,
annotations,
countEmpty,
isExpanded,
}: { control: ControlTag; annotations: AnnotationSummary[]; countEmpty: boolean; isExpanded: boolean }) => {
}: { control: ControlTag; annotations: AnnotationSummary[]; isExpanded: boolean }) => {
const allResults = annotations.flatMap((ann) => ann.results.filter((r) => r.from_name === control.name));
const totalAnnotations = annotations.length;

if (!allResults.length) {
return <span className="text-neutral-content-subtler text-xs italic">No data</span>;
}

const totalAnnotations = countEmpty ? annotations.length : allResults.length;

// Handle labels-type controls (rectanglelabels, polygonlabels, labels, etc.)
if (control.type.endsWith("labels")) {
const allLabels = allResults.flatMap((r) => resultValue(r)).flat();
Expand Down Expand Up @@ -145,7 +143,7 @@ export const AggregationCell = ({
const ratings = allResults.map((r) => resultValue(r)).filter(Boolean);
if (!ratings.length) return <span className="text-neutral-content-subtler text-xs italic">No ratings</span>;

const avgRating = ratings.reduce((sum, val) => sum + val, 0) / (countEmpty ? totalAnnotations : ratings.length);
const avgRating = ratings.reduce((sum, val) => sum + val, 0) / totalAnnotations;
return (
<span className="text-sm font-medium text-neutral-content-subtle">
Avg: <span className="font-bold">{avgRating.toFixed(1)}</span> <span className="text-yellow-500">★</span>
Expand All @@ -158,7 +156,7 @@ export const AggregationCell = ({
const numbers = allResults.map((r) => resultValue(r)).filter((v) => v !== null && v !== undefined);
if (!numbers.length) return <span className="text-neutral-content-subtler text-xs italic">No data</span>;

const avg = numbers.reduce((sum, val) => sum + Number(val), 0) / (countEmpty ? totalAnnotations : numbers.length);
const avg = numbers.reduce((sum, val) => sum + Number(val), 0) / totalAnnotations;
return (
<span className="text-sm font-medium text-neutral-content-subtle">
Avg: <span className="font-bold">{avg.toFixed(1)}</span>
Expand All @@ -167,7 +165,7 @@ export const AggregationCell = ({
}

// Default: show N/A
return <span className="text-sm font-medium text-neutral-content-subtler">N/A</span>;
return <span className="text-neutral-content-subtler text-xs italic">N/A</span>;
};

/**
Expand All @@ -177,14 +175,12 @@ export const AggregationCell = ({
*/
export const AggregationTableRow = ({
headers,
processedControls,
controls,
annotations,
countEmpty,
}: {
headers: Header<AnnotationSummary, unknown>[];
processedControls: ControlTag[];
controls: ControlTag[];
annotations: AnnotationSummary[];
countEmpty: boolean;
}) => {
const [isExpanded, setIsExpanded] = useState(false);
const [hasOverflow, setHasOverflow] = useState(false);
Expand All @@ -200,7 +196,7 @@ export const AggregationTableRow = ({
});

setHasOverflow(hasOverflowingCells);
}, [annotations, processedControls]);
}, [annotations, controls]);

return (
<tr ref={rowRef} className={cnm("relative z-2", styles["aggregation-row"])}>
Expand Down Expand Up @@ -233,12 +229,7 @@ export const AggregationTableRow = ({
className="px-4 py-2.5 overflow-hidden border-y-2 border-neutral-border-bold"
style={{ width: header.getSize() }}
>
<AggregationCell
control={processedControls[index - 1]}
annotations={annotations}
countEmpty={countEmpty}
isExpanded={isExpanded}
/>
<AggregationCell control={controls[index - 1]} annotations={annotations} isExpanded={isExpanded} />
</td>
),
)}
Expand Down
73 changes: 5 additions & 68 deletions web/libs/editor/src/components/TaskSummary/LabelingSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ const columnHelper = createColumnHelper<AnnotationSummary>();

export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect }: Props) => {
const currentUser = window.APP_SETTINGS?.user;
const [showEmpty, setShowEmpty] = useState(true);
const [countEmpty, setCountEmpty] = useState(false);
const [popularFirst, setPopularFirst] = useState(false);
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
const tableRef = useRef<HTMLTableElement>(null);

Expand All @@ -70,42 +67,14 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect
: (annotation.versions.result ?? []),
}));

// Filter and sort controls based on toggles
const processedControls = useMemo(() => {
let result = [...controls];

// Filter out empty columns if showEmpty is false
if (!showEmpty) {
result = result.filter((control) => {
const hasResults = annotations.some((ann) => ann.results.some((r) => r.from_name === control.name));
return hasResults;
});
}

// Sort by popularity if enabled
if (popularFirst) {
result = result.sort((a, b) => {
const aCount = annotations.reduce((sum, ann) => {
return sum + ann.results.filter((r) => r.from_name === a.name).length;
}, 0);
const bCount = annotations.reduce((sum, ann) => {
return sum + ann.results.filter((r) => r.from_name === b.name).length;
}, 0);
return bCount - aCount;
});
}

return result;
}, [controls, annotations, showEmpty, popularFirst]);

// Measure initial column widths after first render
useEffect(() => {
if (tableRef.current && Object.keys(columnWidths).length === 0) {
const headers = tableRef.current.querySelectorAll("thead th");
const widths: Record<string, number> = {};

headers.forEach((header, index) => {
const columnId = index === 0 ? "id" : processedControls[index - 1]?.name;
const columnId = index === 0 ? "id" : controls[index - 1]?.name;
if (columnId) {
// Get the computed width
const width = header.getBoundingClientRect().width;
Expand All @@ -115,10 +84,10 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect

setColumnWidths(widths);
}
}, [processedControls, columnWidths]);
}, [controls, columnWidths]);

const columns = useMemo(() => {
const columns: ColumnDef<AnnotationSummary, unknown>[] = processedControls.map((control) =>
const columns: ColumnDef<AnnotationSummary, unknown>[] = controls.map((control) =>
columnHelper.display({
id: control.name,
header: () => (
Expand Down Expand Up @@ -165,7 +134,7 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect
},
});
return columns;
}, [processedControls, onSelect, hideInfo, columnWidths]);
}, [controls, onSelect, hideInfo, columnWidths]);

const table = useReactTable<AnnotationSummary>({
data: annotations,
Expand All @@ -182,37 +151,6 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect

return (
<div className="mb-base">
{/* Controls */}
<div className="hidden gap-base mb-base p-tight bg-neutral-surface-subtle border border-neutral-border rounded-small">
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
<input
type="checkbox"
checked={showEmpty}
onChange={(e) => setShowEmpty(e.target.checked)}
className="cursor-pointer"
/>
<span className="text-sm font-medium">Show empty</span>
</label>
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
<input
type="checkbox"
checked={countEmpty}
onChange={(e) => setCountEmpty(e.target.checked)}
className="cursor-pointer"
/>
<span className="text-sm font-medium">Count empty</span>
</label>
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
<input
type="checkbox"
checked={popularFirst}
onChange={(e) => setPopularFirst(e.target.checked)}
className="cursor-pointer"
/>
<span className="text-sm font-medium">Popular first</span>
</label>
</div>

<div className="overflow-x-auto pb-tight">
<table
ref={tableRef}
Expand Down Expand Up @@ -257,9 +195,8 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect
{/* Distribution/Aggregation Row */}
<AggregationTableRow
headers={table.getHeaderGroups()[0]?.headers ?? []}
processedControls={processedControls}
controls={controls}
annotations={annotations}
countEmpty={countEmpty}
/>
{/* Annotation Rows */}
{table.getRowModel().rows.map((row, rowIndex) => (
Expand Down
Loading