Tabular data as the row list the generators consume.
Every generator takes a list of rows. rows/1 turns the other shapes data arrives in —
a column-oriented map, a keyword list of columns, an Nx.Tensor, an Explorer DataFrame
or anything else implementing the Table.Reader protocol — into that list, and passes a
list of rows through untouched (spec/08 §6).
Visualize.Data.Table.rows(%{t: [1, 2, 3], v: [10, 20, 30]})
# => [%{t: 1, v: 10}, %{t: 2, v: 20}, %{t: 3, v: 30}]Sources that name their columns with strings (Explorer does) yield rows keyed by
strings; accessor/1 reads a column by either spelling, so :v reaches "v" and the
other way round. time_columns/1 names the columns whose every value is temporal, for a
time scale to be inferred from.
The table package is optional, like Nx: without it lists, column maps and tensors still
work, and a struct source raises UndefinedFunctionError at Table.to_rows/1 (D-52).
Summary
Types
A column name, as the source spells it.
A row: a map keyed by column name, or a tuple in column order.
Anything rows/1 accepts: a list of rows, a keyword list or map of equal-length columns,
an Nx.Tensor of rank 1 or 2, or a struct implementing Table.Reader.
Functions
The accessor fn row -> get(row, name) end, for a shape's x/y setters.
Every named column's type, read whole (spec/08 §6.3, spec/14 §2.3, #369): all non-nil
values temporal is :time, all numbers :number, all strings :text, all atoms or
booleans :category; a mixed or empty column is left out. A suggestion for a tool, never
something the layer reads at render.
The value of column name in row, by either spelling of the name.
The rows of a tabular source, as a list.
Whether a value is a point in time: a DateTime, Date or NaiveDateTime, or a string
in ISO 8601 form that one of those parses (DateTime.from_iso8601/1 first, then
NaiveDateTime.from_iso8601/1, then Date.from_iso8601/1).
The names of the columns whose values are all temporal.
Types
A column name, as the source spells it.
A row: a map keyed by column name, or a tuple in column order.
Anything rows/1 accepts: a list of rows, a keyword list or map of equal-length columns,
an Nx.Tensor of rank 1 or 2, or a struct implementing Table.Reader.
Functions
The accessor fn row -> get(row, name) end, for a shape's x/y setters.
A function is returned unchanged, so a generator can normalise any accessor form through this one call.
Every named column's type, read whole (spec/08 §6.3, spec/14 §2.3, #369): all non-nil
values temporal is :time, all numbers :number, all strings :text, all atoms or
booleans :category; a mixed or empty column is left out. A suggestion for a tool, never
something the layer reads at render.
iex> rows = [%{t: ~U[2024-01-01 00:00:00Z], v: 1, k: :a, s: "x", m: 1},
...> %{t: ~U[2024-01-02 00:00:00Z], v: 2.5, k: :b, s: "y", m: "two"}]
iex> Visualize.Data.Table.column_types(rows)
%{t: :time, v: :number, k: :category, s: :text}
iex> Visualize.Data.Table.column_types([])
%{}
The value of column name in row, by either spelling of the name.
Map.get(row, name) when the key is present; otherwise an atom name is tried as its
string and a string name as the atom key spelled the same. nil when neither is a key.
No atom is ever created. A tuple row has no names and raises BadMapError.
The rows of a tabular source, as a list.
- A list of rows is returned as-is: no copy, no traversal.
- A keyword list whose values are equal-length lists is a list of columns; the rows are
maps keyed by the keys. (
tablereads a list the same way, columns before rows.) - A map whose values are equal-length lists is a map of columns, rows keyed likewise.
Any other plain map raises
ArgumentError. - An
Nx.Tensorof rank 2 yields one tuple per row, in column order — the shape the defaultVisualize.Shape.Lineaccessors read; rank 1 yields its values. Any other rank raisesArgumentError. - Any other struct is read through
Table.to_rows/1: rows keyed by the reader's column names as it spells them. A struct with noTable.Readerimpl raisesProtocol.UndefinedError; a reader answering:noneraisesArgumentError.
The empty list, an empty map and an empty keyword list all yield [].
Whether a value is a point in time: a DateTime, Date or NaiveDateTime, or a string
in ISO 8601 form that one of those parses (DateTime.from_iso8601/1 first, then
NaiveDateTime.from_iso8601/1, then Date.from_iso8601/1).
The names of the columns whose values are all temporal.
The candidate names are every key of every map row, sorted by term order (a map's own key
order is unspecified); a row without the key contributes nil. A column is temporal
when it has at least one value that is not nil and every value is nil or satisfies
temporal?/1. Detection reads the whole column, not a first row: every row of every
column is visited and every string is parsed, so the cost is the size of the table. A
source whose rows are tuples has no names and yields [].