R's scales package for Elixir: the pieces a chart's scales are built from, as plain functions of values, for any charting tool. Each gives the answer R's scales 1.4.0 gives, to the last digit; where one departs from R, its documentation says how and why.
The families
Each module holds one of R's families, and each function is R's name less the family's prefix,
its documentation naming R's: R's breaks_extended() is Scales.Breaks.extended/2.
| Module | What it holds | R's family |
|---|---|---|
Scales.Breaks | where an axis's breaks go | breaks_* |
Scales.MinorBreaks | minor breaks between them | regular_minor_breaks(), minor_breaks_* |
Scales.Labels | labels for breaks | label_*, cut_* |
Scales.Transform | transformations, with their breaks and labels | transform_* |
Scales.Palette | palettes, from a place or a count to an aesthetic's value | pal_*, palette_*, as_*_pal() |
Scales.Bounds | rescaling, zero width, widening, values outside a range | rescale*, oob_*, zero_range(), expand_range() |
Scales.DataRange | the range of the data a scale has seen | train_* |
Scales.ColorOperations | colours as written and as R's palettes make them | col_* |
Conventions
- A range is
{low, high}. - A double is held as R holds one (
double/0):nilis R'sNA, a missing value,:nanR'sNaN, and:infinityand:neg_infinityR's infinities. - A colour is uppercase
#RRGGBB, or#RRGGBBAAwith an alpha of its own;:noneis no colour, R'sNA. - A function takes a list where R takes a vector, and its options as a keyword list of R's arguments, spelled out, checked as it is called: a bad one raises.
- A colour operation takes one colour, where R takes a vector of them: a list of colours is mapped through it.
- Elixir's words stand where R's differ:
:timeis a time of day (R'shms),{:datetime, ...}a date-time (R'sPOSIXct), and grey isgray. - A step on a calendar or a clock is written as
Date.shift/2takes one,[month: 1], where R writes"1 month".
An example
The steps a charting tool takes for a continuous colour scale: train a range on the data, find its breaks, some of which may fall outside it, label them, and map each value through a palette by its place in the range.
iex> values = [12.0, 31.5, 18.25, nil]
iex> range = Scales.DataRange.train_continuous(:none, values)
{12.0, 31.5}
iex> breaks = Scales.Breaks.extended(range)
[10.0, 15.0, 20.0, 25.0, 30.0]
iex> Scales.Labels.comma(breaks, suffix: " km")
["10 km", "15 km", "20 km", "25 km", "30 km"]
iex> places = Scales.Bounds.rescale(values, range, {0, 1})
[0.0, 1.0, 0.32051282051282054, nil]
iex> Scales.Palette.continuous({:gradient, ["#132B43", "#56B1F7"]}, places)
["#132B43", "#56B1F7", "#275278", nil]
Summary
Types
@type double() :: number() | :infinity | :neg_infinity | :nan | nil
A double as R holds one: a number; :infinity or :neg_infinity; :nan, R's NaN, not a
number; or nil, R's NA, a missing value.