Skip to content
Merged
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: 5 additions & 0 deletions src/components/DatasetCompositionChart.css
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@

.pie-chart-container {
margin: 1rem 0;
min-height: 420px;
}
}

Expand All @@ -103,4 +104,8 @@
.chart-title {
font-size: 1.1rem;
}

.pie-chart-container {
min-height: 300px;
}
}
58 changes: 47 additions & 11 deletions src/components/DatasetCompositionChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, LabelList } from 'recharts';
import './DatasetCompositionChart.css';

Expand Down Expand Up @@ -105,13 +105,49 @@ const DatasetCompositionChart: React.FC = () => {
const [hoveredCategory, setHoveredCategory] = useState<string | null>(null);
const [hoveredSubcategory, setHoveredSubcategory] = useState<string | null>(null);

// Define chart dimensions as constants for easy adjustment
const CHART_DIMENSIONS = {
innerRadius: 100,
outerRadius: 250,
labelRadius: 330, // Distance from center to labels
chartSize: 800, // Container height
};
const [viewportWidth, setViewportWidth] = useState(
typeof window !== 'undefined' ? window.innerWidth : 1200
);

useEffect(() => {
if (typeof window === 'undefined') return;
const handleResize = () => setViewportWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const CHART_DIMENSIONS = useMemo(() => {
if (viewportWidth <= 480) {
return {
innerRadius: 50,
outerRadius: 125,
labelRadius: 185,
chartSize: 320,
};
}
if (viewportWidth <= 768) {
return {
innerRadius: 70,
outerRadius: 170,
labelRadius: 240,
chartSize: 460,
};
}
if (viewportWidth <= 1024) {
return {
innerRadius: 90,
outerRadius: 210,
labelRadius: 290,
chartSize: 620,
};
}
return {
innerRadius: 100,
outerRadius: 250,
labelRadius: 330,
chartSize: 800,
};
}, [viewportWidth]);

// Prepare data for the main pie chart (outer ring)
const prepareMainChartData = (): ChartData[] => {
Expand Down Expand Up @@ -323,7 +359,7 @@ const DatasetCompositionChart: React.FC = () => {
pointerEvents: 'none',
zIndex: 0,
}}
viewBox="0 0 800 800"
viewBox={`0 0 ${CHART_DIMENSIONS.chartSize} ${CHART_DIMENSIONS.chartSize}`}
>
{mainChartData.map((entry, index) => {
const totalValue = mainChartData.reduce((sum, item) => sum + item.value, 0);
Expand All @@ -347,8 +383,8 @@ const DatasetCompositionChart: React.FC = () => {
const radius = CHART_DIMENSIONS.outerRadius + baseOffset + sideBoost * angleFactor;

// Use exact center coordinates matching Recharts
const centerX = 400; // Exact center of 800x800 viewBox
const centerY = 400; // Exact center of 800x800 viewBox
const centerX = CHART_DIMENSIONS.chartSize / 2;
const centerY = CHART_DIMENSIONS.chartSize / 2;
const x = centerX - radius * Math.sin(midAngle * RADIAN);
const y = centerY - radius * Math.cos(midAngle * RADIAN);

Expand Down
14 changes: 14 additions & 0 deletions src/components/DeferralCurve.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
.deferral-curve-wrapper svg {
overflow: visible;
flex-shrink: 0;
height: auto;
max-width: 500px;
}

.deferral-legend-side {
Expand Down Expand Up @@ -99,3 +101,15 @@
grid-template-columns: repeat(2, 1fr);
}
}

@media (max-width: 640px) {
.deferral-legend-side {
flex-direction: column;
align-items: stretch;
gap: 1.5rem;
}

.legend-items {
grid-template-columns: 1fr;
}
}
71 changes: 58 additions & 13 deletions src/components/DeferralCurve.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import './DeferralCurve.css';

interface DeferralCurveProps {
Expand All @@ -11,6 +11,44 @@ interface DeferralCurveProps {
}

const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedSourcePoints }) => {
const [viewportWidth, setViewportWidth] = useState(
typeof window !== 'undefined' ? window.innerWidth : 1200
);

useEffect(() => {
if (typeof window === 'undefined') return;
const handleResize = () => setViewportWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const chartLayout = useMemo(() => {
if (viewportWidth <= 480) {
return {
width: 320,
height: 260,
margin: { top: 15, right: 10, bottom: 50, left: 60 },
pointSize: 5,
fontScale: 0.78,
};
}
if (viewportWidth <= 768) {
return {
width: 400,
height: 320,
margin: { top: 20, right: 15, bottom: 55, left: 70 },
pointSize: 6,
fontScale: 0.9,
};
}
return {
width: 500,
height: 400,
margin: { top: 20, right: 20, bottom: 60, left: 80 },
pointSize: 6.5,
fontScale: 1,
};
}, [viewportWidth]);
// Extract all accuracy and cost values
const allPoints = [...Object.values(openSourcePoints), ...Object.values(closedSourcePoints)];
const accuracyValues = allPoints.map(p => p.accuracy);
Expand All @@ -32,9 +70,9 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
const costMax = maxCost * 1.2; // Extend a bit beyond maximum

// Chart dimensions
const chartWidth = 500;
const chartHeight = 400;
const margin = { top: 20, right: 20, bottom: 60, left: 80 };
const chartWidth = chartLayout.width;
const chartHeight = chartLayout.height;
const margin = chartLayout.margin;
const plotWidth = chartWidth - margin.left - margin.right;
const plotHeight = chartHeight - margin.top - margin.bottom;

Expand Down Expand Up @@ -67,8 +105,14 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
];

// Function to render different shapes
const renderShape = (x: number, y: number, shape: string, color: string, key: string) => {
const size = 6;
const renderShape = (
x: number,
y: number,
shape: string,
color: string,
key: string,
size: number = chartLayout.pointSize
) => {
switch (shape) {
case 'square':
return (
Expand Down Expand Up @@ -163,6 +207,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
};

const costTicks = generatePowersOf10(costMin, costMax);
const scaledFont = (size: number) => size * chartLayout.fontScale;

return (
<div className="deferral-curve-container">
Expand Down Expand Up @@ -234,7 +279,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
<text
x={margin.left + plotWidth - 5}
y={scaleY(0.9089) - 8}
fontSize="1.15rem"
fontSize={scaledFont(18)}
fill="#22c55e"
textAnchor="end"
fontWeight="600"
Expand Down Expand Up @@ -276,7 +321,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
<text
x={x}
y={margin.top + plotHeight + 20}
fontSize="1.1rem"
fontSize={scaledFont(17)}
fill="#374151"
textAnchor="middle"
>
Expand All @@ -303,7 +348,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
<text
x={margin.left - 10}
y={y + 4}
fontSize="1.1rem"
fontSize={scaledFont(17)}
fill="#374151"
textAnchor="end"
>
Expand All @@ -319,7 +364,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
<text
x={margin.left + plotWidth / 2}
y={chartHeight - 10}
fontSize="16"
fontSize={scaledFont(16)}
fill="#374151"
textAnchor="middle"
fontWeight="500"
Expand All @@ -329,7 +374,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
<text
x={20}
y={margin.top + plotHeight / 2}
fontSize="16"
fontSize={scaledFont(16)}
fill="#374151"
textAnchor="middle"
fontWeight="500"
Expand All @@ -349,7 +394,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
return (
<div key={name} className="legend-item">
<svg className="legend-shape" width="16" height="16">
{renderShape(8, 8, 'circle', color, `legend-${name}`)}
{renderShape(8, 8, 'circle', color, `legend-${name}`, 5)}
</svg>
<span className="legend-label">{name}</span>
</div>
Expand All @@ -367,7 +412,7 @@ const DeferralCurve: React.FC<DeferralCurveProps> = ({ openSourcePoints, closedS
return (
<div key={name} className="legend-item">
<svg className="legend-shape" width="16" height="16">
{renderShape(8, 8, 'triangle', color, `legend-${name}`)}
{renderShape(8, 8, 'triangle', color, `legend-${name}`, 5)}
</svg>
<span className="legend-label">{name}</span>
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/SpiderChart.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
border-radius: 0;
padding: 0;
box-shadow: none;
max-width: 600px;
max-width: 100%;
margin: 0 auto;
overflow: visible;
width: 100%;
}

.spider-chart svg {
overflow: visible;
width: 100%;
height: auto;
max-width: 450px;
}

.metric-label {
Expand Down
43 changes: 34 additions & 9 deletions src/components/SpiderChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { Router } from '../types';
import './SpiderChart.css';

Expand All @@ -8,6 +8,27 @@ interface SpiderChartProps {
}

const SpiderChart: React.FC<SpiderChartProps> = ({ routers, maxRouters = 5 }) => {
const [viewportWidth, setViewportWidth] = useState(
typeof window !== 'undefined' ? window.innerWidth : 1200
);

useEffect(() => {
if (typeof window === 'undefined') return;
const handleResize = () => setViewportWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const chartLayout = useMemo(() => {
if (viewportWidth <= 480) {
return { size: 300, radius: 120, labelOffset: 28, fontScale: 0.8 };
}
if (viewportWidth <= 768) {
return { size: 360, radius: 150, labelOffset: 35, fontScale: 0.9 };
}
return { size: 450, radius: 180, labelOffset: 40, fontScale: 1 };
}, [viewportWidth]);

// Get top N routers by overall rank
const topRouters = routers
.sort((a, b) => a.metrics.overallRank - b.metrics.overallRank)
Expand Down Expand Up @@ -71,14 +92,18 @@ const SpiderChart: React.FC<SpiderChartProps> = ({ routers, maxRouters = 5 }) =>
const axisMax = 100;
const axisRange = axisMax - axisMin;

const chartRadius = 180;
const centerX = 225;
const centerY = 225;
const chartRadius = chartLayout.radius;
const centerX = chartLayout.size / 2;
const centerY = chartLayout.size / 2;

return (
<div className="spider-chart-container">
<div className="spider-chart">
<svg width="450" height="450" viewBox="0 0 450 450">
<svg
width={chartLayout.size}
height={chartLayout.size}
viewBox={`0 0 ${chartLayout.size} ${chartLayout.size}`}
>
{/* Grid circles drawn at fixed 0-100 scale */}
{gridTicks.map((value, index) => {
const scale = (value - axisMin) / axisRange;
Expand All @@ -101,7 +126,7 @@ const SpiderChart: React.FC<SpiderChartProps> = ({ routers, maxRouters = 5 }) =>
dominantBaseline="middle"
className="grid-label"
fill="#9ca3af"
fontSize="22"
fontSize={22 * chartLayout.fontScale}
>
{value.toString()}
</text>
Expand Down Expand Up @@ -131,8 +156,8 @@ const SpiderChart: React.FC<SpiderChartProps> = ({ routers, maxRouters = 5 }) =>
{/* Metric labels */}
{metrics.map((metric, index) => {
const angle = (index * 2 * Math.PI) / metrics.length - Math.PI / 2;
const labelX = centerX + Math.cos(angle) * (chartRadius + 40);
const labelY = centerY + Math.sin(angle) * (chartRadius + 40);
const labelX = centerX + Math.cos(angle) * (chartRadius + chartLayout.labelOffset);
const labelY = centerY + Math.sin(angle) * (chartRadius + chartLayout.labelOffset);

return (
<g key={metric.key}>
Expand All @@ -143,7 +168,7 @@ const SpiderChart: React.FC<SpiderChartProps> = ({ routers, maxRouters = 5 }) =>
dominantBaseline="middle"
className="metric-label"
fill="#1f2937"
fontSize="16"
fontSize={16 * chartLayout.fontScale}
fontWeight="600"
>
{metric.label}
Expand Down
4 changes: 2 additions & 2 deletions src/data/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ const routersWithRanks = rawRouterData.map(router => {
optimalAccScore: roundNullableToOneDecimal(router['Optimal Acc. Score']),
robustnessScore: roundNullableToOneDecimal(router['Robustness Score']),
latencyScore: roundNullableToOneDecimal(router['Latency Score']),
accuracy: roundToOneDecimal(router['Accuracy']),
costPer1k: roundToOneDecimal(router['Cost per 1k']),
accuracy: router['Accuracy'],
costPer1k: router['Cost per 1k'],
overallRank: 0, // Will be calculated below
};

Expand Down
Loading