fix: bar chart in day modal shows that day's field values per subject
Previously showed cumulative success/failure counts across all days. Now shows the selected field's actual value for each subject on that specific day — numeric values only, subjects with empty or non-numeric values are excluded from the chart. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,32 +48,30 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected
|
||||
return map;
|
||||
}, [allStatuses, dateStr]);
|
||||
|
||||
const barData = useMemo(() => {
|
||||
if (!selectedField) return [];
|
||||
const isBuiltin = BUILTIN_KEYS_SET.has(selectedField);
|
||||
return animals
|
||||
.map((animal) => {
|
||||
const statuses = allStatuses.filter((s) => s.animal_id === animal.id);
|
||||
const total = statuses.length;
|
||||
const success = statuses.filter((s) => {
|
||||
const val = isBuiltin ? s[selectedField] : s.custom_fields?.[selectedField];
|
||||
return val !== null && val !== undefined && String(val).trim() !== '';
|
||||
}).length;
|
||||
return {
|
||||
name: animal.animal_name || animal.animal_id_string || animal.id.slice(0, 8),
|
||||
total,
|
||||
success,
|
||||
failure: total - success,
|
||||
pct: total > 0 ? Math.round((success / total) * 100) : 0,
|
||||
};
|
||||
})
|
||||
.filter((d) => d.total > 0);
|
||||
}, [animals, allStatuses, selectedField]);
|
||||
// Only show animals that have a status record for this day
|
||||
const animalsWithData = animals.filter((a) => statusByAnimal[a.id]);
|
||||
|
||||
const fieldLabel = fieldOptions.find((f) => f.value === selectedField)?.label;
|
||||
|
||||
// Only show animals that have a status record for this day
|
||||
const animalsWithData = animals.filter((a) => statusByAnimal[a.id]);
|
||||
// Bar chart: this day's field value per subject (numeric fields only)
|
||||
const barData = useMemo(() => {
|
||||
if (!selectedField) return [];
|
||||
const isBuiltin = BUILTIN_KEYS_SET.has(selectedField);
|
||||
return animalsWithData
|
||||
.map((animal) => {
|
||||
const status = statusByAnimal[animal.id];
|
||||
if (!status) return null;
|
||||
const raw = isBuiltin ? status[selectedField] : status.custom_fields?.[selectedField];
|
||||
if (raw === null || raw === undefined || String(raw).trim() === '') return null;
|
||||
const num = parseFloat(raw);
|
||||
if (isNaN(num)) return null;
|
||||
return {
|
||||
name: animal.animal_name || animal.animal_id_string || animal.id.slice(0, 8),
|
||||
value: num,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}, [animalsWithData, statusByAnimal, selectedField]);
|
||||
|
||||
return (
|
||||
<div className="space-y-3 max-h-[80vh] overflow-y-auto pr-1">
|
||||
@@ -123,28 +121,17 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected
|
||||
{barData.length > 0 && (
|
||||
<div className="mt-4 pt-4 border-t border-gray-100">
|
||||
<h4 className="text-sm font-semibold text-gray-700 mb-3">
|
||||
Overall completeness by subject
|
||||
{fieldLabel && <span className="ml-2 font-normal text-gray-400">— {fieldLabel}</span>}
|
||||
{fieldLabel ?? 'Field'} by subject
|
||||
</h4>
|
||||
<ResponsiveContainer width="100%" height={200}>
|
||||
<BarChart data={barData} margin={{ top: 4, right: 16, left: 0, bottom: 4 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||
<XAxis dataKey="name" tick={{ fontSize: 11 }} />
|
||||
<YAxis tick={{ fontSize: 11 }} allowDecimals={false} />
|
||||
<Tooltip />
|
||||
<Legend wrapperStyle={{ fontSize: 11 }} />
|
||||
<Bar dataKey="total" name="Total" fill="#94a3b8" />
|
||||
<Bar dataKey="success" name="Success" fill="#22c55e" />
|
||||
<Bar dataKey="failure" name="Failure" fill="#f87171" minPointSize={2} />
|
||||
<YAxis tick={{ fontSize: 11 }} />
|
||||
<Tooltip formatter={(v) => [v, fieldLabel ?? 'Value']} />
|
||||
<Bar dataKey="value" name={fieldLabel ?? 'Value'} fill="#6366f1" radius={[3, 3, 0, 0]} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
<div className="mt-2 flex flex-wrap gap-4">
|
||||
{barData.map((d) => (
|
||||
<span key={d.name} className="text-xs text-gray-500">
|
||||
<span className="font-medium text-gray-700">{d.name}</span>: {d.pct}% complete
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user