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

Geographic plots.

All geographic plots project longitude and latitude coordinates on the plane with a
cartographic projection, set by the `:projection` option. Common projections are
`:equal_earth` or `:natural_earth1` for world maps, `:albers_usa` for the United
States and `:mercator` for small areas. Additional projection properties, like the
`:scale`, the `:center` or the `:rotate` angles, can be set through the
`:projection_opts` option.

## Geographic data

Maps are drawn from geographic features in GeoJSON or TopoJSON format:

* A TopoJSON file contains named objects, e.g. the `states` and the `counties` of
the `:us_10m` dataset. Set the `:feature` option to the name of the object to draw
its features, or the `:mesh` option to draw only the borders between them.
* A GeoJSON file is expected to contain a feature collection, if neither `:feature`
nor `:mesh` are set.

The `:us_10m` and `:world_110m` datasets default to their `states` and `countries`
objects respectively.

The geographic features are loaded from a dataset or a URL, inline geographic data
are not supported.

## Combining maps

All plots of this module are single views with their own projection, so they can be
combined with `Tucan.layers/1`, e.g. to draw some points on top of a base map. Use
the same projection for all layers.

```tucan
Tucan.layers([
  Tucan.Geo.basemap(:us_10m),
  Tucan.Geo.scatter(:airports, "longitude", "latitude", point_size: 4, point_color: "firebrick")
])
```

# `basemap`

```elixir
@spec basemap(geodata :: atom() | String.t(), opts :: keyword()) :: VegaLite.t()
```

Draws a base map of geographic features.

`geodata` is a dataset, e.g. `:us_10m` or `:world_110m`, or the URL of a GeoJSON or
TopoJSON file. See the module documentation for the supported formats.

## Options

* `:feature` (`t:String.t/0`) - The name of the TopoJSON object whose features are drawn. Defaults to `"states"`
  for the `:us_10m` dataset and to `"countries"` for the `:world_110m` dataset.
* `:mesh` (`t:String.t/0`) - The name of the TopoJSON object whose borders are drawn. Set it instead of
  `:feature` to draw only the borders between the features.

### Styling Options

* `:fill_color` (`t:String.t/0`) - The fill color of the features. The default value is `"#e3e3e3"`.
* `:graticule` (`t:boolean/0`) - Whether a graticule, the grid of meridians and parallels, is drawn. The default value is `false`.
* `:height` (`t:pos_integer/0`) - The height of the plot in pixels. The default value is `300`.
* `:line_color` (`t:String.t/0`) - The color of the borders of the features. The default value is `"white"`.
* `:projection` - The cartographic projection. One of `:albers`, `:albers_usa`, `:azimuthal_equal_area`, `:azimuthal_equidistant`, `:conic_conformal`, `:conic_equal_area`, `:conic_equidistant`, `:equal_earth`, `:equirectangular`, `:gnomonic`, `:mercator`, `:natural_earth1`, `:orthographic`, `:stereographic`, `:transverse_mercator`.
  Defaults to `:albers_usa` for the `:us_10m` and `:airports` datasets and to
  `:equal_earth` otherwise.
* `:projection_opts` (`t:keyword/0`) - Additional properties of the projection, e.g. `[scale: 300, center: [20, 50]]`.
  Check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/projection.html)
  for the supported properties. The default value is `[]`.
* `:sphere` (`t:boolean/0`) - Whether the outline of the globe is drawn, filled with the `:sphere_color`. The default value is `false`.
* `:sphere_color` (`t:String.t/0`) - The fill color of the sphere, if `:sphere` is set. The default value is `"#e8f1f8"`.
* `:stroke_width` - The width of the borders in pixels. The default value is `0.5`.
* `:title` (`t:String.t/0`) - The title of the plot.
* `:width` (`t:pos_integer/0`) - The width of the plot in pixels. The default value is `500`.

### 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

The countries of the world, with the outline of the globe and a graticule:

```tucan
Tucan.Geo.basemap(:world_110m, sphere: true, graticule: true)
```

The states of the US:

```tucan
Tucan.Geo.basemap(:us_10m, fill_color: "#dce9d5", line_color: "#7a9a6f")
```

Only the borders between the counties of the US, with a mesh:

```tucan
Tucan.Geo.basemap(:us_10m, mesh: "counties", line_color: "gray", stroke_width: 0.3)
```

Europe, with an orthographic projection centered on it:

```tucan
Tucan.Geo.basemap(:world_110m,
  projection: :orthographic,
  projection_opts: [rotate: [-15, -50, 0], scale: 500],
  sphere: true,
  graticule: true,
  width: 400,
  height: 400
)
```

# `choropleth`

```elixir
@spec choropleth(
  geodata :: atom() | String.t(),
  data :: Tucan.plotdata(),
  key :: String.t(),
  value :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws a choropleth map.

A choropleth map colors each geographic feature, e.g. the states of a country, by a
value. The features of `geodata` are matched with the rows of `data`, by their
`:feature_key` and the `key` field of the data, and colored by the `value` field.
Features without a matching row, or without a valid value, are drawn with the
`:missing_color`.

`geodata` is a dataset or the URL of a GeoJSON or TopoJSON file, see the module
documentation for details, and `data` any data supported by `Tucan.new/2`.

## Options

* `:feature` (`t:String.t/0`) - The name of the TopoJSON object whose features are drawn. Defaults to `"states"`
  for the `:us_10m` dataset and to `"countries"` for the `:world_110m` dataset.
* `:feature_key` (`t:String.t/0`) - The field of the geographic features that is matched with the `key` field of the
  data, e.g. `"properties.name"`. TopoJSON features usually have an `"id"`. The default value is `"id"`.
* `:fields` (list of `t:String.t/0`) - Additional fields of the data that are joined to the features, e.g. to be shown
  in the tooltip. The default value is `[]`.
* `:mesh` (`t:String.t/0`) - The name of the TopoJSON object whose borders are drawn. Set it instead of
  `:feature` to draw only the borders between the features.

### Styling Options

* `:color_scheme` (`t:atom/0`) - The color scheme to use, for supported color schemes check `Tucan.Scale`.
* `:height` (`t:pos_integer/0`) - The height of the plot in pixels. The default value is `300`.
* `:line_color` (`t:String.t/0`) - The color of the borders of the features. The default value is `"white"`.
* `:missing_color` (`t:String.t/0`) - The fill color of the features without a value. The default value is `"#e3e3e3"`.
* `:projection` - The cartographic projection. One of `:albers`, `:albers_usa`, `:azimuthal_equal_area`, `:azimuthal_equidistant`, `:conic_conformal`, `:conic_equal_area`, `:conic_equidistant`, `:equal_earth`, `:equirectangular`, `:gnomonic`, `:mercator`, `:natural_earth1`, `:orthographic`, `:stereographic`, `:transverse_mercator`.
  Defaults to `:albers_usa` for the `:us_10m` and `:airports` datasets and to
  `:equal_earth` otherwise.
* `:projection_opts` (`t:keyword/0`) - Additional properties of the projection, e.g. `[scale: 300, center: [20, 50]]`.
  Check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/projection.html)
  for the supported properties. The default value is `[]`.
* `:stroke_width` - The width of the borders in pixels. The default value is `0.3`.
* `:title` (`t:String.t/0`) - The title of the plot.
* `:width` (`t:pos_integer/0`) - The width of the plot in pixels. The default value is `500`.

### 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

The unemployment rate of the US counties:

```tucan
Tucan.Geo.choropleth(:us_10m, :us_county_unemployment, "id", "rate",
  feature: "counties",
  color_scheme: :reds
)
```

The population of the US states, with a tooltip:

```tucan
Tucan.Geo.choropleth(:us_10m, :us_state_population, "id", "population",
  fields: ["state"],
  color_scheme: :blues,
  tooltip: true
)
```

With inline data, where the states without a value are drawn in gray. The states
are identified by their FIPS codes, e.g. `6` for California:

```tucan
data = [
  %{fips: 6, score: 9},
  %{fips: 53, score: 7},
  %{fips: 41, score: 6},
  %{fips: 32, score: 4},
  %{fips: 8, score: 5},
  %{fips: 36, score: 3},
  %{fips: 12, score: 2},
  %{fips: 48, score: 1}
]

