mapgl wraps
Maplibre GL JS and Mapbox GL JS, giving you GPU-accelerated interactive
maps that render directly in the viewer or in knitted HTML. This
vignette shows how to map earthquake data with circle layers,
data-driven styling, and a heatmap.
Circle layer with data-driven styling
add_circle_layer() accepts Maplibre expressions
for any paint property. interpolate() builds a linear
interpolation expression that scales radius by magnitude and colors
circles by depth.
maplibre(
style = carto_style("dark-matter"),
center = c(-98, 38),
zoom = 2,
projection = "globe"
) |>
set_fog(
space_color = "#0a0a1a",
star_intensity = 0.3,
horizon_blend = 0.1
) |>
add_circle_layer(
id = "quakes",
source = quakes,
circle_radius = interpolate(
column = "mag",
type = "linear",
values = c(2.5, 5, 7),
stops = c(3, 8, 18)
),
circle_color = interpolate(
column = "depth",
type = "linear",
values = c(0, 50, 150, 300),
stops = c("#ffffb2", "#fecc5c", "#fd8d3c", "#bd0026")
),
circle_opacity = 0.75,
circle_stroke_color = "#ffffff",
circle_stroke_width = 0.5,
tooltip = "place",
popup = c("mag", "depth", "datetime")
) |>
add_continuous_legend(
legend_title = "Depth (km)",
values = c(0, 50, 150, 300),
colors = c("#ffffb2", "#fecc5c", "#fd8d3c", "#bd0026")
)Hover over a point for the location name; click for magnitude, depth, and time.
Heatmap
A heatmap shows overall seismicity density without the visual clutter of individual points. Weight each event by magnitude so larger quakes contribute more to the kernel.
maplibre(
style = carto_style("dark-matter"),
center = c(-98, 38),
zoom = 2,
projection = "globe"
) |>
set_fog(
space_color = "#0a0a1a",
star_intensity = 0.3,
horizon_blend = 0.1
) |>
add_heatmap_layer(
id = "quakes-heat",
source = quakes,
heatmap_weight = interpolate(
column = "mag",
type = "linear",
values = c(2.5, 7),
stops = c(0.1, 1)
),
heatmap_radius = 20,
heatmap_opacity = 0.85,
heatmap_color = list(
"interpolate",
list("linear"),
list("heatmap-density"),
0, "rgba(0,0,0,0)",
0.2, "#4575b4",
0.4, "#74add1",
0.6, "#fee090",
0.8, "#f46d43",
1, "#d73027"
)
)Filtering by magnitude
Use filter to show only the largest events — useful as
an overlay on the heatmap to highlight notable earthquakes without
redrawing the source.
maplibre(
style = carto_style("dark-matter"),
center = c(-98, 38),
zoom = 2,
projection = "globe"
) |>
set_fog(
space_color = "#0a0a1a",
star_intensity = 0.3,
horizon_blend = 0.1
) |>
add_heatmap_layer(
id = "quakes-heat",
source = quakes,
heatmap_weight = interpolate(
column = "mag",
type = "linear",
values = c(2.5, 7),
stops = c(0.1, 1)
),
heatmap_radius = 20,
heatmap_opacity = 0.8
) |>
add_circle_layer(
id = "quakes-m4plus",
source = quakes,
filter = list(">=" , "mag", 4),
circle_radius = interpolate(
column = "mag",
type = "linear",
values = c(4, 7),
stops = c(5, 20)
),
circle_color = "#bd0026",
circle_opacity = 0.8,
circle_stroke_color = "#ffffff",
circle_stroke_width = 1,
tooltip = "place",
popup = c("mag", "depth", "datetime")
)Global seismicity — last 7 days
Pull the full global extent by overriding the default US bounding box. M2.5+ worldwide over a week typically returns 1,000–2,000 events, well within the 20,000-event cap.
quakes_global <- get_quakes(
start_time = Sys.time() - 7 * 86400,
end_time = Sys.time(),
min_mag = 2.5,
min_lat = -90, max_lat = 90,
min_lng = -180, max_lng = 180
) |>
mutate(datetime = as.POSIXct(time / 1000, origin = "1970-01-01", tz = "UTC"))The globe spins automatically on load — drag to take control, and it stops.
library(htmlwidgets)
maplibre(
style = carto_style("dark-matter"),
center = c(0, 20),
zoom = 1.8,
projection = "globe"
) |>
set_fog(
space_color = "#0a0a1a",
star_intensity = 0.3,
horizon_blend = 0.1
) |>
add_circle_layer(
id = "quakes-global",
source = quakes_global,
circle_radius = interpolate(
column = "mag",
type = "linear",
values = c(2.5, 5, 7),
stops = c(2, 6, 16)
),
circle_color = interpolate(
column = "depth",
type = "linear",
values = c(0, 70, 300, 700),
stops = c("#ffffb2", "#fecc5c", "#fd8d3c", "#bd0026")
),
circle_opacity = 0.8,
circle_stroke_color = "#ffffff",
circle_stroke_width = 0.4,
tooltip = "place",
popup = c("mag", "depth", "datetime")
) |>
add_continuous_legend(
legend_title = "Depth (km)",
values = c(0, 70, 300, 700),
colors = c("#ffffb2", "#fecc5c", "#fd8d3c", "#bd0026")
) |>
onRender("
function(el) {
var map = el.map;
var spinning = true;
function spin() {
if (!spinning) return;
var center = map.getCenter();
center.lng -= 0.05;
map.setCenter(center);
requestAnimationFrame(spin);
}
map.on('load', spin);
map.on('mousedown', function() { spinning = false; });
map.on('touchstart', function() { spinning = false; });
}
")