feat(export): buildSubjectSeriesMatrix — subjects as columns over an X field

This commit is contained in:
Experiments DB Dev
2026-07-19 14:59:42 -04:00
parent 8510903771
commit 39a5a4ec0c
2 changed files with 94 additions and 0 deletions
+36
View File
@@ -120,6 +120,42 @@ export function buildSampleIndex(statuses, xField, dailyTemplate) {
return index;
}
function xFieldLabel(xField, dailyTemplate) {
if (xField === '__date__') return 'Date';
if (xField === '__days__') return '# Days Reach';
return (dailyTemplate ?? []).find((f) => f.fieldId === xField)?.label ?? '';
}
// Subjects as columns, X-field values as rows, one Data value per cell.
// Returns the { context, corner, groupAxis, columns, rows } shape toCSV consumes.
export function buildSubjectSeriesMatrix({ xField, dataParam, groupField }, { statuses, animals, dailyTemplate }) {
const columns = listSubjectMembers(animals, groupField);
const rowMembers = listSampleMembers(statuses, xField, dailyTemplate);
const index = buildSampleIndex(statuses, xField, dailyTemplate);
const cellValue = (sampleValue, animalId) => {
const status = index.get(animalId)?.get(sampleValue);
if (!status || !dataParam) return '';
const v = extractValue(status, dataParam);
return hasValue(v) ? v : '';
};
let rows = rowMembers.map((rm) => ({
member: rm,
values: columns.map((c) => cellValue(rm.sampleValue, c.animalId)),
}));
rows = rows.filter((r) => r.values.some((v) => v !== '')); // drop entirely-blank sample rows
const grouped = !!groupField && groupField !== '__none__';
return {
corner: xFieldLabel(xField, dailyTemplate),
context: { label: 'Data', value: dataParam?.label ?? '' },
groupAxis: grouped ? 'col' : null,
columns,
rows,
};
}
export const EXPORT_DIMENSIONS = [
{ dim: 'date', label: 'Date' },
{ dim: 'subject', label: 'Subject' },