Tucan.Geo.choropleth(:us_10m, data, "fips", "score", color_scheme: :greens)
```

# `connections`

```elixir
@spec connections(
  plotdata :: Tucan.plotdata(),
  longitude :: String.t(),
  latitude :: String.t(),
  longitude2 :: String.t(),
  latitude2 :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws lines between pairs of geographic locations, e.g. flight routes.

`longitude` and `latitude` are the fields with the coordinates of the start of
each line, and `longitude2` and `latitude2` the fields with the coordinates of its
end.

The lines are straight lines on the projected map, and not great circles.

The lines are drawn without a map, combine them with a `basemap/2` using
`Tucan.layers/1`, see the module documentation.

## 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.
* `: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.

### Styling Options

* `:height` (`t:pos_integer/0`) - The height of the plot in pixels. The default value is `300`.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:opacity` (`t:number/0`) - The overall opacity of the mark The default value is `0.6`.
* `:projection` - The cartographic projection. One of `:albers`, `:albers_usa`, `:azimuthal_equal_area`, `:azimuthal_equidistant`, `:conic_conformal`, `:conic_equal_area`, `:conic_equidistant`, `:equal_earth`, `:equirectangular`, `:gnomonic`, `:mercator`, `:natural_earth1`, `:orthographic`, `:stereographic`, `:transverse_mercator`.
  Defaults to `:albers_usa` for the `:us_10m` and `:airports` datasets and to
  `:equal_earth` otherwise.
* `:projection_opts` (`t:keyword/0`) - Additional properties of the projection, e.g. `[scale: 300, center: [20, 50]]`.
  Check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/projection.html)
  for the supported properties. The default value is `[]`.
* `:stroke_width` - The width of the lines in pixels. Ignored if `:size_by` is set. The default value is `1`.
* `:title` (`t:String.t/0`) - The title of the plot.
* `:width` (`t:pos_integer/0`) - The width of the plot in pixels. The default value is `500`.

### 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

Flights from London to some cities of the world, with made up weekly frequencies:

```tucan
london = %{lon: -0.45, lat: 51.47}

routes =
  for {city, lon, lat, weekly} <- [
        {"New York", -73.78, 40.64, 140},
        {"Dubai", 55.36, 25.25, 90},
        {"Singapore", 103.99, 1.36, 35},
        {"Johannesburg", 28.24, -26.13, 21},
        {"São Paulo", -46.47, -23.43, 14},
        {"Tokyo", 139.78, 35.55, 28},
        {"Los Angeles", -118.41, 33.94, 50}
      ] do
    %{city: city, lon: london.lon, lat: london.lat, lon2: lon, lat2: lat, weekly: weekly}
  end

Tucan.layers([
  Tucan.Geo.basemap(:world_110m),
  Tucan.Geo.connections(routes, "lon", "lat", "lon2", "lat2",
    size_by: "weekly",
    line_color: "firebrick",
    tooltip: true
  )
])
```

The flights from Seattle to other US airports. The coordinates of the airports are
joined to the flights with lookup transforms:

