Skip to content
render_layers

render_layers

Mojo function 🡭

render_layers

fn def render_layers(mut plots: List[Plot]) -> Canvas

Render 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/AREAMark.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: