The realised frame of a chart: its scales, built once, and the static furniture — grid, axes, legend and labels — rendered from them (spec/14 §4, D-60).
new/2 takes a Visualize.Chart and the sources its marks are bound to, realises every
:scale node through the existing scale modules — a domain: :auto inferred from the
whole column of every mark channel that names the scale, a range: :auto from the plot
area by the scale's name — and caches the structs on the frame. scales/1 reads them,
the escape hatch for annotations, brush conversion and custom marks; put_scale/3
replaces one. generate/2 is the furniture as one Visualize.IR.Element group with
the margins applied and every theme slot resolved through Visualize.Theme.resolve/3;
render/2 is the same as a string. Given sources:, both also draw every mark of the
design between the grid and the axes through Visualize.Chart.Mark.generate/3
(spec/14 §5.6); without them a frame renders the furniture alone, over its unit
domains, which is what the static split of a compiled chart needs (spec/14 §12).
Examples
iex> chart =
...> Visualize.Chart.from_map!(%{
...> version: 2,
...> sources: %{primary: %{fields: [:t, :v]}},
...> frames: %{main: %{
...> kind: :cartesian,
...> scales: %{x: %{kind: :linear}, y: %{kind: :linear, domain: [0, :auto]}},
...> axes: [%{scale: :x, side: :bottom}, %{scale: :y, side: :left, grid: true}]
...> }},
...> marks: [%{type: :line, data: :primary, channels: %{x: :t, y: :v}}]
...> })
iex> frame = Visualize.Chart.Frame.new(chart, sources: %{primary: %{t: [1, 2, 3], v: [4, 9, 2]}}, size: {300, 200})
iex> Visualize.Chart.Frame.scale(frame, :x).domain
[1, 3]
iex> Visualize.Chart.Frame.scale(frame, :y).domain
[0, 9]
iex> frame.plot
%{width: 240, height: 150}
Summary
Functions
The size a frame is realised at when no size: is given (spec/14 §4.2).
As generate/2 with resolve: :css.
The frame as one Visualize.IR.Element group (spec/14 §4.7): the static furniture,
and every mark of the design between the grid and the axes when sources are given.
The frame of a chart, every scale realised and the theme resolved (spec/14 §4.7).
The projection of a :geo frame (spec/14 §4.6), nil for any other kind.
The frame with the realised scale replaced: the override of spec/14 §4.3.
As render/2 with [] options.
generate/2 rendered through Visualize.Render.to_string/2.
One realised scale; ArgumentError when the frame declares no such scale.
The realised scales by name: the escape hatch (spec/14 §4.3).
The attributes of a sync group for the frame it reads (spec/14 §2.9, D-116):
data-vis-sync, the group, and data-vis-sync-x, d0,d1,x0,x1,width — the x
scale's domain (milliseconds since the Unix epoch for a time scale), the chart pixels of
its ends and the chart's width — which is all the hooks need to map a shared x through
this frame's own scale. %{} for a frame that is no group's.
Types
@type kind() :: :cartesian | :polar | :geo | :facet
A frame kind of spec/14 §4.1.
@type t() :: %Visualize.Chart.Frame{ axes: [map()], background: term() | nil, box: [number()], defs: %{required(atom()) => map()}, design_styles: %{required(atom()) => map()}, domains: %{required(atom()) => term()}, facet: %{by: atom(), columns: pos_integer()} | nil, forces: map(), kind: kind(), label_paths: [non_neg_integer()], labels: [map()], legend: map() | nil, margin: %{top: number(), right: number(), bottom: number(), left: number()}, mark_paths: [non_neg_integer()], marks: [map()], name: atom() | nil, now: term() | nil, panels: [term()], plot: %{width: number(), height: number()}, projection: Visualize.Geo.Projection.t() | nil, scales: %{required(atom()) => struct()}, size: %{width: number(), height: number()}, styles: %{required(atom()) => map()}, sync: String.t() | nil, theme: Visualize.Theme.t(), z: integer() }
Functions
The size a frame is realised at when no size: is given (spec/14 §4.2).
@spec generate(t()) :: Visualize.IR.Element.t()
As generate/2 with resolve: :css.
@spec generate(t(), keyword()) :: Visualize.IR.Element.t()
The frame as one Visualize.IR.Element group (spec/14 §4.7): the static furniture,
and every mark of the design between the grid and the axes when sources are given.
Options
:resolve- how the theme's slots render::css(default) for references a stylesheet can override,:literalfor the plain values a canvas needs:sources- a map from source name to anythingVisualize.Data.Table.rows/1reads, asnew/2takes; when given, the marks are drawn from them (spec/14 §5.6):paths-truefor every design node's element to carrydata-nodewith the node's path asVisualize.Chart.Validator.format_path/1spells it —frame,marks[0],frames.main.axes[0],frames.main.legend,labels[0]— for a caller that must name what it drew, as the builder's graph does (spec/14 §4.7, D-105);false(default) leaves the markup as it is
Examples
iex> chart = Visualize.Chart.from_map!(%{version: 2, sources: %{s: %{fields: [:x, :y]}},
...> frames: %{main: %{kind: :cartesian, scales: %{x: %{kind: :linear}, y: %{kind: :linear}}}},
...> marks: [%{type: :line, data: :s, channels: %{x: :x, y: :y}}]})
iex> rows = [%{x: 0, y: 1}, %{x: 1, y: 2}]
iex> group = Visualize.Chart.Frame.new(chart, sources: %{s: rows}) |> Visualize.Chart.Frame.generate(sources: %{s: rows}, paths: true)
iex> {group.attrs["data-node"], Enum.map(group.children, & &1.attrs["data-node"])}
{"frames.main", ["marks[0]"]}
@spec new(Visualize.Chart.t(), keyword()) :: t()
The frame of a chart, every scale realised and the theme resolved (spec/14 §4.7).
Options
:sources- a map from source name to anythingVisualize.Data.Table.rows/1reads; the columns:autodomains are inferred from (default%{}):theme- a%Visualize.Theme{}; taken for any theme name the design gives, and required for one that is neither built-in nor inline:size- the{width, height}the frame is realised at (default{600, 400}, spec/14 §4.2); a design records none:now- the instant a:windowstep measures its durations back from (spec/14 §5.4.1); without it each such step takes the newest reading of its own column:warm- the force layouts a compiled chart carries between ticks (spec/14 §12.5, D-132); every:forcestep is cold without it (default%{})
Each distinct :force step of the frame's marks is laid out once, before any domain is
inferred, and held in forces: every pipeline that reaches the step reads that layout
(spec/14 §5.4.3).
Raises ArgumentError for an unresolved variable, a theme name it cannot resolve, a
bound value a scale cannot take, or a legend in a margin that cannot hold it (spec/14
§4.5).
@spec projection(t()) :: Visualize.Geo.Projection.t() | nil
The projection of a :geo frame (spec/14 §4.6), nil for any other kind.
The frame with the realised scale replaced: the override of spec/14 §4.3.
As render/2 with [] options.
generate/2 rendered through Visualize.Render.to_string/2.
Options
:backend-:svg,:canvas, or a module; defaults to the configured backend:resolve- the theme mode ofgenerate/2; defaults toVisualize.Theme.mode/1of the backend:sourcesand:paths- asgenerate/2takes them
One realised scale; ArgumentError when the frame declares no such scale.
The realised scales by name: the escape hatch (spec/14 §4.3).
The attributes of a sync group for the frame it reads (spec/14 §2.9, D-116):
data-vis-sync, the group, and data-vis-sync-x, d0,d1,x0,x1,width — the x
scale's domain (milliseconds since the Unix epoch for a time scale), the chart pixels of
its ends and the chart's width — which is all the hooks need to map a shared x through
this frame's own scale. %{} for a frame that is no group's.
iex> chart = Visualize.Chart.from_map!(%{version: 2,
...> interaction: %{sync: "dash"},
...> frames: %{main: %{kind: :cartesian, scales: %{x: %{kind: :linear, domain: [0, 100]}}}}})
iex> Visualize.Chart.Frame.new(chart, size: {300, 200}) |> Visualize.Chart.Frame.sync_attrs()
%{"data-vis-sync" => "dash", "data-vis-sync-x" => "0,100,40,280,300"}