Skip to content
Open
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
5 changes: 3 additions & 2 deletions microimputation-dashboard/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
@import "tailwindcss";
@import "@policyengine/design-system/tokens.css";

:root {
--background: #ffffff;
--foreground: #171717;
--background: var(--pe-color-bg-primary);
--foreground: var(--pe-color-text-primary);
}

@theme inline {
Expand Down
1,013 changes: 1,013 additions & 0 deletions microimputation-dashboard/bun.lock

Large diffs are not rendered by default.

73 changes: 37 additions & 36 deletions microimputation-dashboard/components/BenchmarkLossCharts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from 'recharts';
import { ImputationDataPoint } from '@/types/imputation';
import { getMethodColor } from '@/utils/colors';
import { colors } from '@policyengine/design-system/tokens';

interface BenchmarkLossChartsProps {
data: ImputationDataPoint[];
Expand Down Expand Up @@ -413,24 +414,24 @@ export default function BenchmarkLossCharts({ data }: BenchmarkLossChartsProps)
</h3>
<ResponsiveContainer width="100%" height={400}>
<BarChart data={quantileChartData}>
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
<CartesianGrid strokeDasharray="3 3" stroke={colors.border.light} />
<XAxis
dataKey="quantile"
label={{ value: 'Quantiles', position: 'insideBottom', offset: -5 }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<YAxis
label={{ value: 'Test quantile loss', angle: -90, position: 'insideLeft' }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #ccc',
color: '#000',
backgroundColor: colors.white,
border: `1px solid ${colors.border.medium}`,
color: colors.text.primary,
}}
labelStyle={{ color: '#000', fontWeight: 'bold' }}
itemStyle={{ color: '#000' }}
labelStyle={{ color: colors.text.primary, fontWeight: 'bold' }}
itemStyle={{ color: colors.text.primary }}
formatter={(value: number) => value.toFixed(6)}
/>
<Legend wrapperStyle={{ paddingTop: '20px' }} />
Expand Down Expand Up @@ -462,23 +463,23 @@ export default function BenchmarkLossCharts({ data }: BenchmarkLossChartsProps)
</h3>
<ResponsiveContainer width="100%" height={400}>
<BarChart data={logLossChartData}>
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
<CartesianGrid strokeDasharray="3 3" stroke={colors.border.light} />
<XAxis
dataKey="method"
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<YAxis
label={{ value: 'Log loss', angle: -90, position: 'insideLeft' }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #ccc',
color: '#000',
backgroundColor: colors.white,
border: `1px solid ${colors.border.medium}`,
color: colors.text.primary,
}}
labelStyle={{ color: '#000', fontWeight: 'bold' }}
itemStyle={{ color: '#000' }}
labelStyle={{ color: colors.text.primary, fontWeight: 'bold' }}
itemStyle={{ color: colors.text.primary }}
formatter={(value: number) => [value.toFixed(6), 'Log loss']}
/>
<Bar dataKey="value">
Expand Down Expand Up @@ -534,29 +535,29 @@ export default function BenchmarkLossCharts({ data }: BenchmarkLossChartsProps)
<h4 className="text-lg font-semibold mb-3 text-gray-900">Quantile loss: train vs test</h4>
<ResponsiveContainer width="100%" height={350}>
<BarChart data={trainTestData.quantile}>
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
<CartesianGrid strokeDasharray="3 3" stroke={colors.border.light} />
<XAxis
dataKey="quantile"
label={{ value: 'Quantiles', position: 'insideBottom', offset: -5 }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<YAxis
label={{ value: 'Quantile loss', angle: -90, position: 'insideLeft' }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #ccc',
color: '#000',
backgroundColor: colors.white,
border: `1px solid ${colors.border.medium}`,
color: colors.text.primary,
}}
labelStyle={{ color: '#000', fontWeight: 'bold' }}
itemStyle={{ color: '#000' }}
labelStyle={{ color: colors.text.primary, fontWeight: 'bold' }}
itemStyle={{ color: colors.text.primary }}
formatter={(value: number) => value.toFixed(6)}
/>
<Legend wrapperStyle={{ paddingTop: '25px' }} />
<Bar dataKey="train" fill="#06b6d4" name="Train" />
<Bar dataKey="test" fill="#16a34a" name="Test" />
<Bar dataKey="train" fill={colors.primary[400]} name="Train" />
<Bar dataKey="test" fill={colors.success} name="Test" />
</BarChart>
</ResponsiveContainer>
</div>
Expand All @@ -568,28 +569,28 @@ export default function BenchmarkLossCharts({ data }: BenchmarkLossChartsProps)
<h4 className="text-lg font-semibold mb-3 text-gray-900">Log loss: train vs test</h4>
<ResponsiveContainer width="100%" height={350}>
<BarChart data={trainTestData.logLoss}>
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
<CartesianGrid strokeDasharray="3 3" stroke={colors.border.light} />
<XAxis
dataKey="category"
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<YAxis
label={{ value: 'Log loss', angle: -90, position: 'insideLeft' }}
tick={{ fill: '#666' }}
tick={{ fill: colors.gray[500] }}
/>
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #ccc',
color: '#000',
backgroundColor: colors.white,
border: `1px solid ${colors.border.medium}`,
color: colors.text.primary,
}}
labelStyle={{ color: '#000', fontWeight: 'bold' }}
itemStyle={{ color: '#000' }}
labelStyle={{ color: colors.text.primary, fontWeight: 'bold' }}
itemStyle={{ color: colors.text.primary }}
formatter={(value: number) => value.toFixed(6)}
/>
<Legend wrapperStyle={{ paddingTop: '25px' }} />
<Bar dataKey="train" fill="#06b6d4" name="Train" />
<Bar dataKey="test" fill="#16a34a" name="Test" />
<Bar dataKey="train" fill={colors.primary[400]} name="Train" />
<Bar dataKey="test" fill={colors.success} name="Test" />
</BarChart>
</ResponsiveContainer>
</div>
Expand Down
41 changes: 21 additions & 20 deletions microimputation-dashboard/components/DistributionOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ResponsiveContainer,
Brush,
} from 'recharts';
import { colors } from '@policyengine/design-system/tokens';

