1 Punto 1

Utilizando los datos de clima de línea base a nivel global, genere un código en R que permita construir mapas de aptitud en términos climáticos para la caña de azúcar (con base en los rangos óptimos). Grafique los mapas con una escala de colores adecuada.

1.1 Respuesta:

Inicialmente, se cargaron los archivos raster utilizando el paquete terra, el cual permite manipular datos espaciales de manera eficiente. Las capas de temperatura provenientes de WorldClim se encontraban almacenadas en décimas de grado Celsius, por lo que fue necesario dividir sus valores entre diez para obtener temperaturas reales en grados Celsius. Posteriormente, se calculó la temperatura media mediante el promedio entre la temperatura máxima y mínima, debido a que esta variable representa de forma más adecuada las condiciones térmicas generales que afectan el crecimiento de la caña de azúcar.

Una vez obtenidas las variables climáticas principales, se procedió a definir criterios de aptitud basados en rangos óptimos reportados agronómicamente para el cultivo. La lógica empleada consistió en construir índices parciales de aptitud para cada variable climática, asignando valores entre 0 y 1. Los valores cercanos a 1 representan condiciones altamente favorables, mientras que los valores próximos a 0 indican condiciones poco aptas para el desarrollo del cultivo.

En el caso de la temperatura media, se consideró que el rango óptimo para la caña de azúcar se encuentra aproximadamente entre 24 °C y 32 °C, ya que en este intervalo se favorecen procesos fisiológicos como la fotosíntesis, el crecimiento vegetativo y la acumulación de biomasa. Valores ligeramente fuera de este rango fueron clasificados como condiciones intermedias, mientras que temperaturas muy bajas o excesivamente altas fueron consideradas no aptas. De manera similar, para la temperatura mínima se estableció como condición óptima valores superiores a 18 °C, debido a que temperaturas bajas pueden limitar el crecimiento y afectar la brotación del cultivo.

Respecto a la precipitación, se utilizaron umbrales mensuales que representan condiciones favorables de disponibilidad hídrica. La caña de azúcar es un cultivo con alta demanda de agua, especialmente durante las etapas iniciales de crecimiento, por lo que regiones con precipitaciones moderadas a altas fueron clasificadas con mayor aptitud climática. En contraste, zonas áridas o con lluvias insuficientes recibieron valores bajos de aptitud.

Posteriormente, los índices parciales generados para temperatura media, temperatura mínima y precipitación fueron integrados en un único índice climático total mediante un promedio simple. Este procedimiento permitió sintetizar la información climática en una sola capa raster, facilitando la interpretación espacial de las condiciones favorables para el cultivo a escala global.

Finalmente, el raster resultante fue transformado a un data.frame con coordenadas espaciales para su representación gráfica mediante ggplot2. Se utilizó geom_raster() debido a su eficiencia para representar superficies espaciales continuas de gran tamaño. Además, se aplicó una escala de colores continua que varía desde tonos rojos hasta verdes, donde el color rojo representa baja aptitud climática, el amarillo condiciones intermedias y el verde alta aptitud para el cultivo de caña de azúcar. Esta elección cromática facilita la interpretación visual del mapa y permite identificar rápidamente las regiones tropicales y húmedas con mejores condiciones climáticas para el desarrollo del cultivo.

## cargar tmp max y min
setwd("~/Estudio/MAESTRIA EN CIENCIA DE DATOS/Analisis_Datos_Geo/Actividad_2")
temp_max <- rast("wc2.1_cruts4.09_10m_tmax_2024-05.tif")
temp_min <- rast("wc2.1_cruts4.09_10m_tmin_2024-05.tif")
precipitaciones <- rast("wc2.1_cruts4.09_10m_prec_2024-05.tif")

temp_max <- temp_max / 10
temp_min <- temp_min / 10

# Temperatura media
temp_media <- (temp_max + temp_min) / 2
# Aptitud temperatura media
apt_temp <- ifel(
  temp_media >= 24 & temp_media <= 32,
  1,
  ifel(
    temp_media >= 20 & temp_media < 24 |
    temp_media > 32 & temp_media <= 35,
    0.5,
    0
  )
)

# Aptitud temperatura mínima
apt_tmin <- ifel(
  temp_min >= 18,
  1,
  ifel(
    temp_min >= 15 & temp_min < 18,
    0.5,
    0
  )
)

