Skip to content

feat(render): rewrite VL→matplotlib as a staged tree-walking interpreter - #1

Merged
Roy-Kid merged 1 commit into
MolCrafts:devfrom
Roy-Kid:feat/vl-mpl-interpreter
Jul 4, 2026
Merged

feat(render): rewrite VL→matplotlib as a staged tree-walking interpreter#1
Roy-Kid merged 1 commit into
MolCrafts:devfrom
Roy-Kid:feat/vl-mpl-interpreter

Conversation

@Roy-Kid

@Roy-Kid Roy-Kid commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What

Rewrites the Vega-Lite → matplotlib renderer from an ad-hoc, specs.py-coupled
prototype into a small tree-walking interpreter (molplot.vlmpl) whose
source language is Vega-Lite and target machine is matplotlib.

Four passes, each a classic compiler stage:

  1. model.py — normalize the raw spec into an immutable, field-name-agnostic
    AST (Unit/Channel/Scale); resolves layer inheritance and mark shape.
  2. scales.py — bind scales: colour maps, per-series numeric maps, and
    positional axis config.
  3. marks.py — dispatch each mark to an encoder (MARK_ENCODERS registry);
    encoders read typed channels (enc["x"].field), never hardcoded field names.
  4. axes.py — finalize titles, positional scales, and legend.

render.py is now a thin shim re-exporting molplot.vlmpl.render; the public
molplot.render(spec, *, preset, mode, ax, apply_style) API is unchanged.

Why — two parity gaps the prototype had

  • Positional scales were dropped. specs.py emits scale.type: "log" and
    scale.domain, but the old renderer never applied them — a web log axis
    rendered linear in matplotlib, and x_domain/y_domain were ignored. The
    axes pass now applies both.
  • Per-layer transform filters were ignored. The line spec's marker layer
    is gated by transform: [{filter: {oneOf: markerKeys}}]; the old renderer
    drew marker points on every line chart. Filters are now honoured, and the
    detail channel splits series that share a legend colour.

Tests

test_vlmpl.py adds coverage for the fixed behaviour (log axis, domain limits,
no stray markers, detail splitting). Full suite: 33 passed (27 existing + 6
new).

Note for reviewers: the local pre-push hook runs cd python && pytest
against the editable-installed molplot, which points at your main checkout —
so it can show the new tests failing against old code if you have a stale
install. pip install -e ./python on this branch (as CI does) → all green.

Replace the ad-hoc per-mark render.py prototype with a small interpreter
package (molplot.vlmpl) structured as four compiler passes: normalize →
bind scales → dispatch marks → finalize axes. Mark encoders read typed
channels instead of hardcoded field names, so marks and scales are extensible.

Fixes two Vega-Lite → matplotlib parity gaps the prototype had:
- positional scales are applied: log axes (scale.type) and explicit domains
  (scale.domain → axis limits) now reach the figure.
- per-layer transform filters are honoured, so a plain line chart no longer
  draws the stray marker-layer points; the detail channel splits series that
  share a legend colour.

render.py becomes a thin shim re-exporting molplot.vlmpl.render, preserving the
public molplot.render API. Adds test_vlmpl.py for the fixed behaviour.
@Roy-Kid
Roy-Kid marked this pull request as ready for review July 4, 2026 07:49
@Roy-Kid
Roy-Kid merged commit 9246f34 into MolCrafts:dev Jul 4, 2026
@Roy-Kid
Roy-Kid deleted the feat/vl-mpl-interpreter branch July 4, 2026 07:59
@Roy-Kid Roy-Kid mentioned this pull request Jul 10, 2026
4 tasks
Roy-Kid added a commit that referenced this pull request Jul 10, 2026
…ter (#1)

Replace the ad-hoc per-mark render.py prototype with a small interpreter
package (molplot.vlmpl) structured as four compiler passes: normalize →
bind scales → dispatch marks → finalize axes. Mark encoders read typed
channels instead of hardcoded field names, so marks and scales are extensible.

Fixes two Vega-Lite → matplotlib parity gaps the prototype had:
- positional scales are applied: log axes (scale.type) and explicit domains
  (scale.domain → axis limits) now reach the figure.
- per-layer transform filters are honoured, so a plain line chart no longer
  draws the stray marker-layer points; the detail channel splits series that
  share a legend colour.

render.py becomes a thin shim re-exporting molplot.vlmpl.render, preserving the
public molplot.render API. Adds test_vlmpl.py for the fixed behaviour.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant