---
title: "Introduction to rdeck"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to rdeck}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  out.width = "100%"
)
```

`{rdeck}` lets you use R to describe interactive WebGL maps built with Uber's
[deck.gl](https://deck.gl) framework and [mapbox](https://www.mapbox.com/)
base maps.

These maps can smoothly render data interactively on a much larger scale than html/svg
frameworks like Leaflet. Visually appealing 3D and lighting effects are also possible, thanks
to WebGL rendering.

`{rdeck}` maps consist of a basemap (requires a mapbox account) and 0 or more layers.
Basemaps are defined via the `rdeck(map_style)` parameter, which is any valid mapbox style
identifier, e.g. `"mapbox://styles/mapbox/dark-v10"`.  The basemap can be disabled with
`rdeck(map_style = NULL)`.

Layers are added to an `{rdeck}` map by calling one of the _add layer_ methods on an rdeck
instance. e.g. `rdeck() %>% add_scatterplot_layer()`. The order in which layers are added
determines their z-index; each layer added to the map will appear _on top_ of all previously
added layers.

Every layer can be created with their defaults, however layers without data are almost useless
as they will be empty. All layer arguments (other than `rdeck`) must be named.

Some examples follow.

# Packages

These packages are required for the following examples. With exception of `RcppSimdJson`, these
packages will be frequently used in creating `{rdeck}` maps.

```{r packages, message=FALSE}
library(rdeck)
library(dplyr)
library(sf)
library(viridis)
# loading deck.gl example data
library(RcppSimdJson)
```

# Loading example data

In this example, we create a simple scatterplot layer using the [manhattan example data](https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/scatterplot/manhattan.json)
from deck.gl. This data can be used directly from the URL, however this is not typical usage of
`{rdeck}`, so first we'll load this data into a data frame.


```{r manhattan-data}
url <- file.path(
  "https://raw.githubusercontent.com/visgl/deck.gl-data/master",
  "examples/scatterplot/manhattan.json",
  fsep = "/"
)
manhattan_data <- fload(url) %>%
  as_tibble(.name_repair = ~ c("lon", "lat", "species")) %>%
  mutate(
    position = sfc_point(lon, lat),
    species = as.factor(species),
    species_name = if_else(species == 1, "dog", "cat")
  )
```

The manhattan data we have loaded. Our scatterplot layer will make use of the `position` column
to define the centre of each rendered point, and the `species` column to change the point
colours and sizes. `lon` and `lat` aren't used in any of the layer parameters, so they won't
be serialised.

```{r echo=FALSE}
manhattan_data
```

# Scatterplot map

Here we create a simple scatterplot map with a dark vector basemap and `cividis()` colour scale
for the scatterplot layer.

The scatterplot points are _scaled_ by the `species` categories found in the data (which in this
dataset are `dog` and `cat`); this colour scale generates a categorical legend.

Point density is highlighted with `additive` blending, making dense areas appear brighter.

All points have the same radius of `30 metres`, with a minimum of `0.5 pixels` (to prevent them
from disappearing at low zooms).

Hovered points will become brighter --- by using a similar colour scale as `get_fill_color` --- and
will render a tooltip containing the `species` category from the data.

```{r scatterplot-map}
rdeck(
  map_style = mapbox_dark(),
  # set the bounds of the map to include all of the manhattan data
  initial_bounds = st_bbox(manhattan_data$position),
  # add a 2 pixel buffer to each point, making it easier to hover
  picking_radius = 2
) %>%
  add_scatterplot_layer(
    name = "manhattan_animals",
    data = manhattan_data,
    # the coloumn in manhattan_data which contains the location of each point
    get_position = position,
    # a categorical colour scale, using the species column and a cividis colour palette
    get_fill_color = scale_color_category(
      col = species,
      palette = cividis(2)
    ),
    # the radius of each point (default 1 metre) is scaled by 30
    radius_scale = 30,
    radius_min_pixels = 0.5,
    # highlight dot density
    blending_mode = "additive",
    # interactivity
    pickable = TRUE,
    auto_highlight = TRUE,
    # per-species highlight colour
    highlight_color = scale_color_category(
      col = species,
      palette = c("#0060e6", "#fff399"),
      legend = FALSE
    ),
    tooltip = c(species, species_name)
  )
```

# Grouping points

In the following example, we group all points by `species_name` so that we can highlight all points of
a given species at once.

```{r manhattan-data-grouped}
manhattan_data_grouped <- manhattan_data %>%
  group_by(species_name) %>%
  summarise(
    position = st_union(position),
    count = n(),
    .groups = "drop"
  )
