Skip to content

Feature request: add a generic function that mimics mapview::mapview() #57

@atsyplenkov

Description

@atsyplenkov

Hi Kyle 👋

Could you please consider adding a function similar to what mapview::mapview() does? I.e., a generic one that takes an sf/sfc object and plots it depending on the geometry. For example, I foresee it to be something like the following.

I am interested because sometimes I just want to visually inspect the geometry, but I found mapview a bit slow. And mapgl is so responsive!

If you like the approach, I am more than happy to create a PR. It can be scaled for terra support.

library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.3.1; sf_use_s2() is TRUE
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(mapgl)

mapglview <- function(
    x,
    fill_color = "#1f77b4",
    fill_opacity = 0.7,
    line_color = "#000000",
    line_width = 1,
    circle_radius = 6,
    circle_color = "#1f77b4",
    circle_opacity = 0.7,
    popup = NULL,
    ...) {
  # Get all attribute names if popup is NULL
  if (is.null(popup)) {
    popup <- names(x)[!names(x) %in% attr(x, "sf_column")]
  }

  # Create formatted popup content
  popup_template <- paste(
    sprintf("<strong>%s: </strong>{%s}", popup, popup),
    collapse = "<br>"
  )

  # Create popup for each feature
  x$popup_info <- apply(sf::st_drop_geometry(x[popup]), 1, function(row) {
    glue::glue(popup_template, .envir = as.list(row))
  })

  # Initialize map centered on data
  m <- maplibre(bounds = x, ...)

  # Add source
  m <- add_source(m, "data", x)

  # Determine geometry type
  geom_type <- sf::st_geometry_type(x, by_geometry = FALSE)

  # Add appropriate layers based on geometry type
  if (grepl("POLYGON", geom_type)) {
    m <- m %>%
      add_fill_layer(
        id = "data_fill",
        source = "data",
        fill_color = fill_color,
        fill_opacity = fill_opacity,
        popup = "popup_info"
      ) %>%
      add_line_layer(
        id = "data_line",
        source = "data",
        line_color = line_color,
        line_width = line_width
      )
  } else if (grepl("LINE", geom_type)) {
    m <- m %>%
      add_line_layer(
        id = "data_line",
        source = "data",
        line_color = line_color,
        line_width = line_width,
        popup = "popup_info"
      )
  } else if (grepl("POINT", geom_type)) {
    m <- m %>%
      add_circle_layer(
        id = "data_point",
        source = "data",
        circle_color = circle_color,
        circle_opacity = circle_opacity,
        circle_radius = circle_radius,
        popup = "popup_info"
      )
  }

  # Add navigation control
  m <- add_navigation_control(m)

  return(m)
}

# Set seed for reproducibility
set.seed(1234)

# Define the bounding box for Washington DC (approximately)
bbox <- st_bbox(
  c(
    xmin = -77.119759,
    ymin = 38.791645,
    xmax = -76.909393,
    ymax = 38.995548
  ),
  crs = st_crs(4326)
)

# Generate 30 random points within the bounding box
random_points <- st_as_sf(
  data.frame(
    id = 1:30,
    lon = runif(30, bbox["xmin"], bbox["xmax"]),
    lat = runif(30, bbox["ymin"], bbox["ymax"])
  ),
  coords = c("lon", "lat"),
  crs = 4326
)

# Assign random categories
categories <- c("music", "bar", "theatre", "bicycle")
random_points <- random_points %>%
  mutate(category = sample(categories, n(), replace = TRUE))

polygons <- sf::read_sf(system.file("shape/nc.shp", package = "sf"))

# mapglview(polygons)
# mapglview(random_points)

Positron_kjfaDlQTaP

Created on 2024-11-13 with reprex v2.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions