1 Contenido

  1. Introducción
  2. configuración
  3. Definición del MultiscaleDTM
  4. Leer datos de entrada
  5. Transformación de coordenadas
  6. Cálculo de atributos del terreno
  7. Cálculo de las estadísticas zonales
  8. Trazando la pendiente del terreno
  9. Alternative visualization of terrain slope
  10. Visualización de la orientación del terreno

2 Introducción

El estudio del relieve mediante variables geomorfométricas, como la pendiente (slope) y la orientación del terreno (aspect), es fundamental para comprender la dinámica ambiental y las condiciones físicas que influyen en el uso del suelo, la agricultura y la gestión del territorio. En el caso del departamento del Valle del Cauca, caracterizado por una marcada heterogeneidad topográfica que abarca desde las planicies del río Cauca hasta las laderas de las cordilleras Occidental y Central, el análisis del relieve permite identificar zonas con diferentes niveles de aptitud para actividades agrícolas, conservación ambiental o desarrollo urbano.

El cálculo y visualización de estas variables se realizan a partir de un Modelo Digital de Elevación (DEM), el cual proporciona información altimétrica del terreno. A partir del DEM es posible derivar atributos como la pendiente, que representa la inclinación del terreno en grados o porcentaje, y la orientación o aspecto, que indica la dirección hacia la cual se inclina la superficie.

Estos parámetros son esenciales para múltiples disciplinas, incluyendo la agronomía, la hidrología, la planificación territorial y los estudios de riesgo ambiental, ya que influyen en la escorrentía, la exposición solar, la retención de humedad y la erosión del suelo.

En este cuaderno se presenta el procedimiento completo para el cálculo, análisis y visualización interactiva de estas variables geomorfométricas aplicadas al territorio del Valle del Cauca, empleando herramientas del lenguaje R como terra,sf,leaflet y MultiscaleDTM, las cuales permiten reproducir un flujo de trabajo técnico, automatizado y visualmente comprensible para la interpretación espacial del relieve departamental.

3 Configuracion

Limpiamos la memoria.

rm(list=ls())

Cargamos las librerías:

Estas son las librerías que necesitaremos para realizar el trabajo

library(sf)
## Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE
library(leaflet)
library(terra)
## terra 1.8.70
library(MultiscaleDTM)
## Warning: package 'MultiscaleDTM' was built under R version 4.5.2
library(exactextractr)
## Warning: package 'exactextractr' was built under R version 4.5.2

Las funciones de las librerías son las siguientes:

terra sirve para la lectura, el procesamiento y el análisis de datos espaciales raster.

sf trabaja con datos espaciales vectoriales.

leaflet permite la creación de mapas interactivos directamente en R o RMarkdown. MultiscaleDTM sirve para el análisis de terreno a diferentes escalas espaciales usando modelos digitales de terreno (DTM O DEM).

exactextractr sirve para extraer valores de raster como DTM, dentro de polígonos de forma muy precisa y eficiente.

4 Definición de MultiscaleDTM

MultiscaleDTM es un paquete del lenguaje R diseñado para el análisis geomorfométrico de modelos digitales del terreno (DTM o DEM, por sus siglas en inglés). Su principal función es calcular de manera eficiente y precisa diferentes atributos del relieve, tales como pendiente (slope), orientación (aspect), curvatura, rugosidad, altitud relativa, entre otros, a múltiples escalas espaciales.

El enfoque “multiescala” permite analizar cómo cambian las características del terreno cuando se usan diferentes tamaños de ventana o vecindario. Por ejemplo, una ventana pequeña (3x3 celdas) detecta variaciones locales —como microrelieves o pequeños taludes—, mientras que una ventana grande (9x9 o más) suaviza el terreno y resalta las formas generales del paisaje, como laderas o divisorias de aguas.

En términos prácticos, el paquete MultiscaleDTM combina métodos geométricos y estadísticos para derivar variables topográficas a partir de un raster de elevación. Una de sus funciones más empleadas, SlpAsp(), permite calcular simultáneamente la pendiente y la orientación del terreno en grados o radianes, a partir de un modelo digital de elevación previamente reproyectado a coordenadas planas.

