library(tidyverse)
library(sf) # Para trabajar con shapefiles
library(readxl) # Para leer archivos Excel
library(kableExtra) # Para tablas de datos
library(ggplot2)
library(ggtext)
library(showtext)
library(patchwork) # Para combinar múltiples ggplots
library(colorspace) # Para paletas de colores
library(grid) # Para añadir líneas y elementos de texto a objetos gráficosTres mapas para examinar la prevalencia de la violencia de pareja (IPV) en Camboya
Desarrollando mapas coropléticos con {ggplot2}, {sf} y shapefiles
Panorama
De acuerdo con el módulo de Violencia Doméstica 2021-22 de la Encuesta Demográfica y de Salud de Camboya (CDHS), más del 21% de las mujeres camboyanas de 15 a 49 años que alguna vez han tenido esposo (o pareja íntima) han experimentado violencia de pareja íntima física, sexual, económica y/o emocional a lo largo de su vida. Estas cifras varían significativamente en todo el país, con algunas provincias reportando tasas de hasta 45%, mientras que otras reportan tasas tan bajas como 6%.
Una mejor comprensión de la distribución geográfica de la violencia de pareja íntima (VPI) en Camboya puede ayudar a los responsables de políticas y a las organizaciones a orientar sus esfuerzos de manera más efectiva. En esta entrada de blog, mostraré cómo crear mapas coropléticos usando R y archivos shapefiles para visualizar la prevalencia de la VPI en Camboya a nivel provincial. Además, utilizaré el paquete {patchwork} para combinar estos mapas en una misma gráfica. El resultado se verá así:
Sobre los datos
La información proviene del documento “Further Data Analysis Report. From the Cambodia Demographic and Health Survey 2021-2022”, disponible aquí. En particular, utilizaré la Tabla A.1: Violencia de pareja íntima según características de fondo.
Preparación
Primero, instalamos y cargamos los paquetes de R necesarios.
Carga de datos
Guardé la información de la Tabla A.1: Violencia de pareja íntima según características de fondo en el archivo Excel intimate-partner-violence-cambodia.xlsx.
ipv_cambodia <- read_excel("intimate-partner-violence-cambodia.xlsx")Así se ve la información:
ipv_cambodia |>
kbl(
caption = "Experiencia de por vida de actos específicos de violencia física de pareja íntima cometidos por su pareja actual o más reciente, por provincias, Camboya 2021-22"
) |>
kable_paper("hover", full_width = F)| Region | Emotional violence | Physical violence | Sexual violence | Physical or sexual | Physical or sexual or emotional | Number of women who ever had a husband/intimate partner |
|---|---|---|---|---|---|---|
| Banteay Meanchey | 31.3 | 18.2 | 4.6 | 20.2 | 34.9 | 235 |
| Battambang | 24.9 | 16.1 | 6.3 | 19.8 | 30.4 | 378 |
| Kampong Cham | 7.7 | 5.2 | 1.1 | 5.8 | 11.5 | 352 |
| Kampong Chhnang | 19.2 | 6.7 | 1.7 | 6.7 | 19.2 | 213 |
| Kampong Speu | 16.6 | 9.5 | 2.6 | 10.1 | 19.1 | 362 |
| Kampong Thom | 32.4 | 12.1 | 5.0 | 14.4 | 35.1 | 242 |
| Kampot | 20.8 | 6.4 | 4.0 | 9.0 | 23.0 | 218 |
| Kandal | 23.9 | 6.2 | 2.0 | 6.5 | 23.9 | 423 |
| Koh Kong | 5.4 | 3.8 | 0.4 | 3.8 | 6.2 | 41 |
| Kratie | 13.7 | 9.1 | 2.8 | 10.2 | 15.9 | 138 |
| Mondul Kiri | 42.7 | 19.0 | 3.6 | 19.4 | 45.2 | 34 |
| Phnom Penh | 10.3 | 5.1 | 1.3 | 5.8 | 11.0 | 904 |
| Preah Vihear | 38.1 | 20.2 | 8.5 | 22.4 | 40.0 | 108 |
| Prey Veng | 25.0 | 7.2 | 1.7 | 8.6 | 26.3 | 366 |
| Pursat | 10.8 | 3.6 | 0.7 | 3.6 | 10.8 | 111 |
| Ratanak Kiri | 24.7 | 6.6 | 0.8 | 7.1 | 25.7 | 96 |
| Siemreap | 21.5 | 12.0 | 2.9 | 13.5 | 24.6 | 482 |
| Preah Sihanouk | 10.3 | 3.4 | 1.6 | 4.0 | 10.8 | 75 |
| Stung Treng | 29.3 | 12.5 | 7.5 | 16.3 | 31.5 | 66 |
| Svay Rieng | 10.9 | 8.3 | 2.1 | 8.8 | 13.6 | 217 |
| Takeo | 18.4 | 7.4 | 1.2 | 8.0 | 19.3 | 344 |
| Otdar Meanchey | 15.1 | 6.1 | 0.0 | 6.1 | 15.4 | 77 |
| Kep | 8.0 | 7.2 | 1.2 | 7.7 | 11.0 | 18 |
| Pailin | 11.3 | 9.5 | 1.7 | 9.5 | 14.2 | 29 |
| Tboung Khmum | 11.1 | 7.3 | 2.3 | 7.3 | 14.0 | 252 |
Ahora, cargamos los datos geográficos de la división administrativa de Camboya. Estos datos se obtuvieron de la iniciativa Humanitarian Data Exchange (HDX) de la Oficina de Coordinación de Asuntos Humanitarios de las Naciones Unidas (OCHA). La información viene en un archivo shapefile .shp y está disponible aquí en un archivo zip llamado khm_admbnda_adm1_gov_20181004.zip. Descargué este archivo y lo ubiqué en la carpeta /khmadm_gov_20181004_ab_shp.
shp_cambodia <- read_sf("khmadm_gov_20181004_ab_shp/khm_admbnda_adm1_gov_20181004.shp")Preparación de los datos
El siguiente paso es combinar la información geográfica del shapefile, shp_cambodia, con la base de datos que contiene la información sobre IPV, ipv_cambodia. Para lograr este objetivo, necesitamos asegurarnos de que ambos conjuntos de datos tengan una variable común para hacer el cruce. En este caso, utilizaremos el nombre de la provincia ADM1_EN en el shapefile y Region en la base de datos. Luego, comparo si los nombres de las provincias en ambos conjuntos coinciden:
setdiff(shp_cambodia$ADM1_EN, ipv_cambodia$Region)[1] "Oddar Meanchey"
La salida indica que existe una discrepancia. En shp_cambodia, el nombre de la provincia “Oddar Meanchey” corresponde a “Otdar Meanchey” en ipv_cambodia. Renombraré esta provincia en el shapefile para que coincida con el nombre en los datos del informe oficial.
Después de esta modificación, uno ambos conjuntos de datos usando un left join para conservar todas las provincias del shapefile y añadir los valores de VPI correspondientes desde el marco de datos:
Creación del mapa
Mi idea es desarrollar tres mapas, cada uno representando un tipo de violencia contra mujeres y niñas: emocional, física y sexual. Primero, crearé el mapa correspondiente a la violencia emocional.
# Más alternativas de fuentes aquí https://fonts.google.com/
font_add_google("Scada", "Scada")
showtext_auto()
map_ipv_emotional_cambodia <- ggplot() +
geom_sf(
data = shp_cambodia,
aes(fill = `Emotional violence`),
color = "white", # Color de los bordes de las provincias
linewidth = 0.5
) +
geom_sf_text(
data = shp_cambodia,
aes(label = `Emotional violence`),
check_overlap = TRUE, # Evita que se sobreponga el texto en el gráfico
size = 4,
color = "black",
fontface = "bold"
) +
scale_fill_gradient2(
low = "#FFFE9EB3",
mid = "#C53270B3",
high = "#040404B3",
midpoint = 22.5,
limits = c(0, 45),
breaks = c(0, 15, 30, 45),
labels = c("0", "15", "30", "45")
) +
labs(
title = "Emocional", # Título de este submapa
subtitle = "",
caption = "",
x = "",
y = "",
fill = "Porcentaje de víctimas (%)" # Título de la leyenda
) +
theme_minimal(
base_family = "Scada"
) +
theme(
plot.margin = margin(0, 40, 0, 40),
plot.background = element_blank(), # Sin color de fondo
plot.title = element_text(
color = "black",
face = "bold",
size = 22,
hjust = 0.5,
margin = margin(5, 0, 5, 0)
)
)Ahora replico el mismo formato para violencia física y sexual.
map_ipv_physical_cambodia <- ggplot() +
geom_sf(
data = shp_cambodia,
aes(fill = `Physical violence`),
color = "white",
linewidth = 0.5
) +
geom_sf_text(
data = shp_cambodia,
aes(label = `Physical violence`),
check_overlap = TRUE,
size = 4,
color = "black",
fontface = "bold"
) +
scale_fill_gradient2(
low = "#FFFE9EB3",
mid = "#C53270B3",
high = "#040404B3",
midpoint = 22.5,
limits = c(0, 45)
) +
labs(
title = "Física",
subtitle = "",
caption = "",
x = "",
y = "",
fill = ""
) +
guides(fill = "none") +
theme_minimal(
base_family = "Scada"
) +
theme(
plot.margin = margin(0, 40, 0, 40),
plot.background = element_blank(),
plot.title = element_text(
color = "black",
face = "bold",
size = 22,
hjust = 0.5,
margin = margin(5, 0, 5, 0)
)
)
map_ipv_sexual_cambodia <- ggplot() +
geom_sf(
data = shp_cambodia,
aes(fill = `Sexual violence`),
color = "white",
linewidth = 0.5
) +
geom_sf_text(
data = shp_cambodia,
aes(label = `Sexual violence`),
check_overlap = TRUE,
size = 4,
color = "black",
fontface = "bold"
) +
scale_fill_gradient2(
low = "#FFFE9EB3",
mid = "#C53270B3",
high = "#040404B3",
midpoint = 22.5,
limits = c(0, 45)
) +
labs(
title = "Sexual",
subtitle = "",
caption = "",
x = "",
y = "",
fill = ""
) +
guides(fill = "none") +
theme_minimal(
base_family = "Scada"
) +
theme(
plot.margin = margin(0, 40, 0, 40),
plot.background = element_blank(),
plot.title = element_text(
color = "black",
face = "bold",
size = 22,
hjust = 0.5,
margin = margin(5, 0, 5, 0)
)
)Ahora, usando el paquete {patchwork}, combino los tres gráficos en una sola representación. También uso la función plot_annotation() para añadir un título, subtítulo y nota al diseño general.
# El diseño muestra dos filas: una con los tres mapas y la segunda solo con la guía común
map_ipv_cambodia <- (map_ipv_emotional_cambodia + map_ipv_physical_cambodia + map_ipv_sexual_cambodia) / guide_area() +
# Título, subtítulo y nota personalizados
plot_annotation(
title = "Violencia de pareja íntima en Camboya, 2021-22",
subtitle = "Proporción de mujeres y niñas de 15 a 49 años que han tenido pareja alguna vez y han sido víctimas de violencia ejercida por su pareja íntima, según tipo de violencia.",
caption = "**Datos:** Encuesta Demográfica y de Salud de Camboya (CDHS) 2021-22 <br> **Gráfico:** Juan Torres Munguía",
theme = theme(
# Configuración del título
plot.title.position = "plot",
plot.title = element_text(
color = "black",
face = "bold",
size = 30,
hjust = 0,
margin = margin(5, 0, 5, 50)
),
plot.subtitle = element_text(
color = "grey20",
size = 25,
hjust = 0,
margin = margin(5, 0, 40, 50)
),
# Configuración de la nota
# Uso element_markdown() porque la nota contiene texto en markdown
plot.caption = element_markdown(
color = "black",
size = 15,
hjust = 0,
margin = margin(80, 0, 5, 50)
)
)) +
plot_layout(guides = "collect",
heights = unit(c(13, 1),
c('cm', 'cm'))
) +
theme_minimal(
base_family = "Scada"
) &
# Configuración personalizada del tema
theme(
legend.background = element_blank(),
legend.position = "bottom",
legend.title = element_text(
margin = margin(5, 0, 10, 0),
face = "bold",
color = "grey10",
size = 14,
hjust = 0.5
),
legend.title.position = "top",
legend.text = element_text(
margin = margin(5, 5, 5, 5),
face = "bold",
color = "grey10",
size = 14
),
legend.key.width = unit(1.4, "cm"),
legend.key.height = unit(1, "cm"),
legend.direction = "horizontal",
plot.background = element_rect(
color = "#E5E5E5",
fill = "#E5E5E5"),
# Configuración de ejes
axis.title = element_blank(),
axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank()
)Finalmente, uso grid.lines() del paquete {grid} para añadir una línea horizontal después del subtítulo.
map_ipv_cambodia
grid.lines(
x = c(0.04, 0.96), # Los valores deben estar entre 0 y 1
y = 0.88, # El valor debe estar entre 0 y 1
gp = gpar(col = "#C53270B3",
lwd = 4)
)Citation
@online{torres munguía2025,
author = {Torres Munguía, Juan Armando},
title = {Tres Mapas Para Examinar La Prevalencia de La Violencia de
Pareja {(IPV)} En {Camboya}},
date = {2025-05-10},
url = {https://juan-torresmunguia.netlify.app/blog/posts-es/map-intimate-partner-violence-cambodia},
langid = {en}
}
