Este es un R Notebook que ilustra varias funcionalidades para obtener, procesar y visualizar modelos digitales de elevación en R. Tiene como objetivo respondera las activides del curso de Geomatica BÔsica de la Universidad Nacional durante este tiempo de distanciamiento social.
Los datos de elevación se utilizan para una amplia gama de aplicaciones, que incluyen, por ejemplo, visualización, hidrologĆa y modelado ecológico. Obtener acceso a estos datos en R no ha tenido una sola interfaz, estĆ” disponible a travĆ©s de funciones en muchos paquetes o requiere acceso local a los datos. Esto ya no es necesario, ya que existe una variedad de API que brindan acceso programĆ”tico a los datos de elevación. El paquete elevatr se escribió para estandarizar el acceso a los datos de elevación desde las API web.
Para acceder a los datos de elevación rÔster (por ejemplo, un DEM), el paquete elevatr utiliza los mosaicos de terreno de Amazon Web Services. Utilizaremos esta funcionalidad en este cuaderno.
instalaremos la siguientes librerias: ārgdalā, ārasterā, āelevatrā, ārasterVisā, ārglā. Descomentar el siguiente comando
# install.packages("rgdal")
# install.packages("raster")
# install.packages("elevatr")
# install.packages("rasterVis")
# install.packages("rgl")
Ahora correremos las librerias instaladas
library(rasterVis)
Loading required package: raster
Loading required package: sp
Loading required package: lattice
Loading required package: latticeExtra
library(raster)
library(rgl)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(rgdal)
rgdal: version: 1.5-16, (SVN revision 1050)
Geospatial Data Abstraction Library extensions to R successfully loaded
Loaded GDAL runtime: GDAL 3.0.4, released 2020/01/28
Path to GDAL shared files: C:/Users/rojas/OneDrive/Documentos/R/win-library/4.0/rgdal/gdal
GDAL binary built with GEOS: TRUE
Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
Path to PROJ shared files: C:/Users/rojas/OneDrive/Documentos/R/win-library/4.0/rgdal/proj
Linking to sp version:1.4-2
To mute warnings of possible GDAL/OSR exportToProj4() degradation,
use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
library(elevatr)
Hay varias fuentes de modelos digitales de elevación, como Shuttle Radar Topography Mission (SRTM), USGS National Elevation Dataset (NED), Global DEM (GDEM) y otras. Cada uno de estos DEM tiene ventajas y desventajas para su uso. Antes de su cierre en enero de 2018, Mapzen combinó varias de estas fuentes para crear un producto de elevación de sĆntesis que utiliza los mejores datos de elevación disponibles para una región determinada a un nivel de zoom determinado. Aunque cerrados, estos datos compilados por Mapzen son actualmente accesibles a travĆ©s de Terrain Tiles en Amazon Web Services (AWS).
La entrada para get_elev_raster () es un data.frame con ubicaciones x (longitud) e y (latitud) como las dos primeras columnas, cualquier objeto sp o cualquier objeto rƔster y devuelve un RasterLayer de los mosaicos que se superponen al cuadro delimitador de la entrada. Si se recuperan varios mosaicos, la salida resultante es una capa rƔster combinada.
Como se mencionó, un marco de datos con columnas x e y, un objeto sp o un objeto raster debe ser la entrada y src debe establecerse en āmapzenā (este es el valor predeterminado).
No hay diferencia en el uso de los tipos de datos de entrada sp y rƔster. El marco de datos requiere un prj. MostrarƩ ejemplos usando un SpatialPolygonsDataFrame.
Primero, necesitamos cargar un shapefile que represente a los municipios del departamento de Cauca, revisemos estos datos.
list.files("C:/Users/rojas/OneDrive/Escritorio/R estudio/Geomatica/Departamento/19_CAUCA/Cauca/ADMINISTRATIVO")
[1] "MGN_DPTO_POLITICO.cpg" "MGN_DPTO_POLITICO.dbf"
[3] "MGN_DPTO_POLITICO.prj" "MGN_DPTO_POLITICO.sbn"
[5] "MGN_DPTO_POLITICO.sbx" "MGN_DPTO_POLITICO.shp"
[7] "MGN_DPTO_POLITICO.shp.xml" "MGN_DPTO_POLITICO.shx"
[9] "MGN_MPIO_POLITICO.cpg" "MGN_MPIO_POLITICO.dbf"
[11] "MGN_MPIO_POLITICO.prj" "MGN_MPIO_POLITICO.sbn"
[13] "MGN_MPIO_POLITICO.sbx" "MGN_MPIO_POLITICO.shp"
[15] "MGN_MPIO_POLITICO.shp.xml" "MGN_MPIO_POLITICO.shx"
Ahora, leamos el shapefile usando una función proporcionada por el paquete raster
(munic <- shapefile("C:/Users/rojas/OneDrive/Escritorio/R estudio/Geomatica/Departamento/19_CAUCA/Cauca/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class : SpatialPolygonsDataFrame
features : 42
extent : -77.92834, -75.74782, 0.9580285, 3.328941 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
variables : 9
names : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR, MPIO_CRSLC, MPIO_NAREA, MPIO_NANO, DPTO_CNMBR, Shape_Leng, Shape_Area
min values : 19, 19001, ALMAGUER, 1535, 56.65263628, 2017, CAUCA, 0.367595051566, 0.00459170058711
max values : 19, 19845, VILLA RICA, Ordenanza 45 de 1914, 3619.37102503, 2017, CAUCA, 3.67422122731, 0.29359453607
Reviemos los atribusto del obejto munic
head(munic)
Seleccionemos solo la ciudad capital de este departamento.
## para entender el codigo se recomiendo revisar la documentación
##https://www.neonscience.org/dc-shapefile-attributes-r
Popay <- munic[munic$MPIO_CNMBR=="POPAYĆ\201N",]
plot(Popay, main="PopayƔn.", axes=TRUE)
plot(munic, add=TRUE)
invisible(text(coordinates(munic), labels=as.character(munic$MPIO_CNMBR), cex=0.8))
Con el siguiente comando descargaremos los datos de elevación:
elevation <- get_elev_raster(Popay, z = 8)
CRS object has comment, which is lost in outputCRS object has comment, which is lost in outputCRS object has comment, which is lost in outputDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition
Downloading DEMs [=============>-------------] 50% eta: 3sDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition
Downloading DEMs [===================>-------] 75% eta: 1sDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition
Downloading DEMs [===========================] 100% eta: 0s
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionMerging DEMs
Reprojecting DEM to original projection
Note: Elevation units are in meters.
Note: The coordinate reference system is:
+proj=longlat +datum=WGS84 +no_defs
Ahora, vamos a revisar qué hay dentro del objeto de elevación:
elevation
class : RasterLayer
dimensions : 1032, 1033, 1066056 (nrow, ncol, ncell)
resolution : 0.00275, 0.00275 (x, y)
extent : -77.3575, -74.51675, -0.01287881, 2.825121 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : -120.551, 4591.825 (min, max)
Observe algunas cosas sobre este DEM:
°dimensiones: el ātamaƱoā del archivo en pĆxeles
°nrow, ncol: el número de filas y columnas en los datos (imagine una hoja de cÔlculo o una matriz).
°ncells: el nĆŗmero total de pĆxeles o celdas que componen el rĆ”ster.
°resolución: el tamaƱo de cada pĆxel (en grados decimales en este caso). Recordemos que 1 grado decimal representa aproximadamente 111,11 km.
°extensión: la extensión espacial del rÔster. Este valor estarÔ en las mismas unidades de coordenadas que el sistema de referencia de coordenadas del rÔster.
°crs: la cadena del sistema de referencia de coordenadas para el rÔster. Este rÔster estÔ en coordenadas geogrÔficas con un datum de WGS 84.
plot(elevation, main="Este es el DEM descargado [metros]")
plot(Popay, add=TRUE)
Note que el DEM cubre una extensión mayor que la que necesitamos. Esto se debe a la disposición espacial de los mosaicos de elevación en AWS.
De todos modos, es una buena idea guardar el DEM para el futuro.
writeRaster(elevation, filename="Popay", datatype='INT4S', overwrite=TRUE)
class : RasterLayer
dimensions : 1032, 1033, 1066056 (nrow, ncol, ncell)
resolution : 0.00275, 0.00275 (x, y)
extent : -77.3575, -74.51675, -0.01287881, 2.825121 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : C:/Users/rojas/OneDrive/Escritorio/R estudio/Geomatica/Popay.grd
names : layer
values : -121, 4592 (min, max)
Ahora, recortemos los datos de elevación correspondientes a Cauca:
elev_crop = crop(elevation, Popay)
plot(elev_crop, main="Modelo de elevación digital recortado")
plot(Popay, add=TRUE)
Revisemos el nuevo objeto:
elev_crop
class : RasterLayer
dimensions : 95, 142, 13490 (nrow, ncol, ncell)
resolution : 0.00275, 0.00275 (x, y)
extent : -76.7745, -76.384, 2.310871, 2.572121 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : 1194.329, 4563.661 (min, max)
Al trabajar con DEM, siempre es una buena idea utilizar coordenadas de mapa en lugar de coordenadas geogrÔficas. Esto se debe al hecho de que, en coordenadas geogrÔficas, las unidades de dimensiones horizontales son grados decimales PERO la unidad de dimensión vertical son metros. Reproyectemos los datos de elevación.
Podemos ir a epsg.io y buscar la proyección de la zona MAGNA Colombia BogotÔ. Necesitamos obtener la definición de esta referencia espacial en formato PROJ.4 (el que se usa para las bibliotecas sp y rÔster. Copiemos el texto PROJ.4 y guÔrdelo.)
spatialref <- "+proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
Ahora, podemos reproyectar los datos de elevación de las coordenadas geogrÔficas WGS84 en la zona MAGNA Colombia BogotÔ.
pr3 <- projectExtent(elev_crop, spatialref)
res(pr3) <- 100
rep_elev <- projectRaster(elev_crop, pr3)
¿Qué tenemos?
rep_elev
class : RasterLayer
dimensions : 290, 435, 126150 (nrow, ncol, ncell)
resolution : 100, 100 (x, y)
extent : 699903.5, 743403.5, 747497, 776497 (xmin, xmax, ymin, ymax)
crs : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
source : memory
names : layer
values : 1179.856, 4566.843 (min, max)
Ahora, volvamos a proyectar el SpatialPolygonsDataFrame que representa la capital de nuestro departamento:
(rep_Popay = spTransform(Popay,spatialref))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definition,
but +towgs84= values preserved
class : SpatialPolygonsDataFrame
features : 1
extent : 700089, 743251.7, 747584.8, 776638.3 (xmin, xmax, ymin, ymax)
crs : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
variables : 9
names : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR, MPIO_CRSLC, MPIO_NAREA, MPIO_NANO, DPTO_CNMBR, Shape_Leng, Shape_Area
value : 19, 19001, POPAYĆĀN, 1537, 480.17981672, 2017, CAUCA, 1.37293710691, 0.038969995214
Es tiempo de trazar:
plot(rep_elev, main="Reprojected Digital elevation model")
plot(rep_Popay, add=TRUE)
Para evitar perder lo que llevamos, guardemos nuestro DEM:
writeRaster(rep_elev, filename="dem_rep_Popay_eleve.tif", datatype='INT4S', overwrite=TRUE)
Discarded datum Unknown_based_on_GRS80_ellipsoid in CRS definition: +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs,
but +towgs84= values preservedDiscarded datum Unknown based on GRS80 ellipsoid in CRS definition,
but +towgs84= values preserved
Una exploración rĆ”pida de las estadĆsticas de DEM:
hist(rep_elev)
promedio <- cellStats(rep_elev, 'mean')
minimo <- cellStats(rep_elev, 'min')
maximo <- cellStats(rep_elev, 'max')
desviacion <- cellStats(rep_elev, 'sd')
# crear vector unidimensional
metricas <- c('mean', 'min', 'max', 'std')
valores <- c(promedio, minimo, maximo, desviacion)
# creacion de data frame con estadisticas de elevacion [metros]
# el parƩntesis externo sirve para "imprimir" el contenido de un objeto
(df_estadisticas <- data.frame(metricas, valores))
Primero, calcule la pendiente, el aspecto y el sombreado:
slope = terrain(rep_elev,opt='slope', unit='degrees')
aspect = terrain(rep_elev,opt='aspect',unit='degrees')
hill = hillShade(slope,aspect,40,315)
Elevación de la parcela. Tenga en cuenta la paleta de colores utilizada aquĆ.
plot(rep_elev,main="DEM para PopayƔn [metros]", col=terrain.colors(25,alpha=0.8))
Pendiente de la parcela. Tenga en cuenta la paleta de colores utilizada aquĆ.
plot(slope,main="Pendiente para PopayƔn [grados]", col=topo.colors(25,alpha=0.7))
Aspecto de la parcela. Tenga en cuenta la paleta de colores utilizada aquĆ.
plot(aspect,main="Aspecto para PopayƔn [grados]", col=rainbow(25,alpha=0.7))
Una trama combinada:
plot(hill,
col=grey(1:100/100), # crea una rampa de color de colores grises para sombreado
legend=FALSE, # sin leyenda, no nos importa el gris de la sombra
main="DEM para PopayƔn",
axes=FALSE) # hace una trama mƔs limpia, si las coordenadas no son necesarias
plot(rep_elev,
axes=FALSE,
col=terrain.colors(12, alpha=0.35), add=TRUE)
La biblioteca rayshader es un paquete de código abierto para producir visualizaciones de datos 2D y 3D en R. rayshader usa datos de elevación en una matriz R base y una combinación de trazado de rayos, mapeo de textura esférica, superposiciones y oclusión ambiental para generar hermosos mapas topogrÔficos 2D y 3D . AdemÔs de los mapas, rayshader también permite al usuario traducir objetos ggplot2 en hermosas visualizaciones de datos en 3D.
# install.packages ("rayshader")
library(rayshader)
Convierta el DEM en una matriz:
elmat = raster_to_matrix(rep_elev)
[1] "Dimensions of matrix are: 435x290."
Usamos otra de las texturas integradas de rayshader:
elmat %>%
sphere_shade(texture = "imhof2") %>%
plot_map()
detect_water y add_water agregan una capa de agua al mapa:
elmat %>%
sphere_shade(texture = "desert") %>%
add_water(detect_water(elmat), color = "desert") %>%
plot_map()
Y también podemos agregar una capa con trazado de rayos desde esa dirección del sol:
elmat %>%
sphere_shade(texture = "desert") %>%
add_water(detect_water(elmat), color = "desert") %>%
add_shadow(ray_shade(elmat), 0.5) %>%
plot_map()
Un experto en R sugiere aquà otra forma de visualización.
Vamos a intentarlo:
# install.packages("jpeg")
library(jpeg)
Función de sombreado de mapeo de entorno esférico
getv=function(i,a,s){
ct = dim(i)[1:2]/2
sx = values(s)/90 * ct[1]
sy = values(s)/90 * ct[2]
a = values(a) * 0.01745
px = floor(ct[1] + sx * -sin(a))
py = floor(ct[2] + sy * cos(a))
template = brick(s,s,s)
values(template)=NA
cellr = px + py * ct[1]*2
cellg = px + py * ct[1]*2 + (ct[1]*2*ct[2]*2)
cellb = px + py * ct[1]*2 + 2*(ct[1]*2*ct[2]*2)
template[[1]] = i[cellr]
template[[2]] = i[cellg]
template[[3]] = i[cellb]
template = template * 256
template
}
Cargar una imagen de mapa del entorno Se puede encontrar un ejemplo en http://i.imgur.com/9pvbHjN.jpg
map=readJPEG("C:/Users/rojas/OneDrive/Escritorio/R estudio/Geomatica/9pvbHjN.jpg")
# Hacer el mapeo
out = getv(map, aspect, slope)
ningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infningę¼ć¹”n argumento finito para min; retornando Infningun argumento finito para max; retornando -Inf
# Traza montaƱas
plotRGB(out, main = "MontaƱas supuestamente bonitas en el PopayƔn")
sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18363)
Matrix products: default
locale:
[1] LC_COLLATE=Spanish_Mexico.1252 LC_CTYPE=Spanish_Mexico.1252
[3] LC_MONETARY=Spanish_Mexico.1252 LC_NUMERIC=C
[5] LC_TIME=Spanish_Mexico.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] jpeg_0.1-8.1 raster_3.3-13 sp_1.4-2
loaded via a namespace (and not attached):
[1] Rcpp_1.0.5 lattice_0.20-41 codetools_0.2-16
[4] digest_0.6.25 grid_4.0.2 jsonlite_1.7.0
[7] magrittr_1.5 evaluate_0.14 stringi_1.4.6
[10] rlang_0.4.7 rmarkdown_2.3 tools_4.0.2
[13] stringr_1.4.0 htmlwidgets_1.5.1 xfun_0.16
[16] yaml_2.2.1 compiler_4.0.2 base64enc_0.1-3
[19] htmltools_0.5.0 knitr_1.29