/**
* Format a number to scientific notation if it's very large or very small
Expand Down Expand Up @@ -161,22 +162,22 @@ export default function DistributionOverlay({
angle={-45}
textAnchor="end"
height={80}
tick={{ fill: '#000000', fontSize: 11 }}
tick={{ fill: colors.text.primary, fontSize: 11 }}
label={{
value: `${dist.variable} (binned values)`,
position: 'insideBottom',
offset: -50,
style: { fill: '#000000' },
style: { fill: colors.text.primary },
}}
/>
<YAxis
tick={{ fill: '#000000' }}
tick={{ fill: colors.text.primary }}
label={{
value: 'Percentage (%)',
angle: -90,
position: 'insideLeft',
offset: 10,
style: { fill: '#000000', textAnchor: 'middle' },
style: { fill: colors.text.primary, textAnchor: 'middle' },
}}
/>
<Tooltip
Expand All @@ -191,31 +192,31 @@ export default function DistributionOverlay({
}
return `Bin: ${_label}`;
}}
contentStyle={{ color: '#000000' }}
labelStyle={{ color: '#000000' }}
contentStyle={{ color: colors.text.primary }}
labelStyle={{ color: colors.text.primary }}
/>
<Bar
dataKey="Donor"
fill="#3b82f6"
fill={colors.blue[500]}
fillOpacity={0.7}
name={`Donor (n=${dist.nSamplesDonor})`}
/>
<Bar
dataKey="Receiver"
fill="#ef4444"
fill={colors.error}
fillOpacity={0.7}
name={`Receiver (n=${dist.nSamplesReceiver})`}
/>
<Brush
dataKey="name"
height={30}
stroke="#8884d8"
fill="#f3f4f6"
stroke={colors.primary[500]}
fill={colors.gray[50]}
tickFormatter={() => ''}
/>
<Legend
verticalAlign="bottom"
wrapperStyle={{ color: '#000000', paddingTop: '45px' }}
wrapperStyle={{ color: colors.text.primary, paddingTop: '45px' }}
/>
</BarChart>
</ResponsiveContainer>
Expand Down Expand Up @@ -244,39 +245,39 @@ export default function DistributionOverlay({
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="category"
tick={{ fill: '#000000', fontSize: 12 }}
tick={{ fill: colors.text.primary, fontSize: 12 }}
label={{
value: `${dist.variable} (categories)`,
position: 'insideBottom',
offset: -10,
style: { fill: '#000000' },
style: { fill: colors.text.primary },
}}
/>
<YAxis
tick={{ fill: '#000000' }}
tick={{ fill: colors.text.primary }}
label={{
value: 'Percentage (%)',
angle: -90,
position: 'insideLeft',
offset: 10,
style: { fill: '#000000', textAnchor: 'middle' },
style: { fill: colors.text.primary, textAnchor: 'middle' },
}}
/>
<Tooltip
formatter={(value: number) => [`${value.toFixed(2)}%`, '']}
contentStyle={{ color: '#000000' }}
labelStyle={{ color: '#000000' }}
contentStyle={{ color: colors.text.primary }}
labelStyle={{ color: colors.text.primary }}
/>
<Legend wrapperStyle={{ color: '#000000', paddingTop: '10px' }} />
<Legend wrapperStyle={{ color: colors.text.primary, paddingTop: '10px' }} />
<Bar
dataKey="Donor"
fill="#3b82f6"
fill={colors.blue[500]}
fillOpacity={0.7}
name={`Donor (n=${dist.nSamplesDonor})`}
/>
<Bar
dataKey="Receiver"
fill="#ef4444"
fill={colors.error}
fillOpacity={0.7}
name={`Receiver (n=${dist.nSamplesReceiver})`}
/>
Expand Down
41 changes: 21 additions & 20 deletions microimputation-dashboard/components/ImputationResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useMemo } from 'react';
import { ImputationDataPoint } from '@/types/imputation';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell } from 'recharts';
import DistributionOverlay from './DistributionOverlay';
import { colors } from '@policyengine/design-system/tokens';

interface ImputationResultsProps {
data: ImputationDataPoint[];
Expand Down Expand Up @@ -102,19 +103,19 @@ export default function ImputationResults({ data }: ImputationResultsProps) {
const value = normalizedValue ?? (rawValue * 100); // Assume raw is already a fraction if no range

// Thresholds as percentage of variable range
if (value < 1) return '#16a34a'; // Dark green - excellent (<1% of range)
if (value < 3) return '#22c55e'; // Green - good (<3% of range)
if (value < 5) return '#eab308'; // Yellow - moderate (<5% of range)
if (value < 10) return '#f97316'; // Orange - fair (<10% of range)
return '#ef4444'; // Red - poor (>=10% of range)
if (value < 1) return colors.success; // Green - excellent (<1% of range)
if (value < 3) return colors.success; // Green - good (<3% of range)
if (value < 5) return colors.warning; // Yellow - moderate (<5% of range)
if (value < 10) return colors.warning; // Yellow/orange - fair (<10% of range)
return colors.error; // Red - poor (>=10% of range)
};

const getKLColor = (value: number): string => {
if (value < 0.1) return '#16a34a'; // Dark green - excellent
if (value < 0.5) return '#22c55e'; // Green - good
if (value < 1.0) return '#eab308'; // Yellow - moderate
if (value < 5.0) return '#f97316'; // Orange - fair
return '#ef4444'; // Red - poor
if (value < 0.1) return colors.success; // Green - excellent
if (value < 0.5) return colors.success; // Green - good
if (value < 1.0) return colors.warning; // Yellow - moderate
if (value < 5.0) return colors.warning; // Yellow/orange - fair
return colors.error; // Red - poor
};

return (
Expand Down Expand Up @@ -168,19 +169,19 @@ export default function ImputationResults({ data }: ImputationResultsProps) {
margin={{ top: 20, right: 30, left: 100, bottom: 20 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis type="number" tick={{ fill: '#000000' }} />
<YAxis type="category" dataKey="variable" width={90} tick={{ fill: '#000000' }} />
<XAxis type="number" tick={{ fill: colors.text.primary }} />
<YAxis type="category" dataKey="variable" width={90} tick={{ fill: colors.text.primary }} />
<Tooltip
formatter={(value: number, _name: string, props: { payload?: DistributionMetric }) => {
const normalizedValue = props.payload?.normalizedValue;
const distanceStr = value.toFixed(6);
const pctStr = normalizedValue !== undefined ? ` (${normalizedValue.toFixed(2)}% of range)` : '';
return [`${distanceStr}${pctStr}`, 'Wasserstein Distance'];
}}
contentStyle={{ color: '#000000' }}
labelStyle={{ color: '#000000' }}
contentStyle={{ color: colors.text.primary }}
labelStyle={{ color: colors.text.primary }}
/>
<Legend wrapperStyle={{ color: '#000000' }} />
<Legend wrapperStyle={{ color: colors.text.primary }} />
<Bar dataKey="value" name="Wasserstein Distance">
{wassersteinData.map((entry, index) => (
<Cell
Expand Down Expand Up @@ -296,14 +297,14 @@ export default function ImputationResults({ data }: ImputationResultsProps) {
margin={{ top: 20, right: 30, left: 100, bottom: 20 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis type="number" tick={{ fill: '#000000' }} />
<YAxis type="category" dataKey="variable" width={90} tick={{ fill: '#000000' }} />
<XAxis type="number" tick={{ fill: colors.text.primary }} />
<YAxis type="category" dataKey="variable" width={90} tick={{ fill: colors.text.primary }} />
<Tooltip
formatter={(value: number) => [value.toFixed(6), 'KL-Divergence']}
contentStyle={{ color: '#000000' }}
labelStyle={{ color: '#000000' }}
contentStyle={{ color: colors.text.primary }}
labelStyle={{ color: colors.text.primary }}
/>
<Legend wrapperStyle={{ color: '#000000' }} />
<Legend wrapperStyle={{ color: colors.text.primary }} />
<Bar dataKey="value" name="KL-Divergence">
{klDivergenceData.map((entry, index) => (
<Cell
Expand Down
Loading