The goal of mapboxer is to make it easy to create interactive maps using Mapbox GL JS within R. Visualizations can be used at the R console, embedded in R Markdown documents or Shiny apps.
This guide covers the basic usage.
Map:
The map is the main component of your visualization to which you then
add other components like layers, controls or sources. Maps are created
with mapboxer()
.
Sources:
Sources state which type of data should be displayed on the map. R
objects can be converted to Mapbox sources with
as_mapbox_source()
. With add_source()
or as
first parameter of mapboxer()
sources can be added to the
map so that they can be used accross layers.
Layers:
A layer’s style define how a source is displayed on the map.
Furthermore, you can apply filters to the data of a source. With
add_layer()
you can add any type of layer to the map but in
most cases it is easier to use one of the shortcuts like
add_circle_layer()
.
Controls:
Controls are used to interact with the map. Besides the standard
controls like NavigationControl
included in Mapbox GL JS,
mapboxer provides additional controls. For example,
add_filter_control()
can be used to filter your data on the
fly without having to set up a Shiny app.
Expressions: Expressions are pretty powerful. Among other things, they can be used for data-driven-styling or to filter your data.
Shiny Bindings: With
renderMapboxer()
and mapboxerOutput()
you can
integrate your visualizations in Shiny apps. Furthermore, you can use
mapboxer_proxy()
and update_mapboxer()
to
update an already rendered widget. Observe the
input$<widget_id>_onclick
event to get the properties
for a clicked feature.
# Load the library
library(mapboxer)
# Create a source
motor_vehicle_collisions_nyc %>%
dplyr::mutate(color = ifelse(injured > 0, "red", "yellow")) %>%
as_mapbox_source(lng = "lng", lat = "lat") %>%
# Setup a map with the default source above
mapboxer(
center = c(-73.9165, 40.7114),
zoom = 10
) %>%
# Add a navigation control
add_navigation_control() %>%
# Add a layer styling the data of the default source
add_circle_layer(
circle_color = c("get", "color"),
circle_radius = 3,
# Use a mustache template to add popups to the layer
popup = "Number of persons injured: {{injured}}"
)
With mapboxer()
you create a map object. This is the
main component of your vizualization. To add components like layers or
controls or to modify your map you use the add_*
and
set_*
functions. The options to configure your map are set
via the ...
parameter that allows you to pass on any option
described in the Map API
Reference:
mapboxer(
style = basemaps$Carto$dark_matter,
center = c(-73.9165, 40.7114),
zoom = 9,
minZoom = 8
)
With the optional source
parameter you can add a default
source to the map that will be used by the layers if no source is
provided. Therefore, it is easy to integrate mapboxer()
into your workflow:
motor_vehicle_collisions_nyc %>%
dplyr::filter(killed > 0) %>%
as_mapbox_source() %>%
mapboxer(
center = c(-73.9165, 40.7114),
zoom = 9
) %>%
add_circle_layer(circle_color = "red")
As you can see above mapboxer is designed to use the widely used piping style provided by magrittr.
The style
parameter passed to mapboxer()
sets the style of the basemap. By default mapboxer uses a Carto vector style.
It is also possible to use raster tiles or a background color as
basemap. Therefore, you can use the helpers
basemap_raster_style()
or
basemap_background_style()
:
To use styles from Mapbox
it is recommened that your store your API token in an environment
variable called MAPBOX_API_TOKEN
. If not set globally you
can store it as follows:
Sources state which data the map should display. To show the data on
the map you need to bind a source to a layer which contains the styling
details like color or width. This makes it possible to style the same
source in different ways. The easiest way to create a source from an R
data object is to use as_mapbox_source()
. Supported
structures are sf-objects and data
frames that contain longitudes and latitudes:
mvc_sf <- motor_vehicle_collisions_nyc %>%
sf::st_as_sf(coords = c("lng", "lat"), crs = 4326)
mvc_source_from_sf <- mvc_sf %>%
as_mapbox_source()
mvc_source_from_df <- motor_vehicle_collisions_nyc %>%
as_mapbox_source(lng = "lng", lat = "lat")
With the ...
parameter you can pass additional options
to the source:
mvc_cluster <- motor_vehicle_collisions_nyc %>%
as_mapbox_source(
lat = "lat",
lng = "lng",
cluster = TRUE,
clusterMaxZoom = 14,
clusterRadius = 50
)
See the Sources
API Reference for available options for the used source type.
Sources are either passed to the add_*_layer
functions or
as first parameter to mapboxer()
setting it as default
source. With add_source()
you can add a source to the map
that you refer to in the layer definition by its ID.
Layers style the data of the source to which they refer. Optionally
you can filter features. Each layer must have a unique ID. If you use
the generic function add_layer()
, the type of the layer is
specified by the type
property. See the Layers
API Reference for available types. In most cases it is convenient to
use one of the add_*_layer()
functions:
Usually popups are added to a layer with the popup
parameter of the add_*_layer()
functions. Optionally you
can also use add_popups()
. The popup text (HTML) is
specified by a mustache template in
which the tags refer to the properties of the layer’s data object. If
your data contains the properties name
and
population
, it could look like this:
With add_tooltips()
you can add tooltips to a layer in
the same way.
Controls are used to interact with the user. They are displayed as
overlays on top of the map. Options of the standard controls described
in the Markers and
Controls API Reference are provided with the ...
parameter. The position is set with the pos
parameter, one
of top-left
, top-right
,
bottom-right
, bottom-left
:
The value of any layout property, paint property (data-driven-styling) or filter may be specified as an expression. Expressions in Mapbox GL JS use a Lisp-like syntax represented as JSON arrays:
Therefore, in R you must use the list
structure:
If all elements are of the same type you can also use a vector:
A simple expression is to use a data property to style your data:
map <- motor_vehicle_collisions_nyc %>%
dplyr::mutate(
color = ifelse(injured > 0, "red", "yellow")
) %>%
as_mapbox_source() %>%
mapboxer(
center = c(-73.9165, 40.7114),
zoom = 9
)
map %>%
add_circle_layer(
# Expression to get the color from the data's color property
circle_color = c("get", "color")
)
You can get the same result for the circle_color
without
modifying the data but using expressions only:
map %>%
add_circle_layer(
circle_color = list(
"case",
# 'red' if 'injured > 0'
list(">", c("get", "injured"), 0), "red",
# Defaults to 'yellow'
"yellow"
)
)
A filter could look like this:
map %>%
add_circle_layer(
circle_color = c("get", "color"),
# Expression to display only data where 'injured > 1'
filter = list(">", "injured", 1)
)
See also add_filter_control()
to modify filter
expressions on the fly to update your map without the need of a Shiny
app, Get
started with expressions for a tutorial and the Expressions
Style Specification for details.
Use mapboxerOutput()
and renderMapboxer()
to integrate mapboxer in a Shiny app:
library(shiny)
library(mapboxer)
view <- fluidPage(
h1("mapboxer"),
mapboxerOutput("map")
)
backend <- function(input, output) {
output$map <- renderMapboxer({
mapboxer(center = c(9.5, 51.3), zoom = 10) %>%
add_navigation_control() %>%
add_marker(lng = 9.5, lat = 51.3, popup = "mapboxer")
})
}
if (interactive()) shinyApp(view, backend)
With mapboxer_proxy()
and update_mapboxer()
you can update your already rendered map:
LAYER_ID <- "crashes"
START_VALUE <- 4
view <- basicPage(
sliderInput("slider", "Number of persons injured:",
min = 0, max = 7, step = 1, value = START_VALUE),
mapboxerOutput("map")
)
backend <- function(input, output) {
output$map <- renderMapboxer({
mapboxer(
center = c(-73.9165, 40.7114),
zoom = 9
) %>%
add_circle_layer(
source = as_mapbox_source(motor_vehicle_collisions_nyc),
circle_color = "red",
popup = "{{injured}}",
filter = list("==", "injured", START_VALUE),
id = LAYER_ID
)
})
observeEvent(input$slider, {
mapboxer_proxy("map") %>%
set_filter(LAYER_ID, list("==", "injured", input$slider)) %>%
update_mapboxer()
})
}
if (interactive()) shinyApp(view, backend)
Observe the input$<widget_id>_onclick
event to get
the properties for a clicked feature.