# Aptitud precipitación mensual
apt_prec <- ifel(
  precipitaciones >= 100 & precipitaciones <= 300,
  1,
  ifel(
    precipitaciones >= 50 & precipitaciones < 100,
    0.5,
    0
  )
)

# =========================
# 4. Índice climático total
# =========================

aptitud_total <- (apt_temp + apt_tmin + apt_prec) / 3

names(aptitud_total) <- "aptitud"
df <- as.data.frame(
  aptitud_total,
  xy = TRUE,
  na.rm = TRUE
)
ggplot(df) +
  geom_raster(
    aes(
      x = x,
      y = y,
      fill = aptitud
    )
  ) +
  coord_equal() +
  scale_fill_gradientn(
    colours = c(
      "#8B0000",   # rojo oscuro
      "#FFD700",   # amarillo
      "#006400"    # verde oscuro
    ),
    values = c(0, 0.5, 1),
    limits = c(0, 1),
    name = "Aptitud"
  ) +
  labs(
    title = "Mapa Global de Aptitud Climática para la Caña de Azúcar",
    subtitle = "Basado en temperatura y precipitación mensual",
    x = "Longitud",
    y = "Latitud"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    panel.grid = element_blank(),
    axis.text = element_text(color = "black"),
    plot.title = element_text(
      face = "bold",
      size = 18
    ),
    legend.position = "right"
  )

2 Punto 2

Identifique 2 o 3 países con áreas de alto potencial para la caña de azúcar y realice un corte para estas zonas con el shape global. Grafique los mapas con una escala de colores adecuada.

2.1 Respuesta:

En esta etapa del análisis se buscó identificar países con alto potencial climático para el cultivo de sugarcane a partir del índice global de aptitud construido previamente. El propósito principal fue delimitar espacialmente las regiones más favorables y realizar un análisis más focalizado sobre territorios que presentan condiciones ambientales adecuadas para el desarrollo del cultivo.

Para ello, se seleccionaron países reconocidos internacionalmente por su elevada producción de caña de azúcar y por poseer condiciones climáticas tropicales y subtropicales favorables. Entre los países identificados se encuentran Brazil, India y Thailand, los cuales destacan por combinar temperaturas elevadas, alta disponibilidad hídrica y extensas áreas agrícolas aptas para este cultivo.

Metodológicamente, el procedimiento inició con la carga de un shapefile mundial utilizando información vectorial de límites políticos nacionales. Posteriormente, se realizó un filtrado espacial para conservar únicamente los países seleccionados. Este paso permitió construir una capa geográfica específica que funcionó como máscara espacial para recortar el raster global de aptitud climática generado anteriormente.

Una vez definidos los límites territoriales de los países de interés, se aplicaron operaciones de recorte (crop) y enmascaramiento (mask) sobre el raster de aptitud. El recorte permitió limitar la extensión espacial del raster únicamente al área aproximada de los países seleccionados, mientras que el enmascaramiento eliminó los valores externos a sus fronteras políticas. De esta manera, se obtuvo una representación espacial centrada exclusivamente en las regiones de interés.

Posteriormente, el raster resultante fue convertido a un data.frame con coordenadas geográficas para facilitar su visualización mediante ggplot2. La representación cartográfica se realizó utilizando geom_raster(), lo cual permitió mostrar la variabilidad espacial del índice de aptitud climática dentro de cada país seleccionado. Adicionalmente, se superpusieron los límites políticos nacionales mediante geometrías vectoriales, facilitando la interpretación territorial del análisis.

# =========================
# 1. Cargar shapefile mundial
# =========================

mundo <- ne_countries(
  scale = "medium",
  returnclass = "sf"
)

# =========================
# 2. Seleccionar países
# =========================

paises <- mundo |>
  filter(
    admin %in% c(
      "Brazil",
      "India",
      "Thailand"
    )
  )

# =========================
# 3. Convertir a SpatVector
# =========================

paises_vect <- vect(paises)

# =========================
# 4. Recortar raster
# =========================

aptitud_crop <- crop(
  aptitud_total,
  paises_vect
)

aptitud_mask <- mask(
  aptitud_crop,
  paises_vect
)

# =========================
# 5. Convertir a dataframe
# =========================

df_crop <- as.data.frame(
  aptitud_mask,
  xy = TRUE,
  na.rm = TRUE
)
ggplot() +

  geom_raster(
    data = df_crop,
    aes(
      x = x,
      y = y,
      fill = aptitud
    )
  ) +

  geom_sf(
    data = paises,
    fill = NA,
    color = "black",
    linewidth = 0.3
  ) +

  coord_sf() +

  scale_fill_gradientn(
    colours = c(
      "#8B0000",
      "#FFD700",
      "#006400"
    ),
    values = c(0, 0.5, 1),
    limits = c(0, 1),
    name = "Aptitud"
  ) +

  labs(
    title = "Áreas de Alto Potencial Climático para la Caña de Azúcar",
    subtitle = "Brasil, India y Tailandia",
    x = "Longitud",
    y = "Latitud"
  ) +

  theme_minimal(base_size = 14) +

  theme(
    panel.grid = element_blank(),
    plot.title = element_text(
      face = "bold",
      size = 18
    ),
    axis.text = element_text(
      color = "black"
    )
  )

3 Punto 3

Identificar algunos puntos (2 o 3) al azar en la región del valle del cauca (use google maps) y extraer la información de clima. Grafique las series de tiempo de temperatura y precipitación.

3.1 Respuesta:

En este ejercicio se seleccionaron tres puntos geográficos en la región del Valle del Cauca (Palmira, Candelaria y Buga) mediante Google Maps para realizar un análisis de su comportamiento meteorológico. Utilizando el entorno de programación R y la API de Open-Meteo, se automatizó la extracción de datos horarios de temperatura (°C) y precipitación (mm) para un horizonte de siete días. El procesamiento y la consolidación de la información se realizaron mediante las librerías del ecosistema tidyverse (específicamente httr2 y purrr), permitiendo estructurar los datos para generar, a través de ggplot2, las series de tiempo correspondientes. Finalmente, estas variables se representaron visualmente mediante gráficos de líneas continuas para la temperatura —facilitando la observación de los ciclos térmicos diarios— y de barras para la precipitación, logrando así un flujo de trabajo replicable y eficiente para el monitoreo climático local.

# Tu dataframe original con los puntos en el Valle del Cauca
puntos <- data.frame(
  sitio = c("Palmira", "Candelaria", "Buga"),
  lon = c(-76.3036, -76.3487, -76.2978),
  lat = c(3.5394, 3.4067, 3.9009)
)

# 2. Función para extraer datos del clima (Pronóstico para los próximos 7 días)
get_clima <- function(sitio, lat, lon) {
  url <- "https://api.open-meteo.com/v1/forecast"
  
  # Construir y ejecutar la solicitud HTTP
  req <- request(url) %>% 
    req_url_query(
      latitude = lat,
      longitude = lon,
      hourly = "temperature_2m,precipitation", # Variables solicitadas
      timezone = "America/Bogota"
    )
  
  resp <- req_perform(req)
  data <- resp_body_json(resp, simplifyVector = TRUE)
  
  # Organizar la respuesta en un dataframe limpio
  df_clima <- data.frame(
    fecha_hora = as.POSIXct(data$hourly$time, format="%Y-%m-%dT%H:%M", tz="America/Bogota"),
    temperatura = data$hourly$temperature_2m,
    precipitacion = data$hourly$precipitation,
    sitio = sitio
  )
  
  return(df_clima)
}

# 3. Descargar los datos para todos los puntos y unirlos en un solo dataframe
datos_clima <- puntos %>%
  split(.$sitio) %>%  # Divide el dataframe por sitio
  purrr::map_dfr(~get_clima(sitio = .x$sitio, lat = .x$lat, lon = .x$lon))

