Why glmap?
-
One-Line Magic: Give
glmap()almost any spatial object in R (points, polygons, or aterraraster grid) and it figures out how to draw it automatically. -
No More Color Functions: In
leaflet, you had to build a separatepal <- colorNumeric(…)function and manually wire up a legend. Inglmap, you just writecolor = ~my_column, palette = “viridis”and both the colors and legend appear automatically. -
Instant Raster Sliders: When you plot a
terraraster,glmapsends the actual numbers to your graphics card. You can flip between palettes or turn on 3D hillshade shadows in the browser in 0 milliseconds without waiting for R!
⚙️ Technical Mode (C++17 + WebGL2
Pipeline)
Traditional R mapping packages built on
Leaflet.js serialize spatial objects into GeoJSON text
inside HTML and draw features using DOM/SVG/2D Canvas. When your dataset
reaches 100,000 to 1,000,000+ features or uses high-resolution
terra rasters, R spends tens of seconds converting
coordinates to text and the browser tab freezes.glmap eliminates the JSON and DOM bottlenecks entirely via
C++17 GLMP/GLMR binary buffers, C++
mapbox/earcut.h polygon triangulation, and WebGL2 instanced
SDF & RGBA32F floating-point raster fragment
shaders.
1. Instant One-Line Exploration
glmap() inspects your input (sf,
sfc, terra::SpatRaster,
terra::SpatVector, wk::xy,
nanoarrow, data.frame, or
crosstalk::SharedData) and automatically chooses the right
GPU layer:
library(glmap)
# Generate synthetic benchmark data
bench <- gl_benchmark_data(n_points = 100000L, n_polygons = 2000L)
# Instant GPU map of 100,000 points
glmap(bench$points_df, color = ~intensity, palette = "turbo", radius = 3)
# Instant GPU map of a Float32 DEM raster with real-time hillshading
glmap(bench$raster_mat, palette = "terrain", hillshade = TRUE)2. Building Multi-Layer GPU Maps with Pipes
(|>)
Use glmap() with add_raster(),
add_polygons(), add_lines(),
add_points(), add_hexbin(),
add_heatmap(), and add_labels():
glmap(basemap = "dark") |>
add_raster(
bench$raster_mat,
palette = "terrain",
hillshade = TRUE,
opacity = 0.65,
group = "Terrain DEM (Float32)"
) |>
add_polygons(
bench$polygons_sf,
fill_color = ~elevation,
palette = "viridis",
fill_opacity = 0.65,
group = "Polygons (C++ Earcut)"
) |>
add_hexbin(
bench$points_df,
hex_radius = 0.035,
palette = "plasma",
opacity = 0.75,
group = "Hexbins (C++ 64-bit Hash)"
) |>
add_points(
bench$points_df,
color = ~intensity,
palette = "turbo",
radius = 3.0,
opacity = 0.85,
group = "Points (WebGL2 SDF)"
) |>
use_plugin("export_png")3. Handling 1M–10M+ Features with In-Memory C++ Spatial Indexing or DuckDB
For massive datasets in interactive R or Shiny sessions, enable
dynamic_viewport = TRUE, transport = "server",
or add_duckdb(). glmap builds an in-memory C++
spatial index (gl_spatial_index()) or queries DuckDB to
stream only the features inside the current viewport with automatic
Level-of-Detail (LOD) stride sampling:
big_df <- data.frame(
lon = runif(1e6, -75, -71),
lat = runif(1e6, 45, 48),
val = rnorm(1e6)
)
glmap(basemap = "dark", transport = "server") |>
add_points(
big_df,
color = ~val,
palette = "viridis",
radius = 2.5,
dynamic_viewport = TRUE
)