De esta manera, MultiscaleDTM se convierte en una herramienta fundamental para estudios en geografía, geomorfología, hidrología, agricultura de precisión y planificación ambiental, al facilitar el procesamiento reproducible y automatizado de información topográfica en entornos de código abierto.

5 Lectura datos de entrada

Necesitamos cargar el raster con DEM de nuestro departamento realizado con anterioridad. Para ello vamos a utilizar la librería terra

list.files()
##  [1] "COL_msk_alt.tif"                           
##  [2] "cuadermopendiente_cnd.nb.html"             
##  [3] "Datos de elevacion del Valle del Cauca.Rmd"
##  [4] "ElevacionValleDelCauca.tif"                
##  [5] "pendientevdc.html"                         
##  [6] "pendientevdc.nb.html"                      
##  [7] "pendientevdc.Rmd"                          
##  [8] "pendientevdc_files"                        
##  [9] "tabla.png"                                 
## [10] "ValleDelCaucaDANE.gpkg"
(dem = terra::rast("COL_msk_alt.tif"))
## class       : SpatRaster 
## size        : 2136, 1800, 1  (nrow, ncol, nlyr)
## resolution  : 0.008333333, 0.008333333  (x, y)
## extent      : -81.8, -66.8, -4.3, 13.5  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 
## source      : COL_msk_alt.tif 
## name        : COL_msk_alt 
## min value   :         -28 
## max value   :        5453

Es recomendable reducir la resolución del DEM para evitar problemas con la memoria del ordenador:

dem2 = terra::aggregate(dem,2, "mean")
## |---------|---------|---------|---------|=========================================                                          

Leeremos nuestros municipios utilizando la librería del sf:

(munic <- sf::st_read("ValleDelCaucaDANE.gpkg"))
## Reading layer `mgn_anm_mpios' from data source 
##   `C:\Users\José Aguirre\Documents\GB2\DatosR\ValleDelCaucaDANE.gpkg' 
##   using driver `GPKG'
## Simple feature collection with 42 features and 6 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -77.54977 ymin: 3.091239 xmax: -75.70724 ymax: 5.047394
## Geodetic CRS:  MAGNA-SIRGAS
## Simple feature collection with 42 features and 6 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -77.54977 ymin: 3.091239 xmax: -75.70724 ymax: 5.047394
## Geodetic CRS:  MAGNA-SIRGAS
## First 10 features:
##    DPTO_CCDGO MPIO_CCDGO          MPIO_CNMBR MPIO_CDPMP VERSION STCTNENCUE
## 1          76        001                CALI      76001    2018     749642
## 2          76        036           ANDALUCÍA      76036    2018       9439
## 3          76        041        ANSERMANUEVO      76041    2018      10533
## 4          76        054             ARGELIA      76054    2018       2900
## 5          76        111 GUADALAJARA DE BUGA      76111    2018      48459
## 6          76        113        BUGALAGRANDE      76113    2018      10610
## 7          76        122          CAICEDONIA      76122    2018      11841
## 8          76        126              CALIMA      76126    2018      11549
## 9          76        130          CANDELARIA      76130    2018      30849
## 10         76        147             CARTAGO      76147    2018      50848
##                              geom
## 1  MULTIPOLYGON (((-76.59175 3...
## 2  MULTIPOLYGON (((-76.22406 4...
## 3  MULTIPOLYGON (((-76.01558 4...
## 4  MULTIPOLYGON (((-76.14316 4...
## 5  MULTIPOLYGON (((-76.31608 3...
## 6  MULTIPOLYGON (((-76.15131 4...
## 7  MULTIPOLYGON (((-75.8539 4....
## 8  MULTIPOLYGON (((-76.51747 4...
## 9  MULTIPOLYGON (((-76.30455 3...
## 10 MULTIPOLYGON (((-75.94518 4...

