Es habitual que las organizaciones, de acuerdo a sus intereses, estructuren el territorio en entidades que no coinciden con las unidades administrativas oficiales. Esto puede generar un problema a la hora de visualizar sus datos y métricas en informes y cuadros de mando.
En este trabajo se presentan diversos desarrollos a partir de la librería MapSpain, donde por agregación y desagregación de las unidades administrativas estándar (comunidades autónomas, provincias y municipios) se pueden definir nuevas entidades de acuerdo a las necesidades de cada momento. Es también posible incorporar otras subdivisiones menores no incluidas en la librería MapSpain, como barrios de ciudades o comarcas no coincidentes con las oficialmente definidas.
Las nuevas entidades pueden a su vez mantener la estructura de las entidades menores que las conforman, o bien fusionarlas completamente dentro de la nueva entidad. Esto permite tanto el modificar el nivel de detalle al que se presentan los datos, como redefinir las visualizaciones si se produce un cambio en la estructura territorial de la organización.
Establecer workdir:
setwd("~/R/Creacion de mapas personalizados de Espana con R y MapSpain")
Cargar librerías necesarias:
library (mapSpain)
library (tidyverse)
library (sf)
library (knitr)
library (readxl)
library (kableExtra)
library (rsconnect)
La librería mapSpain permite crear mapas de España utilizando diferentes niveles administrativos: municipio, comarca, provincia, CCAA y país.
esp_get_munic -> Municipios de España como polígonos sf.
esp_get_comarca -> Comarcas de España como polígonos sf.
esp_get_prov -> Provincias de España como polígonos o puntos sf.
esp_get_ccaa -> Comunidades Autónomas de España como polígonos y puntos sf.
esp_get_country -> Són los límites (o fronteras de España) como un polígono sf.
Un aspecto importante es que los mapas no están como data sets, sino que se invocan desde un conjunto de funciones referidas a los niveles mencionados.
Por ejemplo, es posible representar un mapa de España directamente desde la función esp_get_country ()
de la librería mapSpain.
esp_get_country() %>% ggplot() + geom_sf() + theme_minimal()
Es también posible crear primero un objeto a partir de dicha función y operar posteriormente con él. En este caso, vamos a utilizar la función esp_get_ccaa()
, que contiene los datos de las comunidades autónomas, y vamos a asignarla al objeto “ccaa”.
ccaa <- esp_get_ccaa()
ccaa %>% ggplot() + geom_sf() + theme_minimal()
Vamos a examinar el objeto “ccaa”. Empezamos por ver su contenido.
names(ccaa)
## [1] "codauto" "iso2.ccaa.code" "nuts1.code"
## [4] "nuts2.code" "ine.ccaa.name" "iso2.ccaa.name.es"
## [7] "iso2.ccaa.name.ca" "iso2.ccaa.name.gl" "iso2.ccaa.name.eu"
## [10] "nuts2.name" "cldr.ccaa.name.en" "cldr.ccaa.name.es"
## [13] "cldr.ccaa.name.ca" "cldr.ccaa.name.ga" "cldr.ccaa.name.eu"
## [16] "ccaa.shortname.en" "ccaa.shortname.es" "ccaa.shortname.ca"
## [19] "ccaa.shortname.ga" "ccaa.shortname.eu" "nuts1.name"
## [22] "geometry"
Hay 22 columnas. Las 21 primeras son codificaciones de las comunidades autónomas en diversos estándares e idiomas. La última, geometry, contiene los puntos que definen al polígono correspondiente a cada una de ellas.
Vamos a seleccionar 3 de esas columnas, para mostrar su contenido. La sintaxis es la típica del universo tidyverse.
ccaa <- ccaa %>% select(codauto, ine.ccaa.name, geometry)
head(ccaa) %>%
kable("html", align=c('l', 'r','r')) %>%
kable_styling(full_width = FALSE, position="left")%>%
row_spec(0, background = "#F3E2A9")
codauto | ine.ccaa.name | geometry | |
---|---|---|---|
15 | 01 | Andalucía | MULTIPOLYGON (((-4.268895 3… |
7 | 02 | Aragón | POLYGON ((-0.724501 42.9201… |
2 | 03 | Asturias, Principado de | MULTIPOLYGON (((-4.512301 4… |
14 | 04 | Balears, Illes | MULTIPOLYGON (((3.176714 39… |
19 | 05 | Canarias | MULTIPOLYGON (((-11.18653 3… |
3 | 06 | Cantabria | MULTIPOLYGON (((-3.153338 4… |
Codauto es el código de la ccaa, ine.ccaa.name es su nombre según las tablas normalizadas del INE y geometry la definición de los polígonos que la conforma.
Ahora vamos a ver que clase de objeto es.
class(ccaa)
## [1] "sf" "data.frame"
Es un objeto con una naturaleza dual. Por un lado es un objeto espacial, y, por otro, una tabla de datos. Esto nos ha permitido tanto representarlo directamente en el sistema gráfico ggplot mediante la función geom_sf()
, como operar sobre el con la sintaxis propia del universo tidyverse. Esta última propiedad es la que va a permitir desarrollar fácilmente mapas personalizados a partir de otras estructuras previas.
En este trabajo se muestran tres posibles maneras de crear mapas personalizados:
Por agregación de niveles administrativos existentes o estándar.
Por desagregación de niveles administrativos existentes o estándar.
Importando datos externos, ajenos a la librearía mapSpain.
En este ejemplo vamos a suponer que se nos pide un mapa de España con 4 zonas, constituida cada una de ellas por diversas comunidades autónomas. En concreto, son las zonas Norte, Sur, Centro y Levante.
A partir del objeto ccaa ya creado, vamos a ver los nombres de las comunidades autónomas.
ccaa$ine.ccaa.name
## [1] "Andalucía" "Aragón"
## [3] "Asturias, Principado de" "Balears, Illes"
## [5] "Canarias" "Cantabria"
## [7] "Castilla y León" "Castilla - La Mancha"
## [9] "Cataluña" "Comunitat Valenciana"
## [11] "Extremadura" "Galicia"
## [13] "Madrid, Comunidad de" "Murcia, Región de"
## [15] "Navarra, Comunidad Foral de" "País Vasco"
## [17] "Rioja, La" "Ceuta"
## [19] "Melilla"
La estrategia va a ser crear 4 objetos, uno por cada zona, seleccionando en cada uno de ellos las ccaa correspondientes. Evidentemente, esta asignación ya ha sido proporcionada por el “cliente”.
Crear Zona Norte
Norte <- ccaa %>% select (codauto, ine.ccaa.name) %>%
filter (ine.ccaa.name %in% c("Galicia", "Asturias, Principado de",
"Cantabria", "País Vasco" ))
Vemos la tabla resultante.
head(Norte) %>%
kable("html", align=c('l', 'l','r')) %>%
kable_styling(full_width = FALSE, position="left")%>%
row_spec(0, background = "#F3E2A9")
codauto | ine.ccaa.name | geometry |
---|---|---|
03 | Asturias, Principado de | MULTIPOLYGON (((-4.512301 4… |
06 | Cantabria | MULTIPOLYGON (((-3.153338 4… |
12 | Galicia | MULTIPOLYGON (((-7.699736 4… |
16 | País Vasco | MULTIPOLYGON (((-2.412847 4… |
Para que el objeto Norte esté completo y listo para su utilización, hay que añadirle dos nuevas columnas, conteniendo un código y un nombre para la zona.
Norte <- Norte %>%
mutate(cod_zona = 1,
name_zona = "Zona Norte")
Comprobamos.
head(Norte) %>%
kable("html", align=c('l', 'l','r')) %>%
kable_styling(full_width = FALSE, position="left")%>%
row_spec(0, background = "#F3E2A9")
codauto | ine.ccaa.name | geometry | cod_zona | name_zona |
---|---|---|---|---|
03 | Asturias, Principado de | MULTIPOLYGON (((-4.512301 4… | 1 | Zona Norte |
06 | Cantabria | MULTIPOLYGON (((-3.153338 4… | 1 | Zona Norte |
12 | Galicia | MULTIPOLYGON (((-7.699736 4… | 1 | Zona Norte |
16 | País Vasco | MULTIPOLYGON (((-2.412847 4… | 1 | Zona Norte |
Podemos representar el objeto para ver el resultado.
Norte %>%
ggplot () +
geom_sf() +
theme_minimal()
Repetimos esta operación para el resto de zonas.
Zona Sur
Sur <- ccaa %>%
select (codauto, ine.ccaa.name) %>%
filter (ine.ccaa.name %in% c("Andalucía", "Canarias", "Ceuta", "Melilla")) %>%
mutate(cod_zona = 2,
name_zona = "Zona Sur")
Zona Centro
Centro <- ccaa %>%
select (codauto, ine.ccaa.name) %>%
filter (ine.ccaa.name %in% c("Castilla y León", "Rioja, La",
"Navarra, Comunidad Foral de", "Aragón",
"Madrid, Comunidad de", "Castilla - La Mancha",
"Extremadura")) %>%
mutate(cod_zona = 3,
name_zona = "Zona Centro")
Zona Levante
Levante <- ccaa %>%
select (codauto, ine.ccaa.name) %>%
filter (ine.ccaa.name %in% c( "Comunitat Valenciana", "Murcia, Región de",
"Cataluña", "Balears, Illes" )) %>%
mutate(cod_zona = 4,
name_zona = "Zona Levante")
Unir las zonas
Ahora unimos las zonas que se han creado, creadndo un nuevo objeto, mapa_zonas, utilizando la función rbind()
de R base.
mapa_zonas <- rbind(Norte, Sur, Centro, Levante)
Vemos la tabla que henos creado.
head(mapa_zonas) %>%
kable("html", align=c('l', 'l','r')) %>%
kable_styling(full_width = FALSE, position="left") %>%
row_spec(0, background = "#F3E2A9")
codauto | ine.ccaa.name | cod_zona | name_zona | geometry |
---|---|---|---|---|
03 | Asturias, Principado de | 1 | Zona Norte | MULTIPOLYGON (((-4.512301 4… |
06 | Cantabria | 1 | Zona Norte | MULTIPOLYGON (((-3.153338 4… |
12 | Galicia | 1 | Zona Norte | MULTIPOLYGON (((-7.699736 4… |
16 | País Vasco | 1 | Zona Norte | MULTIPOLYGON (((-2.412847 4… |
01 | Andalucía | 2 | Zona Sur | MULTIPOLYGON (((-4.268895 3… |
05 | Canarias | 2 | Zona Sur | MULTIPOLYGON (((-11.18653 3… |
Podemos representar el objeto para ver el mapa resultante.
mapa_zonas %>%
ggplot() +
geom_sf(aes(fill = name_zona)) +
theme_minimal()
Las nuevas entidades pueden a su vez mantener la estructura de las entidades menores que las conforman, o bien fusionarlas completamente dentro de la nueva entidad. Para entender las implicaciones de esta decisión, vamos a poner un ejemplo.
Tenemos una tabla con los resultados de cada zona, por ejemplo, el volumen de ventas.
Cargamos los datos.
datos_zonas_figurados <- read_excel("./data/datos zonas figurados.xlsx")
head(datos_zonas_figurados)
## # A tibble: 4 x 2
## cod_zona Ventas
## <dbl> <dbl>
## 1 1 2000000
## 2 2 1500000
## 3 3 3200000
## 4 4 890000
Los unimos al mapa por zonas.
mapa_zonas_datos <-left_join(mapa_zonas, datos_zonas_figurados)
Esta es la tabla resultante:
head(mapa_zonas_datos) %>%
kable("html", align=c('l', 'l','c', 'l', 'r','c' )) %>%
kable_styling(full_width = FALSE, position="left") %>%
row_spec(0, background = "#F3E2A9")
codauto | ine.ccaa.name | cod_zona | name_zona | Ventas | geometry |
---|---|---|---|---|---|
03 | Asturias, Principado de | 1 | Zona Norte | 2000000 | MULTIPOLYGON (((-4.512301 4… |
06 | Cantabria | 1 | Zona Norte | 2000000 | MULTIPOLYGON (((-3.153338 4… |
12 | Galicia | 1 | Zona Norte | 2000000 | MULTIPOLYGON (((-7.699736 4… |
16 | País Vasco | 1 | Zona Norte | 2000000 | MULTIPOLYGON (((-2.412847 4… |
01 | Andalucía | 2 | Zona Sur | 1500000 | MULTIPOLYGON (((-4.268895 3… |
05 | Canarias | 2 | Zona Sur | 1500000 | MULTIPOLYGON (((-11.18653 3… |
La representamos.
mapa_zonas_datos %>%
ggplot() +
geom_sf(aes(fill = name_zona)) +
theme_minimal()
Parece correcto, pero, ¿qué ocurre si queremos poner en cada zona el valor de las ventas?
mapa_zonas_datos %>%
ggplot() +
geom_sf(aes(fill = name_zona, label = Ventas), alpha = 0.5) +
geom_sf_text(aes(label = Ventas)) +
theme_minimal()
La etiqueta se ha representado en cada comunidad autónoma. Esto es así, porque en la tabla que conforma el objeto mapa_zonas, estas siguen existiendo de forma independiente. Para evitar este problema hay que fusionarlas.
mapa_zonas_datos <- mapa_zonas_datos %>%
group_by(cod_zona, name_zona) %>%
summarise(Ventas = mean(Ventas)) %>%
st_cast()
Comprobamos en el mapa.
mapa_zonas_datos %>%
ggplot() +
geom_sf(aes(fill = name_zona, label = Ventas), alpha = 0.5) +
geom_sf_text(aes(label = Ventas)) +
theme_minimal()
El formato es claramente mejorable, pero el problema se ha solucionado.
Esto no quiere decir que siempre sea necesario fusionar las entidades espaciales. Puede ser buena idea disponer de las dos capas de objetos. Superponiéndolas, es posible mostrar el detalle de los contornos de cada ccaa sin que las etiquetas se repitan.
mapa_zonas_datos %>%
ggplot() +
geom_sf(aes(fill = name_zona, label = name_zona), alpha = 0.5) +
geom_sf_text(aes(label = name_zona)) +
geom_sf(data = mapa_zonas, color = "darkgrey", fill = NA) +
theme_minimal()
En este ejemplo vamos a establecer del paquete mapSpain un objeto con el detalle de las provincias de España para crear una división de las provincias de Andalucía. La distribución será Andalucía Oriental y Andalucía Occidental.
Establecemos del paquete mapSpain un objeto con el detalle de provincias de España.
provincias <- esp_get_prov()
Dibujamos el mapa de España por provincias.
provincias %>%
ggplot +
geom_sf () +
labs (fill="",
title= "Distribución de provincias de España") +
theme_minimal()+
theme (
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank() )
De este paquete, vamos a extraer la CCAA de Andalucía para crear un nuevo objeto y poder trabajar con él.
provincias_Andalucía <- provincias %>%
select (nuts2.name, ine.prov.name, cpro) %>%
filter (nuts2.name == "Andalucía")
Dibujamos el mapa de las provincias de Andalucía.
provincias_Andalucía %>%
ggplot +
geom_sf (data=provincias_Andalucía ,
fill = "lightblue") +
labs (fill="",
title= "Distribución de provincias en Andalucía") +
geom_sf_text (aes(label=ine.prov.name)) +
theme_minimal()+
theme (
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank() )
Vamos a dividir las provincias de Andalucía en: Oriental (Córdoba, Jaén, Granada y Almería) y Occidental (Huelva, Sevilla, Cadiz y Málaga).
provincias_Andalucía2 <- provincias_Andalucía %>%
mutate (división = ifelse (ine.prov.name %in% c("Córdoba", "Jaén", "Granada", "Almería"),
"Oriental", "Occidental" ))
Como hemos visto con anterioridad, las nuevas entidades pueden a su vez mantener la estructura de las entidades menores que las conforman, o bien fusionarlas completamente dentro de la nueva entidad. Decidimos fusionar polígonos para que sólo muestre el contorno de esta agrupación de provincias y no las entidades menores de las cuales está formado.
Andalucía <- provincias_Andalucía2 %>%
group_by(división) %>%
summarise (n=1) %>%
st_cast()
Dibujamos esta nueva estructura.
Andalucía %>%
ggplot +
geom_sf (aes(fill = división)) +
labs (fill="",
title= "Nueva distribución creada de Andalucía") +
geom_sf_text (aes(label= división)) +
theme_minimal()+
theme (
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
legend.position = "none")
En este ejemplo vamos a incorporar datos externos de los distritos de Barcelona Ciudad encontrados en la página de Open Data del Ayuntamiento de Barcelona. La información se puede encontrar en este enlace.
Una vez importados los datos, vamos a extraer del paquete mapSpain datos de los municipios de la comarca del Barcelonés. Crearemos un objeto nuevo excluyendo el municipio de Barcelona Capital para luego poder incorporar los datos de los distritos.
Cargamos los datos externos de los distritos de Barcelona ciudad.
distritos_Barcelona <- st_read("data/Distritos Barcelona Capital")
## Reading layer `0301040100_Districtes_UNITATS_ADM' from data source
## `C:\Users\SAG0000\Documents\R\Creacion de mapas personalizados de Espana con R y MapSpain\data\Distritos Barcelona Capital'
## using driver `ESRI Shapefile'
## Simple feature collection with 10 features and 48 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 420812.5 ymin: 4574282 xmax: 435480.4 ymax: 4591066
## Projected CRS: ETRS89 / UTM zone 31N
Seleccionamos sólo las columnas que nos interesan.
distritos_Barcelona <- distritos_Barcelona %>%
select(CODI_UA, NOM, geometry)
Añadimos una nueva columna para luego poder diferenciar distritos de municipios.
distritos_Barcelona <- distritos_Barcelona %>%
mutate (tipo= "distrito")
Extraemos los municipios del Barcelonés de mapSpain, excepto Barcelona Capital, y añadimos una columna para poder diferenciar municipios de distritos, como hemos hecho anteriormente con los distritos.
Barcelones <- esp_get_munic() %>%
filter(name %in% c("Badalona",
"Santa Coloma de Gramenet",
"Hospitalet de Llobregat, L'",
"Sant Adrià de Besòs")) %>%
mutate(tipo = "municipio")
Representamos este objeto.
ggplot() +
geom_sf(data = Barcelones, aes(fill = name)) +
geom_sf_text(data = Barcelones, aes(label = name)) +
theme_minimal() +
labs(fill = "",
title = "Municipios de la comarca del Barcelonés",
subtitle = "Sin el municipio de Barcelona capital") +
theme(
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
legend.position = "none")
Seleccionamos las mismas columnas que necesitamos y en el mismo orden que en los distritos.
Barcelones <- Barcelones %>%
select(cmun, name, tipo, geometry)
Cambiamos el nombre de las columnas para que coincidan y así después poder crear un nuevo objeto sin problemas.
Barcelones <- Barcelones %>%
rename(CODI_UA=cmun) %>%
rename (NOM=name)
Unificamos los sistemas de coordenadas (asignar a distritos Barcelona los atributos de Barcelonés).
(El CRS es un dato que puede obtenerse directamente de un objeto espacial que lo tenga informado, mediante la función st_crs). En este caso:
st_crs(Barcelones)
## Coordinate Reference System:
## User input: EPSG:4258
## wkt:
## GEOGCRS["ETRS89",
## DATUM["European Terrestrial Reference System 1989",
## ELLIPSOID["GRS 1980",6378137,298.257222101,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Spatial referencing."],
## AREA["Europe - onshore and offshore: Albania; Andorra; Austria; Belgium; Bosnia and Herzegovina; Bulgaria; Croatia; Cyprus; Czechia; Denmark; Estonia; Faroe Islands; Finland; France; Germany; Gibraltar; Greece; Hungary; Ireland; Italy; Kosovo; Latvia; Liechtenstein; Lithuania; Luxembourg; Malta; Moldova; Monaco; Montenegro; Netherlands; North Macedonia; Norway including Svalbard and Jan Mayen; Poland; Portugal; Romania; San Marino; Serbia; Slovakia; Slovenia; Spain; Sweden; Switzerland; United Kingdom (UK) including Channel Islands and Isle of Man; Vatican City State."],
## BBOX[32.88,-16.1,84.17,40.18]],
## ID["EPSG",4258]]
Como el Barcelonés tiene el EPSG:4258 asignamos a distritos_Barcelona el mismo.
distritos_Barcelona <- st_transform(distritos_Barcelona, crs = 4258)
Unimos los dos objetos (Distritos_Barcelona y Barcelonés)
Barcelones <- rbind(Barcelones, distritos_Barcelona)
Por último, representamos nuestro nuevo objeto que contiene los municipios del Barcelonés y los distritos que forman Barcelona capital en un mapa.
ggplot() +
geom_sf(data = Barcelones, aes(fill = tipo)) +
geom_sf_text(data = Barcelones,
aes(label = NOM), size = 3) +
theme_minimal() +
labs(fill = "",
title = "El Barcelonés",
subtitle = "Municipios y Distritos de Barcelona capital") +
theme(
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank())