#install.packages("dplyr")
#install.packages("ggplot2")
library(dplyr) ## Manipulación de datos
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2) ## Creación de visualizaciones
##Carga de las bases de datos
load("base_final_graficos.Rdata")
# Cargar la base de datos
load("base_final_graficos.Rdata")
# Ver las primeras filas de la base principal
head(base_final_long)
## # A tibble: 6 × 8
## codigo_municipio nombre_municipio Sexo Fuente anio casos Codigo Departamento
## <chr> <chr> <chr> <chr> <int> <dbl> <chr> <chr>
## 1 19001 Popayán F RIPS 2009 248 19 Cauca
## 2 19001 Popayán F RIPS 2010 493 19 Cauca
## 3 19001 Popayán F RIPS 2011 1174 19 Cauca
## 4 19001 Popayán F RIPS 2012 2230 19 Cauca
## 5 19001 Popayán F RIPS 2013 3394 19 Cauca
## 6 19001 Popayán F RIPS 2014 4667 19 Cauca
# Tomo el objeto cargado (base_final_long) y lo renombro
stopifnot(exists("base_final_long"))
base_final_grafico <- tibble::as_tibble(base_final_long)
# Chequeo rápido
dim(base_final_grafico)
## [1] 3894 8
# Estructura y dimensiones
str(base_final_grafico) # estructura base R
## tibble [3,894 × 8] (S3: tbl_df/tbl/data.frame)
## $ codigo_municipio: chr [1:3894] "19001" "19001" "19001" "19001" ...
## $ nombre_municipio: chr [1:3894] "Popayán" "Popayán" "Popayán" "Popayán" ...
## $ Sexo : chr [1:3894] "F" "F" "F" "F" ...
## $ Fuente : chr [1:3894] "RIPS" "RIPS" "RIPS" "RIPS" ...
## $ anio : int [1:3894] 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 ...
## $ casos : num [1:3894] 248 493 1174 2230 3394 ...
## $ Codigo : chr [1:3894] "19" "19" "19" "19" ...
## $ Departamento : chr [1:3894] "Cauca" "Cauca" "Cauca" "Cauca" ...
dplyr::glimpse(base_final_grafico) # estructura como tibble
## Rows: 3,894
## Columns: 8
## $ codigo_municipio <chr> "19001", "19001", "19001", "19001", "19001", "19001",…
## $ nombre_municipio <chr> "Popayán", "Popayán", "Popayán", "Popayán", "Popayán"…
## $ Sexo <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F"…
## $ Fuente <chr> "RIPS", "RIPS", "RIPS", "RIPS", "RIPS", "RIPS", "RIPS…
## $ anio <int> 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,…
## $ casos <dbl> 248, 493, 1174, 2230, 3394, 4667, 6774, 8722, 11429, …
## $ Codigo <chr> "19", "19", "19", "19", "19", "19", "19", "19", "19",…
## $ Departamento <chr> "Cauca", "Cauca", "Cauca", "Cauca", "Cauca", "Cauca",…
dim(base_final_grafico) # (filas, columnas)
## [1] 3894 8
nrow(base_final_grafico) # filas
## [1] 3894
ncol(base_final_grafico) # columnas
## [1] 8
names(base_final_grafico) # nombres de variables
## [1] "codigo_municipio" "nombre_municipio" "Sexo" "Fuente"
## [5] "anio" "casos" "Codigo" "Departamento"
# Vistas rápidas
head(base_final_grafico) # 6 primeras
## # A tibble: 6 × 8
## codigo_municipio nombre_municipio Sexo Fuente anio casos Codigo Departamento
## <chr> <chr> <chr> <chr> <int> <dbl> <chr> <chr>
## 1 19001 Popayán F RIPS 2009 248 19 Cauca
## 2 19001 Popayán F RIPS 2010 493 19 Cauca
## 3 19001 Popayán F RIPS 2011 1174 19 Cauca
## 4 19001 Popayán F RIPS 2012 2230 19 Cauca
## 5 19001 Popayán F RIPS 2013 3394 19 Cauca
## 6 19001 Popayán F RIPS 2014 4667 19 Cauca
head(base_final_grafico, 10) # 10 primeras
## # A tibble: 10 × 8
## codigo_municipio nombre_municipio Sexo Fuente anio casos Codigo
## <chr> <chr> <chr> <chr> <int> <dbl> <chr>
## 1 19001 Popayán F RIPS 2009 248 19
## 2 19001 Popayán F RIPS 2010 493 19
## 3 19001 Popayán F RIPS 2011 1174 19
## 4 19001 Popayán F RIPS 2012 2230 19
## 5 19001 Popayán F RIPS 2013 3394 19
## 6 19001 Popayán F RIPS 2014 4667 19
## 7 19001 Popayán F RIPS 2015 6774 19
## 8 19001 Popayán F RIPS 2016 8722 19
## 9 19001 Popayán F RIPS 2017 11429 19
## 10 19001 Popayán F RIPS 2018 13820 19
## # ℹ 1 more variable: Departamento <chr>
tail(base_final_grafico) # 6 últimas
## # A tibble: 6 × 8
## codigo_municipio nombre_municipio Sexo Fuente anio casos Codigo Departamento
## <chr> <chr> <chr> <chr> <int> <dbl> <chr> <chr>
## 1 76895 Zarzal M RIPS 2014 376 76 Valle
## 2 76895 Zarzal M RIPS 2015 538 76 Valle
## 3 76895 Zarzal M RIPS 2016 640 76 Valle
## 4 76895 Zarzal M RIPS 2017 897 76 Valle
## 5 76895 Zarzal M RIPS 2018 1066 76 Valle
## 6 76895 Zarzal M RIPS 2019 1201 76 Valle
# Resumen para todas las variables numéricas
base_final_grafico %>%
dplyr::summarise(
dplyr::across(
where(is.numeric),
list(
n = ~sum(!is.na(.)),
na = ~sum(is.na(.)),
media = ~mean(., na.rm = TRUE),
sd = ~sd(., na.rm = TRUE),
min = ~min(., na.rm = TRUE),
q25 = ~quantile(., 0.25, na.rm = TRUE),
mediana = ~median(., na.rm = TRUE),
q75 = ~quantile(., 0.75, na.rm = TRUE),
max = ~max(., na.rm = TRUE)
),
.names = "{.col}__{.fn}"
)
)
## # A tibble: 1 × 18
## anio__n anio__na anio__media anio__sd anio__min anio__q25 anio__mediana
## <int> <int> <dbl> <dbl> <int> <dbl> <dbl>
## 1 3894 0 2014 3.16 2009 2011 2014
## # ℹ 11 more variables: anio__q75 <dbl>, anio__max <int>, casos__n <int>,
## # casos__na <int>, casos__media <dbl>, casos__sd <dbl>, casos__min <dbl>,
## # casos__q25 <dbl>, casos__mediana <dbl>, casos__q75 <dbl>, casos__max <dbl>
# NA por variable (tabla tidy)
tibble::tibble(variable = names(base_final_grafico)) %>%
dplyr::mutate(
n = purrr::map_int(variable, ~sum(!is.na(base_final_grafico[[.x]]))),
na = purrr::map_int(variable, ~sum( is.na(base_final_grafico[[.x]]))),
prop_na = round(na / (n + na), 3)
)
## # A tibble: 8 × 4
## variable n na prop_na
## <chr> <int> <int> <dbl>
## 1 codigo_municipio 3894 0 0
## 2 nombre_municipio 3894 0 0
## 3 Sexo 3894 0 0
## 4 Fuente 3894 0 0
## 5 anio 3894 0 0
## 6 casos 2661 1233 0.317
## 7 Codigo 3894 0 0
## 8 Departamento 3894 0 0
# Resúmenes ejemplo (solo si existen esas columnas)
if ("casos" %in% names(base_final_grafico)) {
base_final_grafico %>%
dplyr::summarise(
n_registros = dplyr::n(),
total_casos = sum(casos, na.rm = TRUE),
media_casos = mean(casos, na.rm = TRUE),
sd_casos = sd(casos, na.rm = TRUE),
mediana_casos = median(casos, na.rm = TRUE)
)
}
## # A tibble: 1 × 5
## n_registros total_casos media_casos sd_casos mediana_casos
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 3894 4104207 1542. 12935. 116
if (all(c("Departamento","anio","casos") %in% names(base_final_grafico))) {
base_final_grafico %>%
dplyr::group_by(Departamento, anio) %>%
dplyr::summarise(total_casos = sum(casos, na.rm = TRUE), .groups = "drop") %>%
dplyr::arrange(Departamento, anio)
}
## # A tibble: 44 × 3
## Departamento anio total_casos
## <chr> <int> <dbl>
## 1 Cauca 2009 1765
## 2 Cauca 2010 3937
## 3 Cauca 2011 7226
## 4 Cauca 2012 14603
## 5 Cauca 2013 22762
## 6 Cauca 2014 32620
## 7 Cauca 2015 41642
## 8 Cauca 2016 49071
## 9 Cauca 2017 62175
## 10 Cauca 2018 78855
## # ℹ 34 more rows
# PartO de mi base larga ya cargada: base_final_grafico
stopifnot(exists("base_final_grafico"))
# Alias con el nombre que espera la guía
base_final <- tibble::as_tibble(base_final_grafico)
# Chequeos útiles
dplyr::distinct(base_final, Departamento) %>% dplyr::arrange(Departamento)
## # A tibble: 4 × 1
## Departamento
## <chr>
## 1 Cauca
## 2 Choco
## 3 Narino
## 4 Valle
dplyr::distinct(base_final, Sexo)
## # A tibble: 2 × 1
## Sexo
## <chr>
## 1 F
## 2 M
names(base_final)
## [1] "codigo_municipio" "nombre_municipio" "Sexo" "Fuente"
## [5] "anio" "casos" "Codigo" "Departamento"
# La guía me solicita: una fila por municipio (Muni) y una columna por año.
# 1) Renombramos 'nombre_municipio' -> 'Muni' y nos quedamos con lo necesario
base_final <- base_final %>%
dplyr::rename(Muni = nombre_municipio) %>%
dplyr::select(Departamento, Sexo, Muni, anio, casos)
# 2) Aseguro tipos y agregamos por si hay duplicados
base_final <- base_final %>%
dplyr::mutate(anio = as.integer(anio)) %>%
dplyr::group_by(Departamento, Sexo, Muni, anio) %>%
dplyr::summarise(casos = sum(casos, na.rm = TRUE), .groups = "drop")
# 3) Pivot a ancho: una columna por año
base_final <- base_final %>%
tidyr::pivot_wider(
names_from = anio, values_from = casos,
values_fn = sum, values_fill = 0
) %>%
dplyr::arrange(Departamento, Muni)
# 4) Ordeno columnas: (Departamento, Sexo, Muni, 2009..2019) si existen
years <- as.character(2009:2019)
year_cols <- intersect(years, names(base_final))
base_final <- base_final[, c(setdiff(names(base_final), years), year_cols)]
# La guía: filtrar Valle del Cauca y Sexo F
# (Hacemos el filtro robusto a mayúsculas/minúsculas)
base_graficos <- base_final %>%
dplyr::filter(stringr::str_detect(Departamento, stringr::regex("^valle", ignore_case = TRUE)),
Sexo == "F") %>%
dplyr::select(Muni, dplyr::all_of(year_cols))
# Si faltara algún año en la base, lo creo con 0 para que no falle:
faltan <- setdiff(years, names(base_graficos))
for (y in faltan) base_graficos[[y]] <- 0L
base_graficos <- base_graficos[, c("Muni", years)]
# Adapto al bloque de la guía:
# Transponemos para tener los años en filas y municipios en columnas
bg_t <- as.data.frame(t(base_graficos), stringsAsFactors = FALSE)
# La primera "fila" de bg_t (que es la columna 'Muni' original) pasa a ser nombres de columnas
colnames(bg_t) <- bg_t[1, ]
bg_t <- bg_t[-1, , drop = FALSE]
# Creo columna 'anio' desde los rownames
bg_t$anio <- rownames(bg_t)
# Convierto a numéricas las columnas de municipios; 'anio' a entero
num_cols <- setdiff(names(bg_t), "anio")
bg_t[num_cols] <- lapply(bg_t[num_cols], function(x) suppressWarnings(as.numeric(x)))
bg_t$anio <- as.integer(bg_t$anio)
rownames(bg_t) <- NULL
# Dejo el objeto final con el nombre de la guía
base_graficos <- bg_t
# Vista rápida
head(base_graficos)
## Alcalá Andalucía Ansermanuevo Argelia Bolívar Buenaventura Bugalagrande
## 1 3 11 1 0 0 73 4
## 2 4 38 2 0 0 226 8
## 3 0 138 14 0 3 773 20
## 4 6 226 0 1 7 1946 248
## 5 16 349 17 14 9 2830 380
## 6 67 496 48 0 19 4092 905
## Caicedonia Cali Calima Candelaria Cartago Dagua El Cairo El Cerrito El Dovio
## 1 127 2397 0 64 144 2 0 19 0
## 2 208 6012 0 110 265 8 0 29 0
## 3 385 14720 2 233 464 77 0 136 9
## 4 744 28312 3 1270 772 0 7 213 0
## 5 997 40138 14 1414 1266 78 11 657 0
## 6 1363 54700 34 1606 1706 83 61 854 33
## El Águila Florida Ginebra Guacarí Guadalajara De Buga Jamundí La Cumbre
## 1 12 7 0 0 51 30 0
## 2 15 25 0 14 109 42 0
## 3 0 60 15 21 424 126 1
## 4 18 146 25 46 831 241 3
## 5 0 200 44 76 1190 400 0
## 6 19 571 74 117 1751 535 0
## La Unión La Victoria Obando Palmira Pradera Restrepo Riofrío Roldanillo
## 1 0 2 2 130 43 4 12 39
## 2 0 0 0 337 83 8 23 67
## 3 0 0 5 638 151 19 71 83
## 4 16 0 0 1444 393 62 221 107
## 5 66 3 18 1975 491 70 310 126
## 6 136 15 88 2747 659 79 389 166
## San Pedro Sevilla Toro Trujillo Tuluá Ulloa Versalles Vijes Yotoco Yumbo
## 1 0 16 3 0 199 12 0 0 0 31
## 2 0 56 11 10 422 18 0 7 11 88
## 3 0 142 36 19 1119 23 1 30 118 222
## 4 0 260 49 37 2281 29 0 89 211 470
## 5 42 431 70 74 3292 34 0 120 271 1570
## 6 71 635 121 97 4405 35 0 147 375 2089
## Zarzal anio
## 1 61 2009
## 2 80 2010
## 3 122 2011
## 4 210 2012
## 5 324 2013
## 6 454 2014
str(base_graficos)
## 'data.frame': 11 obs. of 43 variables:
## $ Alcalá : num 3 4 0 6 16 67 110 168 205 221 ...
## $ Andalucía : num 11 38 138 226 349 496 597 686 770 813 ...
## $ Ansermanuevo : num 1 2 14 0 17 48 118 138 178 377 ...
## $ Argelia : num 0 0 0 1 14 0 17 0 20 24 ...
## $ Bolívar : num 0 0 3 7 9 19 30 32 35 0 ...
## $ Buenaventura : num 73 226 773 1946 2830 ...
## $ Bugalagrande : num 4 8 20 248 380 ...
## $ Caicedonia : num 127 208 385 744 997 ...
## $ Cali : num 2397 6012 14720 28312 40138 ...
## $ Calima : num 0 0 2 3 14 34 41 69 100 302 ...
## $ Candelaria : num 64 110 233 1270 1414 ...
## $ Cartago : num 144 265 464 772 1266 ...
## $ Dagua : num 2 8 77 0 78 83 90 91 133 377 ...
## $ El Cairo : num 0 0 0 7 11 61 72 84 89 0 ...
## $ El Cerrito : num 19 29 136 213 657 ...
## $ El Dovio : num 0 0 9 0 0 33 48 0 58 66 ...
## $ El Águila : num 12 15 0 18 0 19 0 20 28 63 ...
## $ Florida : num 7 25 60 146 200 ...
## $ Ginebra : num 0 0 15 25 44 74 105 144 316 459 ...
## $ Guacarí : num 0 14 21 46 76 117 154 231 373 420 ...
## $ Guadalajara De Buga: num 51 109 424 831 1190 ...
## $ Jamundí : num 30 42 126 241 400 ...
## $ La Cumbre : num 0 0 1 3 0 0 0 0 0 54 ...
## $ La Unión : num 0 0 0 16 66 136 189 212 274 372 ...
## $ La Victoria : num 2 0 0 0 3 15 0 20 39 87 ...
## $ Obando : num 2 0 5 0 18 88 181 275 308 321 ...
## $ Palmira : num 130 337 638 1444 1975 ...
## $ Pradera : num 43 83 151 393 491 ...
## $ Restrepo : num 4 8 19 62 70 79 119 133 226 400 ...
## $ Riofrío : num 12 23 71 221 310 389 419 452 497 720 ...
## $ Roldanillo : num 39 67 83 107 126 166 214 225 329 482 ...
## $ San Pedro : num 0 0 0 0 42 71 95 148 173 273 ...
## $ Sevilla : num 16 56 142 260 431 ...
## $ Toro : num 3 11 36 49 70 121 161 213 258 322 ...
## $ Trujillo : num 0 10 19 37 74 97 116 134 188 307 ...
## $ Tuluá : num 199 422 1119 2281 3292 ...
## $ Ulloa : num 12 18 23 29 34 35 0 0 46 113 ...
## $ Versalles : num 0 0 1 0 0 0 0 0 2 15 ...
## $ Vijes : num 0 7 30 89 120 147 194 199 200 223 ...
## $ Yotoco : num 0 11 118 211 271 375 433 541 604 645 ...
## $ Yumbo : num 31 88 222 470 1570 ...
## $ Zarzal : num 61 80 122 210 324 ...
## $ anio : int 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 ...
# Reemplazo "Cali" por el municipio que tengo en columnas
plot(base_graficos$anio, base_graficos[["Cali"]], type = "l",
xlab = "Año", ylab = "Casos", main = "Cali (F) - Valle del Cauca")