Necesitamos que ambos conjuntos están en coordenadas geograficas que coincidan. Para esto usaremos el siguiente código:

(ValleDelCauca_crs = crs(munic))
## [1] "GEOGCRS[\"MAGNA-SIRGAS\",\n    DATUM[\"Marco Geocentrico Nacional de Referencia\",\n        ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n            LENGTHUNIT[\"metre\",1]]],\n    PRIMEM[\"Greenwich\",0,\n        ANGLEUNIT[\"degree\",0.0174532925199433]],\n    CS[ellipsoidal,2],\n        AXIS[\"geodetic latitude (Lat)\",north,\n            ORDER[1],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n        AXIS[\"geodetic longitude (Lon)\",east,\n            ORDER[2],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n    USAGE[\n        SCOPE[\"Horizontal component of 3D system.\"],\n        AREA[\"Colombia - onshore and offshore. Includes San Andres y Providencia, Malpelo Islands, Roncador Bank, Serrana Bank and Serranilla Bank.\"],\n        BBOX[-4.23,-84.77,15.51,-66.87]],\n    ID[\"EPSG\",4686]]"

Y lo atribuimos a nuestro “DEM”:

crs(dem2)
## [1] "GEOGCRS[\"WGS 84\",\n    DATUM[\"unknown\",\n        ELLIPSOID[\"WGS84\",6378137,298.257223563,\n            LENGTHUNIT[\"metre\",1,\n                ID[\"EPSG\",9001]]]],\n    PRIMEM[\"Greenwich\",0,\n        ANGLEUNIT[\"degree\",0.0174532925199433,\n            ID[\"EPSG\",9122]]],\n    CS[ellipsoidal,2],\n        AXIS[\"latitude\",north,\n            ORDER[1],\n            ANGLEUNIT[\"degree\",0.0174532925199433,\n                ID[\"EPSG\",9122]]],\n        AXIS[\"longitude\",east,\n            ORDER[2],\n            ANGLEUNIT[\"degree\",0.0174532925199433,\n                ID[\"EPSG\",9122]]]]"

Entonces tenemos que atribuir el sistema de coordenadas del Valle del Cauca a nuestro “DEM2

crs(dem2)  <-  ValleDelCauca_crs

Como se puede observar:

crs(dem2)
## [1] "GEOGCRS[\"MAGNA-SIRGAS\",\n    DATUM[\"Marco Geocentrico Nacional de Referencia\",\n        ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n            LENGTHUNIT[\"metre\",1]]],\n    PRIMEM[\"Greenwich\",0,\n        ANGLEUNIT[\"degree\",0.0174532925199433]],\n    CS[ellipsoidal,2],\n        AXIS[\"geodetic latitude (Lat)\",north,\n            ORDER[1],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n        AXIS[\"geodetic longitude (Lon)\",east,\n            ORDER[2],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n    USAGE[\n        SCOPE[\"Horizontal component of 3D system.\"],\n        AREA[\"Colombia - onshore and offshore. Includes San Andres y Providencia, Malpelo Islands, Roncador Bank, Serrana Bank and Serranilla Bank.\"],\n        BBOX[-4.23,-84.77,15.51,-66.87]],\n    ID[\"EPSG\",4686]]"

Ahora necesitamos recortar el objeto “dem2” a los limites de nuestro departamento

(dem3 = terra::crop(dem2,munic, mask=TRUE))
## class       : SpatRaster 
## size        : 118, 111, 1  (nrow, ncol, nlyr)
## resolution  : 0.01666667, 0.01666667  (x, y)
## extent      : -77.55, -75.7, 3.083333, 5.05  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat MAGNA-SIRGAS (EPSG:4686) 
## source(s)   : memory
## name        : COL_msk_alt 
## min value   :       -1.25 
## max value   :     3940.00

6 Transformación de coordenadas

Para el siguiente paso tenemos qur calcular los atributos del terreno. Para ello el DEM debe estar en coordenadas planas , por lo que tenemos que modificar los soguientes dos fragmentos de codigo para transformar los datos de entrada al sistema de coordenadas nacional de colombia.

