Spaces:
Running
Running
thibaud frere
commited on
Commit
·
a76e825
1
Parent(s):
ce67e6b
update charts
Browse files- app/src/components/Accordion.astro +7 -0
- app/src/content/article.mdx +1 -1
- app/src/content/embeds/against-baselines-deduplicated.html +33 -7
- app/src/content/embeds/against-baselines.html +38 -7
- app/src/content/embeds/all-ratings.html +33 -7
- app/src/content/embeds/filters-quad.html +19 -4
- app/src/content/embeds/formatting-filters.html +33 -7
- app/src/content/embeds/image-correspondence-filters.html +33 -7
- app/src/content/embeds/internal-deduplication.html +33 -7
- app/src/content/embeds/relevance-filters.html +33 -7
- app/src/content/embeds/remove-ch.html +33 -7
- app/src/content/embeds/s25-ratings.html +33 -7
- app/src/content/embeds/ss-vs-s1.html +33 -7
- app/src/content/embeds/visual-dependency-filters.html +33 -7
app/src/components/Accordion.astro
CHANGED
|
@@ -101,6 +101,11 @@ const wrapperClass = ["accordion", className].filter(Boolean).join(" ");
|
|
| 101 |
position: relative;
|
| 102 |
}
|
| 103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
/* Remove conditional padding to avoid jump on close */
|
| 105 |
|
| 106 |
/* Remove native marker */
|
|
@@ -160,6 +165,7 @@ const wrapperClass = ["accordion", className].filter(Boolean).join(" ");
|
|
| 160 |
padding: 0;
|
| 161 |
}
|
| 162 |
|
|
|
|
| 163 |
/* Separator between header and content when open (edge-to-edge) */
|
| 164 |
.accordion[open] .accordion__content-wrapper::before {
|
| 165 |
content: "";
|
|
@@ -178,6 +184,7 @@ const wrapperClass = ["accordion", className].filter(Boolean).join(" ");
|
|
| 178 |
outline-offset: 3px;
|
| 179 |
border-radius: 8px;
|
| 180 |
}
|
|
|
|
| 181 |
|
| 182 |
|
| 183 |
</style>
|
|
|
|
| 101 |
position: relative;
|
| 102 |
}
|
| 103 |
|
| 104 |
+
.accordion[size="big"] .accordion__summary {
|
| 105 |
+
padding: 16px;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
/* Remove conditional padding to avoid jump on close */
|
| 110 |
|
| 111 |
/* Remove native marker */
|
|
|
|
| 165 |
padding: 0;
|
| 166 |
}
|
| 167 |
|
| 168 |
+
|
| 169 |
/* Separator between header and content when open (edge-to-edge) */
|
| 170 |
.accordion[open] .accordion__content-wrapper::before {
|
| 171 |
content: "";
|
|
|
|
| 184 |
outline-offset: 3px;
|
| 185 |
border-radius: 8px;
|
| 186 |
}
|
| 187 |
+
|
| 188 |
|
| 189 |
|
| 190 |
</style>
|
app/src/content/article.mdx
CHANGED
|
@@ -67,7 +67,7 @@ Projects like The Cauldron, LLaVa and Cambrian aim to provide such datasets, but
|
|
| 67 |
We manually collect **over 180** image-text datasets from the recent literature and create new subsets in lacking domains.
|
| 68 |
|
| 69 |
<Wide>
|
| 70 |
-
<Accordion title="FineVision Subsets">
|
| 71 |
|Subset Name |Total Images|Total Samples|Total Turns|Total Question Tokens|Total Answer Tokens|Category |Source |
|
| 72 |
|--------------------------------------|------------|-------------|-----------|---------------------|-------------------|----------------------|------- |
|
| 73 |
|coco_colors |118,287 |118,287 |118,287 |1,301,157 |6,376,672 |Captioning & Knowledge|[@noauthor_hazal-karakusmscoco-controlnet] |
|
|
|
|
| 67 |
We manually collect **over 180** image-text datasets from the recent literature and create new subsets in lacking domains.
|
| 68 |
|
| 69 |
<Wide>
|
| 70 |
+
<Accordion size="big" title="FineVision Subsets">
|
| 71 |
|Subset Name |Total Images|Total Samples|Total Turns|Total Question Tokens|Total Answer Tokens|Category |Source |
|
| 72 |
|--------------------------------------|------------|-------------|-----------|---------------------|-------------------|----------------------|------- |
|
| 73 |
|coco_colors |118,287 |118,287 |118,287 |1,301,157 |6,376,672 |Captioning & Knowledge|[@noauthor_hazal-karakusmscoco-controlnet] |
|
app/src/content/embeds/against-baselines-deduplicated.html
CHANGED
|
@@ -180,6 +180,7 @@
|
|
| 180 |
const gRoot = svg.append('g');
|
| 181 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 182 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 183 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 184 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 185 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -428,9 +429,27 @@
|
|
| 428 |
values: (map[r]||[])
|
| 429 |
.slice()
|
| 430 |
.sort((a,b)=>a.step-b.step)
|
| 431 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 432 |
}));
|
| 433 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
// Draw lines
|
| 435 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 436 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -531,11 +550,12 @@
|
|
| 531 |
// Tooltip content
|
| 532 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 533 |
series.forEach(s=>{
|
| 534 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 535 |
-
const
|
| 536 |
-
if (
|
| 537 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 538 |
-
|
|
|
|
| 539 |
}
|
| 540 |
});
|
| 541 |
tipInner.innerHTML = html;
|
|
@@ -552,7 +572,13 @@
|
|
| 552 |
(async () => {
|
| 553 |
try {
|
| 554 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 555 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 557 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 558 |
runOrder = runList;
|
|
@@ -560,7 +586,7 @@
|
|
| 560 |
metricList.forEach(m => {
|
| 561 |
const map = {};
|
| 562 |
runList.forEach(r => { map[r] = []; });
|
| 563 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 564 |
dataByMetric.set(m, map);
|
| 565 |
});
|
| 566 |
|
|
|
|
| 180 |
const gRoot = svg.append('g');
|
| 181 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 182 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 183 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 184 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 185 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 186 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 429 |
values: (map[r]||[])
|
| 430 |
.slice()
|
| 431 |
.sort((a,b)=>a.step-b.step)
|
| 432 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 433 |
}));
|
| 434 |
|
| 435 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 436 |
+
gAreas.selectAll('*').remove();
|
| 437 |
+
if (!isRank) {
|
| 438 |
+
series.forEach((s) => {
|
| 439 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 440 |
+
if (withErr.length === 0) return;
|
| 441 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 442 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 443 |
+
const coords = upper.concat(lower);
|
| 444 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 445 |
+
gAreas.append('path')
|
| 446 |
+
.attr('d', pathData)
|
| 447 |
+
.attr('fill', s.color)
|
| 448 |
+
.attr('opacity', 0.15)
|
| 449 |
+
.attr('stroke', 'none');
|
| 450 |
+
});
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
// Draw lines
|
| 454 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 455 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 550 |
// Tooltip content
|
| 551 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 552 |
series.forEach(s=>{
|
| 553 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 554 |
+
const pt = m.get(nearest);
|
| 555 |
+
if (pt && pt.value != null) {
|
| 556 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 557 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 558 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 559 |
}
|
| 560 |
});
|
| 561 |
tipInner.innerHTML = html;
|
|
|
|
| 572 |
(async () => {
|
| 573 |
try {
|
| 574 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 575 |
+
const rows = d3.csvParse(text, d => ({
|
| 576 |
+
run: (d.run||'').trim(),
|
| 577 |
+
step: +d.step,
|
| 578 |
+
metric: (d.metric||'').trim(),
|
| 579 |
+
value: +d.value,
|
| 580 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 581 |
+
}));
|
| 582 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 583 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 584 |
runOrder = runList;
|
|
|
|
| 586 |
metricList.forEach(m => {
|
| 587 |
const map = {};
|
| 588 |
runList.forEach(r => { map[r] = []; });
|
| 589 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 590 |
dataByMetric.set(m, map);
|
| 591 |
});
|
| 592 |
|
app/src/content/embeds/against-baselines.html
CHANGED
|
@@ -177,7 +177,9 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
|
|
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
| 183 |
const gLegend = gRoot.append('foreignObject').attr('class', 'legend');
|
|
@@ -425,9 +427,28 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -439,6 +460,9 @@
|
|
| 439 |
.attr('d', d=>lineGen(d.values));
|
| 440 |
paths.exit().remove();
|
| 441 |
|
|
|
|
|
|
|
|
|
|
| 442 |
// Draw markers for each data point
|
| 443 |
gPoints.selectAll('*').remove();
|
| 444 |
series.forEach((s, seriesIndex) => {
|
|
@@ -528,11 +552,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +574,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +588,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
+
const gErrors = gRoot.append('g').attr('class', 'errors');
|
| 183 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 184 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
| 185 |
const gLegend = gRoot.append('foreignObject').attr('class', 'legend');
|
|
|
|
| 427 |
values: (map[r]||[])
|
| 428 |
.slice()
|
| 429 |
.sort((a,b)=>a.step-b.step)
|
| 430 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 431 |
}));
|
| 432 |
|
| 433 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 434 |
+
gAreas.selectAll('*').remove();
|
| 435 |
+
if (!isRank) {
|
| 436 |
+
series.forEach((s) => {
|
| 437 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 438 |
+
if (withErr.length === 0) return;
|
| 439 |
+
// Build polygon path going forward on upper bound and back on lower bound
|
| 440 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 441 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 442 |
+
const coords = upper.concat(lower);
|
| 443 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 444 |
+
gAreas.append('path')
|
| 445 |
+
.attr('d', pathData)
|
| 446 |
+
.attr('fill', s.color)
|
| 447 |
+
.attr('opacity', 0.15)
|
| 448 |
+
.attr('stroke', 'none');
|
| 449 |
+
});
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
// Draw lines
|
| 453 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 454 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 460 |
.attr('d', d=>lineGen(d.values));
|
| 461 |
paths.exit().remove();
|
| 462 |
|
| 463 |
+
// Remove candle-like error bars in favor of filled areas
|
| 464 |
+
gErrors.selectAll('*').remove();
|
| 465 |
+
|
| 466 |
// Draw markers for each data point
|
| 467 |
gPoints.selectAll('*').remove();
|
| 468 |
series.forEach((s, seriesIndex) => {
|
|
|
|
| 552 |
// Tooltip content
|
| 553 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 554 |
series.forEach(s=>{
|
| 555 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 556 |
+
const pt = m.get(nearest);
|
| 557 |
+
if (pt && pt.value != null) {
|
| 558 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 559 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 560 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 561 |
}
|
| 562 |
});
|
| 563 |
tipInner.innerHTML = html;
|
|
|
|
| 574 |
(async () => {
|
| 575 |
try {
|
| 576 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 577 |
+
const rows = d3.csvParse(text, d => ({
|
| 578 |
+
run: (d.run||'').trim(),
|
| 579 |
+
step: +d.step,
|
| 580 |
+
metric: (d.metric||'').trim(),
|
| 581 |
+
value: +d.value,
|
| 582 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 583 |
+
}));
|
| 584 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 585 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 586 |
runOrder = runList;
|
|
|
|
| 588 |
metricList.forEach(m => {
|
| 589 |
const map = {};
|
| 590 |
runList.forEach(r => { map[r] = []; });
|
| 591 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 592 |
dataByMetric.set(m, map);
|
| 593 |
});
|
| 594 |
|
app/src/content/embeds/all-ratings.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/filters-quad.html
CHANGED
|
@@ -90,6 +90,7 @@
|
|
| 90 |
const gRoot = svg.append('g');
|
| 91 |
const gGrid = gRoot.append('g').attr('class','grid');
|
| 92 |
const gAxes = gRoot.append('g').attr('class','axes');
|
|
|
|
| 93 |
const gLines = gRoot.append('g').attr('class','lines');
|
| 94 |
const gPoints = gRoot.append('g').attr('class','points');
|
| 95 |
const gHover = gRoot.append('g').attr('class','hover');
|
|
@@ -186,7 +187,21 @@
|
|
| 186 |
|
| 187 |
const { innerWidth, innerHeight } = updateScales();
|
| 188 |
|
| 189 |
-
const series = runs.map((r, i) => ({ run:r, color: pool[i % pool.length], marker: markerShapes[i % markerShapes.length], values:(map[r]||[]).slice().sort((a,b)=>a.step-b.step).map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt) }));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 192 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2).attr('opacity',0.9)
|
|
@@ -216,7 +231,7 @@
|
|
| 216 |
const hoverLine = gHover.append('line').attr('stroke','rgba(0,0,0,0.25)').attr('stroke-width',1).attr('y1',0).attr('y2',innerHeight).style('display','none');
|
| 217 |
const stepSet = new Set(); series.forEach(s=>s.values.forEach(v=>stepSet.add(v.step))); const steps = Array.from(stepSet).sort((a,b)=>a-b);
|
| 218 |
function onMove(ev){ const [mx,my]=d3.pointer(ev, overlay.node()); const nearest = steps.reduce((best,s)=> Math.abs(s - xScale.invert(mx)) < Math.abs(best - xScale.invert(mx)) ? s : best, steps[0]); const xpx = xScale(nearest); hoverLine.attr('x1',xpx).attr('x2',xpx).style('display',null);
|
| 219 |
-
let html = `<div><strong>${titleText}</strong></div><div><strong>step</strong> ${nearest}</div>`; series.forEach(s=>{ const m = new Map(s.values.map(v=>[v.step, v
|
| 220 |
tipInner.innerHTML = html; const offsetX=12, offsetY=12; tip.style.opacity='1'; tip.style.transform=`translate(${Math.round(mx+offsetX+margin.left)}px, ${Math.round(my+offsetY+margin.top)}px)`; }
|
| 221 |
function onLeave(){ tip.style.opacity='0'; tip.style.transform='translate(-9999px, -9999px)'; hoverLine.style('display','none'); }
|
| 222 |
overlay.on('mousemove', onMove).on('mouseleave', onLeave);
|
|
@@ -237,10 +252,10 @@
|
|
| 237 |
try { const r = await fetch(p, { cache:'no-cache' }); if (r.ok) { text = await r.text(); break; } } catch(e){}
|
| 238 |
}
|
| 239 |
if (text == null) throw new Error(`CSV not found: ${file}`);
|
| 240 |
-
const rows = d3.csvParse(text, d => ({ run:(d.run||'').trim(), step:+d.step, metric:(d.metric||'').trim(), value:+d.value }));
|
| 241 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 242 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort(); runOrder = runList;
|
| 243 |
-
metricList.forEach(m => { const map={}; runList.forEach(r=>map[r]=[]); rows.filter(r=>r.metric===m).forEach(r=>{ if(!isNaN(r.step)&&!isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); }); dataByMetric.set(m, map); });
|
| 244 |
const def = metricList.find(m => /average_rank/i.test(m)) || metricList[0];
|
| 245 |
renderMetric(def);
|
| 246 |
const ro = window.ResizeObserver ? new ResizeObserver(()=>renderMetric(def)) : null; if (ro) ro.observe(cell);
|
|
|
|
| 90 |
const gRoot = svg.append('g');
|
| 91 |
const gGrid = gRoot.append('g').attr('class','grid');
|
| 92 |
const gAxes = gRoot.append('g').attr('class','axes');
|
| 93 |
+
const gAreas = gRoot.append('g').attr('class','areas');
|
| 94 |
const gLines = gRoot.append('g').attr('class','lines');
|
| 95 |
const gPoints = gRoot.append('g').attr('class','points');
|
| 96 |
const gHover = gRoot.append('g').attr('class','hover');
|
|
|
|
| 187 |
|
| 188 |
const { innerWidth, innerHeight } = updateScales();
|
| 189 |
|
| 190 |
+
const series = runs.map((r, i) => ({ run:r, color: pool[i % pool.length], marker: markerShapes[i % markerShapes.length], values:(map[r]||[]).slice().sort((a,b)=>a.step-b.step).map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt) }));
|
| 191 |
+
|
| 192 |
+
// zones ± stderr (métriques non rank)
|
| 193 |
+
gAreas.selectAll('*').remove();
|
| 194 |
+
if (!isRank) {
|
| 195 |
+
series.forEach((s) => {
|
| 196 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 197 |
+
if (!withErr.length) return;
|
| 198 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 199 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 200 |
+
const coords = upper.concat(lower);
|
| 201 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 202 |
+
gAreas.append('path').attr('d', pathData).attr('fill', s.color).attr('opacity', 0.15).attr('stroke', 'none');
|
| 203 |
+
});
|
| 204 |
+
}
|
| 205 |
|
| 206 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 207 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2).attr('opacity',0.9)
|
|
|
|
| 231 |
const hoverLine = gHover.append('line').attr('stroke','rgba(0,0,0,0.25)').attr('stroke-width',1).attr('y1',0).attr('y2',innerHeight).style('display','none');
|
| 232 |
const stepSet = new Set(); series.forEach(s=>s.values.forEach(v=>stepSet.add(v.step))); const steps = Array.from(stepSet).sort((a,b)=>a-b);
|
| 233 |
function onMove(ev){ const [mx,my]=d3.pointer(ev, overlay.node()); const nearest = steps.reduce((best,s)=> Math.abs(s - xScale.invert(mx)) < Math.abs(best - xScale.invert(mx)) ? s : best, steps[0]); const xpx = xScale(nearest); hoverLine.attr('x1',xpx).attr('x2',xpx).style('display',null);
|
| 234 |
+
let html = `<div><strong>${titleText}</strong></div><div><strong>step</strong> ${nearest}</div>`; series.forEach(s=>{ const m = new Map(s.values.map(v=>[v.step, v])); const pt = m.get(nearest); if (pt && pt.value!=null){ const fmt = (vv)=> (isRankStrictFlag? d3.format('d')(vv) : (+vv).toFixed(4)); const err = (pt.stderr!=null && isFinite(pt.stderr) && pt.stderr>0) ? ` ± ${fmt(pt.stderr)}` : ''; html+=`<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${fmt(pt.value)}${err}</div>`; }});
|
| 235 |
tipInner.innerHTML = html; const offsetX=12, offsetY=12; tip.style.opacity='1'; tip.style.transform=`translate(${Math.round(mx+offsetX+margin.left)}px, ${Math.round(my+offsetY+margin.top)}px)`; }
|
| 236 |
function onLeave(){ tip.style.opacity='0'; tip.style.transform='translate(-9999px, -9999px)'; hoverLine.style('display','none'); }
|
| 237 |
overlay.on('mousemove', onMove).on('mouseleave', onLeave);
|
|
|
|
| 252 |
try { const r = await fetch(p, { cache:'no-cache' }); if (r.ok) { text = await r.text(); break; } } catch(e){}
|
| 253 |
}
|
| 254 |
if (text == null) throw new Error(`CSV not found: ${file}`);
|
| 255 |
+
const rows = d3.csvParse(text, d => ({ run:(d.run||'').trim(), step:+d.step, metric:(d.metric||'').trim(), value:+d.value, stderr: (d.stderr!=null && d.stderr!=='') ? +d.stderr : null }));
|
| 256 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 257 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort(); runOrder = runList;
|
| 258 |
+
metricList.forEach(m => { const map={}; runList.forEach(r=>map[r]=[]); rows.filter(r=>r.metric===m).forEach(r=>{ if(!isNaN(r.step)&&!isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); }); dataByMetric.set(m, map); });
|
| 259 |
const def = metricList.find(m => /average_rank/i.test(m)) || metricList[0];
|
| 260 |
renderMetric(def);
|
| 261 |
const ro = window.ResizeObserver ? new ResizeObserver(()=>renderMetric(def)) : null; if (ro) ro.observe(cell);
|
app/src/content/embeds/formatting-filters.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/image-correspondence-filters.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/internal-deduplication.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/relevance-filters.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/remove-ch.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/s25-ratings.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/ss-vs-s1.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|
app/src/content/embeds/visual-dependency-filters.html
CHANGED
|
@@ -177,6 +177,7 @@
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
|
|
|
| 180 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 181 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 182 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
@@ -425,9 +426,27 @@
|
|
| 425 |
values: (map[r]||[])
|
| 426 |
.slice()
|
| 427 |
.sort((a,b)=>a.step-b.step)
|
| 428 |
-
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value) } : pt)
|
| 429 |
}));
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
// Draw lines
|
| 432 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 433 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
@@ -528,11 +547,12 @@
|
|
| 528 |
// Tooltip content
|
| 529 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 530 |
series.forEach(s=>{
|
| 531 |
-
const m = new Map(s.values.map(v=>[v.step, v
|
| 532 |
-
const
|
| 533 |
-
if (
|
| 534 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 535 |
-
|
|
|
|
| 536 |
}
|
| 537 |
});
|
| 538 |
tipInner.innerHTML = html;
|
|
@@ -549,7 +569,13 @@
|
|
| 549 |
(async () => {
|
| 550 |
try {
|
| 551 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 552 |
-
const rows = d3.csvParse(text, d => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 553 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 554 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 555 |
runOrder = runList;
|
|
@@ -557,7 +583,7 @@
|
|
| 557 |
metricList.forEach(m => {
|
| 558 |
const map = {};
|
| 559 |
runList.forEach(r => { map[r] = []; });
|
| 560 |
-
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value }); });
|
| 561 |
dataByMetric.set(m, map);
|
| 562 |
});
|
| 563 |
|
|
|
|
| 177 |
const gRoot = svg.append('g');
|
| 178 |
const gGrid = gRoot.append('g').attr('class', 'grid');
|
| 179 |
const gAxes = gRoot.append('g').attr('class', 'axes');
|
| 180 |
+
const gAreas = gRoot.append('g').attr('class', 'areas');
|
| 181 |
const gLines = gRoot.append('g').attr('class', 'lines');
|
| 182 |
const gPoints = gRoot.append('g').attr('class', 'points');
|
| 183 |
const gHover = gRoot.append('g').attr('class', 'hover');
|
|
|
|
| 426 |
values: (map[r]||[])
|
| 427 |
.slice()
|
| 428 |
.sort((a,b)=>a.step-b.step)
|
| 429 |
+
.map(pt => isRankStrict ? { step: pt.step, value: Math.round(pt.value), stderr: pt.stderr } : pt)
|
| 430 |
}));
|
| 431 |
|
| 432 |
+
// Uncertainty area (± stderr) for non-rank metrics
|
| 433 |
+
gAreas.selectAll('*').remove();
|
| 434 |
+
if (!isRank) {
|
| 435 |
+
series.forEach((s) => {
|
| 436 |
+
const withErr = s.values.filter(v => v && v.stderr != null && isFinite(v.stderr) && v.stderr > 0 && isFinite(v.value));
|
| 437 |
+
if (withErr.length === 0) return;
|
| 438 |
+
const upper = withErr.map(d => [xScale(d.step), yScale(d.value + d.stderr)]);
|
| 439 |
+
const lower = withErr.slice().reverse().map(d => [xScale(d.step), yScale(d.value - d.stderr)]);
|
| 440 |
+
const coords = upper.concat(lower);
|
| 441 |
+
const pathData = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveLinearClosed)(coords);
|
| 442 |
+
gAreas.append('path')
|
| 443 |
+
.attr('d', pathData)
|
| 444 |
+
.attr('fill', s.color)
|
| 445 |
+
.attr('opacity', 0.15)
|
| 446 |
+
.attr('stroke', 'none');
|
| 447 |
+
});
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
// Draw lines
|
| 451 |
const paths = gLines.selectAll('path.run-line').data(series, d=>d.run);
|
| 452 |
paths.enter().append('path').attr('class','run-line').attr('fill','none').attr('stroke-width',2)
|
|
|
|
| 547 |
// Tooltip content
|
| 548 |
let html = `<div><strong>${getMetricDisplayName(metricKey)}</strong></div><div><strong>step</strong> ${nearest}</div>`;
|
| 549 |
series.forEach(s=>{
|
| 550 |
+
const m = new Map(s.values.map(v=>[v.step, v]));
|
| 551 |
+
const pt = m.get(nearest);
|
| 552 |
+
if (pt && pt.value != null) {
|
| 553 |
const formatVal = (vv) => (isRankStrict ? d3.format('d')(vv) : (+vv).toFixed(4));
|
| 554 |
+
const errTxt = (pt.stderr != null && isFinite(pt.stderr) && pt.stderr > 0) ? ` ± ${formatVal(pt.stderr)}` : '';
|
| 555 |
+
html += `<div><span style=\"display:inline-block;width:10px;height:10px;background:${s.color};border-radius:50%;margin-right:6px;\"></span><strong>${s.run}</strong> ${formatVal(pt.value)}${errTxt}</div>`;
|
| 556 |
}
|
| 557 |
});
|
| 558 |
tipInner.innerHTML = html;
|
|
|
|
| 569 |
(async () => {
|
| 570 |
try {
|
| 571 |
const text = await fetchFirstAvailable(CSV_PATHS);
|
| 572 |
+
const rows = d3.csvParse(text, d => ({
|
| 573 |
+
run: (d.run||'').trim(),
|
| 574 |
+
step: +d.step,
|
| 575 |
+
metric: (d.metric||'').trim(),
|
| 576 |
+
value: +d.value,
|
| 577 |
+
stderr: (d.stderr != null && d.stderr !== '') ? +d.stderr : null
|
| 578 |
+
}));
|
| 579 |
metricList = Array.from(new Set(rows.map(r=>r.metric))).sort();
|
| 580 |
runList = Array.from(new Set(rows.map(r=>r.run))).sort();
|
| 581 |
runOrder = runList;
|
|
|
|
| 583 |
metricList.forEach(m => {
|
| 584 |
const map = {};
|
| 585 |
runList.forEach(r => { map[r] = []; });
|
| 586 |
+
rows.filter(r=>r.metric===m).forEach(r => { if (!isNaN(r.step) && !isNaN(r.value)) map[r.run].push({ step:r.step, value:r.value, stderr:r.stderr }); });
|
| 587 |
dataByMetric.set(m, map);
|
| 588 |
});
|
| 589 |
|