x <- base_graficos$anio
y <- base_graficos[["Cali"]]
cambio_abs <- y[length(y)] - y[1]
cambio_rel <- 100 * cambio_abs / y[1]
tasa_media_anual <- (y[length(y)]/y[1])^(1/(length(y)-1)) - 1
data.frame(
anio_inicial = x[1], casos_inicial = y[1],
anio_final = x[length(x)], casos_final = y[length(y)],
cambio_abs, cambio_rel = round(cambio_rel, 1),
tasa_media_anual = scales::percent(tasa_media_anual)
)
## anio_inicial casos_inicial anio_final casos_final cambio_abs cambio_rel
## 1 2009 2397 2019 112346 109949 4586.9
## tasa_media_anual
## 1 47%
plot(x, y/1000, type="o", xlab="Año", ylab="Casos (miles)",
main="Cali (F) - Valle del Cauca")
grid()

plot_muni <- function(m){
y <- base_graficos[[m]]
plot(x, y, type="o", xlab="Año", ylab="Casos",
main=paste(m, "(F) - Valle del Cauca"))
grid()
}
# Ejemplos:
plot_muni("Cali")

# plot_muni("Palmira")
# Elijo municipio y preparo vectores
muni <- "Cali" # <- cámbialo si quieres
stopifnot(muni %in% names(base_graficos))
x <- base_graficos$anio # años (eje X “correcto”)
y <- base_graficos[[muni]] # serie del municipio
titulo <- paste(muni, "(F) - Valle del Cauca")
plot(base_graficos[[muni]], type = "l",
main = "Número de atenciones a mujeres por diagnósticos relacionados a VIH")