Esta función reproyecta el DEM al sistema de cordenadas planas de colombia

dem_plane = project(dem3, "EPSG:9377")

También debemos asignar de manera similar para el objeto vectorial:

(munic_plane = sf::st_transform(munic, "EPSG:9377"))
## Simple feature collection with 42 features and 6 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 4494194 ymin: 1900273 xmax: 4699750 ymax: 2116536
## Projected CRS: MAGNA-SIRGAS 2018 / Origen-Nacional
## First 10 features:
##    DPTO_CCDGO MPIO_CCDGO          MPIO_CNMBR MPIO_CDPMP VERSION STCTNENCUE
## 1          76        001                CALI      76001    2018     749642
## 2          76        036           ANDALUCÍA      76036    2018       9439
## 3          76        041        ANSERMANUEVO      76041    2018      10533
## 4          76        054             ARGELIA      76054    2018       2900
## 5          76        111 GUADALAJARA DE BUGA      76111    2018      48459
## 6          76        113        BUGALAGRANDE      76113    2018      10610
## 7          76        122          CAICEDONIA      76122    2018      11841
## 8          76        126              CALIMA      76126    2018      11549
## 9          76        130          CANDELARIA      76130    2018      30849
## 10         76        147             CARTAGO      76147    2018      50848
##                              geom
## 1  MULTIPOLYGON (((4600987 195...
## 2  MULTIPOLYGON (((4642160 202...
## 3  MULTIPOLYGON (((4665634 209...
## 4  MULTIPOLYGON (((4651417 208...
## 5  MULTIPOLYGON (((4631835 199...
## 6  MULTIPOLYGON (((4650286 203...
## 7  MULTIPOLYGON (((4683364 204...
## 8  MULTIPOLYGON (((4609484 200...
## 9  MULTIPOLYGON (((4632900 194...
## 10 MULTIPOLYGON (((4673403 208...

7 Cálculos de atributos del terreno

Este paso requiere que calculemos atributos del terreno -específicamente pendiente (slope) y orientacion (aspect)- usando las funciones SLpasp del paquete MulticascaleDTM en R, con el siguiente código:

(slp_asp = MultiscaleDTM::SlpAsp(
  dem_plane,
  w = c(3, 3),
  unit = "degrees",
  method = "queen",
  metrics = c("slope", "aspect"),
  na.rm = TRUE,
  include_scale = FALSE,
  mask_aspect = TRUE
))
## class       : SpatRaster 
## size        : 118, 112, 2  (nrow, ncol, nlyr)
## resolution  : 1848.873, 1848.873  (x, y)
## extent      : 4494097, 4701171, 1899617, 2117784  (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377) 
## source(s)   : memory
## names       :        slope,      aspect 
## min values  :  0.007684549,   0.0725555 
## max values  : 20.357246604, 359.4038646

Una vez calculados los atributos del terreno, dividimos el “slp_asp” en pendiente y orientación

Capa -pendiente- 1:

(slope = subset(slp_asp, 1))
## class       : SpatRaster 
## size        : 118, 112, 1  (nrow, ncol, nlyr)
## resolution  : 1848.873, 1848.873  (x, y)
## extent      : 4494097, 4701171, 1899617, 2117784  (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377) 
## source(s)   : memory
## name        :        slope 
## min value   :  0.007684549 
## max value   : 20.357246604

Miremos como se representa en una tabla la distribución de las pendientes:

terra::hist(slope, 
     main = "Pendiente Valle del Cauca", 
     xlab = "pendiente (en grados)")

(Explicación gráfica)

Capa 2 -orientación-:

(aspect =subset(slp_asp, 2))
## class       : SpatRaster 
## size        : 118, 112, 1  (nrow, ncol, nlyr)
## resolution  : 1848.873, 1848.873  (x, y)
## extent      : 4494097, 4701171, 1899617, 2117784  (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377) 
## source(s)   : memory
## name        :      aspect 
## min value   :   0.0725555 
## max value   : 359.4038646

