English-language version here
Hoy en día ya es posible y además relativamente fácil renderizar (anglicismo para describir el proceso de generar imágenes digitales a partir de un modelo tridimensional) mapas con perspectiva e iluminación usando R. Gracias a los paquetes rayshader
y rayrender
, desarrollados por Tyler Morgan-Wall y elevatr
de Jeff Hollister, podemos combinar una imagen georeferenciada con un modelo de elevación digital (DEM, por sus siglas en inglés) para darle profundidad y ambiente a cualquier mapa que tengamos en formato digital.
El tuitero @flotsam siempre comparte ejemplos muy buenos, como éste que subió hace poco:
A 1972 NRCan (formerly the Department of Energy, Mines, and Resources) map of Montréal, Canada. Spent more time trying to decipher cryptic filenames to find what I want than actually rayshading it. :P#rayshader adventures, an #rstats tale pic.twitter.com/O756ddhs9G
— flotsam (@researchremora) August 2, 2021
El proceso para renderizar imagenes georeferencias está resumido en esta guía.
Hay muchos mapas ya georeferenciados en Internet, y además podemos usar programas de SIG para empatar cualquier mapa digital con su contexto espacial mediante puntos de control. Yo generalmente prefiero hacer mis propios mapa en ggplot2
y quería procesarlos en 3D con rayshader
.
Cuando hacemos mapas en ggplot2
con los paquetes geoespaciales más populares (sf
, stars
, etc.), ya tenemos datos espaciales y no haría falta asignarle a mano coordenadas del mundo real a cada pixel del raster de nuestro mapa. Además, cada que trato de georeferenciar imágenes en qGIS pierdo la paciencia por tener que crear al menos seis puntos de control con el cursor y la mano toda temblorina.
En esta respuesta de StackOverflow, nos explican como extraer la información que describe los valores xy máximos y mínimos del panel de un objeto ggplot, para poder asignarle esta extensión a la versión raster que ya exportamos de nuestro objeto.
Para poder seguir este método, lo importante es asegurarse que el objeto de ggplot no tenga nada de bordes, para que los valores xy que definen su extensión empaten con los bordes de la imagen que exportamos con el fin de usarla en rayshader
. Para lograrlo, usamos el (theme_nothing
) que viene con el paquete cowplot
de Claus Wilke. En resumen, ésto equivale a apagar casi todos los elementos de la figura y en no tener ninguna expansión de los ejes. Aquí podemos ver cuáles elementos se están modificando.
Probemos. Este ejemplo está basado en datos espaciales del portal de datos geográficos de la CONABIO y de la CONANP. Descargué los shapefiles de Áreas Naturales Protegidas y de Uso del suelo y vegetación (escala 1:250000, serie VI continuo nacional), y me enfoqué en la ANP Iztaccíhuatl-Popocatépetl.
Estos pasos cargan los archivos shp, recortan los datos a la ANP de interés, y agrupan (medio arbitrariamente) algunas de las categorías de uso de suelo y vegetación. Luego, podemos hacer un mapa simple pero colorido de los volcanes. Aquí el theme_nothing()
le quita los márgenes y los rótulos de los ejes a la figura, y hay algunos argumentos de coord_sf()
que son para que todo quede dentro del panel principal de la figura.
Me tomó algunos intentos poder exportar el tiff sin que saliera espacio en blanco en los márgenes, pero cuando ésto ya queda podemos importar la imagen usando el paquete raster
.
Revisemos ese tiff.
La información geoespacial que necesitamos está contenida en el objeto ggplot, y la podemos extraer con ggplot_build
. Uno de los componentes del objeto es una lista con los máximos y mínimos para x y para y, y éstos se los damos a la función extent
para georeferenciar el mapa (también hay que definir la proyección). El raster georeferenciado se exporta con INT1U
para que los valores queden entre 0 y 255, y PHOTOMETRIC=RGB
para declarar cómo se interpretan los colores.
Importamos de nuevo el geoTiff
Ahora ya podemos seguir las guías existentes para procesar imágenes con rayshader
. Primero hay que transformar el raster en un array (arreglo de valores numéricos), y usar este objeto para descargar datos de elevación mediante elevatr
. Luego los recortamos, les reducimos la resolución y el tamaño, y los transponemos (los rasters y los arreglos numéricos vienen con orientaciones distintas en R).
Así se ve el DEM.
Ahora calculamos el sombreado y combinamos el arreglo con los datos de elevación.
Así se ve la ventana RGL que genera plot3d
. Ajusté algunos de los valores de la cámara. Sale una vista que conocemos bien los chilangos.
También se ve bien la vista superior que resulta de plot_map()
Finalmente, podemos añadir elementos con rayrender
antes de exportar imágenes de alta resolución con render_highquality()
. Me gustó esta alternativa para darle más ambiente a la escena con el argumento light = FALSE
y una esfera de luz de color colocada en donde nos guste más.
Turn off the lights and add your own🤓: #rstats #rayshader #rayrender
— Tyler Morgan-Wall (@tylermorganwall) October 27, 2019
render_highquality(light = FALSE, scene_elements = sphere(y = 100, radius = 10, material = diffuse(lightintensity = 250, implicit_sample = TRUE))) pic.twitter.com/g1QDEphZGh
Aquí hay algunos renders que saqué con diferentes opciones de cámara e iluminación.
Los resultados me gustaron bastante, y con todo ésto ya hasta se pueden hacer animaciones. Esta manera de georeferenciar imágenes también sirve para mapas que hacemos con R base, siempre y cuando el panel ocupe todo el espacio de la imagen. Espero que esta guía les sirva. Quedo atento a cualquier duda o comentario. Salu-2