plot(x, y, type = "l", xlab = "Año", ylab = "Casos", main = titulo)
grid()

op <- options(scipen = 999) # evita notación científica
on.exit(options(op), add = TRUE)
plot(x, y, type = "l", xlab = "Año", ylab = "Casos", main = titulo,
xaxt = "n", yaxt = "n")
axis(1, at = x, labels = x)
tcks <- pretty(y)
axis(2, at = tcks, labels = format(tcks, big.mark = ".", decimal.mark = ","))
grid(); box()

plot(x, y/1000, type = "o", xlab = "Año", ylab = "Casos (miles)", main = titulo)
grid()

is.numeric(y) # debe ser TRUE
## [1] TRUE
summary(y) # revisa rangos
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2397 21516 54700 53958 82149 112346
any(diff(y) < 0) # FALSE = serie estrictamente ascendente
## [1] FALSE
plot_muni_pretty <- function(m, tipo = "l"){
stopifnot(m %in% names(base_graficos))
yy <- base_graficos[[m]]
op <- options(scipen = 999); on.exit(options(op), add = TRUE)
plot(x, yy, type = tipo, xlab = "Año", ylab = "Casos",
main = paste(m, "(F) - Valle del Cauca"), xaxt = "n", yaxt = "n")
axis(1, at = x, labels = x)
tcks <- pretty(yy)
axis(2, at = tcks, labels = format(tcks, big.mark = ".", decimal.mark = ","))
grid(); box()
}
# Ejemplos:
# plot_muni_pretty("Cali", "o")
# plot_muni_pretty("Palmira", "s")
# Municipio (usa el que ya vienes usando)
# muni <- "Cali"
y <- base_graficos[[muni]]
x <- base_graficos$anio
# Estadísticos
min_val <- min(y, na.rm = TRUE); min_year <- x[which.min(y)]
q1 <- as.numeric(quantile(y, 0.25, names = FALSE))
med <- as.numeric(quantile(y, 0.50, names = FALSE))
q3 <- as.numeric(quantile(y, 0.75, names = FALSE))
q1_year <- x[which.min(abs(y - q1))]
med_year <- x[which.min(abs(y - med))]
q3_year <- x[which.min(abs(y - q3))]
max_val <- max(y, na.rm = TRUE); max_year <- x[which.max(y)]
mean_val <- mean(y); sd_y <- sd(y)
cv <- sd_y / mean_val
IQR_y <- IQR(y)
rango <- max_val - min_val
cambio_abs <- y[length(y)] - y[1]
cambio_rel <- 100 * cambio_abs / y[1]
tasa_media_anual <- 100 * ((y[length(y)]/y[1])^(1/(length(y)-1)) - 1)
# Formateo bonito (puntos para miles, coma para decimales)
fmt_num <- function(v, dig = 0){
format(round(v, dig), big.mark = ".", decimal.mark = ",")
}
fmt_pct <- function(v, dig = 1){
paste0(format(round(v, dig), big.mark = ".", decimal.mark = ","), "%")
}
tabla <- tibble::tibble(
Medida = c(
"Mínimo", "Q1 (25%)", "Mediana (50%)", "Media", "Q3 (75%)", "Máximo",
"Rango (Máx − Mín)", "IQR (Q3 − Q1)", "Desviación estándar",
"Coeficiente de variación", "Cambio absoluto (último − primero)",
"Cambio relativo", "Crecimiento medio anual"
),
Valor = c(
fmt_num(min_val), fmt_num(q1), fmt_num(med), fmt_num(mean_val, 1),
fmt_num(q3), fmt_num(max_val), fmt_num(rango), fmt_num(IQR_y),
fmt_num(sd_y, 1), fmt_pct(cv*100), fmt_num(cambio_abs),
fmt_pct(cambio_rel), fmt_pct(tasa_media_anual)
),
`Año relacionado` = c(
min_year, q1_year, med_year, NA, q3_year, max_year,
NA, NA, NA, NA, NA, NA, NA
),
Explicación = c(
"Año con menor número de atenciones",
"25% de los años tuvieron ≤ este valor",
"50% de los años quedaron por debajo (año típico)",
"Promedio de todos los años",
"75% de los años tuvieron ≤ este valor",
"Año con mayor número de atenciones",
"Amplitud total de la serie (variación total)",
"Variabilidad del 50% central (Q1–Q3)",
"Dispersión promedio alrededor de la media",
"Variabilidad relativa (SD/Media × 100)",
"Diferencia entre último y primer año",
"Incremento total respecto al primer año",
"Crecimiento compuesto promedio por año"
)
)
knitr::kable(
tabla,
caption = paste("Resumen descriptivo de casos por año —", muni, "(F) - Valle del Cauca")
)
Resumen descriptivo de casos por año — Cali (F) - Valle del
Cauca
Mínimo |
2.397 |
2009 |
Año con menor número de atenciones |
Q1 (25%) |
21.516 |
2011 |
25% de los años tuvieron ≤ este valor |
Mediana (50%) |
54.700 |
2014 |
50% de los años quedaron por debajo (año típico) |
Media |
53.957,8 |
NA |
Promedio de todos los años |
Q3 (75%) |
82.149 |
2016 |
75% de los años tuvieron ≤ este valor |
Máximo |
112.346 |
2019 |
Año con mayor número de atenciones |
Rango (Máx − Mín) |
109.949 |
NA |
Amplitud total de la serie (variación total) |
IQR (Q3 − Q1) |
60.633 |
NA |
Variabilidad del 50% central (Q1–Q3) |
Desviación estándar |
38.937,4 |
NA |
Dispersión promedio alrededor de la media |
Coeficiente de variación |
72,2% |
NA |
Variabilidad relativa (SD/Media × 100) |
Cambio absoluto (último − primero) |
109.949 |
NA |
Diferencia entre último y primer año |
Cambio relativo |
4.586,9% |
NA |
Incremento total respecto al primer año |
Crecimiento medio anual |
46,9% |
NA |
Crecimiento compuesto promedio por año |
stopifnot(exists("base_graficos"), exists("muni"), muni %in% names(base_graficos))
anio <- base_graficos$anio
y <- base_graficos[[muni]]
# Cambios vs. año previo
prev <- c(NA, head(y, -1))
delta_abs <- y - prev
delta_pct <- (y / prev - 1) * 100
delta_pct[1] <- NA
delta_pct[is.infinite(delta_pct)] <- NA
total <- sum(y)
# Tabla base numérica
tab_num <- tibble::tibble(
Año = anio,
Casos = y,
`Δ abs. (vs. año previo)` = delta_abs,
`Δ % (vs. año previo)` = delta_pct,
`Acumulado` = cumsum(y),
`% del total` = 100 * y / total
)
# Formateo bonito
fmt_num <- function(v, dig = 0) format(round(v, dig), big.mark = ".", decimal.mark = ",")
fmt_pct <- function(v, dig = 1) ifelse(is.na(v), "–",
paste0(format(round(v, dig), big.mark = ".", decimal.mark = ","), "%"))
tab_fmt <- tab_num %>%
dplyr::mutate(
Año = as.character(Año), # <- clave para que bind_rows no falle
Casos = fmt_num(Casos),
`Δ abs. (vs. año previo)` = ifelse(is.na(`Δ abs. (vs. año previo)`), "–",
fmt_num(`Δ abs. (vs. año previo)`)),
`Δ % (vs. año previo)` = fmt_pct(`Δ % (vs. año previo)`),
`Acumulado` = fmt_num(`Acumulado`),
`% del total` = fmt_pct(`% del total`)
)
# Fila TOTAL (mismos tipos que tab_fmt)
fila_total <- tibble::tibble(
Año = "TOTAL",
Casos = fmt_num(total),
`Δ abs. (vs. año previo)` = "",
`Δ % (vs. año previo)` = "",
`Acumulado` = fmt_num(total),
`% del total` = "100%"
)
tabla_final <- dplyr::bind_rows(tab_fmt, fila_total)
knitr::kable(
tabla_final,
caption = paste("Casos por año —", muni, "(F) - Valle del Cauca")
)
Casos por año — Cali (F) - Valle del Cauca
2009 |
2.397 |
– |
– |
2.397 |
0,4% |
2010 |
6.012 |
3.615 |
150,8% |
8.409 |
1,0% |
2011 |
14.720 |
8.708 |
144,8% |
23.129 |
2,5% |
2012 |
28.312 |
13.592 |
92,3% |
51.441 |
4,8% |
2013 |
40.138 |
11.826 |
41,8% |
91.579 |
6,8% |
2014 |
54.700 |
14.562 |
36,3% |
146.279 |
9,2% |
2015 |
66.082 |
11.382 |
20,8% |
212.361 |
11,1% |
2016 |
74.674 |
8.592 |
13,0% |
287.035 |
12,6% |
2017 |
89.624 |
14.950 |
20,0% |
376.659 |
15,1% |
2018 |
104.531 |
14.907 |
16,6% |
481.190 |
17,6% |
2019 |
112.346 |
7.815 |
7,5% |
593.536 |
18,9% |
TOTAL |
593.536 |
|
|
593.536 |
100% |
library(ggplot2)
# Uso el municipio que ya vengo trabajando
# muni <- "Cali"
# Data frame largo para ggplot2
df_muni <- tibble::tibble(
anio = base_graficos$anio,
casos = base_graficos[[muni]]
)
stopifnot(is.numeric(df_muni$casos))
ggplot(df_muni, aes(x = anio, y = casos)) +
geom_line() +
labs(title = paste("Línea —", muni, "(F) - Valle del Cauca"),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = anio, y = casos)) +
geom_step() +
labs(title = paste("Escaleras —", muni, "(F) - Valle del Cauca"),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = anio, y = casos)) +
geom_point(size = 2) +
labs(title = paste("Puntos —", muni, "(F) - Valle del Cauca"),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = anio, y = casos)) +
geom_line() +
geom_point(size = 2) +
labs(title = paste("Puntos y líneas —", muni, "(F) - Valle del Cauca"),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = anio, y = casos)) +
geom_point(size = 2) +
geom_line() +
labs(title = paste("Puntos encima de la línea —", muni, "(F) - Valle del Cauca"),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = anio, y = casos)) +
geom_col() +
labs(title = paste("Barras por año (análogo a type = 'h') —", muni),
x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(df_muni, aes(x = casos)) +
geom_histogram(bins = 10, boundary = 0, closed = "left") +
labs(title = paste("Histograma de la distribución de casos —", muni),
x = "Casos", y = "Frecuencia") +
scale_x_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

muni <- "Palmira" # por ejemplo
df_muni <- tibble::tibble(anio = base_graficos$anio, casos = base_graficos[[muni]])
# Línea
ggplot(df_muni, aes(anio, casos)) +
geom_line() +
labs(title = paste("Línea —", muni), x = "Año", y = "Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal_mark=","))

# Escaleras
ggplot(df_muni, aes(anio, casos)) + geom_step() + labs(title=paste("Escaleras —", muni), x="Año", y="Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal_mark=","))

# Puntos
ggplot(df_muni, aes(anio, casos)) + geom_point(size=2) + labs(title=paste("Puntos —", muni), x="Año", y="Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal_mark=","))

# Puntos + líneas
ggplot(df_muni, aes(anio, casos)) + geom_line() + geom_point(size=2) +
labs(title=paste("Puntos y líneas —", muni), x="Año", y="Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal_mark=","))

# Barras por año (análogo a type='h')
ggplot(df_muni, aes(anio, casos)) + geom_col() +
labs(title=paste("Barras por año —", muni), x="Año", y="Casos") +
scale_x_continuous(breaks = df_muni$anio) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal_mark=","))

# uso los objetos que ya tienes: x = base_graficos$anio, y = base_graficos[[muni]]
op <- options(scipen = 999); on.exit(options(op), add = TRUE)
plot(x, y, type = "h", lwd = 6, lend = "butt",
xaxt = "n", yaxt = "n",
xlab = "Año", ylab = "Casos",
main = paste("Barras por año —", muni, "(F) - Valle del Cauca)"))
axis(1, at = x, labels = x)
ticks <- pretty(y)
axis(2, at = ticks, labels = format(ticks, big.mark = ".", decimal.mark = ","))
grid(); box()

hist(y, breaks = 6,
main = paste("Histograma de la distribución de casos —", muni),
xlab = "Casos", ylab = "Frecuencia")

library(ggplot2)
ggplot(tibble::tibble(casos = y), aes(casos)) +
geom_histogram(bins = 6, boundary = 0, closed = "left") +
labs(title = paste("Histograma de la distribución de casos —", muni),
x = "Casos", y = "Frecuencia") +
scale_x_continuous(labels = scales::label_number(big.mark=".", decimal.mark=","))

library(tidyr); library(dplyr)
# base_final tiene: Departamento, Sexo, Muni, columnas 2009..2019
datos_long <- base_final %>%
pivot_longer(
cols = matches("^20\\d{2}$"), # toma columnas 2009..2019
names_to = "Año",
values_to = "Valor"
) %>%
mutate(Año = as.integer(Año))
dplyr::glimpse(datos_long)
## Rows: 3,894
## Columns: 5
## $ Departamento <chr> "Cauca", "Cauca", "Cauca", "Cauca", "Cauca", "Cauca", "Ca…
## $ Sexo <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "M…
## $ Muni <chr> "Almaguer", "Almaguer", "Almaguer", "Almaguer", "Almaguer…
## $ Año <int> 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 201…
## $ Valor <dbl> 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, 0, 2, 24, 36, 58, 85, 105, …
library(dplyr); library(stringr)
# 1) ¿Qué hay para 2019, F, Valle?
diag <- datos_long %>%
filter(Año == 2019, Sexo == "F",
str_detect(Departamento, regex("valle", ignore_case = TRUE))) %>%
summarise(
n_filas = n(),
con_valor = sum(!is.na(Valor)),
positivos = sum(Valor > 0, na.rm = TRUE),
muni_distintos = n_distinct(Muni)
)
diag
## # A tibble: 1 × 4
## n_filas con_valor positivos muni_distintos
## <int> <int> <int> <int>
## 1 42 42 40 42
# 2) ¿Cómo se llaman exactamente los municipios?
munis_valle_2019 <- datos_long %>%
filter(Año == 2019, Sexo == "F",
str_detect(Departamento, regex("valle", ignore_case = TRUE))) %>%
distinct(Muni) %>% arrange(Muni)
munis_valle_2019
## # A tibble: 42 × 1
## Muni
## <chr>
## 1 Alcalá
## 2 Andalucía
## 3 Ansermanuevo
## 4 Argelia
## 5 Bolívar
## 6 Buenaventura
## 7 Bugalagrande
## 8 Caicedonia
## 9 Cali
## 10 Calima
## # ℹ 32 more rows
library(ggplot2)
# Filtro 2019, F, Valle y EXCLUIMOS 'Cali' (considerando dos variantes de nombre)
df_v19 <- datos_long %>%
filter(Año == 2019, Sexo == "F",
str_detect(Departamento, regex("valle", ignore_case = TRUE))) %>%
filter(!is.na(Valor)) %>%
filter(!str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali", ignore_case = TRUE)))
# Si no hay datos, se pone aclaracion
if (nrow(df_v19) == 0) {
message("⚠️ No hay datos para 2019 (F) en Valle sin Cali. Revisa los nombres en el chunk de diagnóstico.")
} else {
# Binwidth seguro: si IQR es 0/NA, usamos fallback de 10 bins sobre el rango
iqr <- IQR(df_v19$Valor, na.rm = TRUE)
rng <- range(df_v19$Valor, na.rm = TRUE)
n <- nrow(df_v19)
bw_fd <- if (n >= 2 && is.finite(iqr) && iqr > 0) 2 * iqr / (n^(1/3)) else NA_real_
bw <- if (!is.na(bw_fd) && is.finite(bw_fd) && bw_fd > 0) bw_fd else max(1, diff(rng) / 10)
ggplot(df_v19, aes(x = Valor)) +
geom_histogram(binwidth = bw, boundary = 0, closed = "left",
fill = "lightblue", color = "grey30") +
labs(title = "Histograma — Municipios del Valle (sin Cali), 2019 (F)",
x = "Atenciones", y = "Frecuencia") +
scale_x_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ",")) +
theme_minimal()
}

# Control: mismo filtro pero SIN excluir Cali, y verifico visualmente
df_v19_all <- datos_long %>%
filter(Año == 2019, Sexo == "F",
str_detect(Departamento, regex("valle", ignore_case = TRUE))) %>%
filter(!is.na(Valor))
if (nrow(df_v19_all) > 0) {
ggplot(df_v19_all, aes(x = Valor)) +
geom_histogram(bins = 15, boundary = 0, closed = "left",
fill = "skyblue", color = "grey30") +
labs(title = "Histograma (control) — Municipios del Valle (con Cali), 2019 (F)",
x = "Atenciones", y = "Frecuencia") +
scale_x_continuous(labels = scales::label_number(big.mark=".", decimal.mark=",")) +
theme_minimal()
} else {
message("⚠️ No hay filas para 2019 (F) en Valle ni siquiera incluyendo Cali.")
}

library(dplyr); library(stringr); library(ggplot2)
# 1) Normalizo espacios por si hay dobles o finales
datos_long <- datos_long %>%
mutate(
Departamento = stringr::str_squish(Departamento),
Muni = stringr::str_squish(Muni)
)
# 2) Miro cómo se llama realmente "Cali" y su departamento
vista_cali <- datos_long %>%
filter(Sexo == "F", str_detect(Muni, regex("cali", ignore_case = TRUE))) %>%
distinct(Muni, Departamento) %>%
arrange(Muni)
print(vista_cali, n = nrow(vista_cali))
## # A tibble: 2 × 2
## Muni Departamento
## <chr> <chr>
## 1 Cali Valle
## 2 Calima Valle
# 3) Filtro flexible para Valle y Cali
df_cali <- datos_long %>%
filter(
Sexo == "F",
str_detect(Departamento, regex("valle(\\s+del\\s+cauca)?", ignore_case = TRUE)),
str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali", ignore_case = TRUE))
) %>%
group_by(Año) %>%
summarise(Valor = sum(Valor, na.rm = TRUE), .groups = "drop") %>%
arrange(Año)
if (nrow(df_cali) == 0) {
message("⚠️ El filtro sigue sin devolver filas. Revisa la tabla 'vista_cali' impresa arriba ",
"para ver el nombre exacto de Muni y Departamento y ajústalo en el regex.")
} else {
ggplot(df_cali, aes(x = Año, y = Valor)) +
geom_line() +
geom_point(size = 2) +
labs(title = "Cali (F) — Línea con puntos",
x = "Año", y = "Atenciones") +
scale_x_continuous(breaks = df_cali$Año) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ",")) +
theme_minimal()
}