```tucan
airports = Tucan.Datasets.dataset(:airports)

lookup = fn vl, field, as ->
  VegaLite.transform(vl,
    lookup: field,
    from: [data: [url: airports], key: "iata", fields: ["longitude", "latitude"]],
    as: as
  )
end

flights =
  Tucan.new(:flights_airport)
  |> VegaLite.transform(filter: "datum.origin == 'SEA'")
  |> lookup.("origin", ["origin_lon", "origin_lat"])
  |> lookup.("destination", ["dest_lon", "dest_lat"])
  |> Tucan.Geo.connections("origin_lon", "origin_lat", "dest_lon", "dest_lat",
    projection: :albers_usa,
    size_by: "count",
    line_color: "steelblue"
  )

Tucan.layers([Tucan.Geo.basemap(:us_10m), flights])
```

# `path`

```elixir
@spec path(
  plotdata :: Tucan.plotdata(),
  longitude :: String.t(),
  latitude :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws paths connecting geographic locations, e.g. the track of a storm or the
route of a trip.

`longitude` and `latitude` are the fields with the coordinates of the points of
each path.

The paths are drawn without a map, combine them with a `basemap/2` using
`Tucan.layers/1`, see the module documentation.

## Options

* `:order_by` (`t:String.t/0`) - A field used for ordering the points of each path, e.g. a timestamp. If not set
  the points are connected in the order of the data.

### Data Grouping Options

* `:color_by` (`t:String.t/0`) - A field used for coloring the paths. A separate path is drawn per color.
* `:group_by` (`t:String.t/0`) - A field used for drawing a separate path for each group.

### Styling Options

* `:height` (`t:pos_integer/0`) - The height of the plot in pixels. The default value is `300`.
* `:line_color` (`t:String.t/0`) - The color of the line
* `:points` (`t:boolean/0`) - Whether a point is drawn at each location. The default value is `false`.
* `:projection` - The cartographic projection. One of `:albers`, `:albers_usa`, `:azimuthal_equal_area`, `:azimuthal_equidistant`, `:conic_conformal`, `:conic_equal_area`, `:conic_equidistant`, `:equal_earth`, `:equirectangular`, `:gnomonic`, `:mercator`, `:natural_earth1`, `:orthographic`, `:stereographic`, `:transverse_mercator`.
  Defaults to `:albers_usa` for the `:us_10m` and `:airports` datasets and to
  `:equal_earth` otherwise.
* `:projection_opts` (`t:keyword/0`) - Additional properties of the projection, e.g. `[scale: 300, center: [20, 50]]`.
  Check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/projection.html)
  for the supported properties. The default value is `[]`.
* `:stroke_width` - The width of the paths in pixels. The default value is `2`.
* `:title` (`t:String.t/0`) - The title of the plot.
* `:width` (`t:pos_integer/0`) - The width of the plot in pixels. The default value is `500`.

### 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

The (approximate) tracks of two Atlantic hurricanes:

```tucan
tracks =
  for {storm, points} <- [
        {"Katrina",
         [{-75.1, 23.1}, {-77.6, 24.8}, {-80.1, 26.0}, {-82.6, 25.1}, {-85.3, 25.2},
          {-87.8, 26.2}, {-89.6, 28.2}, {-89.6, 30.8}, {-88.6, 34.0}, {-86.0, 37.0}]},
        {"Ike",
         [{-37.0, 17.2}, {-50.0, 21.0}, {-60.2, 22.8}, {-68.0, 21.4}, {-74.3, 21.1},
          {-79.0, 21.8}, {-84.6, 23.1}, {-89.4, 25.6}, {-94.7, 29.3}, {-93.0, 35.4}]}
      ],
      {{lon, lat}, step} <- Enum.with_index(points) do
    %{storm: storm, lon: lon, lat: lat, step: step}
  end

projection = [projection: :mercator, projection_opts: [scale: 420, center: [-66, 27]]]

