Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Coverage = "a2441757-f6aa-5fb2-8edb-039e3f45d037"
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Expand All @@ -13,6 +14,7 @@ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[compat]
ADTypes = "1"
CairoMakie = "0.15"
Coverage = "1"
DifferentiationInterface = "0.7"
Documenter = "1"
Expand Down
1 change: 1 addition & 0 deletions docs/api_reference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ function generate_api_reference(src_dir::String)
),
),
(:CTBasePlots, ext(joinpath("CTBasePlots.jl"))),
(:CTBaseMakie, ext(joinpath("CTBaseMakie.jl"))),
]
extmod = Base.get_extension(CTBase, sym)
isnothing(extmod) && @warn "Extension $sym is not loaded"
Expand Down
9 changes: 8 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ using Test
using Coverage
using DifferentiationInterface
using Plots
using CairoMakie

# Make extension modules available in Main so that @docs blocks can resolve
# qualified bindings like CTFlowsSciMLIntegrator.SciMLIntegrationResult.
Expand All @@ -28,6 +29,7 @@ for _ext_sym in (
:DocumenterReference,
:CTBaseDifferentiationInterface,
:CTBasePlots,
:CTBaseMakie,
)
_m = Base.get_extension(CTBase, _ext_sym)
isnothing(_m) || @eval Main const $_ext_sym = $_m
Expand Down Expand Up @@ -96,7 +98,12 @@ with_api_reference(src_dir) do api_pages
draft=draft,
remotes=nothing, # Disable remote links. Needed for DocumenterReference
plugins=[links],
warnonly=[:cross_references],
# `:external_cross_references` — the self-referencing `InterLinks` "CTBase"
# entry only resolves against `build/1/objects.inv`, absent on the very first
# build of a fresh checkout; that first build then completes with @errors and
# produces the inventory, and a second build is clean (see Handbook
# documentation.md). Matches CTModels.jl.
warnonly=[:cross_references, :external_cross_references],
sitename="CTBase.jl",
format=DocumenterVitepress.MarkdownVitepress(;
repo=repo_url, devbranch="main", devurl="dev", sidebar_drawer=true
Expand Down
2 changes: 1 addition & 1 deletion docs/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,5 @@ For more, see the **[Data guide](guide/data.md)**.
| Semantic color roles and themes | [Color System](guide/color-system.md) |
| Linear and piecewise-constant interpolation | [Interpolation](guide/interpolation.md) |
| Unicode subscript/superscript helpers | [Unicode Helpers](guide/unicode.md) |
| Backend-agnostic plotting IR and render contract | [Plotting Engine](guide/plotting.md) |
| Backend-agnostic plotting IR and render contract (Plots.jl and Makie.jl backends) | [Plotting Engine](guide/plotting.md) |
| Full API reference | API Reference (left sidebar) |
67 changes: 54 additions & 13 deletions docs/src/guide/plotting.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ Panel ──lower──► IR (Series, Axes, Leaf/HBox/VBox, Figure)
│ │
│ │ render / render!
▼ ▼
Combinators Backend (Plots.jl via CTBasePlots extension)
(Stacked / Paired / Grid)
Combinators Backend
(Stacked / Paired / Grid) ├─ Plots.jl → CTBasePlots extension
└─ Makie.jl → CTBaseMakie extension
```

All IR types and transforms live in `src` (no backend dependency). Only the drawing
lives in a weak-dependency extension (`CTBasePlots`, loaded automatically when
`Plots` is available).
lives in weak-dependency extensions — `CTBasePlots` for [Plots.jl](https://docs.juliaplots.org)
and `CTBaseMakie` for [Makie.jl](https://docs.makie.org) — each loaded automatically
when its backend package (`Plots`, or `CairoMakie` / `GLMakie`) is available.

## Intermediate Representation

Expand Down Expand Up @@ -178,29 +180,68 @@ full = CTBase.Plotting.Stacked([state_node, control_node])
[`CTBase.Plotting.PlotsBackend`](@ref) is the concrete Plots.jl backend — its `render`/`render!`
methods live in the `CTBasePlots` extension.

[`CTBase.Plotting.MakieBackend`](@ref) is a proof-of-concept
[Makie.jl](https://docs.makie.org) backend (issue `CTModels#366`); its `render`
method lives in the `CTBaseMakie` extension, loaded automatically when `Makie` is
available (for example via `CairoMakie` or `GLMakie`). It implements `render` only
for the common figure shapes — `render!` (overlay), reference-line decorations,
`:steppost`/`:scatter` series types and `z_order` are not handled yet and are
tracked in a parity follow-up.
[`CTBase.Plotting.MakieBackend`](@ref) is the [Makie.jl](https://docs.makie.org)
backend, at feature parity with the Plots backend; its `render` / `render!` methods
live in the `CTBaseMakie` extension, loaded automatically when `Makie` is available
(for example via `CairoMakie` or `GLMakie`).

[`CTBase.Plotting.render`](@ref) turns a `Figure` into a backend figure. [`CTBase.Plotting.render!`](@ref) overlays
a `Figure` onto an existing backend target, targeting cells by the deterministic
leaf order (see [`CTBase.Plotting.leaves`](@ref)).

Without a backend loaded, the fallback throws an
[`CTBase.Exceptions.ExtensionError`](@ref). This cannot be demonstrated
in these docs because `Plots` is loaded by `make.jl` to produce the
examples below, which causes the `CTBasePlots` extension to be active.
in these docs because `make.jl` loads both `Plots` and `CairoMakie` to
produce the examples below, so the `CTBasePlots` and `CTBaseMakie`
extensions are both active.

Once `Plots` is loaded, `render(fig)` produces a Plots.jl plot:

```@example plot
CTBase.Plotting.render(fig)
```

The same `fig` rendered through the Makie backend:

```@example plot
using CairoMakie: CairoMakie
CTBase.Plotting.render(CTBase.Plotting.MakieBackend(), fig)
```

## User Attributes: Series vs Axis

`render(fig; kwargs...)` and `render!` accept extra keyword arguments and split them
into **series attributes** — forwarded to every curve — and **axis attributes** —
applied to every cell. `legend` and `ylims` are special-cased: a user value
overrides the IR default. The two backends make that split differently.

The **Plots backend** (`CTBasePlots._partition_user`) asks Plots itself:
`Plots.attributes(:Series)` is the authoritative set of series-attribute names, so
any kwarg in it goes to the series and everything else to the subplot. A key Plots
does not recognise still reaches Plots, which emits its own warning. Layout keys the
renderer owns (`CTBasePlots._RESERVED_AXES_KEYS`: `subplot`, `title`, `xlabel`,
`ylabel`, `legend`, `ylims`, `titlefont`, `guidefontsize`) are dropped so the
computed layout survives.

The **Makie backend** (`CTBaseMakie._partition_user`) has nothing to introspect —
Makie exposes no `attributes(:Series)` analogue — so it carries curated whitelists:
`CTBaseMakie._SERIES_USER_KEYS` (`color`, `linewidth`, `linestyle`, `alpha`,
`marker`, `markersize`, `label`) for series, `CTBaseMakie._AXIS_USER_KEYS` (a fixed
list of `Makie.Axis` constructor keys) plus `legend` / `ylims` for cells, with
`CTBaseMakie._RESERVED_AXES_KEYS` protected. **A kwarg in neither whitelist is
silently dropped** — a bare `Makie.Axis` throws on an unknown keyword, so unknown
keys cannot be forwarded the way Plots tolerates.

For a case layer or a caller this means:

- The portable surface is the neutral style vocabulary (`color`, `linewidth`,
`linestyle`, `alpha`, `seriestype`, `z_order`) plus `legend` and `ylims` — these
behave identically on both backends.
- A genuinely backend-specific option belongs in a [`CTBase.Plotting.Series`](@ref)
style's `backend_kwargs` escape hatch, not in a `render` kwarg: only the matching
backend honours it, and the Makie whitelist would drop it from a `render` call
anyway.

## Leaf Traversal

[`CTBase.Plotting.leaves`](@ref) returns the `Leaf` nodes of a layout tree in deterministic
Expand Down
4 changes: 2 additions & 2 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ It provides the **base layer** shared by all packages: common types, structured
| [`CTBase.Interpolation`](@ref) | Linear and piecewise-constant interpolation with flat extrapolation |
| [`CTBase.DevTools`](@ref) | Developer tools with tag-based dispatch for `run_tests`, `postprocess_coverage`, and `automatic_reference_documentation` |
| [`CTBase.Unicode`](@ref) | Unicode subscript/superscript helpers for display |
| [`CTBase.Plotting`](@ref) | Backend-agnostic plotting IR: series, axes, layout tree, and render contract |
| [`CTBase.Plotting`](@ref) | Backend-agnostic plotting IR: series, axes, layout tree, and a render contract with Plots.jl and Makie.jl backends |

## User Guides

Expand All @@ -56,6 +56,6 @@ It provides the **base layer** shared by all packages: common types, structured
- **[Color System](guide/color-system.md)** — semantic color roles, built-in themes, and runtime customization.
- **[Interpolation](guide/interpolation.md)** — linear and piecewise-constant interpolation with flat extrapolation.
- **[Unicode Helpers](guide/unicode.md)** — subscript and superscript character generation for display.
- **[Plotting Engine](guide/plotting.md)** — backend-agnostic plotting IR, panels, combinators, and render contract.
- **[Plotting Engine](guide/plotting.md)** — backend-agnostic plotting IR, panels, combinators, and a render contract with Plots.jl and Makie.jl backends.

To browse the complete API, see the **API Reference** section in the left sidebar.
Loading
Loading