Miremos como se representa en una tabla la distribución de las pendientes:

terra::hist(aspect, 
     main = "Orientación Valle del Cauca", 
     xlab = "orientación (en grados)")

(Explicación gráfica)

Adicionalmente convertimos los grados de pendiente a porcentaje de pendiente:

(slope_perc = tan(slope*(pi/180))*100)
## class       : SpatRaster 
## size        : 118, 112, 1  (nrow, ncol, nlyr)
## resolution  : 1848.873, 1848.873  (x, y)
## extent      : 4494097, 4701171, 1899617, 2117784  (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377) 
## source(s)   : memory
## name        :       slope 
## min value   :  0.01341207 
## max value   : 37.10475113

Miremos como se representa en una tabla la distribución de las pendientes:

terra::hist(slope_perc, 
     main = "Pendiente Valle del Cauca", 
     xlab = "pendiente (en porcentaje)")

8 Cálculo de las estadisticas zonales

Ahora tenemos que calcular el promedio de los valores de pendiente por municipio. Para ello veamos la clasificación de pendientes del IGAC para fines agronómicos:

knitr::include_graphics("tabla.png")

Explicación de tabla

m <- c(0, 3, 1,  
       3, 7, 2,  
       7, 12,  3, 
       12, 25, 4, 
       25, 50, 5, 
       50, 75, 6,
       75, 160, 7)
m <- matrix(m, ncol=3, byrow = TRUE)
rc <- classify(slope_perc, m, right=TRUE)

Ahora vamos a computar las estadísticas zonales usando exactextractr:

(munic$mean_slope <- exactextractr::exact_extract(slope_perc, munic, 'mean'))
##   |                                                                              |                                                                      |   0%  |                                                                              |==                                                                    |   2%  |                                                                              |===                                                                   |   5%  |                                                                              |=====                                                                 |   7%  |                                                                              |=======                                                               |  10%  |                                                                              |========                                                              |  12%  |                                                                              |==========                                                            |  14%  |                                                                              |============                                                          |  17%  |                                                                              |=============                                                         |  19%  |                                                                              |===============                                                       |  21%  |                                                                              |=================                                                     |  24%  |                                                                              |==================                                                    |  26%  |                                                                              |====================                                                  |  29%  |                                                                              |======================                                                |  31%  |                                                                              |=======================                                               |  33%  |                                                                              |=========================                                             |  36%  |                                                                              |===========================                                           |  38%  |                                                                              |============================                                          |  40%  |                                                                              |==============================                                        |  43%  |                                                                              |================================                                      |  45%  |                                                                              |=================================                                     |  48%  |                                                                              |===================================                                   |  50%  |                                                                              |=====================================                                 |  52%  |                                                                              |======================================                                |  55%  |                                                                              |========================================                              |  57%  |                                                                              |==========================================                            |  60%  |                                                                              |===========================================                           |  62%  |                                                                              |=============================================                         |  64%  |                                                                              |===============================================                       |  67%  |                                                                              |================================================                      |  69%  |                                                                              |==================================================                    |  71%  |                                                                              |====================================================                  |  74%  |                                                                              |=====================================================                 |  76%  |                                                                              |=======================================================               |  79%  |                                                                              |=========================================================             |  81%  |                                                                              |==========================================================            |  83%  |                                                                              |============================================================          |  86%  |                                                                              |==============================================================        |  88%  |                                                                              |===============================================================       |  90%  |                                                                              |=================================================================     |  93%  |                                                                              |===================================================================   |  95%  |                                                                              |====================================================================  |  98%  |                                                                              |======================================================================| 100%
##  [1]  8.234748  2.735861  5.981479  4.842068  9.178998  3.604378  6.068478
##  [8] 10.190221  0.269156  2.386823 12.163800  7.838280  8.935884  8.490119
## [15] 11.703223 12.169142  5.731778  2.972752  3.499377  6.909639 10.938899
## [22]  3.492452  9.220719  6.819207  6.108836  7.643911  7.920785 10.316816
## [29]  9.261460  2.744941  7.617874  6.259845  6.531541  7.808092  1.424047
## [36]  2.004853  6.017721  4.744247  7.055912 10.034364  9.837699  4.146656
hist(munic$mean_slope, 
     main = "Pendiente promedio por municipio en el Valle del Cauca", 
     xlab = "pendiente (en porcentaje)")

