View Source Contex.Dataset (ContEx v0.5.0)

Dataset is a simple wrapper around a datasource for plotting charts.

Dataset marshalls a couple of different data structures into a consistent form for consumption by the chart plotting functions. It allows a list of maps, list of lists or a list of tuples to be treated the same.

The most sensible way to work with a dataset is to provide column headers - it makes code elsewhere readable. When the provided data is a list of maps, headers are inferred from the map keys. If you don't want to, you can also refer to columns by index.

Dataset provides a few convenience functions for calculating data extents for a column, extracting unique values from columns, calculating combined extents for multiple columns (handy when plotting bar charts) and guessing column type (handy when determining whether to use a Contex.TimeScale or a Contex.ContinuousLinearScale).

Datasets can be created from a list of maps:

iex> data = [
...>        %{x: 0.0, y: 0.0, category: "Hippo"},
...>        %{x: 0.2, y: 0.3, category: "Rabbit"}
...>        ] # Wherever your data comes from (e.g. could be straight from Ecto)
...> dataset = Dataset.new(data)
%Contex.Dataset{
  data: [
    %{category: "Hippo", x: 0.0, y: 0.0},
    %{category: "Rabbit", x: 0.2, y: 0.3}
  ],
  headers: nil,
  title: nil
}
iex> Dataset.column_names(dataset)
[:category, :x, :y] # Note ordering of column names from map data is not guaranteed

or from a list of tuples (or lists):

iex> data = [
...>        {0.0, 0.0, "Hippo"},
...>        {0.5, 0.3, "Turtle"},
...>        {0.4, 0.3, "Turtle"},
...>        {0.2, 0.3, "Rabbit"}
...>        ]
...> dataset = Dataset.new(data, ["x", "y", "category"]) # Attach descriptive headers
iex> Dataset.column_names(dataset)
["x", "y", "category"]
...> Dataset.column_extents(dataset, "x") # Get extents for a named column
{0.0, 0.5}
iex> Dataset.column_index(dataset, "x") # Get index of column by name
0
iex> category_col = Dataset.column_name(dataset, 2) # Get name of column by index
"category"
iex> Enum.map(dataset.data, fn row -> # Enumerate values in a column
...>    accessor = Dataset.value_fn(dataset, category_col)
...>    accessor.(row)
...> end)
["Hippo", "Turtle", "Turtle", "Rabbit"]
iex> Dataset.unique_values(dataset, "category") # Extract unique values for legends etc.
["Hippo", "Turtle", "Rabbit"]

Dataset gives facilities to map between names and column indexes. Where headers are not supplied (either directly or via map keys), the column index is treated as the column name internally. Data values are retrieved by column name using accessor functions, in order to avoid expensive mappings in tight loops.

Note There are very few validation checks when a dataset is created (for example, to checks that number of headers supplied matches) the size of each array or tuple in the data. If there are any issues finding a value, nil is returned.

Link to this section Summary

Functions

Calculates the min and max value in the specified column

Looks up the index for a given column name. Returns nil if not found.

Looks up the column name for a given index.

Returns a list of the names of all of the columns in the dataset data (irrespective of whether the column names are mapped to plot elements).

Calculates the data extents for the sum of the columns supplied.

Tries to guess the data type for a column based on contained data.

Optionally sets some metadata.

Creates a new Dataset wrapper around some data.

Creates a new Dataset wrapper around some data with headers.

Optionally sets a title.

Extracts a list of unique values in the given column.

Returns a function that retrieves the value for a given column in given row, accessed by the column name.

Link to this section Types

@type column_name() :: String.t() | integer() | atom()
@type column_type() :: :datetime | :number | :string | :unknown | nil
@type row() :: list() | tuple() | map()
@type t() :: %Contex.Dataset{
  data: term(),
  headers: term(),
  meta: term(),
  title: term()
}

Link to this section Functions

Link to this function

column_extents(dataset, column_name)

View Source
@spec column_extents(t(), column_name()) :: {any(), any()}

Calculates the min and max value in the specified column

Link to this function

column_index(arg1, column_name)

View Source
@spec column_index(t(), column_name()) :: nil | column_name()

Looks up the index for a given column name. Returns nil if not found.

Link to this function

column_name(dataset, column_index)

View Source
@spec column_name(t(), integer() | any()) :: column_name()

Looks up the column name for a given index.

If there are no headers, or the index is outside the range of the headers the requested index is returned.

@spec column_names(t()) :: [column_name()]

Returns a list of the names of all of the columns in the dataset data (irrespective of whether the column names are mapped to plot elements).

Link to this function

combined_column_extents(dataset, column_names)

View Source
@spec combined_column_extents(t(), [column_name()]) :: {any(), any()}

Calculates the data extents for the sum of the columns supplied.

It is the equivalent of evaluating the extents of a calculated row where the calculating is the sum of the values identified by column_names.

Link to this function

guess_column_type(dataset, column_name)

View Source
@spec guess_column_type(t(), column_name()) :: column_type()

Tries to guess the data type for a column based on contained data.

Looks through the rows and returns the first match it can find.

@spec meta(t(), String.t()) :: t()

Optionally sets some metadata.

Allows you to attach whatever you want to the dataset for later retrieval - e.g. information about where the data came from.

@spec new([row()]) :: t()

Creates a new Dataset wrapper around some data.

Data is expected to be a list of tuples of the same size, a list of lists of same size, or a list of maps with the same keys. Columns in map data are accessed by key. For lists of lists or tuples, if no headers are specified, columns are access by index.

@spec new([row()], [String.t()]) :: t()

Creates a new Dataset wrapper around some data with headers.

Data is expected to be a list of tuples of the same size or list of lists of same size. Headers provided with a list of maps are ignored; column names from map data are inferred from the maps' keys.

@spec title(t(), String.t()) :: t()

Optionally sets a title.

Not really used at the moment to be honest, but seemed like a good idea at the time. Might come in handy when overlaying plots.

Link to this function

unique_values(dataset, column_name)

View Source
@spec unique_values(t(), String.t() | integer()) :: [any()]

Extracts a list of unique values in the given column.

Note that the unique values will maintain order of first detection in the data.

Link to this function

value_fn(dataset, column_name)

View Source
@spec value_fn(t(), column_name()) :: (row() -> any())

Returns a function that retrieves the value for a given column in given row, accessed by the column name.

examples

Examples

iex> data = [ ...> %{x: 0.0, y: 0.0, category: "Hippo"}, ...> %{x: 0.2, y: 0.3, category: "Rabbit"} ...> ] iex> dataset = Dataset.new(data) iex> category_accessor = Dataset.value_fn(dataset, :category) iex> category_accessor.(hd(data)) "Hippo"