# `Tucan`
[🔗](https://github.com/pnezis/tucan/blob/v0.6.0/lib/tucan.ex#L1)

A high level API interface for creating plots on top of `VegaLite`.

Tucan is an Elixir plotting library built on top of `VegaLite`,
designed to simplify the creation of interactive and visually stunning
plots. With `Tucan`, you can effortlessly generate a wide range of plots,
from simple bar charts to complex composite plots, all while enjoying the
power and flexibility of a clean composable functional API.

Tucan offers a simple API for creating most common plot types similarly
to the widely used python packages `matplotlib` and `seaborn` without
requiring the end user to be familiar with the Vega Lite grammar.

## Features

- **Versatile Plot Types** - Tucan provides an array of plot types, including
bar charts, line plots, scatter plots, histograms, and more, allowing you to
effectively represent diverse data sets.
- **Clean and consistent API** - A clean and consistent plotting API similar
to `matplotlib` or `seaborn` is provided. You should be able to create most
common plots with a single function call and minimal configuration.
- **Grouping and Faceting** - Enhance your visualizations with grouping and
faceting features, enabling you to examine patterns and trends within subgroups
of your data.
- **Customization** - Customize your plots with ease using Tucan's utilities
for adjusting plot dimensions, titles, and **themes**.
- **Thin wrapper on top of VegaLite** - All `VegaLite` functions can be used
seamlessly with `Tucan` for advanced customizations if needed.
- **Low level API** - A low level API with helper functions allow you to modify
any part of a `VegaLite` specification.

## Basic usage

All supported plots expect as first argument some data, a `VegaLite` specification
or a binary which is considered a url to some data. Additionally you can use
one of the available `Tucan.Datasets`.

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
```

> #### `Nx` support {: .neutral}
>
> If `:nx` is installed as a dependency you can additionally pass directly the data
> columns as tensors. For example:
>
> ```tucan
> x = Nx.linspace(-20, 20, n: 200)
> y = Nx.pow(x, 2)
>
> Tucan.lineplot([x: x, y: y], "x", "y", width: 400)
> ```
>
> For more details check `Tucan.new/2`.

You can apply semantic grouping by a third variable by modifying the color, the
shape or the size of the points:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species", shape_by: "species")
```

Alternatively you could use the helper grouping functions:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.color_by("species")
|> Tucan.shape_by("species")
```

> #### Use the functional API carefully {: .warning}
>
> For some plot types where transformations are applied on the input data it
> is recommended to use the options instead of the functional API, since in the
> first case any required grouping will also be applied to the transformations.

## Composite plots

Tucan also provides some helper functions for generating composite plots.
`pairplot/3` can be used to plot pairwise relationships across a dataset.

```tucan
fields = ["Beak Length (mm)", "Beak Depth (mm)", "Body Mass (g)"]

Tucan.pairplot(:penguins, fields, diagonal: :density)
```

## Customization & Themes

Various methods and helper modules allow you to easily modify the style of
a plot.

```tucan
Tucan.bubble(:gapminder, "income", "health", "population",
  color_by: "region",
  width: 400,
  tooltip: :data
)
|> Tucan.Axes.set_x_title("Gdp per Capita")
|> Tucan.Axes.set_y_title("Life expectancy")
|> Tucan.Scale.set_x_scale(:log)
|> Tucan.Grid.set_color(:x, "red")
```

Additionally `set_theme/2` allows you to set one of the supported `Tucan.Themes`.

```tucan
Tucan.density_heatmap(:penguins, "Beak Length (mm)", "Beak Depth (mm)")
|> Tucan.set_theme(:latimes)
```

## Data types inference

Tucan will try to infer the types of the data you pass to it. Currently this
is mainly used for automatically assigning temporal encodings when your data
contains date or date-time values.

For example the following will mark the `:x` encoding type as `:temporal`:

```tucan
data = [
  %{x: ~D[2020-01-01], y: 12.34},
  %{x: ~D[2020-01-02], y: 13.21},
  %{x: ~D[2020-01-03], y: 9.81}
]

# x is marked as temporal instead of quantitative which is the default for line plots
Tucan.lineplot(data, "x", "y")
```

Type inference will also work if your data contains a binary represenation of timestamps:

```tucan
data = [
  %{x: "2020-01-01T10:00:00Z", y: 12.34},
  %{x: "2020-01-02", y: 13.21},
  %{x: "2020-01-03", y: 9.81}
]

Tucan.lineplot(data, "x", "y")
```

> #### Limitations {: .warning}
>
> Notice that there are some limitations to the type inference:
>
> - Only if you pass actual data the type inference will be performed, if you
> pass a URL to a dataset then no type inference is applied.
> - Types are inferred only from the **first row** of the data, if your data
> are not consistent this may lead to incorrect type inference.
>
> If you want to enforce a specific type you need to override the type
> in the encoding channel options.
>
> ```tucan
> data = [
>   %{x: ~D[2020-01-01], y: 12.34},
>   %{x: ~D[2020-01-02], y: 13.21},
>   %{x: ~D[2020-01-03], y: 9.81}
> ]
>
> # x is marked as nominal instead of temporal
> Tucan.lineplot(data, "x", "y", x: [type: :nominal])
> ```

#### Time columns

Tucan will also parse time columns if they are passed as strings or `Time` structs
and will apply the proper parse format in order to be displayed correctly:

```tucan
data = [
  %{x: ~T[10:00:00], y: 12.34},
  %{x: ~T[11:00:00], y: 13.21},
  %{x: ~T[12:00:00], y: 9.81}
]

Tucan.lineplot(data, "x", "y", points: true)
```

> #### Use time columns carefully {: .warning}
>
> It is advised to use date-time columns instead of time columns, since the
> latter missed the date information. As a result `VegaLite` will assign a
> default date (1900-01-01) to all of them and you may have unexpected results
> if you have data from two different dates.
>
> ```tucan
> data = [
>   %{x: ~T[20:00:00], y: 12.34},
>   %{x: ~T[21:00:00], y: 13.21},
>   %{x: ~T[23:42:22], y: 9.81},
>   # data imply an observiation of the following day
>   %{x: ~T[01:10:10], y: 10.01}
> ]
>
> # notice the default tooltip rendered by vega-lite as well as
> # the position of the last point on the left side of the plot
> Tucan.lineplot(data, "x", "y", points: true, tooltip: true)
> ```
>
> Instead with date time columns you would get:
>
> ```tucan
> data = [
>   %{x: ~U[2020-01-01T20:00:00Z], y: 12.34},
>   %{x: ~U[2020-01-01T21:00:00Z], y: 13.21},
>   %{x: ~U[2020-01-01T23:42:22Z], y: 9.81},
>   %{x: ~U[2020-01-02T01:10:10Z], y: 10.01}
> ]
>
> Tucan.lineplot(data, "x", "y", points: true, tooltip: true)
> ```

## Encoding channels options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Notice that only a tiny subset of vega-lite configuration
options are exported in Tucan's public API. This is more than enough in most
cases. Additionally, an optional configuration option is added for every
encoding channel that is used, that allows you to add any vega-lite option
or change the default options set by Tucan.

For example:

```tucan
Tucan.bar(:weather, "date", "date",
  color_by: "weather",
  tooltip: true,
  x: [type: :ordinal, time_unit: :month],
  y: [aggregate: :count]
)
```

> #### Custom encoding options and `:orient` flag {: .info}
>
> Some plots support the `:orient` flag which flips the default orientation.
> Keep in mind that the `:orient` flag is set then the custom encoding options
> correspond to the final encoding channels and not the default ones.
>
> For example assume that we want to sort a bar chart by the numerical value.
> By default a bar chart has a vertical orientation. So we can achieve the
> sorting by passing the `x: [sort: "-y"]` option:
>
> ```tucan
> data = %{
>   "letter" => ["A", "B", "C", "D", "E", "F", "G"],
>   "count" => [28, 55, 43, 91, 81, 53, 19]
> }
>
> Tucan.bar(data, "letter", "count", x: [sort: "-y"])
> ```
>
> If we want to display the same on a `:horizontal` orientation we need to
> pass the sorting options to the `:y` channel:
>
> ```tucan
> data = %{
>   "letter" => ["A", "B", "C", "D", "E", "F", "G"],
>   "count" => [28, 55, 43, 91, 81, 53, 19]
> }
>
> Tucan.bar(data, "letter", "count", y: [sort: "-x"], orient: :horizontal)
> ```

## Interactive plots

Most tucan plots support zooming and panning. In order to activate them you can set the
`:zoomable` option to `true`. Use your mouse to zoom and pan the following plot. You
can also reset the view with a double click.

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", zoomable: true)
```

Additionally tooltips can be added to the plot by setting the `:tooltip` option.

```tucan
Tucan.histogram(:cars, "Horsepower", tooltip: true, zoomable: true)
```

## Global configuration

You can configure some options that will be applied to all plots by using the `Tucan.configure/1`
function.

For example you can set the default width and height of all plots:

```elixir
Tucan.configure(default_width: 700, default_height: 350)
```

> #### Options precedence {: .info}
>
> Global configuration options will be overridden by plot specific options.
>
> ```elixir
> Tucan.configure(default_width: 400, default_height: 300)
>
> # this will create a plot with the default width and height
> Tucan.scatter(:iris, "sepal_width", "sepal_length")
>
> # this will create a plot with the width to 500 and height having the default
> # value of 300
> Tucan.scatter(:iris, "sepal_width", "sepal_length", width: 500)
> ```

For more details check `Tucan.configure/1`.

# `new`

```elixir
@spec new() :: VegaLite.t()
```

Creates an empty `VegaLite` plot.

This is a simple wrapper around `VegaLite.new/0`.

# `new`

```elixir
@spec new(plotdata :: plotdata(), opts :: keyword()) :: VegaLite.t()
```

Creates if needed a `VegaLite` plot and adds data to it.

The behaviour of this function depends on the type of `plotdata`:

* if a `VegaLite.t()` struct is passed then it is returned unchanged.
* If it is a binary it is considered a url and the `VegaLite.data_from_url/2` is
  called on a newly created `VegaLite` struct.
* if it is an atom then it is considered a `Tucan.Dataset` and it is translated to
  the dataset's url. If the dataset name is invalid an exception is raised.
* in any other case it is considered a set of data values and the values are set
  as data to a newly created `VegaLite` struct. Any tabular data is accepted, as
  long as it adheres to the `Table.Reader` protocol.

## Examples

Passing a URL to some dataset

```elixir
Tucan.new("https://vega.github.io/editor/data/penguins.json")
|> ...

Tucan.new("https://vega.github.io/editor/data/stocks.csv", format: :csv)
|> ...
```

Using a pre-defined `Tucan.Dataset`

```elixir
Tucan.new(:penguins)
|> ...

Tucan.new(:iris)
|> ...
```

Passing directly tabular data

```elixir
data = [
  %{"category" => "A", "score" => 28},
  %{"category" => "B", "score" => 55}
]

Tucan.new(data)
|> ...
```

You can also pass individual series:

```elixir
xs = 1..100
ys = 1..100

Tucan.new(x: xs, y: ys)
|> ...
```

Any data that adheres to the `Table.Reader` protocol is accepted, for example
you could pass an [`Explorer.DataFrame`](https://hexdocs.pm/explorer/Explorer.DataFrame.html)

```elixir
mountains = Explorer.DataFrame.new(
  name: ["Everest", "K2", "Aconcagua"],
  elevation: [8848, 8611, 6962]
)

Tucan.new(mountains)
|> ...
```

Additionally you can pass `Nx.Tensor`s as series. These will be implicitly
transformed to lists.

```elixir
xs = Nx.linspace(0, 10, n: 100)
ys = Nx.sin(xs)

Tucan.new([x: xs, y: ys])
|> ...
```

> #### Valid `Nx.Tensor` shapes {: .info}
>
> 1-dimensional tensors are expected when you pass `Nx` tensors as series.
> Additionally for convenience 2-dimensional tensors where one of the two
> dimensions is `1` are also supported.
>
> For example the following are equivalent
>
> ```elixir
> x = Nx.linspace(0, 10, n: 10)
> y = Nx.pow(x, 2)
>
> plot1 = Tucan.new(x: x, y: y)
>
> x = Nx.reshape(x, {10, 1})
> y = Nx.reshape(y, {1, 10})
>
> plot2 = Tucan.new(x: x, y: y)
>
> assert plot1 == plot2
> ```
>
> For all other tensor shapes an `ArgumentError` will be raised.

# `area`

```elixir
@spec area(plotdata :: plotdata(), x :: field(), y :: field(), opts :: keyword()) ::
  VegaLite.t()
```

Returns the specification of an area plot.

## Options

* `:interpolate` (`t:binary/0`) - The line interpolation method to use for line and area marks. One of the following:

  * `"linear"` - piecewise linear segments, as in a poly-line.
  * `"linear-closed"` - close the linear segments to form a polygon.
  * `"step"` - alternate between horizontal and vertical segments, as in a step function.
  * `"step-before"` - alternate between vertical and horizontal segments, as in a step function.
  * `"step-after"` - alternate between horizontal and vertical segments, as in a step function.
  * `"basis"` - a B-spline, with control point duplication on the ends.
  * `"basis-open"` - an open B-spline; may not intersect the start or end.
  * `"basis-closed"` - a closed B-spline, as in a loop.
  * `"cardinal"` - a Cardinal spline, with control point duplication on the ends.
  * `"cardinal-open"` - an open Cardinal spline; may not intersect the start or end, but will
  intersect other control points.
  * `"cardinal-closed"` - a closed Cardinal spline, as in a loop.
  * `"bundle"` - equivalent to basis, except the tension parameter is used to straighten the spline.
  * `"monotone"` - cubic interpolation that preserves monotonicity in y.
* `:line` (`t:boolean/0`) - Whether the line will be included in the chart The default value is `false`.
* `:mode` - The stacking mode, applied only if `:color_by` is set. Can be one of the
  following:
    * `:stacked` - the default one, areas are stacked
    * `:normalize` - the stacked charts are normalized
    * `:streamgraph` - the chart is displaced around a central axis
    * `:no_stack` - no stacking is applied The default value is `:stacked`.
* `:point_size` (`t:pos_integer/0`) - The size of the points, if `:points` is set to `true`.
* `:points` (`t:boolean/0`) - Whether points will be included in the chart. The default value is `false`.
* `:tension` (`t:number/0`) - Depending on the interpolation type, sets the tension parameter

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:point_color` (`t:String.t/0`) - The color of the points
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

A simple area chart of Google stock price over time. Notice how we change the
`x` axis type from the default (`:quantitative`) to `:temporal` using the generic
`:x` channel configuration option:

```tucan
Tucan.area(:stocks, "date", "price", x: [type: :temporal])
|> VegaLite.transform(filter: "datum.symbol==='GOOG'")
```

You can overlay the points and/or the line, you can change the colors of the points,
the line and the area if needed:

```tucan
Tucan.area(:stocks, "date", "price",
  x: [type: :temporal],
  points: true,
  line: true,
  fill_color: "#fa3456",
  point_color: "orange",
  line_color: "green",
  width: 400
)
|> VegaLite.transform(filter: "datum.symbol==='GOOG'")
```

If you add the `:color_by` property then the area charts are stacked by default. Below
you can see how the generic encoding options can be used in order to modify any part
of the underlying `VegaLite` specification:

```tucan
Tucan.area(:unemployment, "date", "count",
  color_by: "series",
  x: [type: :temporal, time_unit: :yearmonth, axis: [format: "%Y"]],
  y: [aggregate: :sum],
  color: [scale: [scheme: "category20b"]],
  width: 300,
  height: 200
)
```

You could change the mode to `:normalize` or `:streamgraph`:

```tucan
left =
  Tucan.area(:unemployment, "date", "count",
    color_by: "series",
    mode: :normalize,
    x: [type: :temporal, time_unit: :yearmonth, axis: [format: "%Y"]],
    y: [aggregate: :sum]
  )
  |> Tucan.set_title("normalize")

right =
  Tucan.area(:unemployment, "date", "count",
    color_by: "series",
    mode: :streamgraph,
    x: [type: :temporal, time_unit: :yearmonth, axis: [format: "%Y"]],
    y: [aggregate: :sum]
  )
  |> Tucan.set_title("streamgraph")

Tucan.hconcat([left, right])
```

Or you could disable the stacking at all:

```tucan
Tucan.area(:stocks, "date", "price",
  color_by: "symbol",
  mode: :no_stack,
  x: [type: :temporal],
  width: 400,
  fill_opacity: 0.4
)
|> Tucan.Scale.set_y_scale(:log)
```

# `bar`

```elixir
@spec bar(
  plotdata :: plotdata(),
  field :: String.t(),
  value :: String.t(),
  opts :: keyword()
) ::
  VegaLite.t()
```

Draws a bar chart.

A bar chart is consisted by a categorical `field` and a numerical `value` field that
defines the height of the bars. You can create a grouped bar chart by setting
the `:color_by` option.

Additionally you should specify the aggregate for the `y` values, if your dataset contains
more than one values per category.

See also `lollipop/4`.

## Options

* `:mode` - The stacking mode, applied only if `:color_by` is set. Can be one of the
  following:
    * `:stacked` - the default one, bars are stacked
    * `:normalize` - the bars are stacked are normalized
    * `:grouped` - no stacking is applied, a separate bar for each category The default value is `:stacked`.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:corner_radius` (`t:non_neg_integer/0`) - The radius in pixels of rounded rectangles. The end radius is affected:

  - For vertical bars, top-left and top-right corner radius.
  - For horizontal bars, top-right and bottom-right corner radius.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:vertical`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:x_offset` (`t:keyword/0`) - Extra vega lite options for the `:x_offset` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.
* `:y_offset` (`t:keyword/0`) - Extra vega lite options for the `:y_offset` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

A simple bar chart:

```tucan
data = [
  %{"a" => "A", "b" => 28}, %{"a" => "B", "b" => 55}, %{"a" => "C", "b" => 43},
  %{"a" => "D", "b" => 91}, %{"a" => "E", "b" => 81}, %{"a" => "F", "b" => 53},
  %{"a" => "G", "b" => 19}, %{"a" => "H", "b" => 87}, %{"a" => "I", "b" => 52}
]

Tucan.bar(data, "a", "b", fill_color: "#33245A", corner_radius: 5)
```

You can set a `color_by` option that will create a stacked bar chart:

```tucan
Tucan.bar(:weather, "date", "date",
  color_by: "weather",
  tooltip: true,
  x: [type: :ordinal, time_unit: :month],
  y: [aggregate: :count]
)
```

If you set the mode option to `:grouped` you will instead have a different bar
per group, you can also change the orientation by setting the `:orient` flag.
Similarly you can set the mode to `:normalize` in order to have normalized
stacked bars.

```tucan
data = [
    %{"category" => "A", "group" => "x", "value" => 0.1},
    %{"category" => "A", "group" => "y", "value" => 0.6},
    %{"category" => "A", "group" => "z", "value" => 0.9},
    %{"category" => "B", "group" => "x", "value" => 0.7},
    %{"category" => "B", "group" => "y", "value" => 0.2},
    %{"category" => "B", "group" => "z", "value" => 1.1},
    %{"category" => "C", "group" => "x", "value" => 0.6},
    %{"category" => "C", "group" => "y", "value" => 0.1},
    %{"category" => "C", "group" => "z", "value" => 0.2}
]

grouped =
  Tucan.bar(
    data, "category", "value",
    color_by: "group",
    mode: :grouped,
    orient: :horizontal
  )

normalized =
  Tucan.bar(
    data, "category", "value",
    color_by: "group",
    mode: :normalize
  )

Tucan.hconcat([grouped, normalized])
```

# `boxplot`

```elixir
@spec boxplot(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Returns the specification of a box plot.

By default a one dimensional box plot of the `:field` - which must be a numerical variable - is
generated. You can add a second dimension across a categorical variable by either setting the
`:group_by` or `:color_by` options.

By default a Tukey box plot will be generated. In the Tukey box plot the whisker spans from
the smallest data to the largest data within the range `[Q1 - k * IQR, Q3 + k * IQR]` where
`Q1`and `Q3` are the first and third quartiles while `IQR` is the interquartile range
`(Q3-Q1)`. You can specify if needed the constant `k` which defaults to 1.5.

Additionally you can set the `mode` to `:min_max`  where the lower and upper whiskers are
defined as the min and max respectively. No points will be considered as outliers for this
type of box plots. In this case the `k` value is ignored.

> #### What is a box plot {: .info}
>
> A box plot (box and whisker plot) displays the five-number summary of a set of data. The
> five-number summary is the minimum, first quartile, median, third quartile, and maximum.
> In a box plot, we draw a box from the first quartile to the third quartile. A vertical
> line goes through the box at the median.

## Options

* `:k` (`t:float/0`) - The constant used for calculating the extent of the whiskers in a Tukey boxplot. Applicable
  only if `:mode` is set to `:tukey`. The default value is `1.5`.
* `:mode` - The type of the box plot. Either a Tukey box plot (`:tukey`) or a min-max plot (`:min_max`)
  will be created. The default value is `:tukey`.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.
* `:group_by` (`t:String.t/0`) - A field to be used for grouping the boxplot. It is used for adding a second dimension to
  the plot. If not set the plot will be one dimensional. Notice that a grouping is automatically
  applied if the `:color_by` option is set.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:horizontal`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

A one dimensional Tukey boxplot:

```tucan
Tucan.boxplot(:penguins, "Body Mass (g)")
```

You can set `:group_by` or `:color_by` in order to set a second dimension:

```tucan
Tucan.boxplot(:penguins, "Body Mass (g)", color_by: "Species")
```

You can set the mode to `:min_max` in order to extend the whiskers to the min and max values:

```tucan
Tucan.boxplot(:penguins, "Body Mass (g)", color_by: "Species", mode: :min_max)
```

By setting the `:orient` to `:vertical` you can change the default horizontal orientation:

```tucan
Tucan.boxplot(:penguins, "Body Mass (g)", color_by: "Species", orient: :vertical)
```

# `bubble`

```elixir
@spec bubble(
  plotdata :: plotdata(),
  x :: field(),
  y :: field(),
  size :: field(),
  opts :: keyword()
) :: VegaLite.t()
```

Returns the specification of a bubble plot.

A bubble plot is a scatter plot with a third parameter defining the size of the dots.

All `x`, `y` and `size` must be numerical data fields.

See also `scatter/4`.

## Options

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:size` (`t:keyword/0`) - Extra vega lite options for the `:size` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

```tucan
Tucan.bubble(:gapminder, "income", "health", "population", width: 400)
|> Tucan.Axes.set_x_title("Gdp per Capita")
|> Tucan.Axes.set_y_title("Life expectancy")
```

You could use a fourth variable to color the graph. As always you can set the `tooltip` in
order to make the plot interactive:

```tucan
Tucan.bubble(:gapminder, "income", "health", "population", color_by: "region", width: 400, tooltip: :data)
|> Tucan.Axes.set_x_title("Gdp per Capita")
|> Tucan.Axes.set_y_title("Life expectancy")
```

It makes more sense to use a log scale for the _x axis_:

```tucan
Tucan.bubble(:gapminder, "income", "health", "population", color_by: "region", width: 400, tooltip: :data)
|> Tucan.Axes.set_x_title("Gdp per Capita")
|> Tucan.Axes.set_y_title("Life expectancy")
|> Tucan.Scale.set_x_scale(:log)
```

# `countplot`

```elixir
@spec countplot(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Plot the counts of observations for a categorical variable.

Takes a categorical `field` as input and generates a count plot
visualization. By default the counts are plotted on the *y-axis*
and the categorical `field` across the *x-axis*.

This is similar to `histogram/3` but specifically for a categorical
variable.

This is a simple wrapper around `bar/4` where by default the count of
observations is mapped to the `y` variable.

> #### What is a countplot? {: .tip}
>
> A countplot is a type of bar chart used in data visualization to
> display the **frequency of occurrences of categorical data**. It is
> particularly useful for visualizing the *distribution* and *frequency*
> of different categories within a dataset.
>
> In a countplot, each unique category is represented by a bar, and the
> height of the bar corresponds to the number of occurrences of that
> category in the data.

## Options

See `bar/4`

## Examples

We will use the `:titanic` dataset on the following examples. We can
plot the number of passengers by ticket class:

```tucan
Tucan.countplot(:titanic, "Pclass")
```

You can make the bars horizontal by setting the `:orient` option:

```tucan
Tucan.countplot(:titanic, "Pclass", orient: :horizontal)
```

You can set `:color_by` to group it by a second variable:

```tucan
Tucan.countplot(:titanic, "Pclass", color_by: "Survived")
```

By default the bars are stacked. You can unstack them by setting the
`:mode` to `:grouped`

```tucan
Tucan.countplot(:titanic, "Pclass", color_by: "Survived", mode: :grouped)
```

# `density`

```elixir
@spec density(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Plot the distribution of a numeric variable.

Density plots allow you to visualize the distribution of a numeric variable for one
or several groups. If you want to draw the density for several groups you need to
specify the `:color_by` option which is assumed to be a categorical variable.

> ### Avoid calling `color_by/3` with a density plot {: .warning}
>
> Since the grouping variable must also be used for properly calculating the density
> transformation you **should avoid calling the `color_by/3` grouping function** after
> a `density/3` call. Instead use the `:color_by` option, which will ensure that the
> proper settings are applied to the underlying transformation.
>
> Calling `color_by/3` would produce this graph:
>
> ```tucan
> Tucan.density(:penguins, "Body Mass (g)")
> |> Tucan.color_by("Species")
> ```
>
> In the above case the density function has been calculated on the complete dataset
> and you cannot color by the `Species`. Instead you should use the `:color_by`
> option which would calculate the density function per group:
>
> ```tucan
> Tucan.density(:penguins, "Body Mass (g)", color_by: "Species", fill_opacity: 0.2)
> ```
>
> Alternatively you should use the `:group_by` option in order to group the density
> transform by the `Species` field and then apply the `color_by/3` function:
>
> ```elixir
> Tucan.density(:penguins, "Body Mass (g)", group_by: ["Species"], fill_opacity: 0.2)
> |> Tucan.color_by("Species")
> ```

See also `histogram/3`.

## Options

* `:bandwidth` (`t:float/0`) - The bandwidth (standard deviation) of the Gaussian kernel. If unspecified or set to
  zero, the bandwidth value is automatically estimated from the input data using
  Scott’s rule.
* `:counts` (`t:boolean/0`) - A boolean flag indicating if the output values should be probability estimates
  (false) or smoothed counts (true). The default value is `false`.
* `:cumulative` (`t:boolean/0`) - A boolean flag indicating whether to produce density estimates (false) or cumulative
  density estimates (true). The default value is `false`.
* `:extent` - A `[min, max]` domain from which to sample the distribution. If unspecified, the extent
  will be determined by the observed minimum and maximum values of the density value field.
* `:group_by` (list of `t:String.t/0`) - The data fields to group by. If not specified, a single group containing all data
  objects will be used. This is applied only on the density transform.

  In most cases you only need to set `:color_by` which will automatically handle the
  density transform grouping. Use `:group_by` only if you want to manually post-process
  the generated specification, or if you want to apply grouping by more than one
  variable.

  If both `:group_by` and `:color_by` are set then only `:group_by` is used for grouping
  the density transform and `color_by` is used for encoding the color.
* `:interpolate` (`t:binary/0`) - The line interpolation method to use for line and area marks. One of the following:

  * `"linear"` - piecewise linear segments, as in a poly-line.
  * `"linear-closed"` - close the linear segments to form a polygon.
  * `"step"` - alternate between horizontal and vertical segments, as in a step function.
  * `"step-before"` - alternate between vertical and horizontal segments, as in a step function.
  * `"step-after"` - alternate between horizontal and vertical segments, as in a step function.
  * `"basis"` - a B-spline, with control point duplication on the ends.
  * `"basis-open"` - an open B-spline; may not intersect the start or end.
  * `"basis-closed"` - a closed B-spline, as in a loop.
  * `"cardinal"` - a Cardinal spline, with control point duplication on the ends.
  * `"cardinal-open"` - an open Cardinal spline; may not intersect the start or end, but will
  intersect other control points.
  * `"cardinal-closed"` - a closed Cardinal spline, as in a loop.
  * `"bundle"` - equivalent to basis, except the tension parameter is used to straighten the spline.
  * `"monotone"` - cubic interpolation that preserves monotonicity in y.
* `:maxsteps` (`t:integer/0`) - The maximum number of samples to take along the extent domain for plotting the density. The default value is `200`.
* `:minsteps` (`t:integer/0`) - The minimum number of samples to take along the extent domain for plotting the density. The default value is `25`.
* `:stacked` (`t:boolean/0`) - Whether the density plots will be stacked or not. The default value is `false`.
* `:steps` (`t:integer/0`) - The exact number of samples to take along the extent domain for plotting the density. If
  specified, overrides both minsteps and maxsteps to set an exact number of uniform samples.
  Potentially useful in conjunction with a fixed extent to ensure consistent sample points
  for stacked densities.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:filled` (`t:boolean/0`) - Whether the density plot will be filled or not, default to `true` if not set
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:horizontal`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

```tucan
Tucan.density(:penguins, "Body Mass (g)")
```

It is a common use case to compare the density of several groups in a dataset. Several
options exist to do so. You can plot all items on the same chart, using transparency and
annotation to make the comparison possible. You can stack overlapping densities by
setting the `:stacked` property.

```tucan
unstacked =
  Tucan.density(:penguins, "Body Mass (g)", color_by: "Species", fill_opacity: 0.2)
  |> Tucan.set_title("Unstacked")

stacked =
  Tucan.density(:penguins, "Body Mass (g)",
    color_by: "Species",
    fill_opacity: 0.8,
    stacked: true
  )
  |> Tucan.set_title("Stacked")

Tucan.hconcat([unstacked, stacked])
```

You can also combine it with `facet_by/4` in order to draw a different plot for each value
of the grouping variable. Notice that we need to set the `:group_by` variable in order
to correctly calculate the density plot per field's value.

```tucan
Tucan.density(:penguins, "Body Mass (g)", group_by: ["Species"])
|> Tucan.color_by("Species")
|> Tucan.facet_by(:column, "Species")
```

You can control the smoothing by setting a specific `bandwidth` value (if not set it is
automatically calculated by vega lite):

```tucan
Tucan.density(:penguins, "Body Mass (g)",
  color_by: "Species",
  bandwidth: 50.0,
  fill_opacity: 0.5
)
```

You can plot a cumulative density distribution by setting the `:cumulative` option to `true`:

```tucan
Tucan.density(:penguins, "Body Mass (g)", cumulative: true)
```

or calculate a separate cumulative distribution for each group:

```tucan
Tucan.density(:penguins, "Body Mass (g)", cumulative: true, color_by: "Species")
|> Tucan.facet_by(:column, "Species")
```

You can change the color of the plot by setting the `:fill_color` option and/or specify if it
will be filled or not:

```tucan
Tucan.hconcat([
  Tucan.density(:penguins, "Body Mass (g)", fill_color: "red"),
  Tucan.density(:penguins, "Body Mass (g)", filled: false)
])
|> Tucan.set_theme(:ggplot2)
```

# `density_heatmap`

```elixir
@spec density_heatmap(
  plotdata :: plotdata(),
  x :: String.t(),
  y :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws a density heatmap.

A density heatmap is a bivariate histogram, e.g. the `x`, `y` data are binned
within rectangles that tile the plot and then the count of observations within
each rectangle is shown with the fill color.

By default the `count` of observations within each rectangle is encoded, but you
can calculate the statistic of any field and use it instead.

Density heatmaps are a powerful visualization tool that find their best use cases
in situations where you need to explore and understand the distribution and
concentration of data points in a two-dimensional space. They are particularly
effective when dealing with large datasets, allowing you to uncover patterns,
clusters, and trends that might be difficult to discern in raw data.

## Options

* `:aggregate` (`t:atom/0`) - The statistic that will be used for aggregating the observations within a bin. The
  `z` field must be set if `aggregate` is set.
* `:z` (`t:String.t/0`) - If set corresponds to the field that will be used for calculating the color of the
  bin using the provided aggregate. If not set (the default behaviour) the count of
  observations are used for coloring the bin.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

Let's start with a default density heatmap on the penguins dataset:

```tucan
Tucan.density_heatmap(:penguins, "Beak Length (mm)", "Beak Depth (mm)")
```

You can summarize over another field:

```tucan
Tucan.density_heatmap(:penguins, "Beak Length (mm)", "Beak Depth (mm)", z: "Body Mass (g)", aggregate: :mean)
```

# `donut`

```elixir
@spec donut(
  plotdata :: plotdata(),
  field :: String.t(),
  category :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draw a donut chart.

A donut chart is a circular visualization that resembles a pie chart but
features a hole at its center. This central hole creates a _donut_ shape,
distinguishing it from traditional pie charts.

This is a wrapper around `pie/4` that sets by default the `:inner_radius`.

## Options

See `pie/4`

## Examples

```tucan
Tucan.donut(:barley, "yield", "site", aggregate: :sum, tooltip: true)
|> Tucan.facet_by(:column, "year", type: :nominal)
```

# `errorband`

```elixir
@spec errorband(
  plotdata :: plotdata(),
  x :: String.t(),
  y :: String.t(),
  opts :: keyword()
) ::
  VegaLite.t()
```

Draws an error band (confidence interval).

An error band summarizes an error range of quantitative values using a set of summary statistics,
represented by area. Both `x` and `y` should be quantitative variables.

## Options

* `:borders` (`t:boolean/0`) - If set to `true` the error band's border will be added. The default value is `false`.
* `:extent` - The extent of the rule. Can be one of the following:

  * `:ci` - Extend the rule to the confidence interval of the mean.
  * `:stderr` - The size of rule are set to the value of standard error, extending from the mean.
  * `:stdev` - The size of rule are set to the value of standard deviation, extending from the
  mean.
  * `:iqr` - Extend the rule to the q1 and q3.

  The default value is `:stderr`.
* `:interpolate` (`t:binary/0`) - The line interpolation method to use for line and area marks. One of the following:

  * `"linear"` - piecewise linear segments, as in a poly-line.
  * `"linear-closed"` - close the linear segments to form a polygon.
  * `"step"` - alternate between horizontal and vertical segments, as in a step function.
  * `"step-before"` - alternate between vertical and horizontal segments, as in a step function.
  * `"step-after"` - alternate between horizontal and vertical segments, as in a step function.
  * `"basis"` - a B-spline, with control point duplication on the ends.
  * `"basis-open"` - an open B-spline; may not intersect the start or end.
  * `"basis-closed"` - a closed B-spline, as in a loop.
  * `"cardinal"` - a Cardinal spline, with control point duplication on the ends.
  * `"cardinal-open"` - an open Cardinal spline; may not intersect the start or end, but will
  intersect other control points.
  * `"cardinal-closed"` - a closed Cardinal spline, as in a loop.
  * `"bundle"` - equivalent to basis, except the tension parameter is used to straighten the spline.
  * `"monotone"` - cubic interpolation that preserves monotonicity in y.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:stroke_dash` (list of `t:pos_integer/0`) - An array of alternating stroke, space lengths in pixels for creating dashed
  or dotted lines.
* `:stroke_width` (`t:pos_integer/0`) - The stroke width in pixels
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

```tucan
Tucan.errorband(:cars, "Year", "Miles_per_Gallon", x: [time_unit: "year", type: :temporal])
```

You can modify the look of the error band, change the `:extent` and include the borders if needed.

```tucan
Tucan.errorband(:cars, "Year", "Miles_per_Gallon",
  extent: :ci,
  fill_color: "red",
  borders: true,
  x: [time_unit: "year", type: :temporal]
)
```

You can also change the look of the borders:

```tucan
Tucan.errorband(:cars, "Year", "Miles_per_Gallon",
  extent: :ci,
  fill_color: "black",
  borders: true,
  line_color: "red",
  stroke_width: 3,
  stroke_dash: [7, 5],
  x: [time_unit: "year", type: :temporal]
)
```

Usually you want to combine the errorband with the mean trend line. You can use
`Tucan.layers/2` to combine it with a lineplot.

```tucan
errorband = Tucan.errorband(:cars, "Year", "Miles_per_Gallon",
  extent: :ci,
  fill_color: "green",
  x: [time_unit: "year", type: :temporal]
)

trendline = Tucan.lineplot(:cars, "Year", "Miles_per_Gallon",
  x: [time_unit: "year", type: :temporal],
  y: [aggregate: :mean]
)

Tucan.layers([errorband, trendline])
```

Similar to other Tucan plots you can apply semantic grouping:

```tucan
errorband = Tucan.errorband(:cars, "Year", "Miles_per_Gallon",
  extent: :ci,
  x: [time_unit: "year", type: :temporal]
)

trendline = Tucan.lineplot(:cars, "Year", "Miles_per_Gallon",
  x: [time_unit: "year", type: :temporal],
  y: [aggregate: :mean]
)

Tucan.layers([errorband, trendline])
|> Tucan.color_by("Origin")
|> Tucan.set_width(400)
```

# `errorbar`

```elixir
@spec errorbar(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Plots the errorbar for the given numerical variable `field`.

Error bars sho by default the standard error. It can also be explicitly specified by setting
`:extent` to `:stderr`. The length of lower and upper rules represent standard error. By
default, the rule marks expand from the mean.

## Options

* `:extent` - The extent of the rule. Can be one of the following:

  * `:ci` - Extend the rule to the confidence interval of the mean.
  * `:stderr` - The size of rule are set to the value of standard error, extending from the mean.
  * `:stdev` - The size of rule are set to the value of standard deviation, extending from the
  mean.
  * `:iqr` - Extend the rule to the q1 and q3.

  The default value is `:stderr`.
* `:group_by` (`t:String.t/0`) - A field to be used for grouping the error bars by a category. If not set the plot will
  be one dimensional.
* `:points` (`t:boolean/0`) - If set the means of the error bar are also included.
* `:ticks` (`t:boolean/0`) - If set ticks will be included to the error bars ends

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:horizontal`.
* `:point_color` (`t:String.t/0`) - The color of the points if enabled. If not set defaults to the error bars color
* `:stroke_width` (`t:pos_integer/0`) - The stroke width in pixels
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

A 1-d error bar:

```tucan
Tucan.errorbar(:barley, "yield")
```

By setting the `:group_by` option you can show the error range of a continuous field
broken down by categories.

```tucan
Tucan.errorbar(:barley, "yield", group_by: "variety")
```

You can change the orientation by setting the `:orient` option:

```tucan
Tucan.errorbar(:barley, "yield", group_by: "variety", orient: :vertical)
```

By setting `:ticks` to `true` you can enable errorbar end ticks. Also you can overlay the
means by setting `:points` to `true`.

 ```tucan
Tucan.errorbar(:barley, "yield", group_by: "variety", ticks: true, points: true)
```

You can change the `:extent` value in order to configure how the error bars are extended. Below
you can see all supported options:

```tucan
valid_extent_values = [:ci, :stderr, :stdev, :iqr]

plots =
  for extent <- valid_extent_values do
    Tucan.errorbar(:barley, "yield", group_by: "variety", extent: extent)
    |> Tucan.set_title(inspect(extent) <> " extent")
    |> Tucan.Axes.set_enabled(:y, extent == :ci)
    |> Tucan.set_size(160, 160)
  end

Tucan.hconcat(plots)
```

You can use `:line_color` and `:stroke_width` to modify the look of the error bars:

```tucan
Tucan.errorbar(:barley, "yield", group_by: "variety", line_color: "red", stroke_width: 3, ticks: true, points: true)
```

You can color categories by combining it with `Tucan.color_by/3`.

```tucan
Tucan.errorbar(:barley, "yield", group_by: "variety", points: true)
|> Tucan.color_by("variety")
```

# `heatmap`

```elixir
@spec heatmap(
  plotdata :: plotdata(),
  x :: String.t(),
  y :: String.t(),
  color :: nil | String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Returns the specification of a heatmap.

A heatmap is a graphical representation of data where the individual values
contained in a matrix are represented as colors.

It expects two categorical fields `x`, `y` which will be used for the axes
and a numerical field `color`. If `color` is `nil` then the color represents
the count of the observations for each `x, y`.

If an `:aggregate` is set this statistic will be used for encoding the color.
If no `:aggregate` is set the color encodes by default the `:mean` of the
data.

## Options

* `:aggregate` (`t:atom/0`) - The statistic that will be used for aggregating the observations within a heatmap
  tile. Defaults to `:mean` which in case of single data will encode the value of
  the `color` data field.

  Ignored if `:color` is set to `nil`.
* `:annotate` (`t:boolean/0`) - If set to `true` then the values of each cell will be included in the plot. The default value is `false`.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:color_scheme` (`t:atom/0`) - The color scheme to use, for supported color schemes check `Tucan.Scale`. Notice that
  this is just a helper option for easily setting color schemes. If you need to set
  specific colors or customize the scheme, use `Tucan.Scale.set_color_scheme/3`.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:text_color` - The color to be used for the textual annotations. Valid only if `:annotate` is set
  to `true`. Can be one of the following:
  * a `string` with the color to be used, e.g. `"white"`
  * a list of tuples of the form `{low_threshold, upper_threshold, color}` for
  conditionally setting the color based on the value of the annotated variable.
  `low_threshold` and `upper_threshold` can either be a number or `nil`. For example
  `[{nil, 0, "green"}, {0, 5, "red"}, {5, nil, "white"}]` will apply the following
  colors:
    * `green` for all items with `value < 0`
    * `red` for all items with `value >= 0 && value < 5`
    * `white` for all items with `value >= 5`
  Notice that the `low_threshold`, `upper_threshold` correspond to the
  `[low_threshold, upper_threshold)` range.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:text` (`t:keyword/0`) - Extra vega lite options for the `:text` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

A simple heatmap of two categorical variables, using a third one for the
color values.

```tucan
data = [
  %{"x" => "A", "y" => "K", "value" => 0.5},
  %{"x" => "A", "y" => "L", "value" => 1.5},
  %{"x" => "A", "y" => "M", "value" => 4.5},
  %{"x" => "B", "y" => "K", "value" => 1.5},
  %{"x" => "B", "y" => "L", "value" => 2.5},
  %{"x" => "B", "y" => "M", "value" => 0.5},
  %{"x" => "C", "y" => "K", "value" => -1.5},
  %{"x" => "C", "y" => "L", "value" => 5.5},
  %{"x" => "C", "y" => "M", "value" => 1.5},
]

Tucan.heatmap(data, "x", "y", "value", width: 200, height: 200)
```

You can change the color scheme:

```tucan
Tucan.heatmap(:glue, "Task", "Model", "Score", color_scheme: :redyellowgreen, tooltip: true)
```

Heatmaps are also useful for visualizing temporal data. Let's use a heatmap to examine
how Seattle's max temperature changes over the year. On the _x-axis_ we will encode the
days of the month along the x-axis, and the months on the _y-axis_. We will aggregate
over the max temperature for the color field. (example borrowed from
[here](https://observablehq.com/@jonfroehlich/basic-time-series-plots-in-vega-lite?collection=@jonfroehlich/intro-to-vega-lite))

```tucan
Tucan.heatmap(:weather, "date", "date", "temp_max",
  x: [type: :ordinal, time_unit: :date],
  y: [type: :ordinal, time_unit: :month],
  tooltip: true
)
|> Tucan.Scale.set_color_scheme(:redyellowblue, reverse: true)
|> Tucan.Axes.set_x_title("Day")
|> Tucan.Axes.set_y_title("Month")
|> Tucan.Legend.set_title(:color, "Avg Max Temp")
|> Tucan.set_title("Heatmap of Avg Max Temperatures in Seattle (2012-2015)")
```

You can enable annotations by setting the `:annotate` flag. Notice that you can conditionally
color the annotation text by setting the `:text_color` option. It expects a list of tuples
corresponding to `{lower_threshold, upper_threshold, color}`. Below we color white everything
below 0 and black everything with a value `>=0`.

```tucan
Tucan.heatmap(:weather, "date", "date", "temp_max",
  annotate: true,
  text_color: [{nil, 5, "white"}, {5, 25, "black"}, {25, nil, "white"}],
  x: [type: :ordinal, time_unit: :date],
  y: [type: :ordinal, time_unit: :month],
  text: [format: ".1f"],
  tooltip: true,
  width: 800
)
|> Tucan.Scale.set_color_scheme(:redyellowblue, reverse: true)
|> Tucan.Axes.set_x_title("Day")
|> Tucan.Axes.set_y_title("Month")
|> Tucan.Legend.set_title(:color, "Avg Max Temp")
|> Tucan.set_title("Heatmap of Avg Max Temperatures in Seattle (2012-2015)")
```

# `histogram`

```elixir
@spec histogram(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Plots a histogram.

See also `density/3`

## Options

* `:extent` - A two-element (`[min, max]`) array indicating the range of desired bin values.
* `:maxbins` (`t:integer/0`) - Maximum number of bins.
* `:orient` - Histogram's orientation. It specifies the axis along which the field values
  are plotted. The default value is `:horizontal`.
* `:relative` (`t:boolean/0`) - If set a relative frequency histogram is generated. The default value is `false`.
* `:stacked` (`t:boolean/0`) - If set it will stack the group histograms instead of layering one over another. Valid
  only if a semantic grouping has been applied.
* `:step` - An exact step size to use between bins. If provided, options such as `maxbins`
  will be ignored.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - The field to group observations by. This will used for coloring the histogram
  if set.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:corner_radius` (`t:non_neg_integer/0`) - The radius in pixels of rounded rectangles. The end radius is affected:

  - For vertical bars, top-left and top-right corner radius.
  - For horizontal bars, top-right and bottom-right corner radius.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:x2` (`t:keyword/0`) - Extra vega lite options for the `:x2` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.
* `:y2` (`t:keyword/0`) - Extra vega lite options for the `:y2` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

Histogram of `Horsepower`

```tucan
Tucan.histogram(:cars, "Horsepower")
```

You can flip the plot by setting the `:orient` option to `:vertical`:

```tucan
Tucan.histogram(:cars, "Horsepower", orient: :vertical)
```

You can also modify the default color and add a radius to the histogram bars:

```tucan
Tucan.histogram(:cars, "Horsepower", orient: :vertical, fill_color: "red", corner_radius: 5)
```

By setting the `:relative` flag you can get a relative frequency histogram:

```tucan
Tucan.histogram(:cars, "Horsepower", relative: true)
```

You can increase the number of bins by settings the `maxbins` or the `step` options:

```tucan
Tucan.histogram(:cars, "Horsepower", step: 5)
```

You can draw multiple histograms by grouping the observations by a second
*categorical* variable:

```tucan
Tucan.histogram(:cars, "Horsepower", color_by: "Origin", fill_opacity: 0.5)
```

By default the histograms are plotted layered, but you can also stack them:

```tucan
Tucan.histogram(:cars, "Horsepower", color_by: "Origin", fill_opacity: 0.5, stacked: true)
```

or you can facet it, in order to make the histograms more clear:

```tucan
histograms =
  Tucan.histogram(:cars, "Horsepower", color_by: "Origin", tooltip: true)
  |> Tucan.facet_by(:column, "Origin")

relative_histograms =
  Tucan.histogram(:cars, "Horsepower", relative: true, color_by: "Origin", tooltip: true)
  |> Tucan.facet_by(:column, "Origin")

Tucan.vconcat([histograms, relative_histograms])
```

# `lineplot`

```elixir
@spec lineplot(plotdata :: plotdata(), x :: field(), y :: field(), opts :: keyword()) ::
  VegaLite.t()
```

Draw a line plot between `x` and `y`

Both `x` and `y` are considered numerical variables.

## Options

* `:interpolate` (`t:binary/0`) - The line interpolation method to use for line and area marks. One of the following:

  * `"linear"` - piecewise linear segments, as in a poly-line.
  * `"linear-closed"` - close the linear segments to form a polygon.
  * `"step"` - alternate between horizontal and vertical segments, as in a step function.
  * `"step-before"` - alternate between vertical and horizontal segments, as in a step function.
  * `"step-after"` - alternate between horizontal and vertical segments, as in a step function.
  * `"basis"` - a B-spline, with control point duplication on the ends.
  * `"basis-open"` - an open B-spline; may not intersect the start or end.
  * `"basis-closed"` - a closed B-spline, as in a loop.
  * `"cardinal"` - a Cardinal spline, with control point duplication on the ends.
  * `"cardinal-open"` - an open Cardinal spline; may not intersect the start or end, but will
  intersect other control points.
  * `"cardinal-closed"` - a closed Cardinal spline, as in a loop.
  * `"bundle"` - equivalent to basis, except the tension parameter is used to straighten the spline.
  * `"monotone"` - cubic interpolation that preserves monotonicity in y.
* `:tension` (`t:number/0`) - Depending on the interpolation type, sets the tension parameter

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.
* `:group_by` (`t:String.t/0`) - A field to group by the lines without affecting the style of it.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:filled` (`t:boolean/0`) - Whether the points will be filled or not. Valid only if `:points` is set. The default value is `true`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:point_color` (`t:String.t/0`) - The color of the points, if `:points` is set to `true`.
* `:point_size` (`t:pos_integer/0`) - The size of the points, if `:points` is set to `true`.
* `:points` (`t:boolean/0`) - Whether points will be included in the chart. The default value is `false`.
* `:stroke_dash` (list of `t:pos_integer/0`) - An array of alternating stroke, space lengths in pixels for creating dashed
  or dotted lines.
* `:stroke_width` (`t:pos_integer/0`) - The stroke width in pixels
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

Plotting a simple line chart of Google stock price over time. Notice how we change the
`x` axis type from the default (`:quantitative`) to `:temporal` using the generic
`:x` channel configuration option:

```tucan
Tucan.lineplot(:stocks, "date", "price", x: [type: :temporal])
|> VegaLite.transform(filter: "datum.symbol==='GOOG'")
```

You could plot all stocks of the dataset with different colors by setting the `:color_by`
option. If you do not want to color lines differently, you can pass the `:group_by` option
instead of `:color_by`:

```tucan
left = Tucan.lineplot(:stocks, "date", "price", x: [type: :temporal], color_by: "symbol")
right = Tucan.lineplot(:stocks, "date", "price", x: [type: :temporal], group_by: "symbol")

Tucan.hconcat([left, right])
```

You can also overlay the points by setting the `:points` and `:filled` opts. Notice
that below we plot by year and aggregating the `y` values:

```tucan
filled_points =
  Tucan.lineplot(:stocks, "date", "price",
    x: [type: :temporal, time_unit: :year],
    y: [aggregate: :mean],
    color_by: "symbol",
    points: true,
    tooltip: true,
    width: 300
  )

stroked_points =
  Tucan.lineplot(:stocks, "date", "price",
    x: [type: :temporal, time_unit: :year],
    y: [aggregate: :mean],
    color_by: "symbol",
    points: true,
    filled: false,
    tooltip: true,
    width: 300
  )

Tucan.hconcat([filled_points, stroked_points])
```

You can configure the style of the lines using `:stroke_dash`, `:stroke_width`
and `:line_color` options.

```tucan
data =
  for i <- 0..100, x = 0.1*i do
    %{x: x, cos: :math.cos(x), sin: :math.sin(x)}
  end

Tucan.layers([
  Tucan.lineplot(data, "x", "cos", stroke_width: 3, stroke_dash: [5, 2], line_color: "red"),
  Tucan.lineplot(data, "x", "sin", stroke_width: 2, stroke_dash: [5, 3, 2], line_color: "green")
])
|> Tucan.set_width(300)
```

You can use various interpolation methods. Some examples follow:

```tucan
plots =
  for interpolation <- ["linear", "step", "cardinal", "monotone"] do
    Tucan.lineplot(:stocks, "date", "price",
      x: [type: :temporal, time_unit: :year],
      y: [aggregate: :mean],
      color_by: "symbol",
      interpolate: interpolation
    )
    |> Tucan.set_title(interpolation)
  end

Tucan.concat(plots, columns: 2)
```

# `lollipop`

```elixir
@spec lollipop(
  plotdata :: plotdata(),
  field :: String.t(),
  value :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws a lollipop plot.

A lollipop plot is nothing more than a bar plot, where the bar is transformed in a line and a dot. It shows
the relationship between a numeric and a categoric variable.

> #### Comparison to `bar/4` {: .tip}
>
> The lollipop plot is used exactly in the same situation as a bar plot. However it is somewhat more
> appealing and convey as well the information. It is especially useful when you have several bars of the
> same height.
>
> ```tucan
> data = [
>   category: ["A", "B", "C", "D", "E"],
>   value: [99, 97, 94, 90, 88]
> ]
>
> bar = Tucan.bar(data, "category", "value", orient: :horizontal)
> lollipop = Tucan.lollipop(data, "category", "value", orient: :horizontal)
>
> Tucan.hconcat([bar, lollipop])
> ```

See also `bar/4`.

## Options

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.
* `:group_by` (`t:String.t/0`) - A categorical field to group the lollipops by. It is used for adding a second dimension to
  the plot. When set, the groups are also color coded by the same categorical variable.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:line_color` (`t:String.t/0`) - The color of the line The default value is `"black"`.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:vertical`.
* `:point_color` (`t:String.t/0`) - The color of the points The default value is `"black"`.
* `:point_shape` - Shape of the point marks. Circle by default.
* `:point_size` (`t:pos_integer/0`) - The pixel area of the marks. Note that this value sets the area of the symbol;
  the side lengths will increase with the square root of this value. The default value is `60`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:x_offset` (`t:keyword/0`) - Extra vega lite options for the `:x_offset` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.
* `:y_offset` (`t:keyword/0`) - Extra vega lite options for the `:y_offset` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

A lollipop chart for some synthetic data:

```tucan
data =
  for category <- ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] do
    %{category: category, value: 9 + :rand.uniform(90)}
  end

Tucan.lollipop(data, "category", "value", width: 400)
```

You can make the lollipops horizontal by setting the `:orient` flag:

```tucan
data =
  for category <- ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] do
    %{category: category, value: 9 + :rand.uniform(90)}
  end

Tucan.lollipop(data, "category", "value", width: 400, orient: :horizontal)
```

You can change the points shape and the default colors if needed:

```tucan
data =
  for category <- ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] do
    %{category: category, value: 9 + :rand.uniform(90)}
  end

Tucan.lollipop(data, "category", "value",
  point_color: "red",
  point_shape: "square",
  point_size: 80,
  line_color: "blue",
  width: 400
)
```

If you need to group by a second categorical variable you can use the `:group_by` option:

```tucan
data =
  for category <- ["A", "B", "C", "D", "E", "F", "G"],
      country <- ["US", "GR", "UK", "IT"] do
    %{category: category, country: country, value: 9 + :rand.uniform(90)}
  end

Tucan.lollipop(data, "category", "value", group_by: "country", orient: :horizontal)
|> Tucan.set_size(400, 300)
```

# `pie`

```elixir
@spec pie(
  plotdata :: plotdata(),
  field :: String.t(),
  category :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws a pie chart.

A pie chart is a circle divided into sectors that each represents a proportion
of the whole. The `field` specifies the data column that contains the proportions
of each category. The chart will be colored by the `category` field.

> #### Avoid using pie charts {: .warning}
>
> Despite it's popularity pie charts should rarely be used. Pie charts are best
> suited for displaying a small number of categories and can make it challenging
> to accurately compare data. They rely on angle perception, which can lead to
> misinterpretation, and lack the precision offered by other charts like bar
> charts or line charts.
>
> Instead, opt for alternatives such as bar charts for straightforward comparisons,
> stacked area charts for cumulative effects.
>
> The following example showcases the limitations of a pie chart, compared to a
> bar chart:
>
> ```tucan
> alias VegaLite, as: Vl
>
> data = [
>   %{value: 30, category: "A"},
>   %{value: 33, category: "B"},
>   %{value: 38, category: "C"}
> ]
>
> pie = Tucan.pie(data, "value", "category")
> bar = Tucan.bar(data, "category", "value", orient: :horizontal)
>
> Tucan.hconcat([pie, bar])
> |> Tucan.set_title("Pie vs Bar chart", anchor: :middle, offset: 15)
> ```

## Options

* `:aggregate` (`t:atom/0`) - The statistic to use (if any) for aggregating values per pie slice (e.g. `:mean`).
* `:inner_radius` (`t:integer/0`) - The inner radius in pixels. `0` for a pie chart, `> 0` for a donut chart. If not
  set it defaults to 0

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:theta` (`t:keyword/0`) - Extra vega lite options for the `:theta` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

```tucan
Tucan.pie(:barley, "yield", "site", aggregate: :sum, tooltip: true)
|> Tucan.facet_by(:column, "year", type: :nominal)
```

# `punchcard`

```elixir
@spec punchcard(
  plotdata :: plotdata(),
  x :: String.t(),
  y :: String.t(),
  size :: nil | String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Returns the specification of a punch card plot.

A punch card plot is similar to a heatmap but instead of color the third
dimension is encoded by the size of bubbles.

See also `heatmap/5`.

## Options

* `:aggregate` (`t:atom/0`) - The statistic that will be used for aggregating the observations within a heatmap
  tile. Defaults to `:mean` which in case of single data will encode the value of
  the `color` data field.

  Ignored if `:color` is set to `nil`.
* `:annotate` (`t:boolean/0`) - If set to `true` then the values of each cell will be included in the plot. The default value is `false`.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:color_scheme` (`t:atom/0`) - The color scheme to use, for supported color schemes check `Tucan.Scale`. Notice that
  this is just a helper option for easily setting color schemes. If you need to set
  specific colors or customize the scheme, use `Tucan.Scale.set_color_scheme/3`.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:text_color` - The color to be used for the textual annotations. Valid only if `:annotate` is set
  to `true`. Can be one of the following:
  * a `string` with the color to be used, e.g. `"white"`
  * a list of tuples of the form `{low_threshold, upper_threshold, color}` for
  conditionally setting the color based on the value of the annotated variable.
  `low_threshold` and `upper_threshold` can either be a number or `nil`. For example
  `[{nil, 0, "green"}, {0, 5, "red"}, {5, nil, "white"}]` will apply the following
  colors:
    * `green` for all items with `value < 0`
    * `red` for all items with `value >= 0 && value < 5`
    * `white` for all items with `value >= 5`
  Notice that the `low_threshold`, `upper_threshold` correspond to the
  `[low_threshold, upper_threshold)` range.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:size` (`t:keyword/0`) - Extra vega lite options for the `:size` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

```tucan
Tucan.punchcard(:weather, "date", "date", "temp_max",
  tooltip: true,
  x: [type: :ordinal, time_unit: :date],
  y: [type: :ordinal, time_unit: :month]
)
|> Tucan.Axes.set_x_title("Day")
|> Tucan.Axes.set_y_title("Month")
|> Tucan.set_title("Punch card of Avg Max Temperatures in Seattle (2012-2015)")
```

You can add a fourth dimension by coloring the plot by a fourth variable. Notice how
we use `Tucan.Scale.set_color_scheme/3` to apply a semantically reasonable coloring and
`Tucan.Legend.set_orientation/3` to change the default position of the two legends.

```tucan
Tucan.punchcard(:weather, "date", "date", "precipitation",
  tooltip: true,
  x: [type: :ordinal, time_unit: :date],
  y: [type: :ordinal, time_unit: :month]
)
# we need to set recursive to true since this is a layered plot
|> Tucan.color_by("temp_max", aggregate: :mean, recursive: true)
|> Tucan.Scale.set_color_scheme(:redyellowblue, reverse: true)
|> Tucan.Axes.set_x_title("Day")
|> Tucan.Axes.set_y_title("Month")
|> Tucan.Legend.set_orientation(:color, "bottom")
|> Tucan.Legend.set_orientation(:size, "bottom")
```

# `range_bar`

```elixir
@spec range_bar(
  plotdata :: plotdata(),
  field :: String.t(),
  min :: String.t(),
  max :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws a range bar chart.

A range bar chart is a bar chart where the bar is not a single value, but a range defined by a
`min` and `max` value. It is used for showing intervals or ranges of data.

## Options

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:corner_radius` (`t:non_neg_integer/0`) - The radius in pixels of rounded rectangles. The end radius is affected:

  - For vertical bars, top-left and top-right corner radius.
  - For horizontal bars, top-right and bottom-right corner radius.
* `:fill_color` (`t:String.t/0`) - The fill color of the marks. This will override the `color` encoding if set.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:horizontal`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:x2` (`t:keyword/0`) - Extra vega lite options for the `:x2` encoding. The default value is `[]`.
* `:x_offset` (`t:keyword/0`) - Extra vega lite options for the `:x_offset` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.
* `:y2` (`t:keyword/0`) - Extra vega lite options for the `:y2` encoding. The default value is `[]`.
* `:y_offset` (`t:keyword/0`) - Extra vega lite options for the `:y_offset` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

A simple ranged bar chart:

```tucan
data = [
  %{"id" => "A", "min" => 28, "max" => 55},
  %{"id" => "B", "min" => 43, "max" => 91},
  %{"id" => "C", "min" => 13, "max" => 61}
]

Tucan.range_bar(data, "id", "min", "max")
```

You can set a `color_by` option that will create a stacked ranged bar chart:

```tucan
data = [
  %{"product" => "Laptop", "category" => "Basic", "min_price" => 499, "max_price" => 799},
  %{"product" => "Laptop", "category" => "Regular", "min_price" => 999, "max_price" => 1799},
  %{"product" => "Laptop", "category" => "Premium", "min_price" => 1499, "max_price" => 2499},
  %{"product" => "Smartphone", "category" => "Basic", "min_price" => 199, "max_price" => 399},
  %{"product" => "Smartphone", "category" => "Regular", "min_price" => 399, "max_price" => 699},
  %{"product" => "Smartphone", "category" => "Premium", "min_price" => 699, "max_price" => 1299},
  %{"product" => "Tablet", "category" => "Basic", "min_price" => 299, "max_price" => 499},
  %{"product" => "Tablet", "category" => "Regular", "min_price" => 399, "max_price" => 699},
  %{"product" => "Tablet", "category" => "Premium", "min_price" => 599, "max_price" => 1990}
]

Tucan.range_bar(data, "product", "min_price", "max_price",
  color_by: "category",
  tooltip: true
)
```

You can tweak the look of the chart using the supported options:

```tucan
data = [
  %{"id" => "A", "min" => 28, "max" => 55},
  %{"id" => "B", "min" => 43, "max" => 91},
  %{"id" => "C", "min" => 13, "max" => 61}
]

Tucan.range_bar(data, "id", "min", "max", orient: :vertical, fill_color: "#33245A", corner_radius: 5)
```

# `scatter`

```elixir
@spec scatter(
  plotdata :: plotdata(),
  x :: String.t(),
  y :: String.t(),
  opts :: keyword()
) ::
  VegaLite.t()
```

Returns the specification of a scatter plot with possibility of several semantic
groupings.

Both `x` and `y` must be `:quantitative`.

> #### Semantic groupings {: .tip}
>
> The relationship between `x` and `y` can be shown for different subsets of the
> data using the `color_by`, `size_by` and `shape_by` parameters. This is equivalent
> to calling the corresponding functions after a `scatter/4` call.
>
> These parameters control what visual semantics are used to identify the different
> subsets. It is possible to show up to three dimensions independently by using all
> three semantic types, but this style of plot can be hard to interpret and is often
> ineffective.
>
> ```tucan
> Tucan.scatter(:tips, "total_bill", "tip",
>   color_by: "day",
>   shape_by: "sex",
>   size_by: "size"
> )
> ```
>
> The above is equivalent to calling:
>
> ```elixir
> Tucan.scatter(:tips, "total_bill", "tip")
> |> Tucan.color_by("day", type: :nominal)
> |> Tucan.shape_by("sex", type: :nominal)
> |> Tucan.size_by("size", type: :quantitative)
> ```
>
> Using redundant semantics (i.e. both color and shape for the same variable) can be
> helpful for making graphics more accessible.
>
> ```tucan
> Tucan.scatter(:tips, "total_bill", "tip",
>   color_by: "day",
>   shape_by: "day"
> )
> ```

## Options

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.
* `:shape_by` (`t:String.t/0`) - If set a data field that will be used for setting the shape of the data points.
  It is considered `:nominal` by default.
* `:size_by` (`t:String.t/0`) - If set a data field that will be used for controlling the size of the data points.
  It is considered `:quantitative` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:filled` (`t:boolean/0`) - Whether the mark will be filled or not
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:point_color` (`t:String.t/0`) - The color of the points
* `:point_shape` - Shape of the point marks. Circle by default.
* `:point_size` (`t:pos_integer/0`) - The pixel area of the marks. Note that this value sets the area of the symbol;
  the side lengths will increase with the square root of this value.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:shape` (`t:keyword/0`) - Extra vega lite options for the `:shape` encoding. The default value is `[]`.
* `:size` (`t:keyword/0`) - Extra vega lite options for the `:size` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

> We will use the `:tips` dataset throughout the following examples.

Drawing a scatter plot between two variables:

```tucan
Tucan.scatter(:tips, "total_bill", "tip")
```

You can modify the look of the plot by setting various styling options:

```tucan
Tucan.scatter(:tips, "total_bill", "tip",
  point_color: "red",
  point_shape: "triangle-up",
  point_size: 10
)
```

You can combine it with `color_by/3` to color code the points with respect to
another variable:

```tucan
Tucan.scatter(:tips, "total_bill", "tip")
|> Tucan.color_by("time")
```

Assigning the same variable to `shape_by/3` will also vary the markers and create a
more accessible plot:

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 400)
|> Tucan.color_by("time")
|> Tucan.shape_by("time")
```

Assigning `color_by/3` and `shape_by/3` to different variables will vary colors and
markers independently:

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 400)
|> Tucan.color_by("day")
|> Tucan.shape_by("time")
```

You can also color the points by a numeric variable, the semantic mapping will be
quantitative and will use a different default palette:

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 400)
|> Tucan.color_by("size", type: :quantitative)
```

A numeric variable can also be assigned to size to apply a semantic mapping to the
areas of the points:

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 400, tooltip: :data)
|> Tucan.color_by("size", type: :quantitative)
|> Tucan.size_by("size", type: :quantitative)
```

You can also combine it with `facet_by/3` in order to group within additional
categorical variables, and plot them across multiple subplots.

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 300)
|> Tucan.color_by("day")
|> Tucan.shape_by("day")
|> Tucan.facet_by(:column, "time")
```

You can also apply faceting on more than one variables, both horizontally and
vertically:

```tucan
Tucan.scatter(:tips, "total_bill", "tip", width: 300)
|> Tucan.color_by("day")
|> Tucan.shape_by("day")
|> Tucan.size_by("size")
|> Tucan.facet_by(:column, "time")
|> Tucan.facet_by(:row, "sex")
```

# `step`

```elixir
@spec step(plotdata :: plotdata(), x :: field(), y :: field(), opts :: keyword()) ::
  VegaLite.t()
```

Returns the specification of a step chart.

This is a simple wrapper around `lineplot/4` with `:interpolate` set by default
to `"step"`. If `:interpolate` is set to any of `step, step-before, step-after` it
will be used. In any other case defaults to `step`.

## Options

Check `lineplot/4`

## Examples

```tucan
Tucan.step(:stocks, "date", "price", color_by: "symbol", width: 300, x: [type: :temporal])
|> Tucan.Scale.set_y_scale(:log)
```

# `streamgraph`

```elixir
@spec streamgraph(
  plotdata :: plotdata(),
  x :: field(),
  y :: field(),
  group :: field(),
  opts :: keyword()
) :: VegaLite.t()
```

Returns the specification of a streamgraph.

This is a simple wrapper around `area/4` with `:mode` set by default
to `:streamgraph`. Any value set to the `:mode` option will be ignored.

A grouping field must also be provided which will be set as `:color_by` to
the area chart.

## Options

Check `area/4`

## Examples

```tucan
Tucan.streamgraph(:stocks, "date", "price", "symbol",
  width: 300,
  x: [type: :temporal],
  tooltip: true
)
```

# `stripplot`

```elixir
@spec stripplot(plotdata :: plotdata(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Draws a strip plot (categorical scatterplot).

A strip plot is a single-axis scatter plot used to visualize the distribution of
a numerical field. The values are plotted as dots or ticks along one axis, so
the dots with the same value may overlap.

You can use the `:jitter` mode for a better view of overlapping points. In this
case points are randomly shifted along with other axis, which has no meaning in
itself data-wise.

Typically several strip plots are placed side by side to compare the distribution
of a numerical value among several categories.

## Options

* `:group_by` (`t:String.t/0`) - A field to be used for grouping the strip plot. If not set the plot will
  be one dimensional.
* `:jitter_mode` - The distribution from which the jitter (random offset) will be generated. One of
  `:uniform`, `:normal`. Applicable only when the `:style` is set to `:jitter`. The default value is `:normal`.
* `:style` - The style of the plot. Can be one of the following:
    * `:tick` - use ticks for each data point
    * `:point` - use points for each data point
    * `:jitter` - use points but also apply some jittering across the other
    axis

  Use `:jitter` in case of many data points in order to avoid overlaps.

  The default value is `:tick`.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:clip` (`t:boolean/0`) - Whether a mark will be clipped to the enclosing group’s width and height.
* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:orient` (`t:atom/0`) - The plot's orientation, can be either `:horizontal` or `:vertical`. The default value is `:horizontal`.
* `:point_color` (`t:String.t/0`) - The color of the points
* `:point_shape` - Shape of the point marks. Circle by default.
* `:point_size` (`t:pos_integer/0`) - The pixel area of the marks. Note that this value sets the area of the symbol;
  the side lengths will increase with the square root of this value. The default value is `16`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.
* `:x` (`t:keyword/0`) - Extra vega lite options for the `:x` encoding. The default value is `[]`.
* `:x_offset` (`t:keyword/0`) - Extra vega lite options for the `:x_offset` encoding. The default value is `[]`.
* `:y` (`t:keyword/0`) - Extra vega lite options for the `:y` encoding. The default value is `[]`.
* `:y_offset` (`t:keyword/0`) - Extra vega lite options for the `:y_offset` encoding. The default value is `[]`.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used
* `:zoomable` (`t:boolean/0`) - Whether the plot will be zoomable or not. If set to `true` you will be able to pan and
  zoom the plot with your mouse. You can reset to the original view with a double click. The default value is `false`.

## Examples

Assigning a single numeric variable shows the univariate distribution. The default
style is the `:tick`:

```tucan
Tucan.stripplot(:tips, "total_bill")
```

For very dense distribution it makes more sense to use the `:jitter` style in order
to reduce overlapping points:

```tucan
Tucan.stripplot(:tips, "total_bill", style: :jitter, height: 30, width: 300)
```

You can set the `:group_by` option in order to add a second dimension. Notice that
the field must be categorical.

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :jitter)
```

The plot would be more clear if you also colored the points with the same field:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :jitter)
|> Tucan.color_by("day")
```

You can use `:uniform` distribution instead of the default (`:normal`). Below
you can see both side by side:

```tucan
normal =
  Tucan.stripplot(:movies, "IMDB Rating",
    group_by: "Major Genre",
    style: :jitter,
    point_size: 2,
    width: 300
  )
  |> Tucan.color_by("Major Genre", type: :nominal)
  |> Tucan.set_title("Gaussian jittering")
  |> Tucan.Legend.set_enabled(:color, false)

uniform =
  Tucan.stripplot(:movies, "IMDB Rating",
    group_by: "Major Genre",
    style: :jitter,
    jitter_mode: :uniform,
    point_size: 2,
    width: 300
  )
  |> Tucan.color_by("Major Genre", type: :nominal)
  |> Tucan.set_title("Uniform jittering")
  |> Tucan.Legend.set_enabled(:color, false)
  |> Tucan.Axes.set_enabled(:y, false)

Tucan.hconcat([normal, uniform])
|> VegaLite.resolve(:scale, y_offset: :independent, y: :shared)
```

You can also color by a distinct variable to show a multi-dimensional relationship:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :jitter)
|> Tucan.color_by("sex")
```

or you can color by a numerical variable:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :jitter)
|> Tucan.color_by("size", type: :ordinal)
```

You could draw the same with points but without jittering:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :point)
|> Tucan.color_by("sex")
```

or with ticks which is the default one:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :tick)
|> Tucan.color_by("sex")
```

You can set the `:orient` flag to `:vertical` to change the orientation:

```tucan
Tucan.stripplot(:tips, "total_bill", group_by: "day", style: :jitter, orient: :vertical)
|> Tucan.color_by("sex")
```

# `jointplot`

```elixir
@spec jointplot(plotdata :: plotdata(), x :: field(), y :: field(), opts :: keyword()) ::
  VegaLite.t()
```

Returns the specification of a jointplot.

A jointplot is a plot of two numerical variables along with marginal univariate
graphs. If no options are set the joint is a scatter plot and the marginal are
the histograms of the two variables.

> #### Marginal plots dimensions {: .info}
>
> By default a jointplot will have a square shape, e.g. it will have the same
> width and height. The `:width` option affects the width of the central (joint)
> plot.
>
> For the marginal distributions you can the `:ratio` option which specifies
> the ratio of joint axes height to marginal axes height.

## Options

* `:joint` - The plot type to be used for the main (joint) plot. Can be one of
  `:scatter` and `:density_heatmap`. The default value is `:scatter`.
* `:joint_opts` (`t:keyword/0`) - Arbitrary options list for the joint plot. The supported options
  depend on the selected `:joint` type. The default value is `[]`.
* `:marginal` - The plot type to be used for the marginal plots. Can be one of
  `:histogram` and `:density`. The default value is `:histogram`.
* `:marginal_opts` (`t:keyword/0`) - Arbitrary options list for the marginal plots. The supported options
  depend on the selected `:marginal` type. Notice that if `:x`, `:y`
  encodings options are set, they are considered to be defined for the default
  orientation, and will be flipped to `:y`, `:x` respectively for the
  vertical marginal plot. The default value is `[]`.
* `:ratio` (`t:float/0`) - The ratio of the marginal plots secondary dimension with respect to
  the joint plot dimension. The default value is `0.45`.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Styling Options

* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `1`.
* `:spacing` (`t:pos_integer/0`) - The spacing between the marginals and the joint plot. The default value is `15`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - The dimension of the central (joint) plot. The same value is used for
  both the width and height of the plot. The default value is `200`.

## Examples

A simple joint plot between two variables.

```tucan
Tucan.jointplot(:iris, "petal_width", "petal_length", width: 200)
```

You can also pass `:color_by` to apply a semantic grouping. If set it will be
applied both to the joint and the marginal plots.

```tucan
Tucan.jointplot(
  :iris, "petal_width", "petal_length",
  color_by: "species",
  fill_opacity: 0.5,
  width: 200
)
```

You can change the type of the join plot and the marginal distributions:

```tucan
Tucan.jointplot(
  :penguins, "Beak Length (mm)", "Beak Depth (mm)",
  joint: :density_heatmap,
  marginal: :density,
  ratio: 0.3
)
```

# `pairplot`

```elixir
@spec pairplot(plotdata :: plotdata(), fields :: [String.t()], opts :: keyword()) ::
  VegaLite.t()
```

Plot pairwise relationships in a dataset.

This function expects an array of fields to be provided. A grid will be created
where each numeric variable in `fields` will be shared across the y-axes across
a single row and the x-axes across a single column.

> #### Numerical field types {: .warning}
>
> Notice that currently `pairplot/3` works only with numerical (`:quantitative`)
> variables. If you need to create a pair plot containing other variable types
> you need to manually build the grid using the `VegaLite` concatenation operations.

## Options

* `:diagonal` - The plot type to be used for the diagonal subplots. Can be one on
  `:scatter`, `:density` and `:histogram`. The default value is `:scatter`.
* `:plot_fn` (function of arity 3) - An optional function for customizing the look any subplot. It expects a
  function with the following signature:

  ```elixir
  (vl :: VegaLite.t(), row :: {String.t(), integer()}, column :: {String.t(), integer()})
    :: VegaLite.t()
  ```

  where both `row` and `column` are tuples containing the index and field of
  the current and row and column respectively.

  You are free to specify any function for every cell of the grid.

### Data Options

* `:only` - A subset of fields to pick from the data. Applicable only if tabular data
  are provided.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

Notice that if set `width` and `height` will be applied to individual sub plots. On
the other hand `title` is applied to the composite plot.

## Examples

By default a scatter plot will be drawn for all pairwise plots:

```tucan
fields = ["petal_width", "petal_length", "sepal_width", "sepal_length"]

Tucan.pairplot(:iris, fields, width: 130, height: 130)
```

You can color the points by another field in to add some semantic mapping. Notice
that you need the `recursive` option to `true` for the grouping to be applied on all
internal subplots.

```tucan
fields = ["petal_width", "petal_length", "sepal_width", "sepal_length"]

Tucan.pairplot(:iris, fields, width: 130, height: 130)
|> Tucan.color_by("species", recursive: true)
```

By specifying the `:diagonal` option you can change the default plot for the diagonal
elements to a histogram:

```tucan
fields = ["petal_width", "petal_length", "sepal_width", "sepal_length"]

Tucan.pairplot(:iris, fields, width: 130, height: 130, diagonal: :histogram)
|> Tucan.color_by("species", recursive: true)
```

Additionally you have the option to configure a `plot_fn` with which we can go crazy and
modify any part of the grid based on our needs. `plot_fn` should accept as input a `VegaLite`
struct and two tuples containing the row and column fields and indexes. In the following
example we draw differently the diagonal, the lower and the upper grid. Notice that we don't
call `color_by/3` since we color differently the plots based on their index positions.

```tucan
Tucan.pairplot(:iris, ["petal_width", "petal_length", "sepal_width", "sepal_length"],
  width: 150,
  height: 150,
  plot_fn: fn vl, {row_field, row_index}, {col_field, col_index} ->
    cond do
      # For the first two diagonal elements we plot a histogram, no
      row_index == col_index and row_index < 2 ->
        Tucan.histogram(vl, row_field)

      row_index == 2 and col_index == 2 ->
        Tucan.stripplot(vl, row_field, group_by: "species", style: :tick)
        |> Tucan.color_by("species")
        |> Tucan.Axes.put_options(:y, labels: false)

      # For the other diagonal plots we plot a histogram colored_by the species
      row_index == col_index ->
        Tucan.histogram(vl, row_field, color_by: "species")

      # For the upper part of the diagram we apply a scatter plot
      row_index < col_index ->
        Tucan.scatter(vl, col_field, row_field)
        |> Tucan.color_by("species")

      # for anything else scatter plot with a quantitative color scale
      # and size
      true ->
        Tucan.scatter(vl, col_field, row_field)
        |> Tucan.size_by("petal_width", type: :quantitative)

    end
  end
)
```

# `imshow`

```elixir
@spec imshow(data :: Nx.Tensor.t(), opts :: keyword()) :: VegaLite.t()
```

Display data as an image.

The input is expected to be an `Nx.Tensor` containing 2D scalar data, which will be
rendered as a pseudo-color image. The origin is set at the upper left hand corner and
rows (first dimension of the array) are displayed horizontally. By setting `:origin`
to `:lower` you can set the origin to the lower left hand corner.

## Options

* `:color_scheme` (`t:atom/0`) - The color scheme to be used for the image. Should be one of the supported
  color schemes of `Tucan.Scale.set_color_scheme/3`. The default value is `:viridis`.
* `:origin` - Place the `[0, 0]` index of the array in the upper left or lower left corner of the Axes. The
  convention (the default) `:upper` is typically used for matrices and images.

  Note that the vertical axis points upward for `:lower` but downward for `:upper`.

  ```tucan
  data = Nx.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], type: {:f, 32})

  Tucan.hconcat([
    Tucan.imshow(data, width: 200, height: 200, origin: :upper, show_scale: true, tooltip: true)
    |> Tucan.set_title(":upper origin (default)"),
    Tucan.imshow(data, width: 200, height: 200, origin: :lower, show_scale: true, tooltip: true)
    |> Tucan.set_title(":lower origin")
  ])
  ```

  The default value is `:upper`.
* `:reverse` (`t:boolean/0`) - Whether the color scheme will be reversed or not. The default value is `false`.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:show_scale` (`t:boolean/0`) - If set the color scale is displayed. The default value is `false`.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

### Interactivity Options

* `:tooltip` (`boolean() | :data | :encoding`) - The tooltip text string to show upon mouse hover or an object defining which fields
  should the tooltip be derived from. Can be one of the following:

  * `:encoding` - all fields from encoding are used
  * `:data` - all fields of the highlighted data point are used
  * `true` - same as `:encoding`
  * `false`, `nil` - no tooltip is used

## Examples

> In the following examples we use a subset of the [MNIST dataset](https://en.wikipedia.org/wiki/MNIST_database).
> The data are stored as a serialized `Nx.Tensor` with shape `{images, height, width, 1}`.

```tucan
mnist_path = Path.expand("../../assets/mnist_sample.bin", __DIR__)
images = File.read!(mnist_path) |> Nx.deserialize()

Tucan.imshow(images[[images: 5]], width: 200, height: 200)
```

Below we use `Tucan.concat/2` to plot a grid of 40 images of the MNIST dataset. We
also set a grayscale color scheme.

```tucan
mnist_path = Path.expand("../../assets/mnist_sample.bin", __DIR__)
images = File.read!(mnist_path) |> Nx.deserialize()

images =
  for i <- 1..40 do
    image = images[[images: i]]
    Tucan.imshow(image, width: 60, height: 60, color_scheme: :greys, reverse: true)
  end

Tucan.concat(images, columns: 10)
```

You can use any of the supported color schemes. Below we draw the same image with 10
different color schemes with and without `:reverse` set. (Notice how we use `VegaLite.resolve/3`
to ensure that each sub-plot will have an independent color scale.)

```tucan
mnist_path = Path.expand("../../assets/mnist_sample.bin", __DIR__)
images = File.read!(mnist_path) |> Nx.deserialize()
image = images[[images: 2]]

schemes = [:viridis, :inferno, :plasma, :turbo, :greenblue, :darkgold, :rainbow, :redblue, :greens, :greys]

non_reversed =
  for scheme <- schemes do
    Tucan.imshow(image, color_scheme: scheme, width: 60, height: 60, title: Atom.to_string(scheme))
  end

reversed =
  for scheme <- schemes do
    Tucan.imshow(image, color_scheme: scheme, reverse: true, width: 60, height: 60)
  end

Tucan.vconcat([
  Tucan.hconcat(non_reversed)
  |> VegaLite.resolve(:scale, color: :independent),
  Tucan.hconcat(reversed)
  |> VegaLite.resolve(:scale, color: :independent)
])
```

> #### 3d plots visualization {: .tip}
>
> You can also use `imshow/2` to "visualize" 3d plots. Below we create a meshgrid
> and calculate the value of a function across the grid. We then use `imshow/2` to
> visualize `z` using the color:
>
> ```tucan
> nx = 121
> ny = 121
>
> x = Nx.linspace(-20, 20, n: nx)
> y = Nx.linspace(-20, 20, n: ny)
>
> defmodule Foo do
>  import Nx.Defn
>
>  defn f(x, y) do
>    Nx.sqrt(Nx.pow(x - 5, 2) + Nx.pow(y - 5, 2))
>  end
>
>  def meshgrid(x, y, nx, ny) do
>    xx = Nx.broadcast(x, {ny, nx}, axes: [1])
>    yy = Nx.broadcast(y, {ny, nx}, axes: [0])
>
>    {xx, yy}
>  end
> end
>
> {xx, yy} = Foo.meshgrid(x, y, nx, ny)
>
> zz = Foo.f(xx, yy)
>
> Tucan.imshow(zz, width: 300, height: 300, origin: :lower, show_scale: true)
> ```

# `annotate`

```elixir
@spec annotate(
  vl :: VegaLite.t(),
  x :: number(),
  y :: number(),
  text :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Adds a `text` annotation to the given `x, y` position.

## Options

You can pass any of the supported [vega-lite text mark properties](https://vega.github.io/vega-lite/docs/text.html#properties).

## Examples

Multiple annotations on the same plot

```tucan
Tucan.new()
|> Tucan.annotate(15, 45, "Dennis", size: 25, font: "Courier New")
|> Tucan.annotate(40, 35, "José", size: 30, color: :purple, font_weight: :bold)
|> Tucan.annotate(20, 25, "Joe", size: 25, color: :red)
|> Tucan.annotate(30, 15, "Guido", size: 20, color: :blue)
|> Tucan.annotate(5, 5, "James", size: 10, color: :orange, angle: 30)
|> Tucan.Scale.set_x_domain(0, 50)
|> Tucan.Scale.set_y_domain(0, 50)
```

# `hruler`

```elixir
@spec hruler(vl :: VegaLite.t(), position :: number() | String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a horizontal line at the given `h` position.

For supported options check `ruler/4`.

## Examples

You can use `hruler/3` to plot the means of some data points across the
_y axis_:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species")
|> Tucan.hruler("petal_length", color_by: "species", stroke_width: 2)
```

Additionally you can use it to plot a horizontal ruler to an arbitrary
position:

```tucan
Tucan.new()
|> Tucan.hruler(13)
|> Tucan.hruler(11)
|> Tucan.Scale.set_y_domain(10, 15)
```

# `ruler`

```elixir
@spec ruler(
  vl :: VegaLite.t(),
  axis :: :x | :y,
  position :: number() | String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Adds a vertical or horizontal ruler at the given position.

`position` can either be a number representing a coordinate of the _x/y-axis_ or a
binary representing a field. In the latter case an aggregation can also
be provided which will be used for aggregating the field distribution
to a single number. If not set defaults to `:mean`.

`axis` specifies the orientation of the line. Use `:x` for a vertical
line and `:y` for a horizontal one.

See also `vruler/3`, `hruler/3`.

## Options

* `:aggregate` (`t:atom/0`) - The aggregate to used for calculating the line's coordinate The default value is `:mean`.
* `:line_color` - The default value is `"black"`.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - If set a data field that will be used for coloring the data. It is considered
  `:nominal` by default.

### Styling Options

* `:stroke_dash` (list of `t:pos_integer/0`) - An array of alternating stroke, space lengths in pixels for creating dashed
  or dotted lines.
* `:stroke_width` (`t:pos_integer/0`) - The stroke width in pixels The default value is `1`.

### Encodings Custom Options

All Tucan plots are building a `VegaLite` specification based on some sane
default parameters. Through these encodings options you are free to set any
vega-lite supported option to any encoding channel of the plot.

Notice that if set they will be merged with any option set by the plot. Since they
have a higher precedence they may override the default settings and affect the
generated plot.

You can set an arbitrary keyword list. Notice that **the contents are not validated.**

* `:color` (`t:keyword/0`) - Extra vega lite options for the `:color` encoding. The default value is `[]`.

## Examples

You can add a vertical ruler to any _x-axis_ point:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.ruler(:x, 1.1, stroke_width: 3, line_color: "blue")
|> Tucan.ruler(:x, 1.4, line_color: "green")
```

Additionally you can can add a vertical line to an aggregated value of
a data field. For example:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.ruler(:x, "petal_width", line_color: "red")
```

You can add multiple lines for each group of the data if you pass the
`color_by` option. Also you can combine vertical with horizontal
lines.

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species")
|> Tucan.ruler(:x, "petal_width", color_by: "species", stroke_width: 3)
|> Tucan.ruler(:y, "petal_length", color_by: "species", stroke_dash: [5, 5])
```

You can also use `ruler/4`, `hruler/3` and `vruler/3` independently in a
layered plot:

```tucan
Tucan.layers([
  Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species"),
  Tucan.hruler(Tucan.new(), 3.2, line_color: "red"),
  Tucan.vruler(Tucan.new(), 1.6, line_color: "green", stroke_width: 2)
])
```

# `vruler`

```elixir
@spec vruler(vl :: VegaLite.t(), position :: number() | String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a vertical line at the given `x` position.

For supported options check `ruler/4`.

## Examples

You can use `vruler/3` to plot the means of some data points across the
_x axis_:

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species")
|> Tucan.vruler("petal_width", color_by: "species", stroke_width: 2)
```

Additionally you can use it to plot a vertical ruler to an arbitrary
position:

```tucan
Tucan.new()
|> Tucan.vruler(5)
|> Tucan.vruler(11)
|> Tucan.Scale.set_x_domain(3, 15)
```

# `concat`

```elixir
@spec concat(plots :: [VegaLite.t()], opts :: keyword()) :: VegaLite.t()
```

Concatenates the given plots.

This corresponds to the general concatenation of vega-lite (wrappable).

## Options

* `:align` - The alignment to apply to grid rows and columns. The supported values are `:all`,
  `:each`, and `:none`.

  * For `:none`, a flow layout will be used, in which adjacent subviews are simply
  placed one after the other.
  * For `:each`, subviews will be aligned into a clean grid structure, but each row or
  column may be of variable size.
  * For `:all`, subviews will be aligned and each row or column will be sized identically
  based on the maximum observed size. String values for this property will be applied to
  both grid rows and columns.

  Defaults to `:all` if not set.
* `:bounds` - The bounds calculation method to use for determining the extent of a sub-plot. One
  of `:full` (the default) or `:flush`.

  * If set to `:full`, the entire calculated bounds (including axes, title, and legend)
  will be used.
  * If set to `:flush`, only the specified width and height values for the sub-view
  will be used. The `:flush` setting can be useful when attempting to place sub-plots
  without axes or legends into a uniform grid structure.
* `:columns` (`t:pos_integer/0`) - The number of columns to include in the view composition layout.
* `:spacing` (`t:pos_integer/0`) - The spacing in pixels between sub-views of the composition operator. If not set defaults
  to 20.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

# `hconcat`

```elixir
@spec hconcat(plots :: [VegaLite.t()], opts :: keyword()) :: VegaLite.t()
```

Concatenates horizontally the given plots.

## Options

* `:align` - The alignment to apply to grid rows and columns. The supported values are `:all`,
  `:each`, and `:none`.

  * For `:none`, a flow layout will be used, in which adjacent subviews are simply
  placed one after the other.
  * For `:each`, subviews will be aligned into a clean grid structure, but each row or
  column may be of variable size.
  * For `:all`, subviews will be aligned and each row or column will be sized identically
  based on the maximum observed size. String values for this property will be applied to
  both grid rows and columns.

  Defaults to `:all` if not set.
* `:bounds` - The bounds calculation method to use for determining the extent of a sub-plot. One
  of `:full` (the default) or `:flush`.

  * If set to `:full`, the entire calculated bounds (including axes, title, and legend)
  will be used.
  * If set to `:flush`, only the specified width and height values for the sub-view
  will be used. The `:flush` setting can be useful when attempting to place sub-plots
  without axes or legends into a uniform grid structure.
* `:spacing` (`t:pos_integer/0`) - The spacing in pixels between sub-views of the composition operator. If not set defaults
  to 20.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

# `layers`

```elixir
@spec layers(vl :: VegaLite.t(), plots :: [VegaLite.t()]) :: VegaLite.t()
```

Creates a layered plot.

This is a simple wrapper around `VegaLite.layers/2` which by default adds
the layers under an empty plot. If a multi-layer plot is passed to `plots`
then it's layers will be extracted and merged with the rest layers as long
as the plot has not a top level data item defined.

# `vconcat`

```elixir
@spec vconcat(plots :: [VegaLite.t()], opts :: keyword()) :: VegaLite.t()
```

Concatenates vertically the given plots.

## Options

* `:align` - The alignment to apply to grid rows and columns. The supported values are `:all`,
  `:each`, and `:none`.

  * For `:none`, a flow layout will be used, in which adjacent subviews are simply
  placed one after the other.
  * For `:each`, subviews will be aligned into a clean grid structure, but each row or
  column may be of variable size.
  * For `:all`, subviews will be aligned and each row or column will be sized identically
  based on the maximum observed size. String values for this property will be applied to
  both grid rows and columns.

  Defaults to `:all` if not set.
* `:bounds` - The bounds calculation method to use for determining the extent of a sub-plot. One
  of `:full` (the default) or `:flush`.

  * If set to `:full`, the entire calculated bounds (including axes, title, and legend)
  will be used.
  * If set to `:flush`, only the specified width and height values for the sub-view
  will be used. The `:flush` setting can be useful when attempting to place sub-plots
  without axes or legends into a uniform grid structure.
* `:spacing` (`t:pos_integer/0`) - The spacing in pixels between sub-views of the composition operator. If not set defaults
  to 20.

### Styling Options

* `:height` (`t:pos_integer/0` or `:container`) - Height of the plot. Can either be the height in pixels or `:container` to indicate that
  the height of the plot should be the same as its surrounding container.
* `:title` (`t:String.t/0`) - The title of the graph
* `:width` (`t:pos_integer/0` or `:container`) - Width of the plot. Can either be the width in pixels or `:container` to indicate that
  the width of the plot should be the same as its surrounding container.

# `color_by`

```elixir
@spec color_by(vl :: VegaLite.t(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a `color` encoding for the given field.

## Options

* `:recursive` (`t:boolean/0`) - If set the grouping function will be applied recursively in all valid sub plots. This
  includes both layers and concatenated plots. The default value is `false`.

`opts` can also contain an arbitrary set of vega-lite supported options that
will be passed to the underlying encoding.

# `facet_by`

```elixir
@spec facet_by(
  vl :: VegaLite.t(),
  faceting_mode :: :row | :column | :wrapped,
  field :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Apply facetting on the input plot `vl` by the given `field`.

This will create multiple plots either horizontally (`:column` faceting mode),
vertically (`:row` faceting mode) or arbitrarily (`:wrapped` mode). One plot will
be created for each distinct value of the given `field`, which must be a
categorical variable.

In the case of `:wrapped` a `:columns` option should also be provided which
will determine the number of columns of the composite plot.

`opts` is an arbitrary keyword list that will be passed to the `:row` or `:column`
encoding.

> #### Facet plots {: .info}
>
> Facet plots, also known as trellis plots or small multiples, are figures made up
> of multiple subplots which have the same set of axes, where each subplot shows
> a subset of the data.

## Examples

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.facet_by(:column, "species")
|> Tucan.color_by("species")
```

With `:wrapped` mode and custom sorting:

```tucan
Tucan.density(:movies, "IMDB Rating", color_by: "Major Genre")
|> Tucan.facet_by(:wrapped, "Major Genre", columns: 4, sort: [op: :mean, field: "IMDB Rating"])
|> Tucan.Legend.set_enabled(:color, false)
|> Tucan.set_title("Density of IMDB rating by Genre", offset: 20)
```

# `fill_by`

```elixir
@spec fill_by(vl :: VegaLite.t(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a `fill` encoding for the given field.

## Options

* `:recursive` (`t:boolean/0`) - If set the grouping function will be applied recursively in all valid sub plots. This
  includes both layers and concatenated plots. The default value is `false`.

`opts` can also contain an arbitrary set of vega-lite supported options that
will be passed to the underlying encoding.

# `shape_by`

```elixir
@spec shape_by(vl :: VegaLite.t(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a `shape` encoding for the given field.

## Options

* `:recursive` (`t:boolean/0`) - If set the grouping function will be applied recursively in all valid sub plots. This
  includes both layers and concatenated plots. The default value is `false`.

`opts` can also contain an arbitrary set of vega-lite supported options that
will be passed to the underlying encoding.

# `size_by`

```elixir
@spec size_by(vl :: VegaLite.t(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a `size` encoding for the given field.

By default the type of the `field` is set to `:quantitative`. You can override it in the
`opts` by setting another `:type`.

## Options

* `:recursive` (`t:boolean/0`) - If set the grouping function will be applied recursively in all valid sub plots. This
  includes both layers and concatenated plots. The default value is `false`.

`opts` can also contain an arbitrary set of vega-lite supported options that
will be passed to the underlying encoding.

# `stroke_dash_by`

```elixir
@spec stroke_dash_by(vl :: VegaLite.t(), field :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Adds a `stroke_dash` encoding for the given field.

## Options

* `:recursive` (`t:boolean/0`) - If set the grouping function will be applied recursively in all valid sub plots. This
  includes both layers and concatenated plots. The default value is `false`.

`opts` can also contain an arbitrary set of vega-lite supported options that
will be passed to the underlying encoding.

# `background_image`

```elixir
@spec background_image(vl :: VegaLite.t(), image_url :: String.t()) :: VegaLite.t()
```

Adds a background image to the current plot.

## Examples

```tucan
# generate some random samples
shots =
  for _index <- 1..30 do
    %{x: Enum.random(10..90), y: Enum.random(10..90), team: Enum.random([:home, :away])}
  end

pitch_image_url = "https://raw.githubusercontent.com/pnezis/tucan/main/assets/soccer-field.jpeg"

Tucan.scatter(shots, "x", "y", color_by: "team", filled: true, point_size: 80, tooltip: true)
|> Tucan.Scale.set_xy_domain(0, 100)
|> Tucan.Scale.set_color_scheme(["blue", "red"])
|> Tucan.background_image(pitch_image_url)
|> Tucan.Axes.set_enabled(false)
|> Tucan.set_size(700, 350)
|> Tucan.set_title("Shots")
```

# `flip_axes`

```elixir
@spec flip_axes(vl :: VegaLite.t()) :: VegaLite.t()
```

Flips the axes of the provided chart.

This works for both one dimensional and two dimensional charts. All positional channels
that are defined will be flipped.

This is used internally by plots that support setting orientation.

# `href_by`

```elixir
@spec href_by(vl :: VegaLite.t(), field :: String.t()) :: VegaLite.t()
```

Adds a hyperlink encoding.

The `field` should be the URL that will be loaded upon mouse click.

# `configure`

```elixir
@spec configure(opts :: keyword()) :: :ok
```

Sets default `Tucan` options.

> #### Usage {: .info}
>
> These options will be set as default `tucan` options. Notice that if you override these
> settings in your plot then the global settings will not be used.
>
> ```elixir
> Tucan.configure(default_width: 400, default_height: 300)
>
> # this will create a plot with the default width and height
> Tucan.scatter(:iris, "sepal_width", "sepal_length")
>
> # this will create a plot with the width to 500 and height having the default
> # value of 300
> Tucan.scatter(:iris, "sepal_width", "sepal_length", width: 500)
>
> # you can also set the width to `:container` to make it responsive
> Tucan.configure(default_width: :container)
> ```

## Options

* `:default_width` - The default width of the plot, if the width is already set it will not be overridden

* `:default_height` - The default height of the plot, if the height is already set it will not be overridden

## Examples

    # Configuring default width and height for tucan plots
    Tucan.configure(default_width: 700, default_height: 350)

> #### Width and Height Configuration {: .info}
>
> The `configure/1` function sets default dimensions for your plots:
>
> **Single-view plots:**
> * Default width and height control the plotting area size
> * Individual plots can override these defaults with their own `width` and `height` properties
>
> **Multi-view plots (concatenated, faceted, or repeated):**
> * Default dimensions apply to each inner view
> * Final size is calculated based on how views are composed
> * To control overall size, adjust dimensions of individual views
>
> **Responsive Layouts:**
> * Use `:container` as width/height to make a dimension match its container
> * Example: `Tucan.configure(default_width: :container, default_height: 350)`
>
> For more details check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/size.html).

# `set_height`

```elixir
@spec set_height(vl :: VegaLite.t(), height :: pos_integer() | :container) ::
  VegaLite.t()
```

Sets the height of the plot (in pixels).

`height` can be either the height in pixels or `:container` to indicate that the height of the
plot should be the same as its surrounding container.

# `set_size`

```elixir
@spec set_size(
  vl :: VegaLite.t(),
  width :: pos_integer() | :container,
  height :: pos_integer() | :container
) :: VegaLite.t()
```

Sets the plot size.

This sets both width and height at once. See also `set_width/2`, `set_height/2`.

# `set_theme`

```elixir
@spec set_theme(vl :: VegaLite.t(), theme :: atom() | keyword()) :: VegaLite.t()
```

Sets the plot's theme.

You can pass either a built-in theme atom or a custom theme as a keyword list
of Vega-Lite configuration options.

## Built-in themes

Check `Tucan.Themes` for the list of available built-in themes.

    Tucan.scatter(:iris, "petal_width", "petal_length")
    |> Tucan.set_theme(:latimes)

## Custom themes

You can also pass a keyword list of Vega-Lite
[config](https://vega.github.io/vega-lite/docs/config.html) options directly:

    Tucan.scatter(:iris, "petal_width", "petal_length")
    |> Tucan.set_theme(
      background: "#0E0E0E",
      axis: [grid: false, label_color: "#FFF"],
      style: [bar: [fill: "#FDDA00"]]
    )

# `set_title`

```elixir
@spec set_title(vl :: VegaLite.t(), title :: String.t(), opts :: keyword()) ::
  VegaLite.t()
```

Sets the title of the plot.

You can optionally pass any title option supported by vega-lite to customize the
style of it.

## Examples

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.set_title("My awesome plot",
    color: "red",
    subtitle: "with a subtitle",
    subtitle_color: "green",
    anchor: "start"
  )
```

If you need to set a multi-line title you can pass a multiline string.

```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.set_title("My multiline\ntitle")
```

# `set_width`

```elixir
@spec set_width(vl :: VegaLite.t(), width :: pos_integer() | :container) ::
  VegaLite.t()
```

Sets the width of the plot (in pixels).

`width` can be either the width in pixels or `:container` to indicate that the width of the
plot should be the same as its surrounding container.

# `field`

```elixir
@type field() :: String.t()
```

A string corresponding to a dataset's field

# `plotdata`

```elixir
@type plotdata() :: String.t() | Table.Reader.t() | Tucan.Datasets.t() | VegaLite.t()
```

The plot data.

This represents the input to all `Tucan` plots. It can be any of the following:

* an existing `t:VegaLite.t/0` struct
* a string corresponding to the url of a dataset
* a dataset implementing the `t:Table.Reader.t/0` protocol
* an atom corresponding to one of the supported `Tucan.Datasets`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
