Mapas 3D

A continuación se muestra el código R utilizado para crear mapas 3D con datos obtenidos de la Paleobiology Database para explorar patrones de extinción

#Load Packages
listOfPackages <- c("ggplot2","tidyverse","rnaturalearth","rnaturalearthdata","png","grid","rayshader",
"sf","rgeos")
lapply(listOfPackages, require, character.only = TRUE)

Primero, descargaremos los datos que vamos a graficar. Para este ejemplo usaremos los géneros del orden Proboscidea. Los datos son filtrados para remover las columnas que no nos son útiles. Todos aquellos registros sin un género asignado son removidos también.

#Download dataset from Paleobiology Database. The id in the url corresponds to the taxa ID in the PBDB

url <- 'https://paleobiodb.org/data1.2/occs/list.txt?base_id=43230&show=full'
full_data <- read_csv(file = url)
sumarized <- full_data [,c(25,14,16,17,30,31)]						 
#Filter data excluding occurrences without genus							 
complete <- subset(sumarized, (!is.na(sumarized$genus))&!is.na(sumarized$lat))

Es necesario crear un mapa base para usarse como fondo. En este caso, se usará un mapa global, por lo que no es necesario ajustar los límites del mapa. Es necesario remover todos los elementos como las rejillas para generar un mapa más limpio.

#Base Map

region <- ne_countries(scale = "medium", returnclass = "sf")
basemap <- ggplot(data = region) + geom_sf(aes(colour="#FFFFFF"))+	
	theme(legend.position = "none",axis.line=element_blank(),axis.text.x=element_blank(), axis.title.x=element_blank(),axis.text.y=element_blank(), axis.title.y=element_blank(),axis.ticks=element_blank(),panel.background = element_blank())

A continuación es necesario definir los límites X y Y en el mapa. Para posteriormente exportar el mapa como una imagen PNG.

#Define limits of the map

xlim = ggplot_build(basemap)$layout$panel_scales_x[[1]]$range$range
ylim = ggplot_build(basemap)$layout$panel_scales_y[[1]]$range$range

#Save map as a PNG object
	
ggsave("map_img.png",plot = basemap, width = diff(xlim), height = diff(ylim), units = "mm")

#Load the PNG map object
background <- readPNG("map_img.png")
Basemap

El mapa ahora puede ser graficado con todos los puntos de ocurrencias sobre él. Diferentes formas y tamaños deben ser asignados a los valores de mínima y máxima edad. El valor de edad mínima debe ser más pequeño para una mejor visualización

#Map with points. Different shape and size for max_ma and min_ma are necesary for a better visualization

map1 <- ggplot(data = region) + annotation_custom(rasterGrob(background, width=unit(1,"npc"), height=unit(1,"npc")), -Inf, Inf, -Inf, Inf)+xlim(xlim[1],xlim[2]) + ylim(ylim[1],ylim[2])+
   geom_point(data = complete, aes(x = lng, y = lat, colour=max_ma),shape=5, size=0.2) + 
   geom_point(data = complete, aes(x = lng, y = lat, colour=min_ma),shape=3, size=1)+
    scale_colour_gradient(name = "Millions of years", 
                          limits=range(complete$max_ma))+
    ggtitle("occurreces")+
    theme(plot.title = element_text(hjust = 0.5))
	
	
Map with occurrence points

Ahora podemos proceder a graficar el mapa 3D.

#3D plot
map_3d <- plot_gg(map1,multicore = TRUE, width = 7 ,height=7, raytrace = FALSE, windowsize = c(1200, 960), fov = 70, zoom = 0.25, theta = 330, phi = 40)		  

Para guardar el mapa 3D usaremos el siguiente comando SIN CERRAR LA VENTANA donde nos muestra la vista previa.

#Save 3D object

save_obj("plot3D.obj", save_texture = TRUE)

Usando más código y opciones de personalización, es posible elaborar mapas más complejos. En el siguiente ejemplo, se muestra un mapa de proboscideos por país.