(munic$class <- exactextractr::exact_extract(rc, munic, 'mode'))
##   |                                                                              |                                                                      |   0%  |                                                                              |==                                                                    |   2%  |                                                                              |===                                                                   |   5%  |                                                                              |=====                                                                 |   7%  |                                                                              |=======                                                               |  10%  |                                                                              |========                                                              |  12%  |                                                                              |==========                                                            |  14%  |                                                                              |============                                                          |  17%  |                                                                              |=============                                                         |  19%  |                                                                              |===============                                                       |  21%  |                                                                              |=================                                                     |  24%  |                                                                              |==================                                                    |  26%  |                                                                              |====================                                                  |  29%  |                                                                              |======================                                                |  31%  |                                                                              |=======================                                               |  33%  |                                                                              |=========================                                             |  36%  |                                                                              |===========================                                           |  38%  |                                                                              |============================                                          |  40%  |                                                                              |==============================                                        |  43%  |                                                                              |================================                                      |  45%  |                                                                              |=================================                                     |  48%  |                                                                              |===================================                                   |  50%  |                                                                              |=====================================                                 |  52%  |                                                                              |======================================                                |  55%  |                                                                              |========================================                              |  57%  |                                                                              |==========================================                            |  60%  |                                                                              |===========================================                           |  62%  |                                                                              |=============================================                         |  64%  |                                                                              |===============================================                       |  67%  |                                                                              |================================================                      |  69%  |                                                                              |==================================================                    |  71%  |                                                                              |====================================================                  |  74%  |                                                                              |=====================================================                 |  76%  |                                                                              |=======================================================               |  79%  |                                                                              |=========================================================             |  81%  |                                                                              |==========================================================            |  83%  |                                                                              |============================================================          |  86%  |                                                                              |==============================================================        |  88%  |                                                                              |===============================================================       |  90%  |                                                                              |=================================================================     |  93%  |                                                                              |===================================================================   |  95%  |                                                                              |====================================================================  |  98%  |                                                                              |======================================================================| 100%
##  [1] 1 1 2 2 4 1 3 4 1 1 3 3 1 2 4 4 1 1 1 1 4 1 2 3 1 3 3 3 4 1 3 2 3 3 1 1 3 2
## [39] 1 3 3 1
hist(munic$class, 
     main = "Pendiente reclasificada del Valle del Cauca", 
     xlab = "Pendiente (como una categoria)")

Vamos a trasformar la pendiente a nuestras coordenadas:

(rc.geo = project(rc, "EPSG:4326"))
## class       : SpatRaster 
## size        : 119, 112, 1  (nrow, ncol, nlyr)
## resolution  : 0.01666619, 0.01666619  (x, y)
## extent      : -77.56107, -75.69445, 3.077098, 5.060374  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326) 
## source(s)   : memory
## name        : slope 
## min value   :     1 
## max value   :     5
(slope.geo = project(slope_perc, "EPSG:4326"))
## class       : SpatRaster 
## size        : 119, 112, 1  (nrow, ncol, nlyr)
## resolution  : 0.01666619, 0.01666619  (x, y)
## extent      : -77.56107, -75.69445, 3.077098, 5.060374  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326) 
## source(s)   : memory
## name        :       slope 
## min value   :  0.04449286 
## max value   : 34.54376221

9 Trazando la pendiente del terreno

Primero necesitamos una paleta de colores para la pendiente:

palredgreen <- colorNumeric(c("darkseagreen3","yellow2", "orange", "brown2", "darkred"), values(slope.geo),
  na.color = "transparent")

Ahora vamos a plotear. Ten presente tener el codigo correctamente:

