A map visualization that displays data points on top of tile-based backgrounds such as OpenStreetMap, Stamen, or satellite imagery. Unlike vector-based basemaps, tile backgrounds provide rich geographic context including street-level detail, terrain, or satellite imagery that loads dynamically as the user navigates. This visualization is essential for location-based analysis where real-world geographic context enhances data interpretation.

#' anyplot.ai
#' map-tile-background: Map with Tile Background
#' Library: ggplot2 3.5.1 | R 4.4.1
#' Quality: 84/100 | Created: 2026-05-27
library(ggplot2)
library(ragg)
set.seed(42)
# Theme tokens
THEME <- Sys.getenv("ANYPLOT_THEME", "light")
PAGE_BG <- if (THEME == "light") "#FAF8F1" else "#1A1A17"
ELEVATED_BG <- if (THEME == "light") "#FFFDF6" else "#242420"
INK <- if (THEME == "light") "#1A1A17" else "#F0EFE8"
INK_SOFT <- if (THEME == "light") "#4A4A44" else "#B8B7B0"
# Map surface colors (visualization area, not chrome)
OCEAN_BG <- if (THEME == "light") "#D3E8F5" else "#1A2835"
LAND_FILL <- if (THEME == "light") "#E5DFC8" else "#2D2D25"
LAND_BORDER <- if (THEME == "light") "#B0A890" else "#4E4C40"
# Simplified continental outlines (approximate shapes for geographic context)
continents <- rbind(
data.frame(
lon = c(-165, -125, -117, -92, -83, -65, -66, -55, -55, -65, -80, -100, -132, -165),
lat = c( 65, 48, 32, 15, 8, 10, 45, 50, 55, 63, 65, 65, 60, 65),
group = "north_america"
),
data.frame(
lon = c( -80, -52, -35, -40, -50, -68, -72, -80, -80),
lat = c( 8, 5, -5, -22, -33, -55, -38, -3, 8),
group = "south_america"
),
data.frame(
lon = c( -9, -9, 3, 12, 22, 28, 30, 24, 18, 5, -3, -9),
lat = c( 36, 44, 52, 57, 62, 70, 60, 57, 55, 52, 44, 36),
group = "europe"
),
data.frame(
lon = c( 14, 16, 18, 20, 18, 16, 14, 12, 14),
lat = c( 56, 58, 63, 70, 71, 68, 63, 58, 56),
group = "scandinavia"
),
data.frame(
lon = c( -5, 15, 30, 42, 43, 40, 35, 28, 18, 10, -5, -17, -17, -5),
lat = c( 35, 37, 30, 22, 5, -3, -15, -30, -35, -35, -25, -5, 14, 35),
group = "africa"
),
data.frame(
lon = c( 26, 40, 60, 80, 100, 120, 135, 142, 140, 130, 120, 110, 100, 103, 85, 70, 55, 42, 36, 26),
lat = c( 38, 42, 45, 50, 55, 55, 50, 48, 40, 35, 22, 15, 5, 1, 8, 18, 22, 12, 30, 38),
group = "asia"
),
data.frame(
lon = c(114, 116, 125, 135, 145, 152, 152, 145, 135, 125, 114),
lat = c(-22, -35, -38, -36, -38, -35, -20, -15, -14, -20, -22),
group = "australia"
)
)
# 12 major cities with annual international visitor counts (millions)
cities <- data.frame(
city = c("New York", "London", "Paris", "Tokyo", "Dubai",
"Singapore", "Sydney", "Mumbai", "Sao Paulo", "Toronto",
"Cairo", "Mexico City"),
lon = c(-74.01, -0.13, 2.35, 139.69, 55.27,
103.82, 151.21, 72.88, -46.63, -79.38,
31.24, -99.13),
lat = c( 40.71, 51.51, 48.85, 35.69, 25.20,
1.35, -33.87, 19.08, -23.55, 43.65,
30.04, 19.43),
visitors_m = c(66.6, 19.1, 38.0, 14.2, 21.3,
19.8, 4.7, 10.5, 3.0, 3.1,
3.7, 4.4)
)
# Label the top 6 cities (>= 14M visitors); hand-tuned nudges to avoid overlap
label_cities <- cities[cities$visitors_m >= 14, ]
label_cities$nudge_x <- c(-9, -6, 5, 9, 8, 9)
label_cities$nudge_y <- c( 5, 6, 6, -6, 6, -6)
label_cities$hjust <- c( 1, 1, 0, 0, 0, 0)
title_str <- "Global City Tourism · map-tile-background · r · ggplot2 · anyplot.ai"
title_size <- max(8, round(12 * 67 / nchar(title_str)))
p <- ggplot() +
geom_polygon(
data = continents,
aes(x = lon, y = lat, group = group),
fill = LAND_FILL,
color = LAND_BORDER,
linewidth = 0.25
) +
geom_point(
data = cities,
aes(x = lon, y = lat, fill = visitors_m, size = visitors_m),
color = PAGE_BG,
shape = 21,
stroke = 0.5,
alpha = 0.9
) +
geom_text(
data = label_cities,
aes(x = lon + nudge_x, y = lat + nudge_y, label = city, hjust = hjust),
color = INK,
size = 2.6,
fontface = "bold"
) +
scale_fill_gradient(
low = "#009E73",
high = "#4467A3",
name = "Annual Visitors\n(millions)"
) +
scale_size_continuous(
range = c(3, 10),
guide = "none"
) +
coord_cartesian(
xlim = c(-160, 170),
ylim = c(-55, 80),
expand = FALSE
) +
labs(
title = title_str,
subtitle = "Top 6 destinations labelled · New York leads at 66.6M visitors/yr",
x = "Longitude",
y = "Latitude"
) +
theme_minimal(base_size = 8) +
theme(
plot.background = element_rect(fill = PAGE_BG, color = PAGE_BG),
panel.background = element_rect(fill = OCEAN_BG, color = NA),
panel.grid.major = element_line(color = INK_SOFT, linewidth = 0.12, linetype = "dotted"),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
axis.title = element_text(color = INK_SOFT, size = 10),
axis.text = element_text(color = INK_SOFT, size = 8),
plot.title = element_text(color = INK, size = title_size, face = "bold"),
plot.subtitle = element_text(color = INK_SOFT, size = 8),
legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT, linewidth = 0.3),
legend.text = element_text(color = INK_SOFT, size = 8),
legend.title = element_text(color = INK, size = 9),
legend.key = element_rect(fill = NA, color = NA),
plot.margin = unit(c(0.4, 0.4, 0.4, 0.4), "cm")
)
ggsave(
filename = sprintf("plot-%s.png", THEME),
plot = p,
device = ragg::agg_png,
width = 8,
height = 4.5,
units = "in",
dpi = 400
)
Part of Map with Tile Background on anyplot.ai.