ggplot(df_cali, aes(Año, Valor)) +
geom_step() +
labs(title = "Cali (F) — Escaleras", x = "Año", y = "Atenciones") +
scale_x_continuous(breaks = df_cali$Año) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal.mark=",")) +
theme_minimal()

ggplot(df_cali, aes(Año, Valor)) +
geom_point(size = 2) +
labs(title = "Cali (F) — Puntos", x = "Año", y = "Atenciones") +
scale_x_continuous(breaks = df_cali$Año) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal.mark=",")) +
theme_minimal()

ggplot(df_cali, aes(Año, Valor)) +
geom_col() +
labs(title = "Cali (F) — Barras por año", x = "Año", y = "Atenciones") +
scale_x_continuous(breaks = df_cali$Año) +
scale_y_continuous(labels = scales::label_number(big.mark=".", decimal.mark=",")) +
theme_minimal()

ggplot(df_cali, aes(Valor)) +
geom_histogram(bins = 8, boundary = 0, closed = "left",
fill = "steelblue", color = "grey30") +
labs(title = "Cali (F) — Histograma de la distribución (2009–2019)",
x = "Atenciones", y = "Frecuencia") +
scale_x_continuous(labels = scales::label_number(big.mark=".", decimal.mark=",")) +
theme_minimal()

