Contexto: El T-MEC será renegociado en 2026. El equipo debe identificar qué productos agrícolas de exportación proteger, cuáles impulsar y cuáles presentan vulnerabilidades.
Datos: Principales cultivos de exportación 2003–2024 (SIAP)
Fuente: https://nube.agricultura.gob.mx/cierre_agricola/
Objetivos:
dplyr: filter,
group_by, summarise, mutate,
arrange, left_join, case_when,
pivot_wider / pivot_longerggplot2sf +
ggplot2for) para automatizar
visualizaciones# Establecer directorio de trabajo
setwd("~/Documents/Cursos-R/Laboratorio-2")
# Leer el archivo Excel
data <- read_xlsx("cultivos.xlsx")
# Vistazo general
glimpse(data)## Rows: 10,315
## Columns: 25
## $ origen <chr> "Cierre_agricola_mun_2003", "Cierre_agricola_mun_20…
## $ Anio <dbl> 2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 200…
## $ Idestado <dbl> 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, …
## $ Nomestado <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes…
## $ Idddr <dbl> 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 7, 8, 8, 9, 9, 9, …
## $ Nomddr <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes…
## $ Idcader <dbl> 1, 1, 3, 3, 3, 3, 6, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, …
## $ Nomcader <chr> "Aguascalientes", "Aguascalientes", "Pabellón", "En…
## $ Idmunicipio <dbl> 11, 11, 9, 1, 1, 1, 2, 2, 2, 2, 1, 8, 8, 8, 2, 2, 6…
## $ Nommunicipio <chr> "San Francisco de Los Romo", "San Francisco de Los …
## $ Idciclo <dbl> 2, 2, 2, 2, 2, 3, 3, 1, 2, 1, 1, 3, 1, 1, 1, 3, 3, …
## $ Nomcicloproductivo <chr> "Primavera-Verano", "Primavera-Verano", "Primavera-…
## $ Idmodalidad <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ Nommodalidad <chr> "Riego", "Riego", "Riego", "Riego", "Riego", "Riego…
## $ Idunidadmedida <dbl> 200201, 200201, 200201, 200201, 200201, 200201, 200…
## $ Nomunidad <chr> "Tonelada", "Tonelada", "Tonelada", "Tonelada", "To…
## $ Idcultivo <dbl> 5740000, 6120000, 6120000, 5940000, 8210000, 739000…
## $ Nomcultivo <chr> "Calabacita", "Chile verde", "Chile verde", "Ceboll…
## $ Sembrada <dbl> 29.00, 40.00, 24.00, 1710.00, 133.00, 80.00, 46.00,…
## $ Cosechada <dbl> 29.00, 40.00, 24.00, 1710.00, 131.00, 72.00, 46.00,…
## $ Siniestrada <dbl> 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 9, 0, 0, 0, 0, 0, 0, …
## $ Volumenproduccion <dbl> 522.00, 288.00, 288.00, 52302.90, 5359.15, 372.24, …
## $ Rendimiento <dbl> 18.00, 7.20, 12.00, 30.59, 40.91, 5.17, 20.50, 12.0…
## $ Precio <dbl> 4069.00, 3595.10, 3000.00, 5158.19, 6136.89, 1974.8…
## $ Valorproduccion <dbl> 2124018.0, 1035388.8, 864000.0, 269788409.3, 328884…
## tibble [10,315 × 25] (S3: tbl_df/tbl/data.frame)
## $ origen : chr [1:10315] "Cierre_agricola_mun_2003" "Cierre_agricola_mun_2003" "Cierre_agricola_mun_2003" "Cierre_agricola_mun_2003" ...
## $ Anio : num [1:10315] 2003 2003 2003 2003 2003 ...
## $ Idestado : num [1:10315] 1 1 1 2 2 2 2 3 3 3 ...
## $ Nomestado : chr [1:10315] "Aguascalientes" "Aguascalientes" "Aguascalientes" "Baja California" ...
## $ Idddr : num [1:10315] 1 1 1 2 2 2 3 4 4 4 ...
## $ Nomddr : chr [1:10315] "Aguascalientes" "Aguascalientes" "Aguascalientes" "Ensenada" ...
## $ Idcader : num [1:10315] 1 1 3 3 3 3 6 1 1 2 ...
## $ Nomcader : chr [1:10315] "Aguascalientes" "Aguascalientes" "Pabellón" "Ensenada" ...
## $ Idmunicipio : num [1:10315] 11 11 9 1 1 1 2 2 2 2 ...
## $ Nommunicipio : chr [1:10315] "San Francisco de Los Romo" "San Francisco de Los Romo" "Tepezalá" "Ensenada" ...
## $ Idciclo : num [1:10315] 2 2 2 2 2 3 3 1 2 1 ...
## $ Nomcicloproductivo: chr [1:10315] "Primavera-Verano" "Primavera-Verano" "Primavera-Verano" "Primavera-Verano" ...
## $ Idmodalidad : num [1:10315] 1 1 1 1 1 1 1 1 1 1 ...
## $ Nommodalidad : chr [1:10315] "Riego" "Riego" "Riego" "Riego" ...
## $ Idunidadmedida : num [1:10315] 2e+05 2e+05 2e+05 2e+05 2e+05 ...
## $ Nomunidad : chr [1:10315] "Tonelada" "Tonelada" "Tonelada" "Tonelada" ...
## $ Idcultivo : num [1:10315] 5740000 6120000 6120000 5940000 8210000 7390000 7390000 5940000 8970000 6120000 ...
## $ Nomcultivo : chr [1:10315] "Calabacita" "Chile verde" "Chile verde" "Cebolla" ...
## $ Sembrada : num [1:10315] 29 40 24 1710 133 80 46 0.5 8 14 ...
## $ Cosechada : num [1:10315] 29 40 24 1710 131 72 46 0.5 8 12 ...
## $ Siniestrada : num [1:10315] 0 0 0 0 2 0 0 0 0 2 ...
## $ Volumenproduccion : num [1:10315] 522 288 288 52303 5359 ...
## $ Rendimiento : num [1:10315] 18 7.2 12 30.6 40.9 ...
## $ Precio : num [1:10315] 4069 3595 3000 5158 6137 ...
## $ Valorproduccion : num [1:10315] 2.12e+06 1.04e+06 8.64e+05 2.70e+08 3.29e+07 ...
## [1] "origen" "Anio" "Idestado"
## [4] "Nomestado" "Idddr" "Nomddr"
## [7] "Idcader" "Nomcader" "Idmunicipio"
## [10] "Nommunicipio" "Idciclo" "Nomcicloproductivo"
## [13] "Idmodalidad" "Nommodalidad" "Idunidadmedida"
## [16] "Nomunidad" "Idcultivo" "Nomcultivo"
## [19] "Sembrada" "Cosechada" "Siniestrada"
## [22] "Volumenproduccion" "Rendimiento" "Precio"
## [25] "Valorproduccion"
Las variables disponibles en la base son:
| Variable | Descripción |
|---|---|
Anio |
Año del registro |
Idestado / Nomestado |
ID y nombre de la entidad federativa |
Idddr / Nomddr |
ID y nombre del Distrito de Desarrollo Rural |
Idcader / Nomcader |
ID y nombre del Centro de Apoyo al Desarrollo Rural |
Idmunicipio / Nommunicipio |
ID y nombre del municipio |
Idciclo / Nomcicloproductivo |
ID y nombre del ciclo agrícola |
Idmodalidad / Nommodalidad |
ID y nombre de la modalidad de producción (riego) |
Idunidadmedida / Nomunidad |
ID y nombre de la unidad de medida (toneladas) |
Idcultiv / Nomcultivo |
ID y nombre del cultivo |
Sembrada |
Superficie sembrada (hectáreas) |
Cosechada |
Superficie cosechada (hectáreas) |
Siniestrada |
Superficie siniestrada (hectáreas) |
Volumenproduccion |
Volumen de producción (toneladas) |
Rendimiento |
Rendimiento (ton/ha) = Volumen / Superficie Cosechada |
Precio |
Precio medio rural (pesos/tonelada) |
Valorproduccion |
Valor de la producción (miles de pesos) |
# Cultivos únicos en la base, ordenados alfabéticamente
sort(unique(data$Nomcultivo), decreasing = FALSE)## [1] "Aguacate" "Arándano" "Brócoli"
## [4] "Calabacita" "Cebolla" "Chile verde"
## [7] "Espárrago" "Frambuesa" "Fresa"
## [10] "Limón" "Mango" "Pepino"
## [13] "Tomate rojo (jitomate)" "Zarzamora"
Preguntas:
1A. ¿Cuál es el volumen de producción para cada cultivo?
1B. ¿Cuánto aporta cada cultivo en valor?
1C. ¿Cuánto ocupa de superficie cada cultivo?
1D. ¿Qué rendimiento tiene cada cultivo?
1E. ¿Qué precio tiene cada cultivo?
# Dataframe con participaciones acumuladas por cultivo
participacion <- data %>%
group_by(Nomcultivo) %>%
summarise(
volumen_acumulado = sum(Volumenproduccion, na.rm = TRUE),
valor_acumulado = sum(Valorproduccion, na.rm = TRUE),
sembrada_acumulada = sum(Sembrada, na.rm = TRUE)
) %>%
mutate(
participacion_volumen = round(volumen_acumulado / sum(volumen_acumulado) * 100, 2),
participacion_valor = round(valor_acumulado / sum(valor_acumulado) * 100, 2),
participacion_sembrada = round(sembrada_acumulada / sum(sembrada_acumulada) * 100, 2)
) %>%
arrange(desc(participacion_valor))
participacion## # A tibble: 14 × 7
## Nomcultivo volumen_acumulado valor_acumulado sembrada_acumulada
## <chr> <dbl> <dbl> <dbl>
## 1 Chile verde 6634062. 51200329015. 274743.
## 2 Aguacate 2378980. 39044237746. 248549.
## 3 Tomate rojo (jitomate) 3608551. 28573708687. 68800.
## 4 Limón 4449211. 20454372613. 344027.
## 5 Fresa 166599184. 13374055651. 16310.
## 6 Mango 3141283. 12625261109. 328686.
## 7 Cebolla 1982329. 8831561863. 65351.
## 8 Pepino 1294626. 6615718223. 27410.
## 9 Frambuesa 147621. 6308827661. 8714.
## 10 Espárrago 167318. 6267944301. 24168
## 11 Zarzamora 201659. 4819921477. 13749.
## 12 Brócoli 746338. 3991657581. 49133.
## 13 Calabacita 763518. 3709448726. 42209.
## 14 Arándano 30974. 1388626426. 2315.
## # ℹ 3 more variables: participacion_volumen <dbl>, participacion_valor <dbl>,
## # participacion_sembrada <dbl>
participacion_volumen <- ggplot(participacion,
aes(x = reorder(Nomcultivo, participacion_volumen),
y = participacion_volumen,
fill = participacion_volumen)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = paste0(participacion_volumen, "%")),
hjust = -0.1, size = 3.2) +
coord_flip() +
scale_fill_gradient(low = "#b7e4c7", high = "#1b4332") +
scale_y_continuous(limits = c(0, max(participacion$participacion_volumen) * 1.15)) +
labs(
title = "Participación del Volumen de Producción en el Volumen Total Exportable",
subtitle = "México 2003-2024 | Acumulado",
x = NULL,
y = "Participación (%)"
) +
theme_minimal(base_size = 12)
ggsave("participacion_volumen.png", participacion_volumen, dpi = 300, width = 12, height = 10)
participacion_volumenparticipacion_valor <- ggplot(participacion,
aes(x = reorder(Nomcultivo, participacion_valor),
y = participacion_valor,
fill = participacion_valor)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = paste0(participacion_valor, "%")),
hjust = -0.1, size = 3.2) +
coord_flip() +
scale_fill_gradient(low = "indianred1", high = "indianred4") +
scale_y_continuous(limits = c(0, max(participacion$participacion_valor) * 1.15)) +
labs(
title = "Participación del Valor en el Valor Total Exportable",
subtitle = "México 2003-2024 | Acumulado",
x = NULL,
y = "Participación (%)"
) +
theme_minimal(base_size = 12)
ggsave("participacion_valor.png", participacion_valor, dpi = 300, width = 12, height = 10)
participacion_valorparticipacion_sembrada <- ggplot(participacion,
aes(x = reorder(Nomcultivo, participacion_sembrada),
y = participacion_sembrada,
fill = participacion_sembrada)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = paste0(participacion_sembrada, "%")),
hjust = -0.1, size = 3.2) +
coord_flip() +
scale_fill_gradient(low = "hotpink", high = "hotpink4") +
scale_y_continuous(limits = c(0, max(participacion$participacion_sembrada) * 1.15)) +
labs(
title = "Participación de la Superficie Sembrada en el Total de la Superficie Sembrada Exportable",
subtitle = "México 2003-2024 | Acumulado",
x = NULL,
y = "Participación (%)"
) +
theme_minimal(base_size = 12)
ggsave("participacion_sembrada.png", participacion_sembrada, dpi = 300, width = 12, height = 10)
participacion_sembradaPreguntas:
2A. ¿Cuántos municipios producen cada cultivo?
2B. ¿Cuántos estados producen cada cultivo?
# Número de municipios por cultivo y año
municipios_cultivo <- data %>%
group_by(Anio, Nomcultivo) %>%
summarise(
num_municipios = n_distinct(Nommunicipio),
.groups = "drop"
)
# Formato ancho (wide)
municipios_wide <- municipios_cultivo %>%
pivot_wider(
names_from = Anio,
values_from = num_municipios
) %>%
arrange(Nomcultivo)
municipios_wide## # A tibble: 14 × 23
## Nomcultivo `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010` `2011`
## <chr> <int> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 Aguacate 43 34 36 24 32 35 31 28 32
## 2 Arándano NA NA NA NA 1 NA NA NA 1
## 3 Brócoli 14 14 14 12 10 11 18 9 15
## 4 Calabacita 48 55 44 52 40 44 40 52 48
## 5 Cebolla 23 27 35 33 28 29 30 33 31
## 6 Chile verde 130 129 126 105 114 117 119 105 121
## 7 Espárrago 2 3 2 3 3 2 1 3 2
## 8 Frambuesa NA 2 4 NA 4 NA 3 2 2
## 9 Fresa NA 1 6 7 7 5 5 5 2
## 10 Limón 33 44 41 45 49 40 46 52 44
## 11 Mango 31 35 47 30 29 34 39 40 51
## 12 Pepino 22 33 23 32 31 32 21 28 32
## 13 Tomate rojo (… 57 55 62 51 57 67 42 66 76
## 14 Zarzamora 2 2 3 4 5 5 6 5 5
## # ℹ 13 more variables: `2012` <int>, `2013` <int>, `2014` <int>, `2015` <int>,
## # `2016` <int>, `2017` <int>, `2018` <int>, `2019` <int>, `2020` <int>,
## # `2021` <int>, `2022` <int>, `2023` <int>, `2024` <int>
municipios_plot <- ggplot(municipios_cultivo,
aes(x = Anio, y = num_municipios,
color = Nomcultivo, group = Nomcultivo)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.8) +
scale_x_continuous(breaks = seq(2003, 2024, by = 2)) +
scale_color_manual(values = colorRampPalette(
RColorBrewer::brewer.pal(12, "Set3"))(14)) +
labs(
title = "Municipios Productores por Cultivo y Año",
subtitle = "México 2003–2024",
x = "Año",
y = "Número de municipios",
color = "Cultivo"
) +
theme_minimal(base_size = 12) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "right",
legend.text = element_text(size = 9)
)
ggsave("municipios_por_cultivo.png", municipios_plot, dpi = 300, width = 14, height = 8)
municipios_plot# Calcular porcentajes
municipios_par_cultivo <- municipios_cultivo %>%
group_by(Anio) %>%
mutate(
total_anio = sum(num_municipios, na.rm = TRUE),
pct = num_municipios / total_anio
) %>%
ungroup() %>%
arrange(Anio, desc(pct))
municipios_par_plot <- ggplot(
municipios_par_cultivo %>%
group_by(Anio) %>%
arrange(desc(pct), .by_group = TRUE),
aes(
x = factor(Anio),
y = pct,
fill = Nomcultivo,
group = interaction(Anio, reorder(Nomcultivo, pct))
)
) +
geom_bar(stat = "identity", position = "stack") +
geom_text(
aes(label = ifelse(pct > 0.02, scales::percent(pct, accuracy = 0.1), NA)),
position = position_stack(vjust = 0.5),
size = 2.5,
na.rm = TRUE
) +
scale_y_continuous(labels = scales::percent_format()) +
scale_x_discrete(drop = FALSE) +
scale_fill_manual(values = colorRampPalette(
RColorBrewer::brewer.pal(12, "Set3"))(14)) +
labs(
title = "Participación de Municipios Productores por Cultivo y Año",
subtitle = "México 2003–2024",
x = "Año",
y = "Porcentaje de municipios",
fill = "Cultivo"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "right",
legend.text = element_text(size = 9)
)
ggsave("municipios_par_plot.png", municipios_par_plot, dpi = 300, width = 14, height = 8)
municipios_par_plot# Transformar para radar
radar_data <- municipios_par_cultivo %>%
select(Anio, Nomcultivo, pct) %>%
pivot_wider(names_from = Nomcultivo, values_from = pct, values_fill = 0) %>%
arrange(Anio)
radar_values <- radar_data %>%
select(-Anio) %>%
mutate(across(everything(), as.numeric))
radar_data_fixed <- radar_values
radar_data_fixed$group <- as.character(radar_data$Anio)
radar_data_fixed <- radar_data_fixed %>% select(group, everything())
# Paleta de colores
anios <- as.numeric(radar_data$Anio)
colores <- colorRampPalette(brewer.pal(12, "Set3"))(length(anios))
# Crear frames del radar
dir.create("frames_radar", showWarnings = FALSE)
unlink(list.files("frames_radar", full.names = TRUE), recursive = FALSE)
for (i in seq_along(anios)) {
anio_i <- anios[i]
datos_i <- radar_data_fixed %>% slice(i)
p <- ggradar(
datos_i,
values.radar = c("0%", "15%", "30%"),
grid.min = 0,
grid.mid = 0.15,
grid.max = 0.30,
group.colours = colores[i],
group.line.width = 1.5,
group.point.size = 3,
axis.label.size = 3,
grid.label.size = 4,
legend.position = "none",
plot.title = paste0("Municipios Productores por Cultivo\nMéxico — ", anio_i)
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 10, face = "plain"),
legend.position = "none"
)
ggsave(
filename = file.path("frames_radar", sprintf("frame_%02d.png", i)),
plot = p, width = 10, height = 8, dpi = 300
)
}
# Generar GIF
frames <- list.files("frames_radar", full.names = TRUE, pattern = "frame_.*png")
gifski(
png_files = frames,
gif_file = "radar_municipios.gif",
width = 1500,
height = 1200,
delay = 1.5
)## [1] "/home/arimarhol/Documents/Cursos-R/Laboratorio-2/radar_municipios.gif"
primer_anio <- min(data$Anio, na.rm = TRUE)
ultimo_anio <- max(data$Anio, na.rm = TRUE)
# Mediana por cultivo
medianas <- data %>%
group_by(Nomcultivo) %>%
summarise(mediana_total = median(Valorproduccion, na.rm = TRUE), .groups = "drop")
# Crecimiento entre primer y último año
crecimiento_total <- data %>%
filter(Anio %in% c(primer_anio, ultimo_anio)) %>%
group_by(Nomcultivo, Anio) %>%
summarise(produccion = mean(Valorproduccion, na.rm = TRUE), .groups = "drop") %>%
pivot_wider(names_from = Anio, values_from = produccion, names_prefix = "anio_") %>%
rename(
produccion_inicial = !!sym(paste0("anio_", primer_anio)),
produccion_final = !!sym(paste0("anio_", ultimo_anio))
) %>%
left_join(medianas, by = "Nomcultivo") %>%
mutate(
produccion_inicial = if_else(is.na(produccion_inicial), mediana_total, produccion_inicial),
produccion_final = if_else(is.na(produccion_final), mediana_total, produccion_final),
crecimiento_pct = (produccion_final / produccion_inicial - 1) * 100
) %>%
filter(produccion_inicial > 0, is.finite(crecimiento_pct)) %>%
select(-mediana_total)# Siete clasificaciones de crecimiento
crecimiento_total <- crecimiento_total %>%
mutate(
clasificacion = case_when(
crecimiento_pct >= 1000 ~ "Crecimiento explosivo (≥1000%)",
crecimiento_pct >= 200 ~ "Crecimiento muy alto (200-999%)",
crecimiento_pct >= 50 ~ "Crecimiento alto (50-199%)",
crecimiento_pct >= 10 ~ "Crecimiento moderado (10-49%)",
crecimiento_pct >= 0 ~ "Crecimiento leve (0-9%)",
crecimiento_pct >= -20 ~ "Declive leve (-20% a -0.1%)",
TRUE ~ "Declive severo (< -20%)"
)
)
# Orden de categorías
orden_categorias <- c(
"Crecimiento explosivo (≥1000%)",
"Crecimiento muy alto (200-999%)",
"Crecimiento alto (50-199%)",
"Crecimiento moderado (10-49%)",
"Crecimiento leve (0-9%)",
"Declive leve (-20% a -0.1%)",
"Declive severo (< -20%)"
)
crecimiento_total$clasificacion <- factor(crecimiento_total$clasificacion, levels = orden_categorias)
# Paleta de colores
colores_categorias <- c(
"Crecimiento explosivo (≥1000%)" = "#00441B",
"Crecimiento muy alto (200-999%)" = "#006D2C",
"Crecimiento alto (50-199%)" = "#238B45",
"Crecimiento moderado (10-49%)" = "#66C2A4",
"Crecimiento leve (0-9%)" = "#BAE4B3",
"Declive leve (-20% a -0.1%)" = "#FCAE91",
"Declive severo (< -20%)" = "#CB181D"
)crecimiento_plot <- ggplot(crecimiento_total,
aes(x = reorder(Nomcultivo, crecimiento_pct),
y = crecimiento_pct,
fill = clasificacion)) +
geom_col(width = 0.7) +
geom_hline(yintercept = 0, linetype = "solid", color = "gray30", linewidth = 0.8) +
geom_text(aes(label = round(crecimiento_pct, 1)),
hjust = -0.1, size = 3, color = "black") +
coord_flip() +
scale_y_continuous(
trans = pseudo_log_trans(sigma = 0.1),
breaks = c(-50, 0, 50, 100, 500, 1000, 5000, 10000, 20000, 50000),
labels = comma_format(accuracy = 1),
limits = c(-50, 55000),
expand = expansion(mult = c(0.02, 0.15))
) +
scale_fill_manual(values = colores_categorias, name = "Clasificación") +
labs(
title = "Crecimiento del Volumen de Producción por Cultivo",
subtitle = paste(primer_anio, "--", ultimo_anio),
x = "Crecimiento (%) – escala pseudo‑logarítmica",
y = NULL,
caption = "Nota: Valores faltantes imputados con mediana del cultivo (todos los años).\nCultivos con producción inicial imputada ≤ 0 excluidos."
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(color = "gray40", hjust = 0.5),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
legend.position = "top",
legend.box = "vertical",
panel.grid = element_blank()
)
ggsave("crecimiento_final.png", crecimiento_plot, dpi = 300, width = 14, height = 10)
crecimiento_plot# Leer shapefile (los archivos .shp, .dbf, .shx y .prj deben estar en la misma carpeta)
estados_sf <- st_read("00ent.shp")## Reading layer `00ent' from data source
## `/home/arimarhol/Documents/Cursos-R/Laboratorio-2/00ent.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 32 features and 3 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 911292 ymin: 319149.1 xmax: 4083063 ymax: 2349615
## Projected CRS: MEXICO_ITRF_2008_LCC
## Rows: 32
## Columns: 4
## $ CVEGEO <chr> "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "…
## $ CVE_ENT <chr> "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "…
## $ NOMGEO <chr> "Aguascalientes", "Baja California", "Baja California Sur", "…
## $ geometry <MULTIPOLYGON [m]> MULTIPOLYGON (((2469551 115..., MULTIPOLYGON (((…
# Estandarizar nombres de entidades federativas en la base de datos
data <- data %>%
mutate(Nomestado = case_when(
Nomestado %in% c("Michoacán", "Michoacán de Ocampo") ~ "Michoacán de Ocampo",
Nomestado %in% c("Ciudad de México / DF", "Ciudad de México") ~ "Ciudad de México",
Nomestado %in% c("Coahuila", "Coahuila de Zaragoza") ~ "Coahuila de Zaragoza",
Nomestado %in% c("Veracruz", "Veracruz de Ignacio de la Llave") ~ "Veracruz de Ignacio de la Llave",
TRUE ~ Nomestado
))
# Quitar acentos y convertir a mayúsculas para el join (Shapefile)
estados_sf <- estados_sf %>%
mutate(
nom_join = stri_trans_general(NOMGEO, "Latin-ASCII") %>%
toupper() %>%
trimws()
)
# Replicar para el dataframe
data <- data %>%
mutate(
nom_join = stri_trans_general(Nomestado, "Latin-ASCII") %>%
toupper() %>%
trimws()
)prod_estado_2024 <- data %>%
filter(Anio == 2024) %>%
group_by(nom_join) %>%
summarise(
produccion_total = sum(Volumenproduccion, na.rm = TRUE),
valor_total = sum(Valorproduccion, na.rm = TRUE),
.groups = "drop"
)
mapa_total <- estados_sf %>%
left_join(prod_estado_2024, by = "nom_join")
mapa_prod_total <- ggplot(mapa_total) +
geom_sf(aes(fill = produccion_total), color = "white", linewidth = 0.3) +
scale_fill_gradient(
low = "#d8f3dc",
high = "#1b4332",
na.value = "gray90",
name = "Producción\n(ton)",
labels = comma
) +
labs(
title = "Producción Agrícola Total por Estado (2024)",
subtitle = "Suma del volumen de producción de todos los cultivos exportables",
caption = "Fuente: SIAP"
) +
theme_void(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
legend.position = "right"
)
ggsave("mapa_produccion_total_2024.png", mapa_prod_total, dpi = 300, width = 12, height = 8)
mapa_prod_totalEjercicio 4A: Reproducir para el valor de la producción.
prod_estado_cultivo <- data %>%
filter(Anio == 2024) %>%
group_by(nom_join, Nomcultivo) %>%
summarise(
produccion = sum(Volumenproduccion, na.rm = TRUE),
valor = sum(Valorproduccion, na.rm = TRUE),
.groups = "drop"
)
# cross_join para que estados sin cultivo aparezcan en gris (NA)
mapa_cultivos <- estados_sf %>%
cross_join(tibble(Nomcultivo = unique(prod_estado_cultivo$Nomcultivo))) %>%
left_join(prod_estado_cultivo, by = c("nom_join", "Nomcultivo"))
mapa_facet <- ggplot(mapa_cultivos) +
geom_sf(aes(fill = produccion), color = "white", linewidth = 0.15) +
scale_fill_gradient(
low = "#fff3b0",
high = "#c1121f",
na.value = "gray92",
name = "Producción\n(ton)",
labels = comma,
trans = "sqrt" # escala raíz cuadrada para suavizar outliers
) +
facet_wrap(~ Nomcultivo, ncol = 4) +
labs(
title = "Producción por Cultivo y Estado (2024)",
subtitle = "Escala raíz cuadrada para manejar diferencias de magnitud",
caption = "Fuente: SIAP"
) +
theme_void(base_size = 9) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 13),
plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 10),
strip.text = element_text(face = "bold", size = 7.5),
legend.position = "right"
)
ggsave("mapa_cultivos_facet_2024.png", mapa_facet, dpi = 300, width = 20, height = 18)
mapa_facetEjercicio 4B: Reproducir para el valor de la producción.
# Estado con mayor producción por cultivo (2020-2024)
estado_lider <- data %>%
filter(Anio >= 2020) %>%
group_by(Nomcultivo, nom_join) %>%
summarise(produccion = sum(Valorproduccion, na.rm = TRUE), .groups = "drop") %>%
group_by(Nomcultivo) %>%
slice_max(produccion, n = 1, with_ties = FALSE) %>%
ungroup()
liderazgo_estado <- estado_lider %>%
group_by(nom_join) %>%
summarise(
cultivos_liderados = n(),
cultivos = paste(Nomcultivo, collapse = "\n"),
.groups = "drop"
)
mapa_liderazgo <- estados_sf %>%
left_join(liderazgo_estado, by = "nom_join") %>%
mutate(cultivos_liderados = factor(cultivos_liderados, levels = c("1", "2", "3")))
colores_discretos <- c(
"1" = "#c6dbef",
"2" = "#6baed6",
"3" = "#08519c"
)
contorno_nacional <- estados_sf %>%
st_union() %>%
st_boundary()
mapa_lider_plot <- ggplot() +
geom_sf(data = mapa_liderazgo,
aes(fill = cultivos_liderados),
color = "white", linewidth = 0.3) +
geom_sf(data = contorno_nacional,
color = "black", linewidth = 0.8, fill = NA) +
scale_fill_manual(
values = colores_discretos,
na.value = "gray90",
name = "N° cultivos\nliderados"
) +
labs(
title = "Estados Líderes de Producción por Número de Cultivos (2020-2024)",
subtitle = "Cada color representa la cantidad de cultivos donde el estado es el principal productor",
caption = "Fuente: SIAP"
) +
theme_void(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
legend.position = "right"
)
ggsave("mapa_liderazgo_estados.png", mapa_lider_plot, dpi = 300, width = 12, height = 8)
mapa_lider_plotEjercicio 4C: Reproducir para el valor de la producción.
# Crear carpetas de salida
dir.create("mapas_anuales", showWarnings = FALSE)
dir.create("mapas_anuales/total", showWarnings = FALSE)
dir.create("mapas_anuales/facet", showWarnings = FALSE)
dir.create("mapas_anuales/por_cultivo", showWarnings = FALSE)
anios <- sort(unique(data$Anio))
cultivos_lista <- sort(unique(data$Nomcultivo))
# Rangos fijos para escalas consistentes
rango_total <- data %>%
group_by(Anio, nom_join) %>%
summarise(prod = sum(Volumenproduccion, na.rm = TRUE), .groups = "drop") %>%
summarise(min = min(prod, na.rm = TRUE), max = max(prod, na.rm = TRUE))
rango_cultivos <- data %>%
group_by(Nomcultivo, nom_join, Anio) %>%
summarise(prod = sum(Volumenproduccion, na.rm = TRUE), .groups = "drop") %>%
group_by(Nomcultivo) %>%
summarise(max_prod = max(prod, na.rm = TRUE), .groups = "drop")for (anio_i in anios) {
datos_anio <- data %>%
filter(Anio == anio_i) %>%
group_by(nom_join) %>%
summarise(produccion_total = sum(Volumenproduccion, na.rm = TRUE), .groups = "drop")
mapa_i <- estados_sf %>%
left_join(datos_anio, by = "nom_join")
p <- ggplot(mapa_i) +
geom_sf(aes(fill = produccion_total), color = "white", linewidth = 0.3) +
scale_fill_viridis_c(
name = "Producción\n(ton)",
labels = comma,
na.value = "gray90",
option = "viridis"
) +
labs(
title = paste("Producción Agrícola Total por Estado —", anio_i),
subtitle = "Suma de todos los cultivos exportables | Escala viridis flexible",
caption = "Fuente: SIAP"
) +
theme_void(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
legend.position = "right",
legend.key.width = unit(1.2, "cm"),
legend.key.height = unit(1.5, "cm"),
legend.text = element_text(size = 10),
legend.title = element_text(size = 11)
)
ggsave(sprintf("mapas_anuales/total/mapa_total_%d.png", anio_i),
p, dpi = 150, width = 12, height = 8)
message(sprintf(" Guardado: mapa_total_%d.png", anio_i))
}
message("✅ Loop 5A completado")
# Convertir a GIF
carpeta <- "mapas_anuales/total/"
archivos <- list.files(carpeta, pattern = "mapa_total_.*\\.png$", full.names = TRUE)
anios_ord <- as.numeric(gsub(".*mapa_total_([0-9]+)\\.png", "\\1", basename(archivos)))
archivos <- archivos[order(anios_ord)]
gifski(
png_files = archivos,
gif_file = "produccion_total_animado.gif",
width = 900,
height = 600,
delay = 0.5
)## [1] "/home/arimarhol/Documents/Cursos-R/Laboratorio-2/produccion_total_animado.gif"
Ejercicio 5A: Reproducir para el valor de la producción.
for (anio_i in anios) {
datos_anio_cultivo <- data %>%
filter(Anio == anio_i) %>%
group_by(nom_join, Nomcultivo) %>%
summarise(produccion = sum(Volumenproduccion, na.rm = TRUE), .groups = "drop")
cultivos_anio <- unique(datos_anio_cultivo$Nomcultivo)
mapa_facet_i <- estados_sf %>%
cross_join(tibble(Nomcultivo = cultivos_anio)) %>%
left_join(datos_anio_cultivo, by = c("nom_join", "Nomcultivo"))
p <- ggplot(mapa_facet_i) +
geom_sf(aes(fill = produccion), color = "white", linewidth = 0.2) +
scale_fill_viridis_c(
name = "Producción\n(ton)",
labels = comma,
option = "viridis",
na.value = "gray95"
) +
facet_wrap(~ Nomcultivo, ncol = 4) +
labs(
title = paste("Distribución Geográfica de Cultivos por Estado —", anio_i),
subtitle = "Cada panel representa un cultivo | Escala viridis (flexible)",
caption = "Fuente: SIAP"
) +
theme_void(base_size = 9) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 9),
strip.text = element_text(face = "bold", size = 7),
legend.position = "bottom",
legend.key.width = unit(1.5, "cm"),
legend.key.height = unit(0.5, "cm"),
legend.text = element_text(size = 10),
legend.title = element_text(size = 11)
)
ggsave(sprintf("mapas_anuales/facet/mapa_facet_%d.png", anio_i),
p, dpi = 150, width = 14, height = 12)
message(sprintf(" Guardado: mapa_facet_%d.png", anio_i))
}
# Convertir a GIF
carpeta <- "mapas_anuales/facet/"
archivos <- list.files(carpeta, pattern = "mapa_facet_.*\\.png$", full.names = TRUE)
anios_ord <- as.numeric(gsub(".*mapa_facet_([0-9]+)\\.png", "\\1", basename(archivos)))
archivos <- archivos[order(anios_ord)]
gifski(
png_files = archivos,
gif_file = "mapa_facet_animado.gif",
width = 1000,
height = 800,
delay = 0.8
)## [1] "mapa_facet_animado.gif"
Ejercicio 5B: Reproducir para el valor de la producción.
anios_por_imagen <- 6
grupos_anios <- split(anios, ceiling(seq_along(anios) / anios_por_imagen))
for (cultivo_i in cultivos_lista) {
datos_cultivo <- data %>%
filter(Nomcultivo == cultivo_i) %>%
group_by(nom_join, Anio) %>%
summarise(produccion = sum(Volumenproduccion, na.rm = TRUE), .groups = "drop")
for (g in seq_along(grupos_anios)) {
anios_grupo <- grupos_anios[[g]]
rango_grupo <- range(anios_grupo)
datos_grupo <- datos_cultivo %>% filter(Anio %in% anios_grupo)
mapa_cultivo_grupo <- estados_sf %>%
cross_join(tibble(Anio = anios_grupo)) %>%
left_join(datos_grupo, by = c("nom_join", "Anio"))
p <- ggplot(mapa_cultivo_grupo) +
geom_sf(aes(fill = produccion), color = "white", linewidth = 0.15) +
scale_fill_viridis_c(
name = "Producción\n(ton)",
labels = comma,
na.value = "gray92",
option = "viridis"
) +
facet_wrap(~ Anio, ncol = 3) +
labs(
title = paste("Evolución Geográfica de la Producción —", cultivo_i),
subtitle = paste(rango_grupo[1], "-", rango_grupo[2],
"| Escala viridis flexible | Máx. 6 años por imagen"),
caption = "Fuente: SIAP"
) +
theme_void(base_size = 10) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 10),
strip.text = element_text(face = "bold", size = 9),
legend.position = "bottom",
legend.key.width = unit(1.8, "cm"),
legend.key.height = unit(0.6, "cm"),
legend.text = element_text(size = 11),
legend.title = element_text(size = 12)
)
nombre_limpio <- gsub("[^a-zA-Z0-9]", "_", tolower(cultivo_i))
nombre_archivo <- sprintf("mapas_anuales/por_cultivo/evolucion_%s_%d_%d.png",
nombre_limpio, min(anios_grupo), max(anios_grupo))
ggsave(nombre_archivo, p, dpi = 150, width = 12, height = 10)
message(sprintf(" Guardado: %s [%s, años %d-%d]",
nombre_archivo, cultivo_i, min(anios_grupo), max(anios_grupo)))
}
}
message("✅ Loop 5C completado: mapas por cultivo divididos en grupos de años")
# Crear un GIF por cultivo
carpeta_cultivos <- "mapas_anuales/por_cultivo/"
todos_archivos <- list.files(carpeta_cultivos, pattern = "evolucion_.*\\.png$", full.names = TRUE)
cultivos_lista_gif <- unique(gsub("evolucion_([^_]+)_.*", "\\1", basename(todos_archivos)))
for (cultivo in cultivos_lista_gif) {
archivos_cultivo <- todos_archivos[grepl(sprintf("evolucion_%s_", cultivo), basename(todos_archivos))]
anios_inicio <- as.numeric(gsub(sprintf("evolucion_%s_([0-9]+)_[0-9]+\\.png", cultivo), "\\1", basename(archivos_cultivo)))
archivos_cultivo <- archivos_cultivo[order(anios_inicio)]
gifski(
png_files = archivos_cultivo,
gif_file = sprintf("mapas_anuales/por_cultivo/%s_evolucion_completa.gif", cultivo),
width = 800,
height = 700,
delay = 1.2
)
message(sprintf("✅ GIF creado para cultivo: %s", cultivo))
}
message("🎉 Todos los GIFs por cultivo han sido generados.")Ejercicio 5C: Reproducir para el valor de la producción.
Fin de la Práctica 2