Get started with mapboxer: Mapbox GL JS for R

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.

Overview

  • 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.

Quickstart

# 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}}"
  )

Map

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.

Basemaps

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():

mapboxer(style = basemap_raster_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:

Sys.setenv(MAPBOX_API_TOKEN = "<yourSuperSecretToken>")

mapboxer(style = basemaps$Mapbox$satellite_v9)

Sources

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

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:

mapboxer(
  center = c(-73.9165, 40.7114),
  zoom = 9
) %>%
  add_circle_layer(
    source = as_mapbox_source(motor_vehicle_collisions_nyc),
    circle_color = "red",
    circle_radius = 5
  )

Popups and tooltips

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:

popup_template <- "Name: {{name}}</br>Population: {{population}}"

With add_tooltips() you can add tooltips to a layer in the same way.

Controls

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:

mapboxer() %>%
  add_navigation_control(
    pos = "top-left",
    # Option passed to the 'NavigationControl'
    showCompass = FALSE
) %>%
  add_scale_control(
    pos = "bottom-left",
    # Option passed to the 'ScaleControl'
    unit = "nautical"
) %>%
  add_text_control(
    pos = "top-right",
    text = "mapboxer"
  )

Expressions

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:

[expression_name, argument_0, argument_1, ...]

Therefore, in R you must use the list structure:

list(expression_name, argument_0, argument_1, ...)

If all elements are of the same type you can also use a vector:

expr_get_property <- c("get", "<data-property>")`

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.

Shiny Bindings

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.