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 framework and mapbox
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.
These packages are required for the following examples. With exception of RcppSimdJson
, these
packages will be frequently used in creating {rdeck}
maps.
library(rdeck) library(dplyr) library(sf) library(viridis) # loading deck.gl example data library(RcppSimdJson)
In this example, we create a simple scatterplot layer using the manhattan example data
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.
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.
manhattan_data
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.
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) )
In the following example, we group all points by species_name
so that we can highlight all points of
a given species at once.
manhattan_data_grouped <- manhattan_data %>% group_by(species_name) %>% summarise( position = st_union(position), count = n(), .groups = "drop" )
Our grouped data:
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
.
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() )
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
.
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() )
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.
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.
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)) ) )
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.