render_layers
Mojo function 🡭
render_layers
fn def render_layers(mut plots: List[Plot]) -> CanvasRender every Plot in plots onto one shared coordinate system on canvas – one combined x/y domain (computed across every layered plot’s data together, not each plot’s independent domain the way render_facets()’s cells each get), one shared set of axes/gridlines/ticks, each plot’s mark drawn on top of the last in the order given – a line overlaid on a scatter, three comparison lines sharing one y-axis, and so on.
Restricted to Mark.POINT/LINE/AREA –
Mark.BAR’s categorical x-axis and Mark.ARC’s lack of one don’t
share a domain shape with continuous marks or each other; layering
those in is real, separate, deferred work (see the wiki’s Backlog).
Raises if any layered plot uses a different mark.
A layer built via Plot.secondary_axis() scales its y values
against a second, independent y-domain drawn on the plot’s right
edge instead of the shared (primary/left) one every other layer’s
data combines into – a revenue-bars-and-growth-rate-line combo
chart, where the two series’ units are too different to share
one axis without one going flat. See that method’s docstring
for the full mechanics (no gridlines of its own, at least one layer
must stay on the primary axis).
A layer whose mark is Mark.POINT can use color/color_ categories/size encoding exactly like a standalone Mark.POINT
plot (see Plot.encode’s docstring) – each such layer’s domain (color scale, size scale, category palette) is independent
of every other layer’s, the same “each layer’s Theme only
governs its mark’s appearance” independence mark_color/
point_radius/line_width already have. Raises the identical
“only Mark.POINT” error Plot.encode’s single-plot path raises
if a LINE/AREA layer tries to use one of these instead. A
caller wanting several distinctly colored series instead (rather
than per-point encoding within one series) still sets each layer’s
flat Theme.mark_color directly, the same per-layer styling
render_facets() uses, just overlaid here instead of laid out
in a grid) – render_layers still has no per-series name/label
concept for a “which layer is which” legend built from several
flat-colored layers (see the wiki’s Backlog, its “Explicitly
still open” section); that’s a separate feature from per-point
encoding within a single layer, which this one now supports.
Shared chrome – background, gridlines, axis colors, margins, font
size, tick spacing – comes from plots[0]’s Theme; every
other layered plot’s Theme only governs its mark’s
appearance (mark_color, point_radius, line_width, and –
since every render path now builds its curve through the same
_build_line_path, see _draw_line_layer’s docstring – line_ smoothing, each still scaled by that plot’s Theme.scale; see
_Scaled’s docstring). A layered Mark.LINE/AREA curves exactly
the way the identical plot rendered standalone through render()
does, and rejects an out-of-[0.0, 1.0] value there the same way
too. Each encoding-using Mark.POINT layer draws its legend
section(s) (gated by that layer’s Theme.show_legend,
not plots[0]’s), stacked in one shared column in layer order –
the same categorical/continuous-color/size section types and
stacking order _render_generic’s single-plot Mark.POINT
legend uses (see its docstring), just once per
encoding-using layer instead of once per plot. The legend column’s horizontal position is shared (every section starts at the
identical x, from the combined plot_x1), but each section’s row height/font size/colors come from that specific layer’s Theme – so differently-scaled or differently-styled layers each
draw their section correctly, not forced through plots[0]’s
styling.
Plot.labels()’s title/x_title/y_title – like every other piece of
shared chrome – come from plots[0]’s labels, not each layer’s (a layered plot has one combined coordinate system, so one
shared title is the only reading that makes sense here, unlike
render_facets()’s per-cell titles – see that function’s docstring). The same _apply_labels/_label_text_requests
two-phase split render()/render_svg() use.
The one exception: a secondary-axis layer’s y_title captions
the secondary axis itself, mirrored onto the plot’s right edge (see
_secondary_axis_y_title’s docstring for why this reads per-
layer rather than only from plots[0]) – absent whenever no
secondary-axis layer sets one, which is every pre-existing call.
Every Plot in plots must share the same .size() (_require_ uniform_size – see its docstring) since there’s no longer a
caller-supplied canvas to derive one shared size from; raises on
an empty plots for the same reason (there’s no plot left to read
a size off of – a prior version of this function treated an empty
list as a no-op against a canvas the caller already owned, but
that reading doesn’t survive this function building its own
canvas instead).
Supersampled by _RASTER_SUPERSAMPLE exactly like render() (see
its docstring for why, and for the same mut tradeoff: a temporary
List[Plot] can’t bind to a mut argument, so render_layers( build_plots()) inline doesn’t compile – bind it to a variable
first) – every layer’s own _theme.scale is bumped together
(_bump_scale()), not just plots[0]’s shared chrome, so each
layer’s own mark styling stays uniformly sharp too.
Args:
- plots (
List[Plot])
Returns:
Canvas
Raises: