Skip to contents

Example

The following example shows how to create an interactive leaflet map with data retrieved using nominatimlite.

The widget can be browsed and filtered with crosstalk and reactable:

# Coffee shops and restaurants around the Eiffel Tower.

library(nominatimlite)
library(sf)
library(leaflet)
library(dplyr)
library(tidyr)
library(reactable)
library(crosstalk)

# Step 1: Eiffel Tower.
eiffel_tower <- geo_lite_sf(
  "Eiffel Tower, Paris, France",
  points_only = FALSE,
  progressbar = FALSE
)

# Step 2: Coffee shops and restaurants nearby.

# Create a buffer of 1 km around the Eiffel Tower.
buff <- eiffel_tower |>
  st_transform(3857) |>
  st_centroid() |>
  st_buffer(1000)

cf_bk <- geo_amenity_sf(
  buff,
  amenity = c("cafe", "restaurant"),
  limit = 50,
  full_results = TRUE,
  custom_query = list(extratags = TRUE),
  progressbar = FALSE
) |>
  # Build addresses with street, house number, suburb and postcode.
  unite(
    "addr",
    address.road,
    address.house_number,
    address.postcode,
    address.suburb,
    sep = ", ",
    na.rm = TRUE
  )

# Create labels and icons.
labs <- paste0("<strong>", cf_bk$name, "</strong><br>", cf_bk$addr)

# Base URL for icons.
icon_url <- paste0(
  "https://raw.githubusercontent.com/dieghernan/arcgeocoder/",
  "main/vignettes/articles/"
)

leaf_icons <- icons(
  ifelse(
    cf_bk$type == "cafe",
    paste0(icon_url, "coffee-cup.png"),
    paste0(icon_url, "restaurant.png")
  ),
  iconWidth = 20,
  iconHeight = 20,
  iconAnchorX = 10,
  iconAnchorY = 10
)

# Step 3: Create a crosstalk object.
cf_bk_data <- cf_bk |>
  select(
    Place = name,
    Type = type,
    Address = addr,
    City = address.city,
    URL = extratags.website,
    Phone = extratags.phone
  ) |>
  SharedData$new(group = "Food")

# Step 4: Create a leaflet map with crosstalk.
lmend <- leaflet(
  data = cf_bk_data,
  elementId = "EiffelTower",
  width = "100%",
  height = "60vh",
  options = leafletOptions(minZoom = 12)
) |>
  addProviderTiles(
    provider = "CartoDB.Positron",
    group = "CartoDB.Positron"
  ) |>
  addTiles(group = "OSM") |>
  addPolygons(data = eiffel_tower) |>
  addMarkers(popup = labs, icon = leaf_icons) |>
  addLayersControl(
    baseGroups = c("CartoDB.Positron", "OSM"),
    position = "topleft",
    options = layersControlOptions(collapsed = FALSE)
  )

# Step 5: Create a reactable table for filtering.
tb <- reactable(
  cf_bk_data,
  selection = "multiple",
  onClick = "select",
  rowStyle = list(cursor = "pointer"),
  filterable = TRUE,
  searchable = TRUE,
  showPageSizeOptions = TRUE,
  striped = TRUE,
  defaultColDef = colDef(vAlign = "center", minWidth = 150),
  paginationType = "jump",
  elementId = "coffees",
  columns = list(
    Place = colDef(
      sticky = "left",
      rowHeader = TRUE,
      name = "",
      cell = function(value) {
        htmltools::strong(value)
      }
    ),
    URL = colDef(cell = function(value) {
      # Render as a link.
      if (any(is.null(value), is.na(value))) {
        return("")
      }
      htmltools::a(href = value, target = "_blank", as.character(value))
    }),
    Phone = colDef(cell = function(value) {
      # Render as a link.
      if (any(is.null(value), is.na(value))) {
        return("")
      }
      clearphone <- gsub("-", "", value)
      clearphone <- gsub(" ", "", clearphone)
      htmltools::a(
        href = paste0("tel:", clearphone),
        target = "_blank",
        as.character(value)
      )
    })
  )
)

Widget

# Display all widgets.
htmltools::browsable(
  htmltools::tagList(lmend, tb)
)

Attributions