Documentation
¶
Overview ¶
Package a11y makes a chart readable by something other than an eye.
A chart is a picture, and a picture is where the information stops for a reader using a screen reader, a reader on a monochrome printout, and any program that would rather have the numbers. This package produces the two things that fix that: a description in words, and the data as a table.
Where it sits ¶
It reads the model and is read by nobody in it — the same arrangement package spec has, and for the same reason. A geom that knew what a screen reader was would be a geom in the wrong package, so a layer says what it is through geom.Desc and this package decides what that means in words.
What figure does with it ¶
github.com/timzifer/figure.Plot.Describe attaches a summary to a plot, and every backend that can carry words then writes it: an SVG gets a <title> and a <desc> and the role that makes a screen reader read them, a PDF gets a document title, a browser canvas gets an aria-label. github.com/timzifer/figure.Plot.DataTable writes the table.
The third channel — not colour alone — is a theme decision rather than a document one, and lives in github.com/timzifer/figure/theme.Redundant.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func WriteTable ¶
WriteTable writes the chart's data as an HTML table.
This is the fallback a picture cannot be: the numbers themselves, in reading order, in a form a screen reader navigates cell by cell and a spreadsheet opens. It is what the accessibility guidance means by a data table alternative, and it is also the honest answer to "what is actually in this chart".
One table per layer that has data, each with a caption naming the layer and a column per field it reads — x, y, a second y where a band has one, and the column a colour is taken from. A layer with no data source is an annotation: it is listed with its values rather than given a table of one row.
The output is a fragment, not a document: one or more <table> elements with no wrapper, so it drops into a page beside the chart. Everything written is escaped, including column names and category labels, which come from the caller's data rather than from figure.
Types ¶
type Chart ¶
type Chart struct {
Title string
XTitle, YTitle string
X, Y scale.Scale
Layers []geom.Geom
// Z and ZTitle are the depth axis of a three-dimensional chart, and are
// nil and "" for a flat one. A reader who cannot see the picture needs to
// be told there are three axes rather than two, and needs the third one's
// range most of all — it is the one the flat chart of the same table does
// not have.
Z scale.Scale
ZTitle string
// Descs are the layers of a chart whose layers are not geom.Geoms, as
// [github.com/timzifer/figure/three]'s are not: a projected layer emits
// geometry rather than ink and so cannot implement Geom. It is read when
// Layers is empty, and it is the same description Layers is reduced to
// before anything is said about it — so a scene is described in the same
// voice as a flat chart rather than in a second one.
Descs []geom.Desc
// Y2, X2 and their titles are the chart's secondary axes, when it has
// them. A reader who cannot see the picture needs to be told there are
// two: a description that named one axis for a chart with two would say
// the line runs from 0.09 to 0.17 on an axis it called "revenue".
Y2 scale.Scale
Y2Title string
X2 scale.Scale
X2Title string
// Facet names the column a faceted chart is split by, if any. The panels
// themselves are not described one by one: "one panel per region" is the
// fact a reader needs, and thirty near-identical paragraphs is not.
Facet string
}
Chart is what a plot tells this package about itself.
It is deliberately the model rather than the picture: the layers, the scales and the titles, with no rectangle anywhere. A description of where the marks landed on a canvas would be a description of a canvas.
type Range ¶
Range is the extent of a column. Ok is false when there was nothing finite in it to measure.
type Series ¶
type Series struct {
// Label names the layer, and Mark is what it draws.
Label string
Mark geom.Mark
// X and Y name the columns, and Rows is how many there are. Z names the
// depth column of a three-dimensional layer and is empty for a flat one.
X, Y string
Z string
Rows int
// XRange and YRange are the extremes of the plotted columns, and ZRange
// the depth column's. Ok is false for a layer with no numbers in it — an
// annotation, or a column of nothing but missing values.
XRange, YRange Range
ZRange Range
// Time reports whether the corresponding axis is temporal, which decides
// whether a bound reads as a number or as an instant.
XTime, YTime bool
ZTime bool
// SecondaryY and SecondaryX report a layer read against the chart's second
// vertical or horizontal axis, so that a reading of it names the right
// one.
SecondaryY, SecondaryX bool
}
Series is one layer, reduced to what can be said about it.
type Summary ¶
type Summary struct {
// Title is a short label: the chart's own title, or a sentence naming what
// it plots when it has none.
Title string
// Detail is the long reading: what each layer plots, over what range, and
// how many rows there are.
Detail string
// Series is the same thing before it was turned into prose, for a caller
// writing its own.
Series []Series
}
Summary is a chart in words.
func Describe ¶
Describe reads a chart and says what it shows.
It costs one pass over each plotted column, which is why figure does not do it on every render: describing a million rows is cheap compared with drawing them and is not free, and a chart nobody is describing should not pay for it.
A layer that cannot describe itself — a third-party geom implementing no geom.Describer — is named by its position rather than skipped, because a description that quietly omits a series is worse than one that admits to it.