fix: cluster charts cap at 50 bars + silhouette label fix + manual page progress bar
This commit is contained in:
@@ -207,18 +207,28 @@ if (clusterSizes.length > 0) {
|
||||
const canvas = document.getElementById('clusterSizesChart');
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const W = canvas.parentElement.clientWidth || 600;
|
||||
const H = Math.max(200, clusterSizes.length * 40 + 60);
|
||||
var maxClusters = 50;
|
||||
var shownClusters = clusterSizes.slice(0, maxClusters);
|
||||
var note = '';
|
||||
if (clusterSizes.length > maxClusters) {
|
||||
note = ' (top ' + maxClusters + ' of ' + clusterSizes.length + ' clusters)';
|
||||
}
|
||||
var W = canvas.parentElement.clientWidth || 600;
|
||||
var H = Math.max(200, shownClusters.length * 36 + 60);
|
||||
canvas.width = W; canvas.height = H;
|
||||
const pad = { top: 20, bottom: 30, left: 80, right: 30 };
|
||||
const plotW = W - pad.left - pad.right;
|
||||
const plotH = H - pad.top - pad.bottom;
|
||||
const maxSize = Math.max(...clusterSizes.map(d => d.size));
|
||||
var pad = { top: 20, bottom: 30, left: 80, right: 30 };
|
||||
var plotW = W - pad.left - pad.right;
|
||||
var plotH = H - pad.top - pad.bottom;
|
||||
var maxSize = Math.max(1, ...shownClusters.map(function(d) { return d.size; }));
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
clusterSizes.forEach((d, i) => {
|
||||
const barH = Math.min(40, plotH / clusterSizes.length * 0.6);
|
||||
const y = pad.top + i * (barH + 4);
|
||||
const bw = (d.size / maxSize) * plotW;
|
||||
if (note) {
|
||||
ctx.fillStyle = '#999'; ctx.font = '11px sans-serif'; ctx.textAlign = 'left';
|
||||
ctx.fillText(note, pad.left, 15);
|
||||
}
|
||||
shownClusters.forEach(function(d, i) {
|
||||
var barH = Math.min(32, plotH / shownClusters.length * 0.7);
|
||||
var y = pad.top + i * (barH + 4);
|
||||
var bw = Math.max(2, (d.size / maxSize) * plotW);
|
||||
ctx.fillStyle = chartColors[i % chartColors.length];
|
||||
ctx.fillRect(pad.left, y, bw, barH);
|
||||
ctx.fillStyle = '#333';
|
||||
@@ -227,7 +237,7 @@ if (clusterSizes.length > 0) {
|
||||
ctx.fillText('#' + d.label, pad.left - 5, y + barH / 2 + 4);
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillStyle = '#666';
|
||||
ctx.fillText(d.size + ' (' + (d.size / clusterSizes.reduce((a,b) => a+b.size, 0) * 100).toFixed(1) + '%)', pad.left + bw + 5, y + barH / 2 + 4);
|
||||
ctx.fillText(d.size, pad.left + bw + 5, y + barH / 2 + 4);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -266,7 +276,7 @@ if (clusterSizes.length > 0) {
|
||||
ctx.fillText(d.silhouette.toFixed(4), x + bw + 5, y - 2);
|
||||
} else {
|
||||
ctx.textAlign = 'right';
|
||||
ctx.fillText(d.silhouette.toFixed(4), x + bw - 5, y + barH + 12);
|
||||
ctx.fillText(d.silhouette.toFixed(4), x - Math.abs(bw) - 5, y + barH + 12);
|
||||
}
|
||||
});
|
||||
// Zero line
|
||||
|
||||
@@ -135,7 +135,10 @@ async function runAnalysis() {
|
||||
const poll = setInterval(async () => {
|
||||
const r = await fetch(`/runs/${runId}/status/`);
|
||||
const s = await r.json();
|
||||
document.getElementById('runStatus').textContent = s.status;
|
||||
const pct = s.progress_pct || 0;
|
||||
const msg = s.progress_msg || s.status;
|
||||
document.getElementById('runStatus').textContent = msg + ' (' + pct + '%)';
|
||||
document.getElementById('runBar').style.width = pct + '%';
|
||||
if (s.status === 'completed') { clearInterval(poll); window.location.href = `/runs/${runId}/`; }
|
||||
if (s.status === 'failed') { clearInterval(poll); document.getElementById('runStatus').textContent = '失败: ' + (s.error_message || ''); }
|
||||
}, 1000);
|
||||
|
||||
Reference in New Issue
Block a user