leaflet(munic) %>% addTiles() %>% setView(-76.5, 3.8, 8) %>% 
    addPolygons(color = "gray", weight = 1.0, smoothFactor = 0.5,
    opacity = 0.4, fillOpacity = 0.10,
    popup = paste("Municipio: ", munic$MPIO_CNMBR, "<br>",
                          "Clase de Pendiente: ", munic$class, "<br>")) %>%
  addRasterImage(slope.geo, colors = palredgreen, opacity = 0.8)  %>%
  addLegend(pal = palredgreen, values = values(slope.geo),
    title = "Pendiente Valle del Cauca (%)")
## Warning: sf layer has inconsistent datum (+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs).
## Need '+proj=longlat +datum=WGS84'

Visualizacion de pendiente

library(leaflet)
library(htmltools)

Paleta de relleno (igual que antes, si ya la tienes puedes reutilizarla)

pal_igac <- colorFactor(
  palette = c("#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"),
  domain  = munic$class
)

Contenido HTML del tooltip (bonito y claro)

labels <- sprintf("
<div class='ttcard'>
  <div class='tt-title'>%s</div>
  <div class='tt-row'>Pendiente promedio: <b>%.1f%%</b></div>
  <div class='tt-row'>Clase IGAC: <span class='tt-pill tt-%s'>%s</span></div>
</div>",
  munic$MPIO_CNMBR,
  munic$mean_slope,
  munic$class,
  munic$class
) |> lapply(htmltools::HTML)

CSS para estilizar el tooltip (inyectado en el mapa)