url <- 'https://paleobiodb.org/data1.2/occs/list.txt?base_id=105150&show=full'
full_data <- read_csv(file = url)
sumarized <- full_data [,c(6,7,10,12,14,15,16,17,24,25,30,31,33,34,35,36,37,38,43,44,45,51)]
complete <- subset(sumarized, (!is.na(sumarized$family))&(!sumarized$family=="NO_FAMILY_SPECIFIED"))
names(complete)[16] <- "id"

#Due to political changes, all occureces of Western Sahara, will be considered as Morocco occureces

complete$id[complete$id =="EH"] <- "MA"


#Ocurece by country

fam_by_country <- aggregate(data = complete,               
family ~ id,
function(x) length(unique(x)))

occ_by_country <- split(complete, complete[["id"]]) 

#Unique values
genus_unique <-unique(complete[c("genus")])
genus_unique <- na.omit(genus_unique)

family_unique <-unique(complete[c("family")])
family_unique <-na.omit(family_unique)

#Map
world <- ne_countries(scale = "medium", returnclass = "sf")
names(world)[44] <- "id"
fam_by_country$id[fam_by_country$id =="UK"] <- "GB"
world <- merge(world,fam_by_country, by="id", all=TRUE)
world$family[is.na(world$family)]<- 0

#Match dataset with centroid country	

wmap <- getMap(resolution="high")
centroids <- gCentroid(wmap, byid=TRUE)
df <- as.data.frame(centroids)
df <- tibble::rownames_to_column(df, "country")
df$id <-countrycode::countrycode(sourcevar = df$country, origin = "country.name", destination ="iso2c", custom_match = c("United Kingdom"="UK"))			
df <- subset(df, !is.na(df$id)&(!df$country== "US Naval Base Guantanamo Bay" & !df$country== "Korea No Mans Area" & !df$country== "Cyprus No Mans Area" & !df$country=="Northern Cyprus" & !df$country=="West Bank"))
merged <- merge(df,fam_by_country, by="id")
merged$id[merged$id =="UK"] <- "GB"

#convert map to png

map <- ggplot(data = world) + 
geom_sf(aes(fill = family), colour="#FFFFFF") + 
scale_fill_gradient(limits=range(world$family),low="#FFF3B0", high="#E09F3E") + 
theme(legend.position = "none",axis.line=element_blank(),axis.text.x=element_blank(), axis.title.x=element_blank(),axis.text.y=element_blank(), axis.title.y=element_blank(),axis.ticks=element_blank(),panel.background = element_blank())

xlim = ggplot_build(map)$layout$panel_scales_x[[1]]$range$range
ylim = ggplot_build(map)$layout$panel_scales_y[[1]]$range$range

ggsave("map_img.png",plot = map, width = diff(xlim), height = diff(ylim), units = "mm")
worldmap <- readPNG("map_img.png")


mapa1 <- ggplot(merged) + annotation_custom(rasterGrob(worldmap, width=unit(1,"npc"), height=unit(1,"npc")), -Inf, Inf, -Inf, Inf) +
xlim(xlim[1],xlim[2]) + ylim(ylim[1],ylim[2]) +
geom_point(data = merged, aes(x = x, y = y, colour=family), size=2)+ 
scale_colour_gradient(name = "Number of families", 
limits=range(merged$family),low="#FCB9B2", high="#B23A48") +
ggtitle("Mammuthidae family members per country")+
theme(legend.position = "bottom",axis.line=element_blank(), 
axis.text.x=element_blank(), axis.title.x=element_blank(),
axis.text.y=element_blank(), axis.title.y=element_blank(),
axis.ticks=element_blank(),panel.background = element_blank(),plot.title = element_text(hjust = 0.5))

#3D Map

map_3d <- plot_gg(mapa1,multicore = TRUE, width = diff(xlim)/30 ,height=diff(ylim)/30, raytrace = FALSE, windowsize = c(1200, 960), fov = 70, zoom = 0.25, theta = 330, phi = 40)

Miguel Díaz de León

Lic. en Biología por la Universidad de Guadalajara (2010-2015) Maestría en Ciencias de La Tierra UNAM (2017-2020)

Deja un comentario

Tu dirección de correo electrónico no será publicada.