Skip to content

Commit 9c16baa

Browse files
authored
Add resolved vs model release date scatter chart (#48)
- Create js/modelReleaseDates.js with verified release dates for 74 models (90.2% coverage) from official sources including Anthropic, OpenAI, Google, Meta, Mistral, DeepSeek, Qwen, ZhipuAI, Moonshot, MiniMax, ByteDance, and Amazon - Create js/charts/resolvedVsReleaseDateChart.js scatter chart renderer with time-based X-axis and model labels - Add chartjs-adapter-date-fns CDN import for time scale support - Add "Resolved vs model release date" option to chart type dropdown - Update getSelectedModels() to include tags in returned data
1 parent 766cf11 commit 9c16baa

4 files changed

Lines changed: 452 additions & 1 deletion

File tree

js/analysis.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
name: modelName,
5050
resolved: parseFloat(cb.getAttribute('data-resolved')) || 0,
5151
cost: cost,
52-
per_instance_details: fullModelData?.per_instance_details || null
52+
per_instance_details: fullModelData?.per_instance_details || null,
53+
tags: fullModelData?.tags || null
5354
};
5455
});
5556
}
@@ -325,6 +326,14 @@
325326
empty.style.display = '';
326327
}
327328
}
329+
} else if (chartType === 'resolved-vs-release-date') {
330+
compareChart = renderResolvedVsReleaseDateChart(ctx, selected, colors, backgroundPlugin);
331+
if (!compareChart) {
332+
if (empty) {
333+
empty.textContent = 'No release date data available for selected models.';
334+
empty.style.display = '';
335+
}
336+
}
328337
} else {
329338
// Default to bar chart
330339
compareChart = renderBarChart(ctx, selected, colors, backgroundPlugin);
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Scatter chart for resolved % vs model release date
2+
function renderResolvedVsReleaseDateChart(ctx, selected, colors, backgroundPlugin) {
3+
// Filter models with release dates
4+
const modelsWithDates = selected.filter(s => {
5+
const releaseDate = getModelReleaseDate(s.tags);
6+
return releaseDate !== null;
7+
});
8+
9+
if (modelsWithDates.length === 0) {
10+
return null;
11+
}
12+
13+
// Plugin to draw labels on scatter plot
14+
const labelPlugin = {
15+
id: 'releaseDateLabels',
16+
afterDatasetsDraw: (chart, args, options) => {
17+
if (chart.config.type !== 'scatter') return;
18+
const {ctx, chartArea} = chart;
19+
if (!chartArea) return;
20+
21+
ctx.save();
22+
ctx.font = '11px sans-serif';
23+
ctx.fillStyle = colors.textColor;
24+
ctx.textAlign = 'left';
25+
ctx.textBaseline = 'middle';
26+
27+
chart.data.datasets[0].data.forEach((point, index) => {
28+
const meta = chart.getDatasetMeta(0);
29+
const element = meta.data[index];
30+
if (!element) return;
31+
32+
const x = element.x;
33+
const y = element.y;
34+
const label = modelsWithDates[index].name;
35+
36+
// Draw label with slight offset
37+
ctx.fillText(label, x + 8, y);
38+
});
39+
40+
ctx.restore();
41+
}
42+
};
43+
44+
// Prepare scatter data
45+
const scatterData = modelsWithDates.map(s => {
46+
const releaseDateInt = getModelReleaseDate(s.tags);
47+
const releaseDate = parseReleaseDateInt(releaseDateInt);
48+
return {
49+
x: releaseDate.getTime(),
50+
y: s.resolved
51+
};
52+
});
53+
54+
// Calculate y-axis range with nice round numbers
55+
const resolvedValues = modelsWithDates.map(s => s.resolved);
56+
const minResolved = Math.min(...resolvedValues);
57+
const maxResolved = Math.max(...resolvedValues);
58+
59+
// Round to nice values (multiples of 5)
60+
const yMinRaw = Math.max(0, minResolved * 0.9);
61+
const yMaxRaw = Math.min(100, maxResolved * 1.05);
62+
const yMin = Math.floor(yMinRaw / 5) * 5;
63+
const yMax = Math.ceil(yMaxRaw / 5) * 5;
64+
65+
// Calculate x-axis (date) range with padding
66+
const dateValues = scatterData.map(d => d.x);
67+
const minDate = Math.min(...dateValues);
68+
const maxDate = Math.max(...dateValues);
69+
const dateRange = maxDate - minDate;
70+
const xMin = minDate - dateRange * 0.05;
71+
const xMax = maxDate + dateRange * 0.20; // More padding on right for labels
72+
73+
return new Chart(ctx, {
74+
type: 'scatter',
75+
data: {
76+
datasets: [{
77+
label: 'Models',
78+
data: scatterData,
79+
backgroundColor: colors.barBackground,
80+
borderColor: colors.barBorder,
81+
borderWidth: 2,
82+
pointRadius: 6,
83+
pointHoverRadius: 8
84+
}]
85+
},
86+
options: {
87+
responsive: true,
88+
maintainAspectRatio: false,
89+
animation: false,
90+
scales: {
91+
y: {
92+
min: yMin,
93+
max: yMax,
94+
title: {
95+
display: true,
96+
text: '% Resolved',
97+
color: colors.textColor,
98+
font: { size: 14 }
99+
},
100+
ticks: {
101+
stepSize: 5,
102+
callback: (v) => v + '%',
103+
color: colors.textColor,
104+
font: { size: 12 }
105+
},
106+
grid: {
107+
color: colors.gridColor
108+
}
109+
},
110+
x: {
111+
type: 'time',
112+
min: xMin,
113+
max: xMax,
114+
time: {
115+
unit: 'month',
116+
displayFormats: {
117+
month: 'MMM yyyy'
118+
}
119+
},
120+
title: {
121+
display: true,
122+
text: 'Model Release Date',
123+
color: colors.textColor,
124+
font: { size: 14 }
125+
},
126+
ticks: {
127+
color: colors.textColor,
128+
font: { size: 12 },
129+
maxRotation: 45
130+
},
131+
grid: {
132+
color: colors.gridColor
133+
}
134+
}
135+
},
136+
plugins: {
137+
legend: { display: false },
138+
tooltip: {
139+
callbacks: {
140+
label: (ctx) => {
141+
const model = modelsWithDates[ctx.dataIndex];
142+
const releaseDate = parseReleaseDateInt(getModelReleaseDate(model.tags));
143+
const formattedDate = formatReleaseDate(releaseDate);
144+
return `${model.name}: ${formattedDate}, ${ctx.parsed.y.toFixed(2)}%`;
145+
}
146+
}
147+
}
148+
}
149+
},
150+
plugins: [backgroundPlugin, labelPlugin]
151+
});
152+
}

0 commit comments

Comments
 (0)