diff --git a/analyze_results.py b/analyze_results.py index 6ff4941..1088c6f 100644 --- a/analyze_results.py +++ b/analyze_results.py @@ -704,7 +704,7 @@ class WebInterface: .scale-toggle { position: absolute; top: 30px; - right: 140px; + right: 180px; background: var(--border-color); border: none; padding: 10px 20px; diff --git a/templates/dashboard.html b/templates/dashboard.html index fe36bb3..6b587b9 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -81,7 +81,7 @@ .scale-toggle { position: absolute; top: 30px; - right: 140px; + right: 180px; background: var(--border-color); border: none; padding: 10px 20px; @@ -408,6 +408,92 @@ .tooltiptext strong { color: #667eea; } + + .chart-type-toggle { + display: flex; + gap: 5px; + background: var(--border-color); + border-radius: 8px; + padding: 4px; + } + + .chart-type-btn { + padding: 8px 16px; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 0.9em; + transition: all 0.3s; + background: transparent; + color: var(--text-primary); + } + + .chart-type-btn:hover { + background: rgba(102, 126, 234, 0.2); + } + + .chart-type-btn.active { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + } + + .model-toggles { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 15px; + padding: 15px; + background: var(--stat-card-bg); + border-radius: 10px; + } + + .model-toggle-item { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + background: var(--card-bg); + border-radius: 20px; + cursor: pointer; + transition: all 0.3s; + border: 2px solid transparent; + } + + .model-toggle-item:hover { + border-color: var(--text-secondary); + } + + .model-toggle-item.active { + border-color: currentColor; + } + + .model-toggle-checkbox { + width: 18px; + height: 18px; + cursor: pointer; + accent-color: #667eea; + } + + .model-toggle-label { + font-size: 0.9em; + cursor: pointer; + user-select: none; + } + + .model-color-indicator { + width: 12px; + height: 12px; + border-radius: 50%; + flex-shrink: 0; + } + + .radar-controls { + display: none; + } + + .radar-controls.visible { + display: block; + } @@ -473,6 +559,16 @@ +
+ + +
+ +
+

Toggle models to show/hide on the spider web chart:

+
+ +
@@ -924,13 +1020,91 @@ }); if (comparisonData.categories.length > 0) { + initializeModelToggles(); updateCategoryChart(); } } + // Category chart type state + let categoryChartType = 'bar'; + let selectedModelsForRadar = {}; + + // Model colors for radar chart + const modelColors = [ + { bg: 'rgba(102, 126, 234, 0.3)', border: 'rgba(102, 126, 234, 1)' }, + { bg: 'rgba(118, 75, 162, 0.3)', border: 'rgba(118, 75, 162, 1)' }, + { bg: 'rgba(16, 185, 129, 0.3)', border: 'rgba(16, 185, 129, 1)' }, + { bg: 'rgba(245, 158, 11, 0.3)', border: 'rgba(245, 158, 11, 1)' }, + { bg: 'rgba(239, 68, 68, 0.3)', border: 'rgba(239, 68, 68, 1)' }, + { bg: 'rgba(59, 130, 246, 0.3)', border: 'rgba(59, 130, 246, 1)' }, + { bg: 'rgba(236, 72, 153, 0.3)', border: 'rgba(236, 72, 153, 1)' }, + { bg: 'rgba(34, 197, 94, 0.3)', border: 'rgba(34, 197, 94, 1)' }, + { bg: 'rgba(168, 85, 247, 0.3)', border: 'rgba(168, 85, 247, 1)' }, + { bg: 'rgba(251, 146, 60, 0.3)', border: 'rgba(251, 146, 60, 1)' } + ]; + + function initializeModelToggles() { + if (!comparisonData) return; + + const models = Object.keys(comparisonData.models); + const container = document.getElementById('modelToggleContainer'); + container.innerHTML = ''; + + models.forEach((model, index) => { + const colorIndex = index % modelColors.length; + selectedModelsForRadar[model] = true; // All selected by default + + const item = document.createElement('label'); + item.className = 'model-toggle-item active'; + item.style.color = modelColors[colorIndex].border; + item.innerHTML = ` + + + ${model} + `; + container.appendChild(item); + }); + } + + function toggleModelVisibility(model, isVisible, element) { + selectedModelsForRadar[model] = isVisible; + element.classList.toggle('active', isVisible); + updateCategoryChart(); + } + + function setCategoryChartType(type) { + categoryChartType = type; + + // Update button states + document.getElementById('barChartBtn').classList.toggle('active', type === 'bar'); + document.getElementById('radarChartBtn').classList.toggle('active', type === 'radar'); + + // Show/hide radar controls + document.getElementById('radarModelToggles').classList.toggle('visible', type === 'radar'); + + // Show/hide category selector (hide for radar since it shows all categories) + document.getElementById('categorySelect').style.display = type === 'radar' ? 'none' : 'block'; + + updateCategoryChart(); + } + function updateCategoryChart() { if (!comparisonData) return; + const ctx = document.getElementById('categoryChart'); + if (window.categoryChartInstance) { + window.categoryChartInstance.destroy(); + } + + if (categoryChartType === 'radar') { + updateRadarChart(ctx); + } else { + updateBarChart(ctx); + } + } + + function updateBarChart(ctx) { const category = document.getElementById('categorySelect').value; const models = Object.keys(comparisonData.models); @@ -939,11 +1113,6 @@ return stats ? stats.average : 0; }); - const ctx = document.getElementById('categoryChart'); - if (window.categoryChartInstance) { - window.categoryChartInstance.destroy(); - } - window.categoryChartInstance = new Chart(ctx, { type: 'bar', data: { @@ -964,6 +1133,92 @@ }); } + function updateRadarChart(ctx) { + const categories = comparisonData.categories; + const models = Object.keys(comparisonData.models); + + // Create datasets for each selected model + const datasets = []; + let allData = []; + + models.forEach((model, index) => { + if (!selectedModelsForRadar[model]) return; + + const colorIndex = index % modelColors.length; + const data = categories.map(category => { + const stats = comparisonData.models[model].category_stats[category]; + return stats ? stats.average : 0; + }); + + allData = allData.concat(data); + + datasets.push({ + label: model, + data: data, + backgroundColor: modelColors[colorIndex].bg, + borderColor: modelColors[colorIndex].border, + borderWidth: 2, + pointBackgroundColor: modelColors[colorIndex].border, + pointBorderColor: '#fff', + pointHoverBackgroundColor: '#fff', + pointHoverBorderColor: modelColors[colorIndex].border, + pointRadius: 4, + pointHoverRadius: 6 + }); + }); + + window.categoryChartInstance = new Chart(ctx, { + type: 'radar', + data: { + labels: categories, + datasets: datasets + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + position: 'top', + labels: { + padding: 20, + usePointStyle: true, + pointStyle: 'circle' + } + }, + tooltip: { + callbacks: { + label: function(context) { + return `${context.dataset.label}: ${context.raw.toFixed(2)}`; + } + } + } + }, + scales: { + r: { + beginAtZero: !zoomedScale, + min: zoomedScale ? Math.max(0, Math.min(...allData) - 0.5) : 0, + max: zoomedScale ? Math.min(5, Math.max(...allData) + 0.5) : 5, + ticks: { + stepSize: zoomedScale ? 0.5 : 1, + backdropColor: 'transparent' + }, + grid: { + color: 'rgba(102, 126, 234, 0.2)' + }, + angleLines: { + color: 'rgba(102, 126, 234, 0.2)' + }, + pointLabels: { + font: { + size: 11 + } + } + } + } + } + }); + } + async function loadModelDetails() { const modelName = document.getElementById('modelSelect').value; if (!modelName || !comparisonData) return;