Skip to content

Commit 620b10c

Browse files
authored
fix: BROS-594: Count empty values in Task Summary (#8836)
Co-authored-by: hlomzik <[email protected]>
1 parent 9afe42a commit 620b10c

File tree

2 files changed

+14
-86
lines changed

2 files changed

+14
-86
lines changed

web/libs/editor/src/components/TaskSummary/Aggregation.tsx

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,15 @@ const resultValue = (result: RawResult) => {
2222
export const AggregationCell = ({
2323
control,
2424
annotations,
25-
countEmpty,
2625
isExpanded,
27-
}: { control: ControlTag; annotations: AnnotationSummary[]; countEmpty: boolean; isExpanded: boolean }) => {
26+
}: { control: ControlTag; annotations: AnnotationSummary[]; isExpanded: boolean }) => {
2827
const allResults = annotations.flatMap((ann) => ann.results.filter((r) => r.from_name === control.name));
28+
const totalAnnotations = annotations.length;
2929

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

34-
const totalAnnotations = countEmpty ? annotations.length : allResults.length;
35-
3634
// Handle labels-type controls (rectanglelabels, polygonlabels, labels, etc.)
3735
if (control.type.endsWith("labels")) {
3836
const allLabels = allResults.flatMap((r) => resultValue(r)).flat();
@@ -145,7 +143,7 @@ export const AggregationCell = ({
145143
const ratings = allResults.map((r) => resultValue(r)).filter(Boolean);
146144
if (!ratings.length) return <span className="text-neutral-content-subtler text-xs italic">No ratings</span>;
147145

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

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

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

173171
/**
@@ -177,14 +175,12 @@ export const AggregationCell = ({
177175
*/
178176
export const AggregationTableRow = ({
179177
headers,
180-
processedControls,
178+
controls,
181179
annotations,
182-
countEmpty,
183180
}: {
184181
headers: Header<AnnotationSummary, unknown>[];
185-
processedControls: ControlTag[];
182+
controls: ControlTag[];
186183
annotations: AnnotationSummary[];
187-
countEmpty: boolean;
188184
}) => {
189185
const [isExpanded, setIsExpanded] = useState(false);
190186
const [hasOverflow, setHasOverflow] = useState(false);
@@ -200,7 +196,7 @@ export const AggregationTableRow = ({
200196
});
201197

202198
setHasOverflow(hasOverflowingCells);
203-
}, [annotations, processedControls]);
199+
}, [annotations, controls]);
204200

205201
return (
206202
<tr ref={rowRef} className={cnm("relative z-2", styles["aggregation-row"])}>
@@ -233,12 +229,7 @@ export const AggregationTableRow = ({
233229
className="px-4 py-2.5 overflow-hidden border-y-2 border-neutral-border-bold"
234230
style={{ width: header.getSize() }}
235231
>
236-
<AggregationCell
237-
control={processedControls[index - 1]}
238-
annotations={annotations}
239-
countEmpty={countEmpty}
240-
isExpanded={isExpanded}
241-
/>
232+
<AggregationCell control={controls[index - 1]} annotations={annotations} isExpanded={isExpanded} />
242233
</td>
243234
),
244235
)}

web/libs/editor/src/components/TaskSummary/LabelingSummary.tsx

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ const columnHelper = createColumnHelper<AnnotationSummary>();
4646

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

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

73-
// Filter and sort controls based on toggles
74-
const processedControls = useMemo(() => {
75-
let result = [...controls];
76-
77-
// Filter out empty columns if showEmpty is false
78-
if (!showEmpty) {
79-
result = result.filter((control) => {
80-
const hasResults = annotations.some((ann) => ann.results.some((r) => r.from_name === control.name));
81-
return hasResults;
82-
});
83-
}
84-
85-
// Sort by popularity if enabled
86-
if (popularFirst) {
87-
result = result.sort((a, b) => {
88-
const aCount = annotations.reduce((sum, ann) => {
89-
return sum + ann.results.filter((r) => r.from_name === a.name).length;
90-
}, 0);
91-
const bCount = annotations.reduce((sum, ann) => {
92-
return sum + ann.results.filter((r) => r.from_name === b.name).length;
93-
}, 0);
94-
return bCount - aCount;
95-
});
96-
}
97-
98-
return result;
99-
}, [controls, annotations, showEmpty, popularFirst]);
100-
10170
// Measure initial column widths after first render
10271
useEffect(() => {
10372
if (tableRef.current && Object.keys(columnWidths).length === 0) {
10473
const headers = tableRef.current.querySelectorAll("thead th");
10574
const widths: Record<string, number> = {};
10675

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

11685
setColumnWidths(widths);
11786
}
118-
}, [processedControls, columnWidths]);
87+
}, [controls, columnWidths]);
11988

12089
const columns = useMemo(() => {
121-
const columns: ColumnDef<AnnotationSummary, unknown>[] = processedControls.map((control) =>
90+
const columns: ColumnDef<AnnotationSummary, unknown>[] = controls.map((control) =>
12291
columnHelper.display({
12392
id: control.name,
12493
header: () => (
@@ -165,7 +134,7 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect
165134
},
166135
});
167136
return columns;
168-
}, [processedControls, onSelect, hideInfo, columnWidths]);
137+
}, [controls, onSelect, hideInfo, columnWidths]);
169138

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

183152
return (
184153
<div className="mb-base">
185-
{/* Controls */}
186-
<div className="hidden gap-base mb-base p-tight bg-neutral-surface-subtle border border-neutral-border rounded-small">
187-
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
188-
<input
189-
type="checkbox"
190-
checked={showEmpty}
191-
onChange={(e) => setShowEmpty(e.target.checked)}
192-
className="cursor-pointer"
193-
/>
194-
<span className="text-sm font-medium">Show empty</span>
195-
</label>
196-
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
197-
<input
198-
type="checkbox"
199-
checked={countEmpty}
200-
onChange={(e) => setCountEmpty(e.target.checked)}
201-
className="cursor-pointer"
202-
/>
203-
<span className="text-sm font-medium">Count empty</span>
204-
</label>
205-
<label className="flex items-center gap-2 cursor-pointer hover:bg-neutral-surface px-2 py-1 rounded-small transition-colors">
206-
<input
207-
type="checkbox"
208-
checked={popularFirst}
209-
onChange={(e) => setPopularFirst(e.target.checked)}
210-
className="cursor-pointer"
211-
/>
212-
<span className="text-sm font-medium">Popular first</span>
213-
</label>
214-
</div>
215-
216154
<div className="overflow-x-auto pb-tight">
217155
<table
218156
ref={tableRef}
@@ -257,9 +195,8 @@ export const LabelingSummary = ({ hideInfo, annotations: all, controls, onSelect
257195
{/* Distribution/Aggregation Row */}
258196
<AggregationTableRow
259197
headers={table.getHeaderGroups()[0]?.headers ?? []}
260-
processedControls={processedControls}
198+
controls={controls}
261199
annotations={annotations}
262-
countEmpty={countEmpty}
263200
/>
264201
{/* Annotation Rows */}
265202
{table.getRowModel().rows.map((row, rowIndex) => (

0 commit comments

Comments
 (0)