library(dplyr); library(ggplot2)
dist_abs_2015F <- datos_long %>%
filter(Año == 2015, Sexo == "F") %>%
filter(!is.na(Valor)) %>% # “disponibles en los datos”
distinct(Departamento, Muni) %>% # 1 vez por municipio
count(Departamento, name = "n_municipios") %>%
arrange(desc(n_municipios))
dist_abs_2015F
## # A tibble: 4 × 2
## Departamento n_municipios
## <chr> <int>
## 1 Narino 64
## 2 Cauca 42
## 3 Valle 42
## 4 Choco 29
ggplot(dist_abs_2015F, aes(x = Departamento, y = n_municipios)) +
geom_col(fill = "royalblue4") +
labs(title = "Distribución de los municipios por departamento (2015, F)",
x = "Departamento", y = "Frecuencia") +
theme_minimal()

dist_rel_2015F <- dist_abs_2015F %>%
mutate(pct = 100 * n_municipios / sum(n_municipios))
dist_rel_2015F
## # A tibble: 4 × 3
## Departamento n_municipios pct
## <chr> <int> <dbl>
## 1 Narino 64 36.2
## 2 Cauca 42 23.7
## 3 Valle 42 23.7
## 4 Choco 29 16.4
ggplot(dist_rel_2015F, aes(x = Departamento, y = pct)) +
geom_col(fill = "royalblue4") +
labs(title = "Distribución relativa de municipios por departamento (2015, F)",
x = "Departamento", y = "%") +
scale_y_continuous(labels = function(x) paste0(x, "%")) +
theme_minimal()

