A fixed list of quantities, each with a base unit and a display-scaling family, and the display scaling they choose (spec/05 §4.2–4.3, D-138).
A quantity is what a unit measures. A unit (a UCUM code, Visualize.Unit) and a
quantity together are a measure, %{unit: code, quantity: quantity}, the two facts a
field description carries. They are facts about the data, not knobs: a measure does
not change a value, it says what the value already is, so a display can choose how to
show it — 0–1,500 ms as 0–1.5 s, 2,500,000 By as 2.5 MB.
The list is fixed and grows by proposal:
| Quantity | Base unit | Display family |
|---|---|---|
:duration | s | ns us ms s min h d |
:information | By | By kBy MBy GBy; binary KiBy MiBy GiBy; bits |
:data_rate | By/s | the information families over /s |
:frequency | Hz | Hz kHz MHz GHz; events /h /min /s |
:ratio | 1 | — |
:count | 1 | — (SI from a thousand) |
:temperature | Cel | — |
:length | m | mm m km |
:speed | m/s | — |
:power | W | W kW MW GW |
:energy | J | J kJ MJ GJ; watt-hours W.h kW.h MW.h GW.h |
:pressure | Pa | Pa kPa MPa |
Information is decimal by default — UCUM's kBy and Telemetry.Metrics'
:kilobyte are 1,000 bytes — and a unit written with a binary prefix (MiBy) or in
bit scales in its own family: the data picks it, no setting does.
Tick formats are built on Visualize.Format.Auto (spec/05 §3), and every function that
formats takes its locale:.
Examples
iex> Visualize.Quantity.display_unit([0, 1500], %{unit: "ms"})
"s"
iex> scale = Visualize.Scale.linear() |> Visualize.Scale.domain([0, 1500])
iex> Visualize.Quantity.formatter(scale, %{unit: "ms"}).(1500)
"1.5 s"
iex> Visualize.Quantity.label(%{unit: "{request}"})
"request"
Summary
Types
A unit and a quantity, either or both; the two facts a field description carries.
Why a measure does not resolve.
One of the fixed list of quantities.
Functions
The fixed list of quantities (spec/05 §4.2).
A quantity's base unit, the unit its values are in when no unit is given.
The family member that fits a domain in a measure (spec/05 §4.3): the largest in which
the domain's magnitude is at least 1, else the smallest. A measure with no family, a
unit without a factor (Cel) or a zero magnitude keeps its unit; no unit is nil.
The display family a unit of the quantity scales in, smallest first; [] for a
quantity displayed in its own unit (spec/05 §4.2). The unit picks among a quantity's
families: bits, binary prefixes, hertz, watt-hours.
The tick formatter of a realised scale in a measure (spec/05 §4.3): each tick scaled
into the display unit, written by Visualize.Format.Auto's notation of the scaled
domain, then followed by the unit's symbol. A log or symlog scale gives each tick its
own display unit; any other scale but the numeric ones is
Visualize.Format.Auto.formatter/2, the measure unused. Raises ArgumentError for a
measure resolve/1 refuses.
The label rule (spec/05 §4.3): the unit, else the quantity, else nothing — the
unit's symbol with its annotations written when it is not empty, else the quantity's
name with spaces for underscores, else nil. Raises ArgumentError for a measure
resolve/1 refuses.
The quantity a code's dimension implies, or nil when none of the list has it. A
dimensionless code holding % is a :ratio, any other a :count.
A measure completed and checked (spec/05 §4.2): a unit alone implies its quantity, a
quantity alone means its base unit, and a unit whose dimension is not its quantity's is
refused. A :ratio or a :count takes any dimensionless unit.
What follows a number written in a unit (spec/05 §4.3): its symbol after a space, %
and a symbol beginning with / directly, and nothing for an empty symbol or no unit.
Types
@type measure() :: %{ optional(:unit) => Visualize.Unit.code() | nil, optional(:quantity) => t() | nil }
A unit and a quantity, either or both; the two facts a field description carries.
@type reason() :: {:unit, Visualize.Unit.code(), Visualize.Unit.reason()} | {:quantity, t(), Visualize.Unit.code()} | {:unknown_quantity, term()}
Why a measure does not resolve.
@type t() ::
:duration
| :information
| :data_rate
| :frequency
| :ratio
| :count
| :temperature
| :length
| :speed
| :power
| :energy
| :pressure
One of the fixed list of quantities.
Functions
@spec all() :: [t(), ...]
The fixed list of quantities (spec/05 §4.2).
@spec base_unit(t()) :: Visualize.Unit.code()
A quantity's base unit, the unit its values are in when no unit is given.
@spec display_unit([term()], measure()) :: Visualize.Unit.code() | nil
The family member that fits a domain in a measure (spec/05 §4.3): the largest in which
the domain's magnitude is at least 1, else the smallest. A measure with no family, a
unit without a factor (Cel) or a zero magnitude keeps its unit; no unit is nil.
@spec family(t(), Visualize.Unit.code() | nil) :: [Visualize.Unit.code()]
The display family a unit of the quantity scales in, smallest first; [] for a
quantity displayed in its own unit (spec/05 §4.2). The unit picks among a quantity's
families: bits, binary prefixes, hertz, watt-hours.
Examples
iex> Visualize.Quantity.family(:information, "MiBy")
["By", "KiBy", "MiBy", "GiBy"]
The tick formatter of a realised scale in a measure (spec/05 §4.3): each tick scaled
into the display unit, written by Visualize.Format.Auto's notation of the scaled
domain, then followed by the unit's symbol. A log or symlog scale gives each tick its
own display unit; any other scale but the numeric ones is
Visualize.Format.Auto.formatter/2, the measure unused. Raises ArgumentError for a
measure resolve/1 refuses.
Options
:count- the tick count the axis asks for (default10):locale- default"en"
The label rule (spec/05 §4.3): the unit, else the quantity, else nothing — the
unit's symbol with its annotations written when it is not empty, else the quantity's
name with spaces for underscores, else nil. Raises ArgumentError for a measure
resolve/1 refuses.
Examples
iex> Visualize.Quantity.label(%{unit: "ms"})
"ms"
iex> Visualize.Quantity.label(%{quantity: :count})
"count"
iex> Visualize.Quantity.label(%{})
nil
@spec of_unit(Visualize.Unit.code()) :: t() | nil
The quantity a code's dimension implies, or nil when none of the list has it. A
dimensionless code holding % is a :ratio, any other a :count.
Examples
iex> Visualize.Quantity.of_unit("kW.h")
:energy
iex> Visualize.Quantity.of_unit("{request}")
:count
@spec resolve(measure()) :: {:ok, %{unit: Visualize.Unit.code() | nil, quantity: t() | nil}} | {:error, reason()}
A measure completed and checked (spec/05 §4.2): a unit alone implies its quantity, a
quantity alone means its base unit, and a unit whose dimension is not its quantity's is
refused. A :ratio or a :count takes any dimensionless unit.
Examples
iex> Visualize.Quantity.resolve(%{quantity: :duration})
{:ok, %{unit: "s", quantity: :duration}}
iex> Visualize.Quantity.resolve(%{unit: "By", quantity: :duration})
{:error, {:quantity, :duration, "By"}}
@spec suffix(Visualize.Unit.code() | nil) :: String.t()
What follows a number written in a unit (spec/05 §4.3): its symbol after a space, %
and a symbol beginning with / directly, and nothing for an empty symbol or no unit.
Examples
iex> Visualize.Quantity.suffix("Cel")
" °C"
iex> Visualize.Quantity.suffix("{request}/s")
"/s"