Fancy-yousa's picture
Upload 12 files
3ac33b9 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Global Leaderboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--primary-color: #8e44ad; /* Purple for global view */
--secondary-color: #2c3e50;
--background-color: #f8f9fa;
--text-color: #333;
--border-color: #dee2e6;
--hover-color: #f1f1f1;
--sidebar-width: 280px;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
min-height: 100vh;
}
/* Sidebar Styling */
.sidebar {
width: var(--sidebar-width);
background-color: var(--secondary-color);
color: white;
position: fixed;
height: 100vh;
overflow-y: auto;
padding: 20px;
box-sizing: border-box;
left: 0;
top: 0;
z-index: 100;
display: flex;
flex-direction: column;
gap: 20px;
}
.sidebar h2 {
font-size: 1.2em;
margin-bottom: 10px;
color: #ecf0f1;
border-bottom: 1px solid #34495e;
padding-bottom: 5px;
}
.nav-links {
list-style: none;
padding: 0;
margin: 0;
}
.nav-links li a {
display: block;
padding: 10px;
color: #bdc3c7;
text-decoration: none;
border-radius: 4px;
transition: background 0.2s;
}
.nav-links li a:hover, .nav-links li a.active {
background: rgba(255,255,255,0.1);
color: white;
}
/* Main Content Styling */
.main-content {
margin-left: var(--sidebar-width);
flex: 1;
padding: 40px;
max-width: calc(100% - var(--sidebar-width));
box-sizing: border-box;
min-width: 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 2px solid var(--primary-color);
padding-bottom: 10px;
}
h1 {
margin: 0;
color: var(--secondary-color);
}
.description-box {
background-color: #e8f4fd;
border-left: 4px solid #3498db;
padding: 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.description-box h3 {
margin-top: 0;
color: #2980b9;
}
.description-box p {
margin: 5px 0;
line-height: 1.5;
}
.weights-control {
background-color: #f1f1f1;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #ddd;
}
.weights-control h3 {
margin-top: 0;
margin-bottom: 15px;
font-size: 1.1em;
}
.sliders-container {
display: flex;
gap: 20px;
flex-wrap: wrap;
align-items: center;
}
.slider-group {
display: flex;
align-items: center;
gap: 10px;
}
.slider-group label {
font-weight: bold;
min-width: 60px;
}
input[type="number"] {
width: 80px;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
input[readonly] {
background-color: #e9ecef;
color: #666;
}
button.recalc-btn {
background-color: var(--primary-color);
color: white;
border: none;
padding: 8px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-left: auto;
}
button.recalc-btn:hover {
opacity: 0.9;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background-color: var(--secondary-color);
color: white;
cursor: pointer;
user-select: none;
position: sticky;
top: 0;
}
th:hover {
background-color: #34495e;
}
th .arrow {
font-size: 10px;
margin-left: 5px;
opacity: 0.7;
}
tr:hover {
background-color: var(--hover-color);
}
.score-bar {
height: 6px;
background-color: #e9ecef;
border-radius: 3px;
overflow: hidden;
margin-top: 5px;
}
.score-fill {
height: 100%;
background-color: var(--primary-color);
}
.version-tag {
font-size: 0.8em;
color: #7f8c8d;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="sidebar">
<div style="text-align: center; margin-bottom: 20px;">
<h1 style="font-size: 1.5em; margin: 0; color: white;">AutoFS</h1>
<div style="font-size: 0.8em; color: #bdc3c7;">Feature Selection Leaderboard</div>
</div>
<div>
<h2>Navigation</h2>
<ul class="nav-links">
<li><a href="/">πŸ“Š Overview</a></li>
<li><a href="/#main-table">πŸ† Leaderboard</a></li>
<li><a href="/#charts">πŸ“ˆ Charts</a></li>
<li><a href="/#details">ℹ️ Details</a></li>
<li><a href="/global" class="active">🌍 Global Rankings</a></li>
<li><a href="/submit">πŸ“€ Submit Data/Method</a></li>
</ul>
</div>
<div style="margin-top: auto; padding-top: 20px; border-top: 1px solid #34495e;">
<p style="font-size: 0.8em; color: #bdc3c7; text-align: center;">
Need help?<br>
<a href="mailto:support@autofs.com" style="color: var(--primary-color);">Contact Support</a>
</p>
</div>
</div>
<div class="main-content">
<div class="container">
<header>
<div>
<h1>🌍 Global Algorithm Rankings</h1>
<div id="last-updated" class="version-tag">Data Last Updated: Loading...</div>
</div>
<!-- Removed redundant back link as sidebar handles navigation -->
</header>
<div class="description-box">
<h3>About Global Rankings</h3>
<p>
This page provides a comprehensive evaluation of feature selection algorithms across all available datasets.
Algorithms are ranked based on a weighted score combining <strong>Accuracy (F1)</strong>, <strong>Robustness (AUC)</strong>, and <strong>Efficiency (Time)</strong>.
You can adjust the importance of each factor below to customize the ranking criteria.
</p>
</div>
<div class="weights-control">
<h3>πŸ† Scoring Formula: S = Ξ±Β·F1 + Ξ²Β·AUC</h3>
<p style="font-size: 0.9em; color: #666; margin-bottom: 10px;">
Constraint: Ξ± + Ξ² = 1.
</p>
<div class="sliders-container">
<div class="slider-group">
<label for="weight-a">F1 (Ξ±):</label>
<input type="number" id="weight-a" value="0.5" step="0.05" min="0" max="1">
</div>
<div class="slider-group">
<label for="weight-b">AUC (Ξ²):</label>
<input type="number" id="weight-b" value="0.5" readonly title="Auto-calculated: 1 - Ξ±">
</div>
<button class="recalc-btn" onclick="calculateAndRender()">Recalculate Rankings</button>
</div>
</div>
<div id="loading-indicator" style="text-align: center; color: #666;">Loading global stats...</div>
<table id="global-table">
<thead>
<tr>
<th data-key="rank">#</th>
<th data-key="algorithm">Algorithm <span class="arrow">↕</span></th>
<th data-key="mean_f1_global">Global F1 <span class="arrow">↕</span></th>
<th data-key="mean_auc_global">Global AUC <span class="arrow">↕</span></th>
<th data-key="final_score">Final Score <span class="arrow">↕</span></th>
</tr>
</thead>
<tbody>
<!-- Data rows -->
</tbody>
</table>
</div>
</div>
<script>
let rawData = [];
let processedData = [];
let sortKey = 'final_score';
let sortDirection = -1; // Descending by default
const tableBody = document.querySelector("#global-table tbody");
const weightA = document.getElementById("weight-a");
const weightB = document.getElementById("weight-b");
const lastUpdatedDiv = document.getElementById("last-updated");
// Fetch datasets info to get latest date
function fetchLastUpdated() {
fetch("/api/datasets")
.then(res => res.json())
.then(data => {
if (data.length > 0) {
// Sort by date to find latest? Or just take one?
// Usually we want the overall latest date.
// Let's just pick the first one's date or find the max date if needed.
// For simplicity, just showing "Latest"
const dates = data.map(d => d.last_updated).filter(d => d !== 'Unknown').sort().reverse();
if (dates.length > 0) {
lastUpdatedDiv.textContent = `Data Last Updated: ${dates[0]}`;
} else {
lastUpdatedDiv.textContent = `Data Last Updated: Unknown`;
}
}
});
}
function fetchGlobalStats() {
fetch("/api/global_stats")
.then(res => res.json())
.then(data => {
rawData = data;
document.getElementById("loading-indicator").style.display = 'none';
calculateAndRender();
})
.catch(err => {
console.error("Error:", err);
document.getElementById("loading-indicator").textContent = "Error loading data.";
});
}
// Weight auto-adjustment logic
function updateWeights(changedInput) {
let a = parseFloat(weightA.value) || 0;
// Clamp inputs to 0-1
if (a < 0) a = 0; if (a > 1) a = 1;
if (changedInput === 'a') {
let b = 1 - a;
// Update UI
weightA.value = parseFloat(a.toFixed(2));
weightB.value = parseFloat(b.toFixed(2));
}
}
weightA.addEventListener('input', () => updateWeights('a'));
function calculateAndRender() {
const a = parseFloat(weightA.value) || 0;
const b = parseFloat(weightB.value) || 0;
// Process data
processedData = rawData.map(d => {
const score = (a * d.mean_f1_global) + (b * d.mean_auc_global);
return {
...d,
final_score: score
};
});
sortData();
renderTable();
}
function sortData() {
processedData.sort((x, y) => {
const valX = x[sortKey];
const valY = y[sortKey];
if (valX < valY) return -1 * sortDirection;
if (valX > valY) return 1 * sortDirection;
return 0;
});
}
function safeFixed(val, digits=4) {
if (val === undefined || val === null) return 'N/A';
return Number(val).toFixed(digits);
}
function renderTable() {
tableBody.innerHTML = "";
if (processedData.length === 0) {
tableBody.innerHTML = '<tr><td colspan="5" style="text-align:center;">No data available</td></tr>';
return;
}
processedData.forEach((row, index) => {
const tr = document.createElement("tr");
// Highlight rank 1-3
let rankHtml = index + 1;
if (index === 0) rankHtml = 'πŸ₯‡ 1';
if (index === 1) rankHtml = 'πŸ₯ˆ 2';
if (index === 2) rankHtml = 'πŸ₯‰ 3';
tr.innerHTML = `
<td>${rankHtml}</td>
<td><strong>${row.algorithm}</strong> <span style="font-size:0.8em; color:#999">(${row.datasets_count} datasets)</span></td>
<td>${safeFixed(row.mean_f1_global)}</td>
<td>${safeFixed(row.mean_auc_global)}</td>
<td>
<strong>${safeFixed(row.final_score)}</strong>
<div class="score-bar"><div class="score-fill" style="width: ${Math.min(row.final_score * 100, 100)}%"></div></div>
</td>
`;
tableBody.appendChild(tr);
});
updateSortArrows();
}
function updateSortArrows() {
document.querySelectorAll('th .arrow').forEach(span => span.textContent = '↕');
const activeHeader = document.querySelector(`th[data-key="${sortKey}"] .arrow`);
if (activeHeader) activeHeader.textContent = sortDirection === 1 ? '↑' : '↓';
}
document.querySelectorAll('th[data-key]').forEach(th => {
th.addEventListener('click', () => {
const key = th.dataset.key;
if (sortKey === key) {
sortDirection *= -1;
} else {
sortKey = key;
sortDirection = (key === 'rank') ? 1 : -1;
}
if (key === 'rank') {
sortKey = 'final_score';
sortDirection = -1;
}
sortData();
renderTable();
});
});
document.addEventListener("DOMContentLoaded", () => {
fetchLastUpdated();
fetchGlobalStats();
});
</script>
</body>
</html>