library(stringr)
# Normalizo espacios y unifico nombres de capitales
caps_df <- datos_long %>%
mutate(
Departamento = str_squish(Departamento),
Muni = str_squish(Muni)
) %>%
filter(Sexo == "F",
str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali|popay[aá]n|^pasto$|quibd[oó]", ignore_case = TRUE))) %>%
mutate(Capital = case_when(
str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali", ignore_case = TRUE)) ~ "Cali",
str_detect(Muni, regex("popay[aá]n", ignore_case = TRUE)) ~ "Popayán",
str_detect(Muni, regex("^pasto$", ignore_case = TRUE)) ~ "Pasto",
str_detect(Muni, regex("quibd[oó]", ignore_case = TRUE)) ~ "Quibdó",
TRUE ~ Muni
)) %>%
filter(!is.na(Valor))
# ---- Opción A: Boxplot con TODOS los años (recomendado) ----
ggplot(caps_df, aes(x = Capital, y = Valor)) +
geom_boxplot(fill = "lightblue", color = "navy") +
labs(title = "Boxplot de atenciones por capitales de la región (todos los años, F)",
x = "Ciudad capital", y = "Número de atenciones") +
theme_minimal()

# ---- Opción B: si quiero mostrar SOLO 2015, uso puntos (no hay caja) ----
caps_2015 <- caps_df %>% filter(Año == 2015)
ggplot(caps_2015, aes(x = Capital, y = Valor)) +
geom_point(size = 3, alpha = 0.8, color = "navy") +
labs(title = "Atenciones en capitales de la región (2015, F)",
x = "Ciudad capital", y = "Número de atenciones") +
theme_minimal()

library(ggplot2)
dist_abs_2015F %>%
ggplot(aes(x = reorder(Departamento, n_municipios), y = n_municipios)) +
geom_col(fill = "royalblue4") +
geom_text(aes(label = n_municipios), vjust = -0.25, size = 4) +
labs(title = "Municipios por departamento (2015, F)",
x = "Departamento", y = "Frecuencia") +
theme_minimal() +
coord_cartesian(ylim = c(0, max(dist_abs_2015F$n_municipios) * 1.1))

dist_rel_2015F %>%
ggplot(aes(x = reorder(Departamento, pct), y = pct)) +
geom_col(fill = "royalblue4") +
geom_text(aes(label = paste0(round(pct,1), "%")),
vjust = -0.25, size = 4) +
labs(title = "Distribución relativa (2015, F)",
x = "Departamento", y = "%") +
theme_minimal() +
coord_cartesian(ylim = c(0, max(dist_rel_2015F$pct) * 1.1))

library(dplyr)
resumen_caps <- caps_df %>%
group_by(Capital) %>%
summarise(
n = n(),
min = min(Valor, na.rm = TRUE),
q1 = quantile(Valor, .25, na.rm = TRUE),
med = median(Valor, na.rm = TRUE),
mean = mean(Valor, na.rm = TRUE),
q3 = quantile(Valor, .75, na.rm = TRUE),
max = max(Valor, na.rm = TRUE),
iqr = IQR(Valor, na.rm = TRUE),
.groups = "drop"
)
resumen_caps
## # A tibble: 4 × 9
## Capital n min q1 med mean q3 max iqr
## <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Cali 11 2397 21516 54700 53958. 82149 112346 60633
## 2 Pasto 11 210 1694 4522 4880. 7916 10182 6222
## 3 Popayán 11 248 1702 4667 6174. 10076. 14958 8374.
## 4 Quibdó 11 163 498. 1071 1380. 2351 2854 1852.
# creo carpeta
if (!dir.exists("figs")) dir.create("figs")
# guardo la última figura generada
ggsave("figs/boxplot_capitales_F_todos.png", width = 9, height = 6, dpi = 300)
library(dplyr)
library(stringr)
library(ggplot2)
library(scales)
# Serie por capitales (Cali, Popayán, Pasto, Quibdó)
caps_ts <- datos_long %>%
mutate(Departamento = str_squish(Departamento),
Muni = str_squish(Muni)) %>%
filter(Sexo == "F",
str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali|popay[aá]n|^pasto$|quibd[oó]", ignore_case = TRUE))) %>%
mutate(Capital = case_when(
str_detect(Muni, regex("^cali$|santiago\\s+de\\s+cali", ignore_case = TRUE)) ~ "Cali",
str_detect(Muni, regex("popay[aá]n", ignore_case = TRUE)) ~ "Popayán",
str_detect(Muni, regex("^pasto$", ignore_case = TRUE)) ~ "Pasto",
str_detect(Muni, regex("quibd[oó]", ignore_case = TRUE)) ~ "Quibdó",
TRUE ~ Muni
)) %>%
group_by(Capital, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop")
# Fila del máximo por capital para anotar
max_caps <- caps_ts %>%
group_by(Capital) %>%
slice_max(order_by = Atenciones, n = 1, with_ties = FALSE) %>%
ungroup()
ggplot(caps_ts, aes(Año, Atenciones, color = Capital)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_smooth(se = FALSE, linewidth = .6, linetype = "dashed") +
geom_label(data = max_caps,
aes(label = number(Atenciones, big.mark = ".", decimal.mark = ",")),
vjust = -0.3, label.size = 0.1, fill = "white", alpha = .85,
show.legend = FALSE) +
scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
scale_color_manual(values = c("Cali"="#1b9e77","Pasto"="#d95f02","Popayán"="#7570b3","Quibdó"="#e7298a")) +
labs(title = "Tendencia de atenciones en capitales de la región (F)",
subtitle = "Con línea suavizada (LOESS) y valor máximo anotado",
x = "Año", y = "Atenciones", color = "Capital") +
theme_minimal(base_size = 12)

library(dplyr)
library(stringr)
library(ggplot2)
library(scales)
valle_rx <- regex("valle(\\s+del\\s+cauca)?", ignore_case = TRUE)
cali_rx <- regex("^cali$|santiago\\s+de\\s+cali", ignore_case = TRUE)
df_heat <- datos_long %>%
mutate(Departamento = str_squish(Departamento),
Muni = str_squish(Muni)) %>%
filter(Sexo == "F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx)) %>%
group_by(Muni, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop")
# Ordeno municipios por total acumulado (para que el eje Y sea informativo)
orden_muni <- df_heat %>%
group_by(Muni) %>% summarise(total = sum(Atenciones), .groups = "drop") %>%
arrange(desc(total)) %>% pull(Muni)
df_heat$Muni <- factor(df_heat$Muni, levels = orden_muni)
ggplot(df_heat, aes(x = Año, y = Muni, fill = Atenciones)) +
geom_tile(color = "white", linewidth = .2) +
scale_fill_viridis_c(option = "C",
labels = label_number(big.mark = ".", decimal.mark = ",")) +
labs(title = "Intensidad de atenciones por municipio — Valle del Cauca (F)",
subtitle = "Sin Cali. Cada celda corresponde a un año",
x = "Año", y = "Municipio", fill = "Atenciones") +
theme_minimal(base_size = 12) +
theme(panel.grid = element_blank(),
axis.text.y = element_text(size = 9))

library(ggrepel)
ult <- caps_ts %>% group_by(Capital) %>% slice_max(Año, n = 1)
okabe <- c("Cali" = "#009E73","Pasto"="#D55E00",
"Popayán"="#0072B2","Quibdó"="#CC79A7")
ggplot(caps_ts, aes(Año, Atenciones, color = Capital)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_smooth(se = FALSE, linewidth = .6, linetype = "dashed") +
geom_label_repel(data = ult,
aes(label = scales::number(Atenciones, big.mark = ".", decimal.mark = ",")),
seed = 123, size = 3.6, label.size = 0.1, fill = "white", alpha = .9,
box.padding = .3, min.segment.length = 0, show.legend = FALSE) +
scale_color_manual(values = okabe) +
scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","), expand = expansion(mult = c(0.02, .08))) +
labs(title = "Tendencia de atenciones en capitales de la región (F)",
subtitle = "Línea suavizada (LOESS) y etiqueta del último año",
x = "Año", y = "Atenciones", color = "Capital",
caption = "Fuente: SISPRO-RIPS. Elaboración propia") +
theme_minimal(base_size = 12) +
theme(panel.grid.minor = element_blank())

ggplot(df_heat, aes(x = Año, y = Muni, fill = Atenciones)) +
geom_tile(color = "white", linewidth = .2) +
scale_x_continuous(breaks = 2009:2019, expand = c(0,0)) +
scale_fill_viridis_c(option = "C",
labels = ~ scales::number(.x, accuracy = 1, big.mark = ".", decimal.mark = ","),
guide = guide_colorbar(barheight = unit(6, "lines"))) +
labs(title = "Intensidad de atenciones por municipio — Valle del Cauca (F)",
subtitle = "Sin Cali. Cada celda corresponde a un año",
x = "Año", y = "Municipio", fill = "Atenciones",
caption = "Fuente: SISPRO-RIPS. Elaboración propia") +
theme_minimal(base_size = 12) +
theme(panel.grid = element_blank(),
axis.text.y = element_text(size = 9))

if (!dir.exists("figs")) dir.create("figs")
ggsave("figs/viz_capitales_trend.png", width = 9, height = 6, dpi = 300)
ggsave("figs/viz_valle_heatmap.png", width = 9, height = 6, dpi = 300)
library(dplyr)
library(ggplot2)
library(ggrepel)
library(scales)
# Paleta Okabe–Ito (amigable para daltónicos)
okabe <- c("Cali"="#009E73","Pasto"="#D55E00","Popayán"="#0072B2","Quibdó"="#CC79A7")
# Etiquetas del último año por capital
ult <- caps_ts %>% group_by(Capital) %>% slice_max(Año, n = 1)
p <- ggplot(caps_ts,
aes(Año, Atenciones, color = Capital)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
# ← Especificamos el método para que NO imprima mensaje
geom_smooth(method = "loess", formula = y ~ x, se = FALSE,
linewidth = .6, linetype = "dashed") +
geom_label_repel(
data = ult,
aes(label = number(Atenciones, big.mark = ".", decimal.mark = ",")),
seed = 123, size = 3.6, label.size = 0.1, fill = "white", alpha = .9,
box.padding = .3, min.segment.length = 0, show.legend = FALSE
) +
scale_color_manual(values = okabe) +
scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
labs(title = "Tendencia de atenciones en capitales de la región (F)",
subtitle = "Línea suavizada (LOESS) y etiqueta del último año",
x = "Año", y = "Atenciones", color = "Capital",
caption = "Fuente: SISPRO-RIPS. Elaboración propia") +
theme_minimal(base_size = 12) +
theme(panel.grid.minor = element_blank())
p

# Paquetes
library(dplyr)
library(stringr)
library(ggplot2)
library(ggrepel)
library(scales)
# --- Supongo que ya tengo 'datos_long' con columnas: Muni, Sexo, Año, Valor ---
# Capitales de la región (regex robustas por si cambian tildes o formas)
cali_rx <- regex("(?:^cali$)|(?:santiago\\s+de\\s+cali)", ignore_case = TRUE)
pasto_rx <- regex("^pasto$", ignore_case = TRUE)
popayan_rx <- regex("popay[aá]n", ignore_case = TRUE)
quibdo_rx <- regex("quibd[oó]", ignore_case = TRUE)
df_cap <- datos_long %>%
filter(Sexo == "F") %>%
mutate(
Capital = case_when(
str_detect(Muni, cali_rx) ~ "Cali",
str_detect(Muni, pasto_rx) ~ "Pasto",
str_detect(Muni, popayan_rx) ~ "Popayán",
str_detect(Muni, quibdo_rx) ~ "Quibdó",
TRUE ~ NA_character_
)
) %>%
filter(!is.na(Capital)) %>%
group_by(Capital, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop") %>%
mutate(Capital = factor(Capital, levels = c("Cali","Pasto","Popayán","Quibdó")))
# Etiquetas con el valor del último año de cada capital
lab_last <- df_cap %>%
group_by(Capital) %>%
filter(Año == max(Año)) %>%
mutate(lbl = label_number(big.mark = ".", decimal.mark = ",")(Atenciones))
# Paleta pastel
pal <- RColorBrewer::brewer.pal(4, "Pastel1")
p <- ggplot(df_cap, aes(x = Año, y = Atenciones, color = Capital)) +
geom_line(size = 1) +
geom_point(size = 2) +
# Línea de tendencia (LOESS) sin banda y punteada
geom_smooth(se = FALSE, method = "loess", formula = y ~ x,
linetype = "dashed", size = 0.6, alpha = 0.8) +
# Etiquetas del último año
geom_label_repel(
data = lab_last,
aes(label = label_number(big.mark = ".", decimal.mark = ",")(Atenciones)),
nudge_x = 0.25, size = 3, label.size = NA, fill = "white", alpha = 0.95,
min.segment.length = 0
) +
scale_color_manual(values = pal) +
scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
labs(
title = "Tendencia de atenciones en capitales de la región (F)",
# sin subtítulo que mencione LOESS
x = "Año",
y = "Atenciones",
color = "Capital",
caption = "Fuente: SISPRO-RIPS. Elaboración propia. (Línea punteada = tendencia)"
) +
theme_minimal(base_size = 13) +
theme(
legend.position = "right",
panel.grid.minor = element_blank()
)
p

# Paquetes
library(dplyr)
library(stringr)
library(ggplot2)
library(ggrepel)
library(scales)
library(plotly)
# Regex de capitales (robustos a tildes/variantes)
cali_rx <- regex("(?:^cali$)|(?:santiago\\s+de\\s+cali)", ignore_case = TRUE)
pasto_rx <- regex("^pasto$", ignore_case = TRUE)
popayan_rx <- regex("popay[aá]n", ignore_case = TRUE)
quibdo_rx <- regex("quibd[oó]", ignore_case = TRUE)
# Agregación (mismo flujo del gráfico estático)
df_cap <- datos_long %>%
filter(Sexo == "F") %>%
mutate(Capital = case_when(
str_detect(Muni, cali_rx) ~ "Cali",
str_detect(Muni, pasto_rx) ~ "Pasto",
str_detect(Muni, popayan_rx) ~ "Popayán",
str_detect(Muni, quibdo_rx) ~ "Quibdó",
TRUE ~ NA_character_
)) %>%
filter(!is.na(Capital)) %>%
group_by(Capital, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop") %>%
mutate(Capital = factor(Capital, levels = c("Cali","Pasto","Popayán","Quibdó")))
# Texto para tooltip
fmt <- label_number(big.mark = ".", decimal.mark = ",")
df_cap_i <- df_cap %>%
mutate(tt = paste0(
"<b>", Capital, "</b><br>",
"Año: ", Año, "<br>",
"Atenciones: ", fmt(Atenciones)
))
# Colores lindos (pasteles vivos)
pal <- RColorBrewer::brewer.pal(4, "Set2")
# ggplot base (igual al tuyo, pero con 'text' para tooltip)
g_trend <- ggplot(df_cap_i, aes(Año, Atenciones, color = Capital, text = tt)) +
geom_line(size = 1) +
geom_point(size = 2) +
geom_smooth(se = FALSE, method = "loess", formula = y ~ x,
linetype = "dashed", size = 0.6, alpha = 0.8) +
scale_color_manual(values = pal) +
scale_y_continuous(labels = fmt) +
labs(title = "Tendencia de atenciones en capitales de la región (F)",
x = "Año", y = "Atenciones", color = "Capital",
caption = "Fuente: SISPRO-RIPS. Elaboración propia. (Línea punteada = tendencia)") +
theme_minimal(base_size = 13) +
theme(panel.grid.minor = element_blank())
# Interactivo
ggplotly(g_trend, tooltip = "text") |>
layout(hoverlabel = list(bgcolor = "white"),
legend = list(orientation = "v")) |>
config(displayModeBar = TRUE, modeBarButtonsToAdd = c("toImage"))
# ---- Heatmap interactivo 2019 (Valle sin Cali, F) ----
suppressPackageStartupMessages({
library(dplyr); library(stringr); library(plotly)
})
stopifnot("datos_long" %in% ls())
valle_rx <- regex("valle", ignore_case = TRUE)
cali_rx <- regex("(^cali$|santiago\\s+de\\s+cali)", ignore_case = TRUE)
yr <- 2019
df19 <- datos_long %>%
filter(Sexo == "F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx),
Año == yr) %>%
group_by(Muni) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(Atenciones))
stopifnot(nrow(df19) > 0)
# matriz z (filas=municipios, 1 columna = año)
z <- matrix(df19$Atenciones,
ncol = 1,
dimnames = list(df19$Muni, yr))
plot_ly(
x = c(yr),
y = df19$Muni,
z = z,
type = "heatmap",
colorscale = "Viridis", # <- clave
colorbar = list(title = "Atenciones"),
hovertemplate = "<b>%{y}</b><br>Año: %{x}<br>Atenciones: %{z:,}<extra></extra>"
) |>
layout(
title = paste0("Intensidad de atenciones — Municipios del Valle (sin Cali), F (", yr, ")"),
xaxis = list(title = "Año"),
yaxis = list(title = "Municipio")
)
# ---- Heatmap interactivo todos los años (Valle sin Cali, F) ----
suppressPackageStartupMessages({
library(dplyr); library(stringr); library(tidyr); library(plotly)
})
stopifnot("datos_long" %in% ls())
valle_rx <- regex("valle", ignore_case = TRUE)
cali_rx <- regex("(^cali$|santiago\\s+de\\s+cali)", ignore_case = TRUE)
heat_df <- datos_long %>%
filter(Sexo == "F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx)) %>%
group_by(Muni, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop")
stopifnot(nrow(heat_df) > 0)
wide <- heat_df %>%
tidyr::pivot_wider(names_from = Año, values_from = Atenciones, values_fill = 0) %>%
arrange(Muni)
# ordenar columnas por año numérico (si aplica)
yrs_chr <- names(wide)[-1]
yrs_num <- suppressWarnings(as.numeric(yrs_chr))
if (any(is.na(yrs_num))) {
x <- yrs_chr
z <- as.matrix(wide[, -1, drop = FALSE])
} else {
ord <- order(yrs_num)
x <- yrs_num[ord]
z <- as.matrix(wide[, -1, drop = FALSE][, ord, drop = FALSE])
}
y <- wide$Muni
plot_ly(
x = x, y = y, z = z,
type = "heatmap",
colorscale = "Viridis", # <- clave
colorbar = list(title = "Atenciones"),
hovertemplate = "<b>%{y}</b><br>Año: %{x}<br>Atenciones: %{z:,}<extra></extra>"
) |>
layout(
title = "Intensidad de atenciones — Municipios del Valle (sin Cali), F",
xaxis = list(title = "Año"),
yaxis = list(title = "Municipio")
)
# Paquetes
library(dplyr)
library(stringr)
library(ggplot2)
library(ggrepel)
library(scales)
library(plotly)
# Regex robustos (por si cambian tildes o formas)
valle_rx <- regex("valle(\\s+del\\s+cauca)?", ignore_case = TRUE)
cali_rx <- regex("(?:^cali$)|(?:santiago\\s+de\\s+cali)", ignore_case = TRUE)
cap_df <- datos_long %>%
filter(Sexo == "F") %>%
mutate(
Capital = case_when(
str_detect(Muni, cali_rx) ~ "Cali",
str_detect(Muni, regex("^pasto$", ignore_case = TRUE)) ~ "Pasto",
str_detect(Muni, regex("popay[aá]n", ignore_case = TRUE)) ~ "Popayán",
str_detect(Muni, regex("quibd[oó]", ignore_case = TRUE)) ~ "Quibdó",
TRUE ~ NA_character_
)
) %>%
filter(!is.na(Capital)) %>%
group_by(Capital, Año) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop")
# Último año por capital para anotar
ult <- cap_df %>% group_by(Capital) %>% slice_max(Año, n = 1, with_ties = FALSE)
p_line <- ggplot(cap_df, aes(Año, Atenciones, color = Capital)) +
geom_line(size = 1.2) +
geom_point(size = 2) +
geom_smooth(se = FALSE, linetype = 2, size = 0.8) + # línea de tendencia (loess)
geom_label_repel(
data = ult,
aes(label = label_number(big.mark=".", decimal.mark=",")(Atenciones)),
size = 3, label.size = 0.2, fill = "white", show.legend = FALSE
) +
scale_color_brewer(palette = "Set2") + # pasteles agradables
scale_y_continuous(labels = label_number(big.mark=".", decimal.mark=",")) +
labs(
title = "Tendencia de atenciones en capitales de la región (F)",
subtitle = "Línea punteada: tendencia (LOESS)",
x = "Año", y = "Atenciones",
caption = "Fuente: SISPRO-RIPS. Elaboración propia."
) +
theme_minimal(base_size = 13) +
theme(legend.position = "right")
# Interactivo
p_line_int <- ggplotly(
p_line,
tooltip = c("Capital", "Año", "Atenciones")
) %>%
layout(hoverlabel = list(bgcolor = "white"))
p_line_int
library(plotly)
top10_2019 <- datos_long %>%
filter(Sexo == "F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx),
Año == 2019) %>%
group_by(Muni) %>%
summarise(Atenciones = sum(Valor, na.rm = TRUE), .groups = "drop") %>%
slice_max(Atenciones, n = 10) %>%
arrange(Atenciones)
plot_ly(
top10_2019,
x = ~Atenciones,
y = ~factor(Muni, levels = top10_2019$Muni), # ordenado
type = "bar",
orientation = "h",
text = ~paste0(
"<b>", Muni, "</b><br>",
"Atenciones: ", scales::label_number(big.mark=".", decimal.mark=",")(Atenciones)
),
hoverinfo = "text",
marker = list(color = ~Atenciones, colorscale = "Tealgrn")
) %>%
layout(
title = "Top-10 municipios del Valle (sin Cali) — 2019, F",
xaxis = list(title = "Atenciones"),
yaxis = list(title = "Municipio")
)
library(dplyr)
library(stringr)
library(plotly)
library(scales)
# Regex que ya vengo usando
valle_rx <- regex("valle(\\s+del\\s+cauca)?", ignore_case = TRUE)
cali_rx <- regex("(?:^cali$)|(?:santiago\\s+de\\s+cali)", ignore_case = TRUE)
# 1) Agrego 2019, F, Valle y excluimos Cali
treemap_2019 <- datos_long %>%
filter(Sexo == "F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx),
Año == 2019) %>%
group_by(Muni) %>%
summarise(Atenciones = as.numeric(sum(Valor, na.rm = TRUE)), .groups = "drop")
# 2) Construyo el árbol con raíz
tree_df <- treemap_2019 %>%
transmute(label = Muni,
parent = "Valle del Cauca",
value = Atenciones) %>%
bind_rows(tibble(label = "Valle del Cauca",
parent = "",
value = sum(treemap_2019$Atenciones, na.rm = TRUE)))
# 3) Treemap interactivo (con escala 'Purples' y tooltips claros)
p_tree <- plot_ly(
data = tree_df,
type = "treemap",
labels = ~label,
parents = ~parent,
values = ~value,
branchvalues = "total",
textinfo = "label+value+percent parent",
hovertemplate = paste0(
"<b>%{label}</b><br>",
"Atenciones: %{value:,.0f}<extra></extra>"
),
marker = list(colors = ~value, colorscale = "Purples")
) %>%
layout(title = "Treemap — Municipios del Valle (sin Cali), 2019 (F)")
p_tree
nrow(treemap_2019) # debe ser > 0
## [1] 41
str(treemap_2019$Atenciones) # debe ser numeric
## num [1:41] 223 831 411 29 0 ...
head(tree_df)
## # A tibble: 6 × 3
## label parent value
## <chr> <chr> <dbl>
## 1 Alcalá Valle del Cauca 223
## 2 Andalucía Valle del Cauca 831
## 3 Ansermanuevo Valle del Cauca 411
## 4 Argelia Valle del Cauca 29
## 5 Bolívar Valle del Cauca 0
## 6 Buenaventura Valle del Cauca 11702
htmlwidgets::saveWidget(p_tree, "treemap_valle_2019_interactivo.html", selfcontained = TRUE)
library(dplyr); library(ggplot2); library(forcats); library(scales)
df_rank19 <- datos_long %>%
filter(Sexo=="F",
str_detect(Departamento, valle_rx),
!str_detect(Muni, cali_rx),
Año == 2019) %>%
group_by(Muni) %>%
summarise(Atenciones = sum(Valor, na.rm=TRUE), .groups="drop") %>%
arrange(desc(Atenciones)) %>%
slice_head(n = 15) %>%
mutate(Muni = fct_reorder(Muni, Atenciones))
ggplot(df_rank19, aes(Atenciones, Muni, fill = Atenciones)) +
geom_col(width = .7) +
geom_text(aes(label = label_number(big.mark=".", decimal.mark=",")(Atenciones)),
hjust = -0.1, size = 3) +
scale_fill_viridis_c(option = "plasma") +
scale_x_continuous(labels = label_number(big.mark=".", decimal.mark=","),
expand = expansion(mult = c(0, .1))) +
labs(title = "Top 15 municipios por atenciones — Valle del Cauca (sin Cali), 2019 (F)",
x = "Atenciones", y = NULL) +
theme_minimal(base_size = 12) +
theme(panel.grid.major.y = element_blank(),
legend.position = "none")

library(dplyr); library(ggplot2); library(scales)
caps <- c("Cali","Pasto","Popayán","Quibdó")
df_caps <- datos_long %>%
filter(Sexo=="F", Muni %in% caps) %>%
group_by(Muni, Año) %>%
summarise(Atenciones = sum(Valor, na.rm=TRUE), .groups="drop")
ggplot(df_caps, aes(Año, Atenciones, color = Muni)) +
geom_line(size = 1) +
geom_point(size = 1.8) +
scale_color_brewer(palette = "Set2") +
facet_wrap(~ Muni, scales = "free_y", ncol = 2) +
scale_y_continuous(labels = label_number(big.mark=".", decimal.mark=",")) +
labs(title = "Tendencia de atenciones por capital (F) — small multiples",
x = "Año", y = "Atenciones") +
theme_minimal(base_size = 12) +
theme(legend.position = "none")
