A chart's text alternative (spec/14 §21, D-142): what a screen reader says for a chart, generated from the design and the data it was applied to.
new/1 reads an applied chart into a summary: its name — the design's meta.name,
else its kind — and, frame by frame, the chart's kind (a line chart, a gauge, a
treemap), the series its marks draw and how many rows, each axis with the range
or the categories its scale holds, and the extremes of the values the marks draw.
text/1 is that summary as sentences, which Visualize.Chart.generate/2 writes into
the root's <desc> (§21.2). A value is written as its axis writes it — the axis's
format, its measure's display unit, its prefix and unit (§4.4) — to four
significant digits rather than at the ticks' step, so an extreme is not rounded to a
tick.
table/2 is the other half of the text alternative (§21.3): the rows each mark draws
as an HTML <table>, visually hidden, for a host to place beside the chart. A
role="img" root hides its children from assistive technology, so the table cannot
live inside the <svg>.
attrs/2 and description/2 name an element that stands for the chart — a <canvas>,
or the wrapper of a hybrid chart's layers (§21.4).
Examples
iex> design = %{
...> version: 2,
...> meta: %{name: "Load"},
...> sources: %{primary: %{fields: [:t, :v]}},
...> frames: %{main: %{
...> kind: :cartesian,
...> scales: %{x: %{kind: :linear}, y: %{kind: :linear}},
...> axes: [%{scale: :x, side: :bottom}, %{scale: :y, side: :left}]
...> }},
...> marks: [%{type: :line, data: :primary, channels: %{x: :t, y: :v}}]
...> }
iex> {:ok, applied} = Visualize.Chart.apply(design, sources: %{primary: %{t: [1, 2, 3], v: [4, 9, 2]}})
iex> summary = Visualize.Chart.Summary.new(applied)
iex> summary.name
"Load"
iex> Visualize.Chart.Summary.text(summary)
"Line chart, 1 series (v) of 3 points. Bottom axis t, from 1 to 3. Left axis v, from 2 to 9. Highest v 9 at t 2; lowest v 2 at t 3."
Summary
Types
An axis as the summary says it: its scale's range, or its categories.
The highest and the lowest value one mark draws, each with where it is; rows is how
many values there were, and a mark of one says its value alone.
One frame of the summary.
Functions
The attributes that make an element stand for the chart (§21.4) — a <canvas>, or the
wrapper of a hybrid chart's layers: role="img", the name as aria-label, and
aria-describedby the id of description/2's element, which the page renders with
the same id. A keyword list, to spread into a HEEx tag.
The element attrs/2 points aria-describedby at: the summary's text in a <p> with
the id <id>-summary and the hidden attribute, read as a description and never
shown. Inside a <canvas> it is also the canvas's fallback content.
The summary of an applied chart: its name and, per frame in drawing order (z, ties
by name, §4.2), its kind, series, axes and extremes.
The data-table fallback (§21.3): the rows each data mark draws, one HTML <table> per
mark — a mark repeating another's table is left out — in a <div> that is visually
hidden and still read. Each table has a <caption> — the chart's name, and the
source's name when there are several — <th scope="col"> headers named by field, and
every value written as the summary writes it. All text is escaped.
The summary as sentences: per frame, the kind with its series, one sentence per axis, then the extremes; a design of several frames says each frame's name first.
Types
@type axis() :: %{ scale: atom(), side: atom(), title: String.t(), range: {String.t(), String.t()} | nil, categories: [String.t()] | nil }
An axis as the summary says it: its scale's range, or its categories.
@type extreme() :: %{ field: String.t(), rows: non_neg_integer(), high: {String.t(), String.t() | nil}, low: {String.t(), String.t() | nil} }
The highest and the lowest value one mark draws, each with where it is; rows is how
many values there were, and a mark of one says its value alone.
@type frame() :: %{ name: atom() | nil, kind: String.t(), series: [String.t()], rows: non_neg_integer(), unit: String.t(), axes: [axis()], extremes: [extreme()] }
One frame of the summary.
Functions
The attributes that make an element stand for the chart (§21.4) — a <canvas>, or the
wrapper of a hybrid chart's layers: role="img", the name as aria-label, and
aria-describedby the id of description/2's element, which the page renders with
the same id. A keyword list, to spread into a HEEx tag.
The element attrs/2 points aria-describedby at: the summary's text in a <p> with
the id <id>-summary and the hidden attribute, read as a description and never
shown. Inside a <canvas> it is also the canvas's fallback content.
@spec new(Visualize.Chart.Applied.t()) :: t()
The summary of an applied chart: its name and, per frame in drawing order (z, ties
by name, §4.2), its kind, series, axes and extremes.
@spec table(Visualize.Chart.Applied.t(), keyword()) :: String.t()
The data-table fallback (§21.3): the rows each data mark draws, one HTML <table> per
mark — a mark repeating another's table is left out — in a <div> that is visually
hidden and still read. Each table has a <caption> — the chart's name, and the
source's name when there are several — <th scope="col"> headers named by field, and
every value written as the summary writes it. All text is escaped.
Options
:hidden- visually hide the tables (defaulttrue):id- the<div>'s id (default none):class- the<div>'s class (default"vis-data-table"):caption- the caption (default the summary's name):limit- the rows a table holds; a table cut short says how many it left out (default1000)
@spec text(t() | Visualize.Chart.Applied.t()) :: String.t()
The summary as sentences: per frame, the kind with its series, one sentence per axis, then the extremes; a design of several frames says each frame's name first.