Palettes: what turns a value's place among the data into a value of its aesthetic, a colour, a
size, a shape or a line type. A palette is a value naming its function, so it compares and
prints. A continuous palette is handed places, 0 to 1 over the data's range (continuous/2); a
discrete one the number of levels it must tell apart (discrete/2).
Continuous palettes
:identity, R'spal_identity(): each place as it is.{:rescale, {low, high}}, R'spal_rescale(): each place moved ontolowtohigh.{:area, {low, high}}, R'spal_area(): each place's square root moved ontolowtohigh, so an area drawn at that size grows with the place.{:abs_area, max}, R'sabs_area(): the square root of each place's size moved onto 0 tomax; a place may lie below 0 or past 1.{:gradient, colors}, R'spal_gradient_n(), which R's two- and three-colour gradients are too: the colour that far along a gradient throughcolors, spaced evenly from 0 to 1, each place between two blended in CIE Lab* and its alpha along a straight line; a place at a colour takes it exactly, one outside 0 to 1 givesnil, and one colour is every place's.:noneamong the colours is R'sNA, white with no alpha, as"transparent"is.{:gradient, colors, values}, R'spal_gradient_n(colours, values): each place moved first along the straight lines throughvalues, each value at its own place spread evenly from 0 to 1, then taken along the gradient; a place outside the values givesnil. The values are taken as R'sapproxfun()takes them: sorted, so unsorted ones run the gradient backwards; anildropped; equal values one, at their places' mean; as many as you like, not one per colour. Fewer than two left raiseArgumentError. R also warns of equal values.
Discrete palettes
{:hue, %{hue: {low, high}, chroma: chroma, luminance: luminance, direction: direction}}, R'spal_hue(): colours of one chroma and luminance, their hues spaced evenly fromlowtohigh, handed out in reverse for adirectionof -1. A range within a degree of the whole circle leaves its last share off, since its end is its start.{:gray, {start, finish}}, R'spal_grey(): greys from the levelstarttofinish, 0 black and 1 white, spaced evenly once raised to the power 2.2.{:viridis, %{option: option, begin: begin, end: end, direction: direction, alpha: alpha}}, R'spal_viridis(): colours of a viridis palette, asScales.ColorOperations.viridis/2gives them.{:shape, :solid}or{:shape, :open}, R'spal_shape(): six shapes by name, solid (:circle_small,:triangle,:square,:plus,:square_cross,:asterisk, R's 16, 17, 15, 3, 7 and 8) or open (:circle_open,:triangle_open,:square_openand the same last three, R's 1, 2, 0, 3, 7 and 8).:linetype, R'spal_linetype(): 13 line types, each as its dash pattern, a tuple of lengths,{}for a solid line.{:manual, values}, R'spal_manual():valuesin order.{:brewer, %{palette: palette, direction: direction}}, R'spal_brewer(): the colours of one of ColorBrewer's palettes, named as R spells it (brewer_palettes/1lists them), which has a set of its own for each count from 3 to its largest. Fewer than 3 levels take the start of its set of 3, and adirectionof -1 hands the colours out in reverse once thenils past its largest set are added, so those come first, as R's do. A name it does not know is refused, where R warns and gives Greens.
A discrete palette asked for more levels than it holds gives nil for each past its end, as R
gives NA (and warns). No levels give none, where R's hue palette refuses them.
A palette of the other kind
Each function takes a palette of the other kind too, as R's as_continuous_pal() and
as_discrete_pal() convert one. continuous/2 hands a discrete palette of colours on as a
gradient through its nlevels/1 colours, and one of numbers as those numbers joined by
straight lines, spaced evenly from 0 to 1; a place outside them gives nil, and a palette of
shapes, line types or other values is refused. discrete/2 hands a continuous palette the
levels' places, spaced evenly from 0 to 1 by spread/2. :identity and {:abs_area, max},
which R gives no type, are not converted: R hands them back as they are, so asked for 3 levels
they give the one number 3, and here they are refused.
Colours are uppercase #RRGGBB, or #RRGGBBAA with an alpha of their own, as
Scales.ColorOperations writes them.
ColorBrewer
This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/). They are Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University, licensed under the Apache License, Version 2.0, as R's RColorBrewer carries them.
Summary
Types
A ColorBrewer palette's type: sequential, diverging or qualitative.
A continuous palette.
A discrete palette.
A palette.
What a palette's values are: colours, numbers, shapes or line types.
Functions
The names of ColorBrewer's palettes of type, sequential (:seq), diverging (:div) or
qualitative (:qual), as R spells them, in the order R's pal_brewer() numbers them, so its
pal_brewer("qual", 5) is "Pastel2".
Each place's value under a continuous palette, a place running from 0 to 1 over the data's
range; a nil place gives nil. A discrete palette is converted first, as the moduledoc says.
The values of a discrete palette for count levels, in level order. A continuous palette is
converted first, as the moduledoc says.
The palette scales names name, R's get_palette() for scales' own names, in any case: each
ColorBrewer palette as pal_brewer() gives it (brewer_palettes/1), each viridis option as
pal_viridis() does (Scales.ColorOperations.viridis_options/0), "grey", pal_grey(), and
"hue", pal_hue(), each with R's defaults. Any other name raises ArgumentError listing
these; R also knows grDevices' palettes by name ("Okabe-Ito", "Blues 3"), which are left
out.
How many levels a discrete palette tells apart, R's palette_nlevels(): 6 shapes, 13 line
types, a manual palette's values, a brewer palette's largest set, and 255 for a hue, grey or
viridis palette, as R says; nil for a continuous palette. A discrete palette converted to a
continuous one is a gradient through this many of its values.
count numbers spread evenly from low to high, R's seq(low, high, length.out = count):
the ends exact, each number between them low plus its index times the step, in R's order of
operations, so the fourth of seven from 0.1 to 1 is 0.54999999999999993, not 0.55.
What a palette's values are, R's palette_type(): :color, :numeric, :shape or
:linetype, or nil for :identity and {:abs_area, max}, which R gives no type.
Types
@type brewer_type() :: :seq | :div | :qual
A ColorBrewer palette's type: sequential, diverging or qualitative.
@type continuous() :: :identity | {:rescale, {number(), number()}} | {:area, {number(), number()}} | {:abs_area, number()} | {:gradient, [Scales.ColorOperations.t(), ...]} | {:gradient, [Scales.ColorOperations.t(), ...], [number() | nil, ...]}
A continuous palette.
@type discrete() :: {:hue, %{ hue: {number(), number()}, chroma: number(), luminance: number(), direction: 1 | -1 }} | {:gray, {number(), number()}} | {:viridis, %{ option: atom(), begin: number(), end: number(), direction: 1 | -1, alpha: number() }} | {:shape, :solid | :open} | :linetype | {:manual, list()} | {:brewer, %{palette: String.t(), direction: 1 | -1}}
A discrete palette.
@type t() :: continuous() | discrete()
A palette.
@type value_type() :: :color | :numeric | :shape | :linetype
What a palette's values are: colours, numbers, shapes or line types.
Functions
@spec brewer_palettes(brewer_type()) :: [String.t(), ...]
The names of ColorBrewer's palettes of type, sequential (:seq), diverging (:div) or
qualitative (:qual), as R spells them, in the order R's pal_brewer() numbers them, so its
pal_brewer("qual", 5) is "Pastel2".
Examples
iex> Scales.Palette.brewer_palettes(:qual)
["Accent", "Dark2", "Paired", "Pastel1", "Pastel2", "Set1", "Set2", "Set3"]
@spec continuous(t(), [Scales.double()]) :: [Scales.double() | String.t()]
Each place's value under a continuous palette, a place running from 0 to 1 over the data's
range; a nil place gives nil. A discrete palette is converted first, as the moduledoc says.
A place may be any double (Scales.double/0), each given R's answer: the numeric palettes
carry an infinity or NaN through their arithmetic, the area palettes' square root making NaN
below 0, and a colour is nil at an infinity or NaN, but one colour's, which an infinity takes
too; a manual palette of numbers keeps NaN.
Examples
iex> Scales.Palette.continuous({:rescale, {2, 5}}, [0, 0.3, 1, nil])
[2.0, 2.9, 5.0, nil]
iex> Scales.Palette.continuous({:area, {1.0, 6.0}}, [0.2, 1])
[3.23606797749979, 6.0]
iex> Scales.Palette.continuous({:gradient, ["#132B43", "#56B1F7"]}, [0, 0.5, 1])
["#132B43", "#336A98", "#56B1F7"]
iex> Scales.Palette.continuous({:gradient, ["#132B43", "#56B1F7"], [0, 0.25]}, [0.1, 0.5])
["#2C5D86", nil]
iex> Scales.Palette.continuous({:gradient, ["#FF000080", "#0000FF"]}, [0.5, 1.5])
["#CA0088C0", nil]
iex> Scales.Palette.continuous({:manual, [1.0, 5.0, 9.0]}, [0.25, 1.5])
[3.0, nil]
iex> Scales.Palette.continuous({:area, {1.0, 6.0}}, [-0.5, :infinity])
[:nan, :infinity]
@spec discrete(t(), non_neg_integer()) :: list()
The values of a discrete palette for count levels, in level order. A continuous palette is
converted first, as the moduledoc says.
Examples
iex> hue = %{hue: {15.0, 375.0}, chroma: 100.0, luminance: 65.0, direction: 1}
iex> Scales.Palette.discrete({:hue, hue}, 3)
["#F8766D", "#00BA38", "#619CFF"]
iex> Scales.Palette.discrete({:manual, ["#FF0000", "#0000FF"]}, 3)
["#FF0000", "#0000FF", nil]
iex> Scales.Palette.discrete({:rescale, {1, 6}}, 3)
[1.0, 3.5, 6.0]
The palette scales names name, R's get_palette() for scales' own names, in any case: each
ColorBrewer palette as pal_brewer() gives it (brewer_palettes/1), each viridis option as
pal_viridis() does (Scales.ColorOperations.viridis_options/0), "grey", pal_grey(), and
"hue", pal_hue(), each with R's defaults. Any other name raises ArgumentError listing
these; R also knows grDevices' palettes by name ("Okabe-Ito", "Blues 3"), which are left
out.
Examples
iex> Scales.Palette.named("set1")
{:brewer, %{palette: "Set1", direction: 1}}
iex> Scales.Palette.named("Grey")
{:gray, {0.2, 0.8}}
@spec nlevels(t()) :: non_neg_integer() | nil
How many levels a discrete palette tells apart, R's palette_nlevels(): 6 shapes, 13 line
types, a manual palette's values, a brewer palette's largest set, and 255 for a hue, grey or
viridis palette, as R says; nil for a continuous palette. A discrete palette converted to a
continuous one is a gradient through this many of its values.
Examples
iex> Scales.Palette.nlevels({:brewer, %{palette: "Paired", direction: 1}})
12
iex> Scales.Palette.nlevels({:gradient, ["#132B43", "#56B1F7"]})
nil
@spec spread({number(), number()}, non_neg_integer()) :: [number()]
count numbers spread evenly from low to high, R's seq(low, high, length.out = count):
the ends exact, each number between them low plus its index times the step, in R's order of
operations, so the fourth of seven from 0.1 to 1 is 0.54999999999999993, not 0.55.
Examples
iex> Scales.Palette.spread({0.0, 1.0}, 5)
[0.0, 0.25, 0.5, 0.75, 1.0]
iex> Scales.Palette.spread({2, 6}, 1)
[2]
@spec type(t()) :: value_type() | nil
What a palette's values are, R's palette_type(): :color, :numeric, :shape or
:linetype, or nil for :identity and {:abs_area, max}, which R gives no type.
A manual palette's is guessed from its values, as R's pal_manual() guesses it: :color where
every value is a string Scales.ColorOperations.parse/1 reads, as no values are, so not
:none, :numeric where every one is a number, else nil, where R names how its values are
stored ("character"). R reads a colour as hex or one of its own colour names, so "grey50" is a
colour there and "transparent" is not; here they are the other way round.
Examples
iex> Scales.Palette.type({:brewer, %{palette: "Set1", direction: 1}})
:color
iex> Scales.Palette.type({:manual, [1, 5, 9]})
:numeric
iex> Scales.Palette.type({:manual, [:circle_small, :triangle]})
nil