#4267·vega

Right-oriented categorical legend shifts by ~1px for path marks when endpoint lands on plot boundary

Author: joelostblomCreated Apr 14, 2026Updated May 10, 2026
Labelsbug

Description

I’m seeing a small but noticeable legend position jitter for path marks (line/trail/area) that appears to come from mark bounds overhang at the plot edge.

What happens

With a right-oriented categorical color legend:

  • If a trail endpoint lands exactly on the max x edge, the legend is shifted right by ~1px.
  • If I nudge that endpoint slightly beyond the edge (e.g. 7 -> 7.1), the legend shifts back.
  • Point marks do not show this behavior in similar setups.

Minimal Vega-Lite reproductions

Spec A (legend shifted)

json
{
  "data": {
    "values": [
      {"z": "a", "x": 0, "y": 0},
      {"z": "a", "x": 1, "y": 0.2},
      {"z": "a", "x": 2, "y": 0.39},
      {"z": "a", "x": 3, "y": 0.56},
      {"z": "a", "x": 4, "y": 0.72},
      {"z": "a", "x": 5, "y": 0.84},
      {"z": "a", "x": 6, "y": 0.93},
      {"z": "a", "x": 7, "y": 0.98},
      {"z": "b", "x": 7, "y": 1.0},
      {"z": "b", "x": 6, "y": 0.97},
      {"z": "b", "x": 5, "y": 0.91},
      {"z": "b", "x": 4, "y": 0.81},
      {"z": "b", "x": 3, "y": 0.68},
      {"z": "b", "x": 2, "y": 0.52},
      {"z": "b", "x": 1, "y": 0.33},
      {"z": "b", "x": 0, "y": 0.14}
    ]
  },
  "mark": {"type": "trail"},
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"},
    "color": {"field": "z"}
  }
}

Spec B (legend stable)

json
{
  "data": {
    "values": [
      {"z": "a", "x": 0, "y": 0},
      {"z": "a", "x": 1, "y": 0.2},
      {"z": "a", "x": 2, "y": 0.39},
      {"z": "a", "x": 3, "y": 0.56},
      {"z": "a", "x": 4, "y": 0.72},
      {"z": "a", "x": 5, "y": 0.84},
      {"z": "a", "x": 6, "y": 0.93},
      {"z": "a", "x": 7.1, "y": 0.98},
      {"z": "b", "x": 7, "y": 1.0},
      {"z": "b", "x": 6, "y": 0.97},
      {"z": "b", "x": 5, "y": 0.91},
      {"z": "b", "x": 4, "y": 0.81},
      {"z": "b", "x": 3, "y": 0.68},
      {"z": "b", "x": 2, "y": 0.52},
      {"z": "b", "x": 1, "y": 0.33},
      {"z": "b", "x": 0, "y": 0.14}
    ]
  },
  "mark": {"type": "trail"},
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"},
    "color": {"field": "z"}
  }
}

Evidence from scenegraph inspection

For the two specs above, observed values are roughly:

  • Spec A: pathgroup.bounds.x2 ≈ 301, legend x ≈ 319
  • Spec B: pathgroup.bounds.x2 = 300, legend x ≈ 318 So a tiny path overhang beyond frame width appears to affect layout bounds and guide placement.

Expected behavior

Right-side legend placement should be stable under tiny path-bound overhang differences at the frame edge.

Suspected cause

Guide layout appears to use scope/scene bounds that include path overhang (caps/joins/trail geometry), so small bound differences near the right edge nudge legend x.

Possible fix direction

A Vega-level layout fix could make this robust for all specs:

  1. Anchor legend placement to plot frame (width/height) rather than dynamic mark overhang in scope bounds, or
  2. Clamp mark-bound contribution to frame bounds for guide-layout calculations (rendering unchanged), and
  3. Add regression test comparing endpoint-at-edge vs slightly-off-edge for right-oriented legend x stability.