The r-deckgl package makes the open-source JavaScript library deck.gl available within R via the htmlwidgets package.
install.packages("deckgl")
You can install the latest version of r-deckgl from github with:
# install.packages("remotes")
remotes::install_github("crazycapivara/deckgl")
library(deckgl)
Create a deckgl
instance:
deckgl()
Add a basemap:
deckgl() %>%
add_basemap()
Add any kind of layers:
# Grid layer example
data("sf_bike_parking")
props <- list(
extruded = TRUE,
cellSize = 200,
elevationScale = 4,
getPosition = ~lng + lat,
tooltip = "Count: {{count}}"
)
deckgl(zoom = 11, pitch = 45) %>%
add_basemap() %>%
add_grid_layer(
data = sf_bike_parking,
properties = props
)
deckgl
InstanceThe deckgl
function creates the widget / renderer to which you add
layers and other configuration parameters:
rdeck <- deckgl(
latitude = 37.8,
longitude = -122.45,
zoom = 12
) %>%
add_grid_layer(
data = data,
properties = props
)
Due to the generic function add_layer
any kind of layer defined in the
deck.gl Layer
Catalog
is supported. The layer type is chosen via the class_name
parameter,
e. g. ScatterplotLayer
or GeoJsonLayer
. Usually you will not use the
generic function but one of the add_*_layer
shortcuts instead:
# Generic function
deckgl() %>%
add_layer("ArcLayer", id, data, properties)
# Shortcut function
deckgl() %>%
add_arc_layer(id, data, properties)
The data
parameter can either be an url to fetch data from or a data
object. In most cases you will pass an object of type data.frame
to
the layers. Use the formula syntax to define data accessors that deck.gl
uses to access the properties of the data object:
props <- list(
getPosition = ~lng + lat
# ...
)
sf
Data ObjectsAn object of class sf is a
data.frame
with a geometry list-column. Set the layer prop that
fetches the geometry to the geometry list-column of your sf
object:
# Example: PolygonLayer
props <- list(
getPolygon = ~geometry
# ...
)
With add_source
you can add a source to the widget that can be used
accross layers:
data("bart_stations")
deckgl() %>%
add_source("bart-stations", bart_stations) %>%
add_scatterplot_layer(
source = "bart-stations",
getPosition = ~lng + lat,
# ...
) %>%
add_text_layer(
source = "bart-stations",
getPosition = ~lng + lat,
# ...
) %>%
add_basemap()
Please note that you use the parameter source
instead of data
.
Layer properties are passed to the add_*_layer
functions either as
named list by the properties
argument or as named parameters / keyword
arguments via the ...
parameter. The names correspond to the
properties of the deck.gl counterparts. Therefore, please see the
deck.gl Layer
Catalog
to determine the available parameters for the used layer. You can also
pass a props list and keyword arguments together. Identical properties
are overwritten by the latter ones.
Grid Layer example:
// JavaScript code
const layer = new GridLayer({
id: "grid-layer",
data: data,
extruded: true,
cellSize: 200,
elevationScale: 4,
getPosition: d => [d.lng, d.lat]
});
# Corresponding R code
# using named arguments
deck <- deckgl() %>%
add_grid_layer(
id = "grid-layer",
data = data,
extruded = TRUE,
cellSize = 200,
elevationScale = 4,
getPosition = ~lng + lat
)
# ... using a named props list
props <- list(
cellSize = 200,
extruded = TRUE,
# ...
)
deckgl() %>%
add_grid_layer(
data = data,
properties = props
)
According to the style conventions in R, camelCased
parameters in
deck.gl can also be passed as snake_cased
parameters in R. For
example, getPosition
can be passed to deck.gl as get_position
:
deckgl() %>%
add_grid_layer(
get_position = ~lng + lat,
cell_size = 200,
# ...
)
Use the formula syntax to define data accessors:
props <- list(
getPosition = ~lng + lat # js: d => [d.lng, d.lat]
getFillColor = ~color # js: d => d.color
# ...
)
The example above assumes that your data contains the columns lng
,
lat
and color
.
It is also possible to pass JavaScript code by using the JS
function
in R:
props <- list(
getColor = JS("d => d.capital ? [140, 10, 10] : [60, 10, 10]")
# ...
)
In deck.gl colors are represented by [r, g, b, a]
arrays. In R you can
pass hex color codes or color names to all color props of the
add_*_layer
functions. They are automatically converted to the
required format:
deckgl() %>%
add_grid_layer(
colorRange = RColorBrewer::brewer.pal(6, "Blues"),
# ...
)
The tooltip for a layer can be set via the tooltip
parameter. You can
either pass a single template string or a list with the following
properties (see also use_tooltip
):
html
: A template string that will be set as the innerHTML
of the
tooltip.style
: A cssText
string that will modefiy the default style of
the tooltip.The tooltip string is a so called “mustache” template in which variable names are identified by the double curly brackets that surround them. The variable names available to the template are given by deck.gl’s pickingInfo.object and vary by layer.
Arc Layer example:
data("bart_segments")
props <- list(
getWidth = 12,
getSourcePosition = ~from_lng + from_lat,
getTargetPosition = ~to_lng + to_lat,
getSourceColor = "yellow",
getTargetColor = "orange",
tooltip = use_tooltip(
html = "{{from_name}} to {{to_name}}",
style = "background: steelBlue; border-radius: 5px;"
)
)
deckgl(zoom = 9.5, pitch = 35) %>%
add_arc_layer(data = bart_segments, properties = props) %>%
add_basemap()
See mustache.js for a complete syntax overwiew.
Controls are displayed as overlays on top of the map / deck. Usually you can set the position and the style of the control. The most basic control is a simple text box:
deckgl() %>%
add_basemap() %>%
add_control(
html = "Plain Base Map",
pos = "top-right",
style = "background: steelblue; color: white"
)
You can add an instance of the ace editor in JSON
mode to the map by using add_json_editor
:
deckgl() %>%
add_grid_layer(
# ...
) %>%
add_json_editor()
This allows you to change your layer props on the fly. You can toggle the visibility of the editor by pressing “e”.
With add_legend
you can add a custom legend to your widget:
deckgl() %>%
add_basemap() %>%
add_legend(
colors = c("yellow", "orange"),
labels = c("Cake", "Icecream"),
title = "Sweets"
)
In most cases, you will create the legend automatically using a palette function:
data_column <- 1:10
pal <- scales::col_bin("Blues", data_column, bins = 5)
deckgl() %>%
add_basemap() %>%
add_legend_pal(pal, title = "Blues")
By default, add_basemap
adds a carto
basemap
to the widget.
To use basemaps from mapbox it is
recommended that you store your API access token in an environment
variable called MAPBOX_API_TOKEN
:
# If not set globally
#Sys.setenv(MAPBOX_API_TOKEN = "xyz")
deckgl() %>%
add_mapbox_basemap("mapbox://styles/mapbox/light-v9")
You can run the API
examples
from the add_*_layer
functions with example(add_*_layer)
:
example(add_grid_layer)
With the renderDeckgl
and deckglOutput
functions you can use
r-deckgl in shiny applications:
library(shiny)
library(deckgl)
backend <- function(input, output) {
output$rdeck <- renderDeckgl({
deckgl() %>%
add_grid_layer(
data = sf_bike_parking,
getPosition = ~lng + lat,
cellSize = 400,
pickable = TRUE
) %>%
add_basemap()
})
}
frontend <- fluidPage(
deckglOutput("rdeck")
)
shinyApp(frontend, backend)
To update a deckgl
instance use deckgl_proxy
in combination with
update_deckgl
.
Furthermore, the onclick
event sends deck.gl’s picking info
object
to your shiny application and updates the corresponding input in the
form of input$widget_id_onclick
. For example, if the widget id is
rdeck
, you can access the pickingInfo
object with
input$rdeck_onclick
:
backend < -function(input, output) {
# ...
observeEvent(input$rdeck_onclick, {
info <- input$rdeck_onclick
print(info$object)
})
}
The JavaScript library of r-deckgl uses
webpack as module bundler. Therefore, you
need node.js to build the module. All JavaScript
code is located in the javascript/src
folder and test components go to
javascript/src/test-components
.
Install deps and build the library from inside the javascript
folder
with:
npm install
npm run build
To spin up the webpack-dev-server run:
npm run start
If the deckgl
widget is not visible in the viewer pane of RStudio,
just open it in your browser by clicking “Show in new window” and
everything will be fine.