```

Our grouped data:

```{r echo=FALSE}
manhattan_data_grouped
```

The following map is almost identical to the previous map, we have replaced the `data` parameter,
the scales to use the `species_name` and the `tooltip` to include the new column, `count`.

```{r scatterplot-map-grouped}
rdeck(
  map_style = mapbox_dark(),
  # set the bounds of the map to include all of the manhattan data
  initial_bounds = st_bbox(manhattan_data_grouped$position),
  # add a 2 pixel buffer to each point, making it easier to hover
  picking_radius = 2
) %>%
  add_scatterplot_layer(
    name = "manhattan_animals",
    data = manhattan_data_grouped,
    # the coloumn in manhattan_data which contains the location of each point
    get_position = position,
    # a categorical colour scale, using the species column and a cividis colour palette
    get_fill_color = scale_color_category(
      col = species_name,
      palette = cividis(2)
    ),
    # the radius of each point (default 1 metre) is scaled by 30
    radius_scale = 30,
    radius_min_pixels = 0.5,
    # highlight dot density
    blending_mode = "additive",
    # interactivity
    pickable = TRUE,
    auto_highlight = TRUE,
    # per-species highlight colour
    highlight_color = scale_color_category(
      col = species_name,
      palette = c("#0060e6", "#fff399"),
      legend = FALSE
    ),
    tooltip = everything()
  )
```

# Scaling additional parameters

We are able to scale many parameters on each layer. In the following example, we additionally scale
the radius by the count of `species_name`.

```{r scatterplot-map-grouped-2}
rdeck(
  map_style = mapbox_dark(),
  # set the bounds of the map to include all of the manhattan data
  initial_bounds = st_bbox(manhattan_data_grouped$position),
  # add a 2 pixel buffer to each point, making it easier to hover
  picking_radius = 2
) %>%
  add_scatterplot_layer(
    name = "manhattan_animals",
    data = manhattan_data_grouped,
    # the coloumn in manhattan_data which contains the location of each point
    get_position = position,
    # a categorical colour scale, using the species column and a cividis colour palette
    get_fill_color = scale_color_category(
      col = species_name,
      palette = cividis(2)
    ),
    # we only have 2 groups, so this scale is equivalent to a categorical scale with the
    # same parameters
    get_radius = scale_linear(
      col = count,
      range = sqrt(1:2)
    ),
    # the radius of each point is scaled by 30
    radius_scale = 30,
    radius_min_pixels = 0.5,
    # highlight dot density
    blending_mode = "additive",
    # interactivity
    pickable = TRUE,
    auto_highlight = TRUE,
    # per-species highlight colour
    highlight_color = scale_color_category(
      col = species_name,
      palette = c("#0060e6", "#fff399"),
      legend = FALSE
    ),
    tooltip = everything()
  )
```

# High-level layers

This example code is repetitive, copy-pasta that will inevitably result in maintenance problems,
as well as increased developer effort.

Generally when creating maps, we will encapsulate the creation of one or more layers in a function.
Similar to creating functions to encapsulate tidy-methods, the use of curly-curly is needed here
for any parameters that accept an `accessor` parameter.

The only rule in creating a layer function is that the function takes an rdeck map as a parameter
(typically first parameter) and that map must be returned; this makes the function chainable.

In the following example, we parameterise the data, fill palette, highlight palette, and
_get radius_ (which will require curl-curly) for our original scatterplot layer.

```{r layer-function}
add_manhattan_layer <- function(rdeck, manhattan_data,
                                fill_palette, highlight_palette, get_radius) {
  rdeck %>%
    add_scatterplot_layer(
      name = "manhattan_animals",
      data = manhattan_data,
      get_position = position,
      get_fill_color = scale_color_category(
        col = species_name,
        palette = fill_palette
      ),
      # we need curly-curly for get_radius
      get_radius = {{ get_radius }},
      radius_scale = 30,
      radius_min_pixels = 0.5,
      blending_mode = "additive",
      pickable = TRUE,
      auto_highlight = TRUE,
      highlight_color = scale_color_category(
        col = species_name,
        palette = highlight_palette,
        legend = FALSE
      ),
      tooltip = everything()
    )
}
```

Usage of our new function is like adding any other layer, just now that it is opinionated and
isn't limited to adding a single layer.

```{r layer-function-usage}
rdeck(
  map_style = mapbox_dark(),
  # set the bounds of the map to include all of the manhattan data
  initial_bounds = st_bbox(manhattan_data$position),
  # add a 2 pixel buffer to each point, making it easier to hover
  picking_radius = 2
) %>%
  add_manhattan_layer(
    manhattan_data = manhattan_data_grouped,
    fill_palette = viridis(2, alpha = 0.7),
    highlight_palette = viridis(2),
    get_radius = scale_category(
      col = species_name,
      # swap the levels order, dogs are now bigger
      levels = c("cat", "dog"),
      range = c(1, sqrt(3))
    )
  )
```
