← Units and rounding

num-01-units.B

Life Expectancy at Birth vs. World Baseline12 countries · baseline 73.48 yrs · World Bank, fetched 2026-07-26Above baselineBelow baseline-25-20-15-10-50+5+10+15baselineJapan+10.56France+9.50Germany+7.31United States+5.41China+4.54Brazil+2.54Mexico+1.78India-1.25Egypt, Arab Rep.-1.67Indonesia-2.19South Africa-7.17Nigeria-18.85Δ years from world baseline
Arm
B · with a skill
Method
dataviz
Ran on
num-01-units.A
Mode
refine — the treated arms ran on the default arm's output, so the only difference is the lever
Fixture
table12
Runs
1 · shipped: only
Generated
2026-07-27

Verbatim prompt

Here is a chart module. Invoke the `dataviz` skill, then apply what it says to the module below.

export const meta = { fixture: "table12", width: 640, height: 400 };

export function render(svg, data) {
  const doc = svg.ownerDocument;
  const svgNS = "http://www.w3.org/2000/svg";
  const FONT = "'Helvetica Neue', Arial, sans-serif";

  const width = meta.width;
  const height = meta.height;

  while (svg.firstChild) svg.removeChild(svg.firstChild);

  svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
  svg.setAttribute("width", String(width));
  svg.setAttribute("height", String(height));
  svg.setAttribute("font-family", FONT);

  function el(tag, attrs, text) {
    const node = doc.createElementNS(svgNS, tag);
    for (const k in attrs) {
      const v = attrs[k];
      if (v !== undefined && v !== null) node.setAttribute(k, String(v));
    }
    if (text !== undefined) node.textContent = text;
    return node;
  }

  // Background
  svg.appendChild(el("rect", { x: 0, y: 0, width, height, fill: "#ffffff" }));

  // Layout
  const margin = { top: 58, right: 74, bottom: 32, left: 132 };
  const chartW = width - margin.left - margin.right;
  const chartH = height - margin.top - margin.bottom;

  // Title + subtitle
  svg.appendChild(
    el(
      "text",
      { x: margin.left, y: 22, "font-size": 16, "font-weight": 700, fill: "#1a1a1a", "font-family": FONT },
      "Life Expectancy at Birth vs. World Baseline"
    )
  );
  svg.appendChild(
    el(
      "text",
      { x: margin.left, y: 39, "font-size": 11.5, fill: "#666666", "font-family": FONT },
      `12 countries · baseline ${data.baseline.toFixed(2)} yrs · World Bank, fetched ${data.fetched}`
    )
  );

  // Legend (top-right)
  const legendX = width - margin.right - 150;
  const legendY = 12;
  svg.appendChild(el("rect", { x: legendX, y: legendY, width: 10, height: 10, fill: "#1b9e77", rx: 2 }));
  svg.appendChild(
    el("text", { x: legendX + 14, y: legendY + 9, "font-size": 10, fill: "#444444", "font-family": FONT }, "Above baseline")
  );
  svg.appendChild(el("rect", { x: legendX, y: legendY + 15, width: 10, height: 10, fill: "#d95f02", rx: 2 }));
  svg.appendChild(
    el("text", { x: legendX + 14, y: legendY + 24, "font-size": 10, fill: "#444444", "font-family": FONT }, "Below baseline")
  );

  // Sort rows by delta, descending (best to worst)
  const rows = data.rows.slice().sort((a, b) => b.delta - a.delta);

  // Domain: pad a few units past the rounded extremes so end labels never
  // crowd the chart edge or the row labels.
  const deltas = rows.map((r) => r.delta);
  const rawMin = Math.min(...deltas, 0);
  const rawMax = Math.max(...deltas, 0);
  const domainMin = Math.floor((rawMin - 3) / 5) * 5;
  const domainMax = Math.ceil((rawMax + 3) / 5) * 5;
  const span = domainMax - domainMin;

  function xScale(v) {
    return margin.left + ((v - domainMin) / span) * chartW;
  }

  const zeroX = xScale(0);
  const chartTop = margin.top;
  const chartBottom = margin.top + chartH;

  const chartG = el("g", {});
  svg.appendChild(chartG);

  // Gridlines + axis ticks
  const tickStep = 5;
  for (let t = domainMin; t <= domainMax + 0.001; t += tickStep) {
    const tx = xScale(t);
    chartG.appendChild(
      el("line", {
        x1: tx,
        x2: tx,
        y1: chartTop,
        y2: chartBottom,
        stroke: t === 0 ? "#999999" : "#e6e6e6",
        "stroke-width": t === 0 ? 1.25 : 1,
      })
    );
    chartG.appendChild(
      el(
        "text",
        { x: tx, y: chartBottom + 16, "font-size": 9.5, fill: "#888888", "text-anchor": "middle", "font-family": FONT },
        (t > 0 ? "+" : "") + t
      )
    );
  }

  chartG.appendChild(
    el(
      "text",
      { x: zeroX, y: chartTop - 8, "font-size": 9.5, fill: "#777777", "text-anchor": "middle", "font-family": FONT },
      "baseline"
    )
  );

  // Bars
  const rowH = chartH / rows.length;
  const barH = rowH * 0.58;

  const posColor = "#1b9e77";
  const negColor = "#d95f02";

  rows.forEach((row, i) => {
    const rowY = chartTop + i * rowH;
    const barY = rowY + (rowH - barH) / 2;
    const vx = xScale(row.delta);
    const barX = Math.min(zeroX, vx);
    const barW = Math.max(Math.abs(vx - zeroX), 0.5);
    const color = row.delta >= 0 ? posColor : negColor;
    const textY = barY + barH / 2 + 3.5;

    chartG.appendChild(el("rect", { x: barX, y: barY, width: barW, height: barH, fill: color, rx: 2, ry: 2 }));

    // Country label (left of chart)
    chartG.appendChild(
      el(
        "text",
        { x: margin.left - 10, y: textY, "font-size": 11, fill: "#333333", "text-anchor": "end", "font-family": FONT },
        row.label
      )
    );

    // Delta value label at the outer end of the bar
    const deltaText = (row.delta > 0 ? "+" : "") + row.delta.toFixed(2);
    const labelX = row.delta >= 0 ? vx + 6 : vx - 6;
    const anchor = row.delta >= 0 ? "start" : "end";

    chartG.appendChild(
      el(
        "text",
        {
          x: labelX,
          y: textY,
          "font-size": 10.5,
          fill: "#333333",
          "text-anchor": anchor,
          "font-weight": 600,
          "font-family": FONT,
        },
        deltaText
      )
    );
  });

  // Axis caption
  svg.appendChild(
    el(
      "text",
      { x: margin.left + chartW / 2, y: height - 4, "font-size": 10, fill: "#888888", "text-anchor": "middle", "font-family": FONT },
      "Δ years from world baseline"
    )
  );
}

Keep the same module shape (meta + render(svg, data)) and the same data, and the
same harness constraints: no network, no fonts loaded at render time, no
Date.now() or Math.random(), and a byte-stable render. Change only what the
skill's remit covers. Return only the module code.

Structural change vs the default arm

Added: path. Removed: nothing.