install.packages("mapSpain", dependencies = TRUE)Welcome to mapSpain
Motivation
mapSpain helps you create maps for the main administrative levels of Spain. It also supports imagery from WMS and WMTS services, either as georeferenced static rasters or as dynamic layers in Leaflet maps.
The package also includes helpers to normalize Autonomous Community and province names. These helpers make it easier to join, clean and transform data, whether or not the data is spatial.
The main data sources used by mapSpain are:
- GISCO (Eurostat), through the giscoR package.
- Instituto Geográfico Nacional (IGN).
- Spanish public institutions that publish WMTS and WMS tile services (https://www.idee.es/web/idee/segun-tipo-de-servicio).
The returned objects are sf objects from the sf package or SpatRaster objects from the terra package.
Package website: https://ropenspain.github.io/mapSpain/.
Installation
CRAN
Development version
Use r-universe:
# Enable this universe.
install.packages(
"mapSpain",
repos = c(
"https://ropenspain.r-universe.dev",
"https://cloud.r-project.org"
),
dependencies = TRUE
)Installation with pak from GitHub
install.packages("pak")
pak::pak("rOpenSpain/mapSpain", dependencies = TRUE)A quick example
library(mapSpain)
library(tidyverse)
galicia <- esp_get_munic_siane(region = "Galicia") |>
# Standardize labels.
mutate(Provincia = esp_dict_translate(ine.prov.name, "es"))
ggplot(galicia) +
geom_sf(aes(fill = Provincia), color = "grey70") +
labs(title = "Provinces of Galicia") +
scale_fill_discrete(type = hcl.colors(4, "Blues")) +
theme_bw()
You can also inspect the dataset interactively:
Comparing mapSpain with other alternatives
The next example compares mapSpain with other packages that provide sf or SpatVector objects for country boundaries:
library(sf) # Spatial data manipulation.
# rnaturalearth
library(rnaturalearth)
esp_rnat <- ne_countries("large", country = "Spain", returnclass = "sf") |>
st_transform(3857)
# mapSpain
esp_mapspain <- esp_get_spain(epsg = 4326) |>
st_transform(3857)
# geodata (GADM)
library(geodata)
esp_geodata <- geodata::gadm("ES", path = ".", level = 0) |>
# Convert from SpatVector to an sf object.
sf::st_as_sf() |>
st_transform(3857)
# geobounds
library(geobounds)
esp_geobounds <- geobounds::gb_get_adm0("ESP", cache_dir = ".") |>
st_transform(3857)
# Image of the Ferrol estuary.
tile <- esp_get_munic_siane(munic = "Ferrol", epsg = 3857) |>
esp_get_tiles("PNOA", bbox_expand = 0.5, zoommin = 1)
# Prepare the plot.
library(tidyterra)
esp_all <- bind_rows(esp_rnat, esp_mapspain, esp_geodata, esp_geobounds)
esp_all$source <- as_factor(c(
"rnaturalearth",
"mapSpain",
"geodata (GADM)",
"geoBoundaries"
))
ggplot(esp_all) +
geom_spatraster_rgb(data = tile, maxcell = Inf, alpha = 0.5) +
geom_sf(
aes(color = source, linetype = source),
fill = NA,
show.legend = "line",
linewidth = 0.5,
alpha = 0.7
) +
coord_sf(
crs = 4326,
xlim = c(-8.384421, -8.154413),
ylim = c(43.43201, 43.59545),
expand = FALSE
) +
scale_color_manual(values = c("red", "black", "blue", "orange")) +
scale_linetype_manual(values = c("solid", "dotted", "dashed", "twodash")) +
theme_void() +
labs(title = "Ferrol estuary")
- rnaturalearth: less precise boundary interpretation.
- mapSpain: satisfactory results.
- GADM (through geodata): very precise results.
- geoBoundaries (through geobounds): satisfactory results.
Caching
mapSpain is an API package that uses web resources. By default, downloaded files are stored in tempdir() for reuse during the current session.
Use esp_set_cache_dir() to choose a user-specific download directory. Add install = TRUE to make that cache configuration persistent across sessions.
esp_set_cache_dir("~/R/mapslib/mapSpain", install = TRUE, verbose = TRUE)
#> ℹ mapSpain cache directory is C:/Users/XXXX/Documents/R/mapslib/mapSpain.
munic <- esp_get_munic_siane(verbose = TRUE)
#> ℹ Cache directory is C:/Users/XXXX/Documents/R/mapslib/mapSpain/siane.
#> ✔ File already cached: C:/Users/XXXX/Documents/R/mapslib/mapSpain/siane/se89_3_admin_muni_a_x.gpkg.
#> ℹ Cache directory is C:/Users/diego/Documents/R/mapslib/GISCO/siane.
#> ✔ File already cached: C:/Users/XXXX/Documents/R/mapslib/mapSpain/siane/se89_3_admin_muni_a_y.gpkgDictionary
Functions for working with text
mapSpain provides two related functions for working with names and codes:
-
esp_dict_region_code()converts text labels into Autonomous Community and province codes. Supported coding schemes are ISO2, NUTS and INE codes (codautoandcpro). -
esp_dict_translate()translates text into Spanish, English, Catalan, Galician or Basque.
These functions are also useful outside spatial workflows, for example when you need to standardize Autonomous Community and province codes in ISCIII COVID data.
esp_dict_region_code()
vals <- c("Errioxa", "Coruna", "Gerona", "Madrid")
esp_dict_region_code(vals, destination = "nuts")
#> [1] "ES23" "ES111" "ES512" "ES30"
esp_dict_region_code(vals, destination = "cpro")
#> [1] "26" "15" "17" "28"
esp_dict_region_code(vals, destination = "iso2")
#> [1] "ES-RI" "ES-C" "ES-GI" "ES-MD"
# From ISO to other codes.
iso2vals <- c("ES-M", "ES-S", "ES-SG")
esp_dict_region_code(iso2vals, origin = "iso2")
#> [1] "Madrid" "Cantabria" "Segovia"
iso2vals <- c("ES-GA", "ES-CT", "ES-PV")
esp_dict_region_code(iso2vals, origin = "iso2", destination = "nuts")
#> [1] "ES11" "ES51" "ES21"
# Support mixed levels.
valsmix <- c("Centro", "Andalucia", "Seville", "Menorca")
esp_dict_region_code(valsmix, destination = "nuts")
#> [1] "ES4" "ES61" "ES618" "ES533"
esp_dict_region_code(c("Murcia", "Las Palmas", "Aragón"), destination = "iso2")
#> [1] "ES-MC" "ES-GC" "ES-AR"
esp_dict_translate()
vals <- c("La Rioja", "Sevilla", "Madrid", "Jaen", "Orense", "Baleares")
esp_dict_translate(vals, lang = "en")
#> [1] "La Rioja" "Seville" "Madrid" "Jaén"
#> [5] "Ourense" "Balearic Islands"
esp_dict_translate(vals, lang = "es")
#> [1] "La Rioja" "Sevilla" "Madrid" "Jaén" "Orense" "Baleares"
esp_dict_translate(vals, lang = "ca")
#> [1] "La Rioja" "Sevilla" "Madrid" "Jaén"
#> [5] "Ourense" "Illes Balears"
esp_dict_translate(vals, lang = "eu")
#> [1] "Errioxa" "Sevilla" "Madril" "Jaén"
#> [5] "Ourense" "Balear Uharteak"
esp_dict_translate(vals, lang = "ga")
#> [1] "A Rioxa" "Sevilla" "Madrid" "Xaén"
#> [5] "Ourense" "Illas Baleares"Political boundaries
mapSpain includes functions to retrieve political boundaries at several levels:
- Whole country.
- NUTS (Eurostat). Eurostat statistical classification, with levels 0 (country), 1, 2 (Autonomous Communities) and 3.
- Autonomous Communities.
- Provinces.
- Municipalities.
For Autonomous Communities, provinces and municipalities there are two families of functions: esp_get_xxxx() (GISCO source) and esp_get_xxxx_siane() (IGN source).
The information is available in different projections and resolution levels.
esp <- esp_get_spain_siane(moveCAN = FALSE)
ggplot(esp) +
geom_sf(fill = "#f9cd94") +
theme_light()
The Canary Islands case
By default, most mapSpain functions move the Canary Islands closer to the mainland to improve visualization. Disable this behavior with moveCAN = FALSE when you need geometries in their original position.
The package also provides helpers for drawing boxes around the inset map. See the examples in the reference page.
esp_can <- esp_get_spain()
can_prov <- esp_get_can_provinces()
can_box <- esp_get_can_box()
ggplot(esp_can) +
geom_sf() +
geom_sf(data = can_prov) +
geom_sf(data = can_box)
Use moveCAN = FALSE when working with imagery, interactive maps or spatial analysis.
NUTS
nuts1 <- esp_get_nuts(resolution = 20, epsg = 3035, nuts_level = 1)
ggplot(nuts1) +
geom_sf() +
labs(title = "NUTS1: low resolution")
# Balearic Islands NUTS3.
nuts3_baleares <- c("ES531", "ES532", "ES533")
paste(esp_dict_region_code(nuts3_baleares, "nuts"), collapse = ", ")
#> [1] "Eivissa y Formentera, Mallorca, Menorca"
nuts3_sf <- esp_get_nuts(region = nuts3_baleares)
ggplot(nuts3_sf) +
geom_sf(aes(fill = NAME_LATN)) +
labs(fill = "Balearic Islands: NUTS3") +
scale_fill_viridis_d() +
theme_minimal()
Autonomous Communities
ccaa <- esp_get_ccaa(
ccaa = c(
"Catalunya",
"Comunidad Valenciana",
"Aragón",
"Baleares"
)
)
ccaa <- ccaa |>
mutate(ccaa_cat = esp_dict_translate(ine.ccaa.name, "ca"))
ggplot(ccaa) +
geom_sf(aes(fill = ccaa_cat)) +
labs(fill = "Autonomous Communities") +
theme_minimal() +
scale_fill_discrete(type = hcl.colors(4, "Plasma"))
Provinces using the *_siane version
Passing a higher-level entity, such as Andalusia, returns all provinces within that entity.
provs <- esp_get_prov_siane(c(
"Andalucía",
"Ciudad Real",
"Murcia",
"Ceuta",
"Melilla"
))
ggplot(provs) +
geom_sf(aes(fill = prov.shortname.es), alpha = 0.9) +
scale_fill_discrete(type = hcl.colors(12, "Cividis")) +
theme_minimal() +
labs(fill = "Provinces")
Municipalities
munic <- esp_get_munic(region = "Segovia") |>
# Example data: INE population.
left_join(
mapSpain::pobmun25 |>
select(-name),
by = c("cpro", "cmun")
)
ggplot(munic) +
geom_sf(aes(fill = pob25), alpha = 0.9, color = NA) +
scale_fill_gradientn(
colors = hcl.colors(100, "Inferno"),
n.breaks = 10,
labels = scales::label_comma(),
guide = guide_legend()
) +
labs(
fill = "Population",
title = "Population in Segovia",
subtitle = "INE data (2025)"
) +
theme_void() +
theme(
plot.background = element_rect("grey80"),
text = element_text(face = "bold"),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5)
)
Hexbin maps
Hexbin maps are available as squares and hexagons for provinces and Autonomous Communities.
cuad <- esp_get_hex_ccaa()
hex <- esp_get_grid_prov()
ggplot(cuad) +
geom_sf() +
geom_sf_text(aes(label = iso2.ccaa.code)) +
theme_void()
ggplot(hex) +
geom_sf() +
geom_sf_text(aes(label = iso2.prov.code)) +
theme_void()
Imagery
mapSpain can also use map imagery, such as satellite imagery, basemaps and roads, provided by different public institutions (https://www.idee.es/web/idee/segun-tipo-de-servicio).
These images can be used to create static maps, as 3- or 4-band raster layers, or as backgrounds for dynamic maps through the leaflet package.
The providers are taken from the leaflet leaflet-providersESP plugin.
Creating static maps
Several options are available for composing basemaps:
madrid_munis <- esp_get_munic_siane(region = "Madrid", epsg = 3857)
base_pnoa <- esp_get_tiles(madrid_munis, "PNOA", bbox_expand = 0.1, zoommin = 1)
library(tidyterra)
ggplot() +
geom_spatraster_rgb(data = base_pnoa) +
geom_sf(
data = madrid_munis,
color = "blue",
fill = "blue",
alpha = 0.25,
linewidth = 0.5
) +
theme_minimal() +
labs(title = "Municipalities in Madrid")
# Use the `mask` option.
madrid <- esp_get_munic_siane(munic = "^Madrid$", epsg = 3857)
madrid_mask <- esp_get_tiles(
madrid,
"IDErioja.Claro",
mask = TRUE,
crop = TRUE,
zoommin = 2
)
ggplot() +
geom_spatraster_rgb(data = madrid_mask) +
theme_void() +
labs(
title = "Basemap of Madrid",
caption = "CC BY 4.0 www.iderioja.org"
)
Dynamic maps with mapSpain
Imagery layers can be used as backgrounds in interactive maps and static maps.
stations <- esp_get_railway(spatialtype = "point", epsg = 4326)
library(leaflet)
# Create an icon.
iconurl <- "https://ropenspain.github.io/mapSpain/icons/train.png"
train_icon <- makeIcon(iconurl, iconurl, 18, 18)
leaflet(stations, elementId = "railway", width = "100%", height = "60vh") |>
addProviderEspTiles("IDErioja.Claro", group = "Base") |>
addProviderEspTiles("MTN", group = "MTN") |>
addProviderEspTiles("RedTransporte.Carreteras", group = "Roads") |>
addProviderEspTiles(
"RedTransporte.Ferroviario",
group = "Railway lines"
) |>
addMarkers(
icon = train_icon,
group = "Stations",
popup = sprintf(
"<strong>%s</strong>",
stations$rotulo
) |>
lapply(htmltools::HTML)
) |>
addLayersControl(
baseGroups = c("Base", "MTN"),
overlayGroups = c("Stations", "Railway lines", "Roads"),
options = layersControlOptions(collapsed = FALSE)
) |>
hideGroup(c("Railway lines", "Roads"))Other resources
mapSpain includes additional functions for retrieving elevation, rivers and river basin data for Spain, as well as Spanish infrastructure lines and points, such as roads and railway lines.