# Visualizar una muestra de los datos obtenidos
head(datos_clima)
|>            fecha_hora temperatura precipitacion sitio
|> 1 2026-05-25 00:00:00        21.9           0.6  Buga
|> 2 2026-05-25 01:00:00        23.1           0.5  Buga
|> 3 2026-05-25 02:00:00        22.4           0.2  Buga
|> 4 2026-05-25 03:00:00        21.8           0.5  Buga
|> 5 2026-05-25 04:00:00        21.8           0.5  Buga
|> 6 2026-05-25 05:00:00        21.8           0.3  Buga
# 4. Graficar la Serie de Tiempo de Temperatura
ggplot(datos_clima, aes(x = fecha_hora, y = temperatura, color = sitio)) +
  geom_line(linewidth = 1) +
  labs(
    title = "Serie de Tiempo: Temperatura de 2 metros",
    subtitle = "Puntos seleccionados en el Valle del Cauca (Próximos 7 días)",
    x = "Fecha y Hora",
    y = "Temperatura (°C)",
    color = "Municipio"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

# 5. Graficar la Serie de Tiempo de Precipitación
ggplot(datos_clima, aes(x = fecha_hora, y = precipitacion, fill = sitio)) +
  geom_col(position = "dodge", alpha = 0.8) +
  labs(
    title = "Serie de Tiempo: Precipitación",
    subtitle = "Puntos seleccionados en el Valle del Cauca (Próximos 7 días)",
    x = "Fecha y Hora",
    y = "Precipitación (mm)",
    fill = "Municipio"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

4 Punto 4

Por medio de alguna métrica de similaridad (ejemplo: distancia euclidiana) genere un código en R que permita identificar mapas de similaridad a nivel global para los sitios identificados en 3. Grafique los mapas con una escala de colores adecuada.

4.1 Respuesta:

# 2. Definir tus puntos originales
puntos <- data.frame(
  sitio = c("Palmira", "Candelaria", "Buga"),
  lon = c(-76.3036, -76.3487, -76.2978),
  lat = c(3.5394, 3.4067, 3.9009)
)

# 3. Descargar datos bioclimáticos globales de WorldClim (Resolución de 10 minutos para agilidad)
# Esto descargará 19 variables (Bio1 = Temp Media Anual, Bio12 = Precipitación Anual, etc.)
bioclim_global <- worldclim_global(var = "bio", res = 10, path = tempdir())

# 4. Extraer los valores climáticos de tus 3 sitios
coordenadas <- puntos[, c("lon", "lat")]
valores_sitios <- terra::extract(bioclim_global, coordenadas)
valores_sitios$sitio <- puntos$sitio

# 5. Estandarizar los datos (Crucial para Distancia Euclidiana)
# Como la precipitación (mm) y la temperatura (°C) tienen escalas muy diferentes,
# debemos normalizar los datos globales y de los sitios usando la media y desv. estándar global.

bioclim_mean <- global(bioclim_global, fun = mean, na.rm = TRUE)[[1]]
bioclim_sd   <- global(bioclim_global, fun = sd, na.rm = TRUE)[[1]]

# Estandarizar el Ráster Global: (X - Media) / Desviación Estándar
bioclim_global_std <- (bioclim_global - bioclim_mean) / bioclim_sd

# Estandarizar los valores de nuestros 3 sitios de interés
valores_sitios_std <- valores_sitios %>% 
  select(starts_with("wc2.1_10m_bio_")) %>% 
  as.matrix()
valores_sitios_std <- scale(valores_sitios_std, center = bioclim_mean, scale = bioclim_sd)

# 6. Calcular la Distancia Euclidiana a nivel global para cada sitio
# Nota: Una distancia menor (cercana a 0) significa ALTA similaridad climática.

mapas_lista <- lapply(1:nrow(puntos), function(i) {
  target_sitio <- valores_sitios_std[i, ]
  dif_cuadrado <- (bioclim_global_std - target_sitio)^2
  dist_euclidiana <- sqrt(app(dif_cuadrado, sum))
  return(dist_euclidiana)
})

# Unimos las capas y les asignamos los nombres de los municipios
mapas_raster <- rarify <- terra::rast(mapas_lista)
names(mapas_raster) <- puntos$sitio

# 2. Graficar con ggplot2 + tidyterra (Resultado profesional en HTML)
ggplot() +
  # geom_spatraster de tidyterra dibuja el mapa a la perfección
  geom_spatraster(data = mapas_raster) +
  # facet_wrap divide el mapa automáticamente en 3 paneles (uno por sitio)
  facet_wrap(~lyr, ncol = 1) + 
  # Escala de colores continua e invertida (lo brillante es más similar)
  scale_fill_viridis_c(
    name = "Distancia\nEuclidiana", 
    direction = -1, 
    na.value = "transparent"
  ) +
  # Añadimos los puntos rojos interactivos/estéticos sobre cada mapa
  geom_point(
    data = puntos, 
    aes(x = lon, y = lat), 
    color = "red", 
    size = 2.5
  ) +
  labs(
    title = "Análisis de Similaridad Climática Global",
    subtitle = "Zonas brillantes (menor distancia) representan homólogos climáticos",
    x = "Longitud",
    y = "Latitud"
  ) +
  theme_minimal() +
  theme(
    strip.text = element_text(face = "bold", size = 11), # Títulos de las facetas
    plot.title = element_text(face = "bold", size = 14),
    panel.background = element_rect(fill = "#f0f8ff", color = NA), # Fondo azul claro para el mar
    legend.position = "right"
  )

5 Punto 5

Compare los mapas generados por ambas aproximaciones y concluya.

5.1 Respuesta:

# Calculamos estadísticas descriptivas horarias para ver la dinámica del Valle
resumen_local <- datos_clima %>%
  group_by(sitio) %>%
  summarise(
    Temp_Max = max(temperatura),
    Temp_Min = min(temperatura),
    Temp_Promedio = mean(temperatura),
    Precip_Total_7dias = sum(precipitacion),
    Precip_Max_Hora = max(precipitacion)
  )

# En HTML, knitr::kable formatea las tablas de manera hermosa y limpia
knitr::kable(resumen_local, caption = "Resumen Meteorológico Local Operativo (Próximos 7 Días)")
Resumen Meteorológico Local Operativo (Próximos 7 Días)
sitio Temp_Max Temp_Min Temp_Promedio Precip_Total_7dias Precip_Max_Hora
Buga 29.0 19.8 22.85119 138.4 11.9
Candelaria 26.2 19.1 21.78929 103.0 5.5
Palmira 26.2 18.6 21.15893 129.8 7.1
# ==============================================================================
# 2. ANÁLISIS DE LA APROXIMACIÓN 2: Correlación Espacial Global (Largo Plazo)
# ==============================================================================

# Al usar 'mapas_raster' (el objeto de tidyterra), podemos extraer los valores
# globales y calcular la correlación de Pearson directamente de forma nativa y ultra veloz.

valores_globales <- terra::values(mapas_raster, dataframe = TRUE)
correlacion_global <- cor(valores_globales, use = "complete.obs")

print("--- MATRIZ DE CORRELACIÓN DE SIMILARIDAD GLOBAL ---")
|> [1] "--- MATRIZ DE CORRELACIÓN DE SIMILARIDAD GLOBAL ---"
knitr::kable(correlacion_global, caption = "Matriz de Correlación Espacial Global (WorldClim)")
Matriz de Correlación Espacial Global (WorldClim)
Palmira Candelaria Buga
Palmira 1.0000000 0.9994380 0.9898846
Candelaria 0.9994380 1.0000000 0.9896183
Buga 0.9898846 0.9896183 1.0000000
# ==============================================================================
# 3. GRAFICAR EL CONTRASTE DE AMBAS APROXIMACIONES
# ==============================================================================

# Filtramos las primeras 24 horas para evaluar el comportamiento local detallado
dia_uno <- datos_clima %>% 
  filter(fecha_hora <= min(fecha_hora) + as.difftime(1, units="days"))

# Extraemos la correlación exacta entre Palmira y Candelaria para el subtítulo
corr_ejemplo <- round(correlacion_global["Palmira", "Candelaria"] * 100, 1)

ggplot(dia_uno, aes(x = fecha_hora, y = temperatura, color = sitio)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Contraste Estadístico: Macroclima Global vs. Dinámica Horaria Local",
    subtitle = paste0("A escala GLOBAL los mapas correlacionan al ", corr_ejemplo, 
                      "%, pero a microescala horaria se evidencian desfases térmicos."),
    x = "Línea de Tiempo Horaria",
    y = "Temperatura (°C)",
    color = "Sitio de Muestreo"
  ) +
  scale_color_brewer(palette = "Set1") + # Paleta de colores atractiva para el reporte
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    plot.subtitle = element_text(size = 10, color = "#7f8c8d"),
    legend.position = "bottom",
    panel.grid.minor = element_blank()
  )