Tucan.layers([
  Tucan.Geo.basemap(:world_110m, projection),
  Tucan.Geo.path(tracks, "lon", "lat", [order_by: "step", color_by: "storm", points: true] ++ projection)
])
```

# `scatter`

```elixir
@spec scatter(
  plotdata :: Tucan.plotdata(),
  longitude :: String.t(),
  latitude :: String.t(),
  opts :: keyword()
) :: VegaLite.t()
```

Draws points at geographic locations.

`longitude` and `latitude` are the fields with the coordinates of each point in
degrees. The points can be colored and sized by data fields, e.g. for a bubble map.

The points are drawn without a map, combine them with a `basemap/2` using
`Tucan.layers/1`, see the module documentation.

> #### Points outside the projection {: .warning}
>
> Points that the projection cannot place are drawn at the top left corner of the
> plot, e.g. the airports of Guam with the `:albers_usa` projection, which covers
> only the 50 states. Filter them out of the data if needed.

## 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.
* `: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.

### Styling Options

* `:fill_opacity` (`t:number/0`) - The fill opacity of the plotted elements. The default value is `0.7`.
* `:filled` (`t:boolean/0`) - Whether the mark will be filled or not The default value is `true`.
* `:height` (`t:pos_integer/0`) - The height of the plot in pixels. The default value is `300`.
* `: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.
* `:projection` - The cartographic projection. One of `:albers`, `:albers_usa`, `:azimuthal_equal_area`, `:azimuthal_equidistant`, `:conic_conformal`, `:conic_equal_area`, `:conic_equidistant`, `:equal_earth`, `:equirectangular`, `:gnomonic`, `:mercator`, `:natural_earth1`, `:orthographic`, `:stereographic`, `:transverse_mercator`.
  Defaults to `:albers_usa` for the `:us_10m` and `:airports` datasets and to
  `:equal_earth` otherwise.
* `:projection_opts` (`t:keyword/0`) - Additional properties of the projection, e.g. `[scale: 300, center: [20, 50]]`.
  Check the [Vega-Lite docs](https://vega.github.io/vega-lite/docs/projection.html)
  for the supported properties. The default value is `[]`.
* `:title` (`t:String.t/0`) - The title of the plot.
* `:width` (`t:pos_integer/0`) - The width of the plot in pixels. The default value is `500`.

### 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

The airports of the United States:

```tucan
Tucan.Geo.scatter(:airports, "longitude", "latitude", point_size: 4)
```

A bubble map of some of the largest cities of the world, sized by their approximate
metropolitan population in millions, on top of a world map:

```tucan
cities = [
  %{city: "Tokyo", lon: 139.69, lat: 35.69, population: 37.4, continent: "Asia"},
  %{city: "Delhi", lon: 77.21, lat: 28.61, population: 31.0, continent: "Asia"},
  %{city: "Shanghai", lon: 121.47, lat: 31.23, population: 27.1, continent: "Asia"},
  %{city: "São Paulo", lon: -46.63, lat: -23.55, population: 22.0, continent: "South America"},
  %{city: "Mexico City", lon: -99.13, lat: 19.43, population: 21.8, continent: "North America"},
  %{city: "Cairo", lon: 31.24, lat: 30.04, population: 21.3, continent: "Africa"},
  %{city: "Mumbai", lon: 72.88, lat: 19.08, population: 20.7, continent: "Asia"},
  %{city: "New York", lon: -74.01, lat: 40.71, population: 18.8, continent: "North America"},
  %{city: "Lagos", lon: 3.38, lat: 6.52, population: 14.9, continent: "Africa"},
  %{city: "Moscow", lon: 37.62, lat: 55.76, population: 12.6, continent: "Europe"},
  %{city: "Paris", lon: 2.35, lat: 48.86, population: 11.1, continent: "Europe"},
  %{city: "Sydney", lon: 151.21, lat: -33.87, population: 5.0, continent: "Oceania"}
]

Tucan.layers([
  Tucan.Geo.basemap(:world_110m),
  Tucan.Geo.scatter(cities, "lon", "lat",
    size_by: "population",
    color_by: "continent",
    tooltip: true
  )
])
```

---

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