tooltip_css <- htmltools::tags$style(htmltools::HTML("
.leaflet-tooltip.ttlabel {
  background: #ffffff;
  color: #111;
  border: 1px solid #b5b5b5;
  border-radius: 10px;
  padding: 8px 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
  font-family: Arial, sans-serif;
  font-size: 13px;
}
.leaflet-tooltip.ttlabel .tt-title {
  font-weight: 700;
  margin-bottom: 4px;
}
.leaflet-tooltip.ttlabel .tt-row {
  margin: 2px 0;
}
.leaflet-tooltip.ttlabel .tt-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  color: #fff;
  font-weight: 600;
}
.leaflet-tooltip.ttlabel .tt-1 { background:#d9f0a3; color:#08306b; }
.leaflet-tooltip.ttlabel .tt-2 { background:#addd8e; color:#08306b; }
.leaflet-tooltip.ttlabel .tt-3 { background:#78c679; }
.leaflet-tooltip.ttlabel .tt-4 { background:#41ab5d; }
.leaflet-tooltip.ttlabel .tt-5 { background:#238443; }
.leaflet-tooltip.ttlabel .tt-6 { background:#006837; }
.leaflet-tooltip.ttlabel .tt-7 { background:#004529; }
"))

Mapa interactivo con tooltip estilizado (hover)

leaflet(munic) %>%
  addProviderTiles(providers$Esri.WorldTopoMap) %>%
  addControl(tooltip_css, position = "topleft") %>%  # inyecta el CSS en el HTML
  setView(lng = -76.5, lat = 3.8, zoom = 8) %>%
  addPolygons(
    fillColor = ~pal_igac(class),
    color = "gray20", weight = 1, opacity = 0.6, fillOpacity = 0.85,
    highlight = highlightOptions(weight = 3, color = "black", fillOpacity = 0.95, bringToFront = TRUE),
    label = labels,  # <- tooltip HTML bonito
    labelOptions = labelOptions(
      className = "ttlabel",    # usa la clase CSS de arriba
      direction = "auto",
      sticky = TRUE,            # el tooltip sigue al puntero
      textsize = "13px",
      opacity = 1
    )
  ) %>%
  addLegend(
    pal = pal_igac,
    values = munic$class,
    title = "Clase de Pendiente IGAC",
    opacity = 1
  )
## Warning: sf layer has inconsistent datum (+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs).
## Need '+proj=longlat +datum=WGS84'

10 Visualización de la orientación del terreno (Aspect)

Asegúrate de tener la capa aspect reproyectada a coordenadas geográficas

(aspect.geo <- project(aspect, "EPSG:4326"))
## class       : SpatRaster 
## size        : 119, 112, 1  (nrow, ncol, nlyr)
## resolution  : 0.01666619, 0.01666619  (x, y)
## extent      : -77.56107, -75.69445, 3.077098, 5.060374  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326) 
## source(s)   : memory
## name        :     aspect 
## min value   :   9.335389 
## max value   : 355.747528

Creamos una paleta circular de colores para mostrar direcciones (0–360°)

pal_aspect <- colorNumeric(
  palette = c("blue", "cyan", "green", "yellow", "orange", "red", "purple", "blue"),
  domain = values(aspect.geo),
  na.color = "transparent"
)

Mapa interactivo del aspecto del terreno

leaflet() %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -76.5, lat = 3.8, zoom = 8) %>%
  addRasterImage(aspect.geo, colors = pal_aspect, opacity = 0.8) %>%
  addPolygons(
    data = munic,
    color = "black", weight = 1,
    opacity = 0.7, fillOpacity = 0,
    popup = paste0("<b>Municipio:</b> ", munic$MPIO_CNMBR)
  ) %>%
  addLegend(
    pal = pal_aspect,
    values = values(aspect.geo),
    title = "Orientación (grados)",
    opacity = 1
  )
## Warning: sf layer has inconsistent datum (+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs).
## Need '+proj=longlat +datum=WGS84'

11 Bibliografía

original notebook, showing the creation of an elevation raster: Lizarazo, I., 2025. Elevation data processing and analysis in R. Available at https://rpubs.com/ials2un/otro_dem

12 Reproductibilidad

sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Colombia.utf8  LC_CTYPE=Spanish_Colombia.utf8   
## [3] LC_MONETARY=Spanish_Colombia.utf8 LC_NUMERIC=C                     
## [5] LC_TIME=Spanish_Colombia.utf8    
## 
## time zone: America/Bogota
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] htmltools_0.5.8.1    exactextractr_0.10.0 MultiscaleDTM_1.0   
## [4] terra_1.8-70         leaflet_2.2.3        sf_1.0-21           
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10             generics_0.1.4          class_7.3-23           
##  [4] KernSmooth_2.23-26      lattice_0.22-7          digest_0.6.37          
##  [7] magrittr_2.0.4          rgl_1.3.24              RColorBrewer_1.1-3     
## [10] evaluate_1.0.5          grid_4.5.1              fastmap_1.2.0          
## [13] jsonlite_2.0.0          e1071_1.7-16            DBI_1.2.3              
## [16] promises_1.5.0          scales_1.4.0            crosstalk_1.2.2        
## [19] codetools_0.2-20        jquerylib_0.1.4         cli_3.6.5              
## [22] shiny_1.11.1            rlang_1.1.6             units_1.0-0            
## [25] base64enc_0.1-3         cachem_1.1.0            yaml_2.3.10            
## [28] otel_0.2.0              tools_4.5.1             raster_3.6-32          
## [31] dplyr_1.1.4             httpuv_1.6.16           png_0.1-8              
## [34] vctrs_0.6.5             R6_2.6.1                mime_0.13              
## [37] proxy_0.4-27            lifecycle_1.0.4         classInt_0.4-11        
## [40] leaflet.providers_2.0.0 htmlwidgets_1.6.4       pkgconfig_2.0.3        
## [43] bslib_0.9.0             pillar_1.11.1           later_1.4.4            
## [46] glue_1.8.0              Rcpp_1.1.0              xfun_0.53              
## [49] tibble_3.3.0            tidyselect_1.2.1        rstudioapi_0.17.1      
## [52] knitr_1.50              farver_2.1.2            xtable_1.8-4           
## [55] rmarkdown_2.30          compiler_4.5.1          sp_2.2-0

post scriptum: In case the error persists, that those easy answers are often hard to find. done by: +BVVR+