Skip to content
Draft
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
272 changes: 125 additions & 147 deletions microcalibration-dashboard/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion microcalibration-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@
"eslint": "^9",
"eslint-config-next": "15.3.4",
"tailwindcss": "^4",
"typescript": "^5"
"typescript": "5.9.3"
}
}
36,974 changes: 36,867 additions & 107 deletions microcalibration-dashboard/public/calibration_log.csv

Large diffs are not rendered by default.

62 changes: 28 additions & 34 deletions microcalibration-dashboard/src/components/FileUpload.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useState, useEffect, useCallback } from 'react';
import Papa from 'papaparse';
import { Upload, File as FileIcon, Link, Database, GitBranch } from 'lucide-react';
import JSZip from 'jszip';
import { DeeplinkParams, GitHubArtifactInfo } from '@/utils/deeplinks';
Expand Down Expand Up @@ -233,58 +234,51 @@ export default function FileUpload({
}, [deeplinkParams, isLoadingFromDeeplink, loadDeeplinkArtifacts]);

function sampleEpochs(csvContent: string, maxEpochs = 10): { content: string; wasSampled: boolean; originalEpochs: number; sampledEpochs: number } {
const lines = csvContent.trim().split('\n');
const header = lines[0];
const dataLines = lines.slice(1);

if (dataLines.length === 0) return { content: csvContent, wasSampled: false, originalEpochs: 0, sampledEpochs: 0 };

// Parse epoch column index
const headerCols = header.toLowerCase().split(',');
const epochIndex = headerCols.findIndex(col => col.trim() === 'epoch');

if (epochIndex === -1) return { content: csvContent, wasSampled: false, originalEpochs: 0, sampledEpochs: 0 };

// Group data by epoch
const epochData = new Map<number, string[]>();
dataLines.forEach(line => {
const cols = line.split(',');
const epoch = parseInt(cols[epochIndex]);
const parsed = Papa.parse<Record<string, string>>(csvContent, {
header: true,
skipEmptyLines: true,
});

if (parsed.data.length === 0 || !parsed.meta.fields?.includes('epoch')) {
return { content: csvContent, wasSampled: false, originalEpochs: 0, sampledEpochs: 0 };
}

const epochData = new Map<number, Record<string, string>[]>();
parsed.data.forEach(row => {
const epoch = parseInt(row.epoch);
if (!isNaN(epoch)) {
if (!epochData.has(epoch)) {
epochData.set(epoch, []);
}
epochData.get(epoch)!.push(line);
epochData.get(epoch)!.push(row);
}
});

// Get sorted unique epochs

const allEpochs = Array.from(epochData.keys()).sort((a, b) => a - b);
const originalEpochCount = allEpochs.length;

if (allEpochs.length <= maxEpochs) {
return { content: csvContent, wasSampled: false, originalEpochs: originalEpochCount, sampledEpochs: originalEpochCount };
}

// Sample evenly spaced epochs

const sampledEpochs: number[] = [];
for (let i = 0; i < maxEpochs; i++) {
const index = Math.round((i / (maxEpochs - 1)) * (allEpochs.length - 1));
sampledEpochs.push(allEpochs[index]);
}

// Collect sampled data
const sampledLines: string[] = [header];

const sampledRows: Record<string, string>[] = [];
sampledEpochs.forEach(epoch => {
const epochLines = epochData.get(epoch) || [];
sampledLines.push(...epochLines);
const rows = epochData.get(epoch) || [];
sampledRows.push(...rows);
});

return {
content: sampledLines.join('\n'),
wasSampled: true,
originalEpochs: originalEpochCount,
sampledEpochs: maxEpochs

const output = Papa.unparse(sampledRows, { columns: parsed.meta.fields });
return {
content: output,
wasSampled: true,
originalEpochs: originalEpochCount,
sampledEpochs: maxEpochs,
};
}

Expand Down
11 changes: 8 additions & 3 deletions microcalibration-dashboard/src/components/MetricsOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ export default function MetricsOverview({ data }: MetricsOverviewProps) {

// Calculate convergence epoch
const lossByEpoch = allEpochs.map(epoch => {
const epochData = data.find(d => d.epoch === epoch);
return { epoch, loss: epochData?.loss || 0 };
const epochData = data.filter(d => d.epoch === epoch);
const meanLoss = epochData.length > 0
? epochData.reduce((sum, d) => sum + d.loss, 0) / epochData.length
: 0;
return { epoch, loss: meanLoss };
});

let convergenceEpoch: number | undefined;
Expand All @@ -43,7 +46,9 @@ export default function MetricsOverview({ data }: MetricsOverviewProps) {
// Calculate quality metrics
const totalTargets = latestData.length;
const avgRelAbsError = latestData.reduce((sum, item) => sum + item.rel_abs_error, 0) / totalTargets;
const finalLoss = latestData[0]?.loss || 0;
const finalLoss = latestData.length > 0
? latestData.reduce((sum, item) => sum + item.loss, 0) / latestData.length
: 0;

// Categorize targets by error quality
const excellentCount = latestData.filter(item => item.rel_abs_error < 0.05).length;
Expand Down
1 change: 1 addition & 0 deletions microcalibration-dashboard/src/types/calibration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface CalibrationDataPoint {
error: number;
abs_error: number;
rel_abs_error: number;
rel_error?: number;
}

export interface CalibrationMetrics {
Expand Down
12 changes: 9 additions & 3 deletions microcalibration-dashboard/src/utils/csvParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,19 @@ export function getCalibrationMetrics(data: CalibrationDataPoint[]): Calibration
const epochs = [...new Set(data.map(d => d.epoch))].sort((a, b) => a - b);
const targetNames = [...new Set(data.map(d => d.target_name))];
const finalEpoch = epochs.length > 0 ? epochs[epochs.length - 1] : 0;
const finalLoss = data.find(d => d.epoch === finalEpoch)?.loss || 0;
const finalEpochData = data.filter(d => d.epoch === finalEpoch);
const finalLoss = finalEpochData.length > 0
? finalEpochData.reduce((sum, d) => sum + d.loss, 0) / finalEpochData.length
: 0;

// Find convergence epoch (when loss stops decreasing significantly)
let convergenceEpoch: number | undefined;
const lossByEpoch = epochs.map(epoch => {
const epochData = data.find(d => d.epoch === epoch);
return { epoch, loss: epochData?.loss || 0 };
const epochData = data.filter(d => d.epoch === epoch);
const meanLoss = epochData.length > 0
? epochData.reduce((sum, d) => sum + d.loss, 0) / epochData.length
: 0;
return { epoch, loss: meanLoss };
});

for (let i = 1; i < lossByEpoch.length; i++) {
Expand Down
Loading