Intrucciones generales:
La función querxc() en el paquete warbleR permite buscar y descargar registros de señales acústicas de aves (e.g. cantos de aves) en la base de datos en linea Xeno-Canto. Estos registros tienen gran cantidad de metadatos, incluyendo el género, especie, subespecie, fecha, hora, y coordenadas geográficas entre otras. Estos datos los vamos a usar para ver la variación en los patrones estacionales de actividad de las especies del género Turdus (al que pertenece el yigüirro Turdus grayi). Turdus es un grupo de distribución cosmopolita que se caracteriza por ser vocalmente muy activo, y por tanto esta ampliamente representado en Xeno-Canto.
Primero debemos instalar y cargar el paquete warbleR:
install.packages("warbleR")
library(warbleR)
Con querxc() podemos hacer búsquedas de familias, géneros o especies (también búsquedas por sitios, grabadores, países, etc, pero estas son mas complejas). En nuestro caso vamos a bajar los metadatos para las grabaciones del género Turdus de la siguiente forma (necesita conexión a internet!, puede tardar unos minutos):
turdus <- querxc("Turdus", download = FALSE)
Podemos ver los nombres de las columnas para darnos una idea de lo que contienen los metadatos:
## [1] "Recording_ID" "Genus" "Specific_epithet"
## [4] "Subspecies" "English_name" "Recordist"
## [7] "Country" "Locality" "Latitude"
## [10] "Longitude" "Vocalization_type" "Audio_file"
## [13] "License" "Url" "Quality"
## [16] "Time" "Date" "Altitude"
## [19] "file.name" "Spectrogram_small" "Spectrogram_med"
## [22] "Spectrogram_large" "Spectrogram_full" "Length"
## [25] "Uploaded" "Other_species" "Remarks"
## [28] "Bird_seen" "Playback_used" "Other_species1"
## [31] "Other_species2" "Other_species3" "Other_species4"
## [34] "Other_species5" "Other_species6" "Other_species7"
## [37] "Other_species8" "Other_species9" "Other_species10"
## [40] "Other_species11" "Other_species12" "Other_species13"
## [43] "Other_species14" "Other_species15" "Other_species16"
Por supuesto también podemos usar head() para ver las primeras filas:
head(turdus[ , 1:18])
Recording_ID | Genus | Specific_epithet | Subspecies | English_name | Recordist | Country | Locality | Latitude | Longitude | Vocalization_type | Audio_file | License | Url | Quality | Time | Date | Altitude |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
504016 | Turdus | litsitsirupa | Groundscraper Thrush | Aladdin | Ethiopia | North Shewa, Amhara | 9.819800 | 39.73410 | call, flight call, life stage uncertain, sex uncertain | //www.xeno-canto.org/504016/download | //creativecommons.org/licenses/by-nc-sa/4.0/ | //www.xeno-canto.org/504016 | no score | 16:30 | 2019-10-24 | 3300 | |
509167 | Turdus | litsitsirupa | Groundscraper Thrush | Peter Boesman | Zambia | Mkushi farm region, Central province | -13.655075 | 29.35882 | song | //www.xeno-canto.org/509167/download | //creativecommons.org/licenses/by-nc-nd/4.0/ | //www.xeno-canto.org/509167 | A | 07:00 | 2019-09-29 | ||
403680 | Turdus | litsitsirupa | Groundscraper Thrush | Mary Simmonds | Ethiopia | Agoro Lodge, Adigrat, Tigray | 14.248900 | 39.48130 | call | //www.xeno-canto.org/403680/download | //creativecommons.org/licenses/by-nc-sa/4.0/ | //www.xeno-canto.org/403680 | A | 07:30 | 2018-01-21 | 2400 | |
347146 | Turdus | litsitsirupa | Groundscraper Thrush | Peter Boesman | Namibia | Omaruru area west | -21.447504 | 15.88762 | song and call | //www.xeno-canto.org/347146/download | //creativecommons.org/licenses/by-nc-nd/4.0/ | //www.xeno-canto.org/347146 | A | 8:30 | 2016-11-11 | ||
300630 | Turdus | litsitsirupa | simensis | Groundscraper Thrush | Peter Boesman | Ethiopia | Debre Birhan area | 9.670645 | 39.53370 | call | //www.xeno-canto.org/300630/download | //creativecommons.org/licenses/by-nc-nd/4.0/ | //www.xeno-canto.org/300630 | A | 15:00 | 2015-12-02 | ? |
300628 | Turdus | litsitsirupa | simensis | Groundscraper Thrush | Peter Boesman | Ethiopia | Debre Libanos area | 9.711656 | 38.85794 | song | //www.xeno-canto.org/300628/download | //creativecommons.org/licenses/by-nc-nd/4.0/ | //www.xeno-canto.org/300628 | A | 10:00 | 2015-12-01 |
Con la función grep() podemos generar vectores con los indices (la posición en el vector) que nos indican si un texto (i.e. palabra) esta presente en cada uno de los elementos de un vector no-numérico. Por ejemplo este código nos dice si “ab” esta en cada elemento del vector v1:
v1 <- c("acd", "abc", "accb", "abb", "aab", "bc")
grep("ab", v1)
## [1] 2 4 5
Respuesta:
sub_turdus <- turdus[grep("song", turdus$Vocalization_type),]
Respuesta:
Usando el argumento “ignore.case = TRUE”
Respuesta:
sub_turdus <- turdus[grep("song", turdus$Vocalization_type, ignore.case = TRUE),]
Podemos darnos una idea de la distribución geográfica de los datos con un histograma de la longitud. Primero debemos convertir la columna Longitude a numérica:
# convertir logitude a numerico
turdus$Longitude <- as.numeric(as.character(turdus$Longitude))
# hacer histograma
hist(turdus$Longitude, main = NULL, col = terrain.colors(20, alpha = 0.5)[2], xlab = "Longitud", ylab = "Frecuencia")
#poner linea roja entre viejo y nuevo mundo
abline(v = -25, col = "red", lty = 3, lwd = 2)
En ese gráfico podemos ver como se separan las grabaciones del Viejo y Nuevo Mundo. Podemos suponer que menos de -25 de Longitud es el Nuevo Mundo. Podemos confirmarlo viendo los paises que quedan por debajo de ese umbral:
unique(turdus$Country[turdus$Longitude < - 25])
## [1] "Brazil" "Venezuela" NA
## [4] "Argentina" "Colombia" "Guyana"
## [7] "Bolivia" "Ecuador" "Peru"
## [10] "Portugal" "Fiji" "Canada"
## [13] "New Zealand" "Chile" "Costa Rica"
## [16] "Panama" "Honduras" "Mexico"
## [19] "Guatemala" "El Salvador" "Uruguay"
## [22] "Paraguay" "United Kingdom" "French Guiana"
## [25] "Suriname" "Nicaragua" "Trinidad & Tobago"
## [28] "Belize" "United States" "St Lucia"
## [31] "Jamaica" "Dominican Republic" "Cuba"
## [34] "Bahamas" "Puerto Rico" "France"
## [37] "Dominica"
El Reino Unido sale por la colonia que tiene en las Malvinas:
turdus$Locality[turdus$Country == "United Kingdom" & turdus$Longitude < -25]
## [1] NA
## [2] NA
## [3] NA
## [4] NA
## [5] "West Point Island, Falkland Islands"
## [6] "The Rookery, Saunder Island, Falkland Islands"
Lo importante aqui es que podemos usar la longitud para determinar si las especies son del Nuevo o Viejo Mundo.
De igual forma podemos usar la columna de “Latitude” para ver la distribución latitudinal de las especies.
Los datos de una sola especie los podemos extraer con indices y parémtesis cuadrados. Por ejemplo, para la especie “Turdus albicollis”:
sp.dt <- turdus[turdus$Specific_epithet == "albicollis", ]
El resultado de la función deberia verse asi
## especie lim.Norte lim.Sur punto.medio
## 1 albicollis 10.7137 -35.2501 -12.2682
Respuesta:
# crear funcion
lat_dist <- function(x){
lim.Sur <- min(x$Latitude, na.rm = TRUE)
lim.Norte <- max(x$Latitude, na.rm = TRUE)
punto.medio <- mean(c(lim.Norte, lim.Sur))
# todo en una base de datos
df <- data.frame(especie = x$Specific_epithet[1], lim.Norte, lim.Sur, punto.medio)
return(df)
}
sp.dt <- turdus[turdus$Specific_epithet == "albicollis", ]
# correr funcion
lat_dist(sp.dt)
## especie lim.Norte lim.Sur punto.medio
## 1 albicollis 10.7137 -35.2501 -12.2682
Respuesta:
# crear funcion
lat_dist <- function(x){
# sacar limites
lim.Sur <- min(x$Latitude, na.rm = TRUE)
lim.Norte <- max(x$Latitude, na.rm = TRUE)
punto.medio <- mean(c(lim.Norte, lim.Sur))
# sacar mundo
lon <- x$Longitude[!is.na(x$Longitude)]
if(max(lon) < -25)
mundo <- "Nuevo Mundo" else
mundo <- "Viejo Mundo"
# todo en una base de datos
df <- data.frame(especie = "albicollis", lim.Norte, lim.Sur, punto.medio, mundo)
return(df)
}
sp.dt <- turdus[turdus$Specific_epithet == "albicollis", ]
# correr funcion
lat_dist(sp.dt)
## especie lim.Norte lim.Sur punto.medio mundo
## 1 albicollis 10.7137 -35.2501 -12.2682 Nuevo Mundo
Respuesta:
# grayi
sp.dt <- turdus[turdus$Specific_epithet == "grayi", ]
# correr funcion
lat_dist(sp.dt)
## especie lim.Norte lim.Sur punto.medio mundo
## 1 albicollis 31.574 3.8313 17.70265 Nuevo Mundo
# nigrescens
sp.dt <- turdus[turdus$Specific_epithet == "nigrescens", ]
# correr funcion
lat_dist(sp.dt)
## especie lim.Norte lim.Sur punto.medio mundo
## 1 albicollis 10.16 8.8036 9.4818 Nuevo Mundo
Estos datos pueden generar información biológica interesante sobre los patrones de variación temporal y geográfica en el comportamiento vocal de estas aves. El siguiente ejercicio intenta probar algunas hipótesis utilizando estos datos:
Las aves producen un repertoirio de sonidos, el cual incluye sonidos para defensa de territorio y busqueda de pareja (cantos) y sonidos para otras interacciones sociales (llamados). Es de esperar que los primeros se restringan a la época de apareamiento mientras que los segundos se produzcan a lo largo del año.
Respuesta:
x <- sp.dt
# crear funcion
temp_vocal <- function(x){
# extraer datos de fecha y tipo de vocalizacion
Y <- x[, c("Date", "Vocalization_type")]
# separar año mes y dia en columnas separadas
Y <- tidyr::separate(data = Y, col = Date, into = c("year", "month", "day"))
# forzar todos a ser el mismo año, asi las diferencias de tiempo se dan dentro del mismo año
Y$year <- 3000
# crear columna de año de nuevo
Y$Date <- paste(Y$year, Y$month, Y$day, sep = "-")
# convertir a formato fecha
Y$Date <- as.Date(Y$Date)
# remove los que no tienen fecha
Y <- Y[!is.na(Y$Date), ]
# seleccionar llamados (note invert = TRUE)
llam <- Y[grep("song", Y$Vocalization_type, ignore.case = TRUE, invert = TRUE), ]
# y cantos
cant <- Y[grep("song", Y$Vocalization_type, ignore.case = TRUE), ]
# calcular rangos de tiempo
rango_llamados <- max(llam$Date) - min(llam$Date)
rango_cantos <- max(cant$Date) - min(cant$Date)
# todo en una base de datos
df <- data.frame(especie = "albicollis", rango_llamados, rango_cantos)
return(df)
}
sp.dt <- turdus[turdus$Specific_epithet == "albicollis", ]
# correr funcion
temp_vocal(sp.dt)
## especie rango_llamados rango_cantos
## 1 albicollis 364 days 361 days
Respuesta:
# grayi
sp.dt <- turdus[turdus$Specific_epithet == "grayi", ]
# correr funcion
temp_vocal(sp.dt)
## especie rango_llamados rango_cantos
## 1 albicollis 355 days 325 days
# nigrescens
sp.dt <- turdus[turdus$Specific_epithet == "nigrescens", ]
# correr funcion
temp_vocal(sp.dt)
## especie rango_llamados rango_cantos
## 1 albicollis 333 days 12 days
Información de la sesión
## R version 4.0.5 (2021-03-31)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.2 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
##
## locale:
## [1] LC_CTYPE=pt_BR.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=es_CR.UTF-8 LC_COLLATE=pt_BR.UTF-8
## [5] LC_MONETARY=es_CR.UTF-8 LC_MESSAGES=pt_BR.UTF-8
## [7] LC_PAPER=es_CR.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=es_CR.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] kableExtra_1.3.4
##
## loaded via a namespace (and not attached):
## [1] compiler_4.0.5 pillar_1.6.1 highr_0.9 tools_4.0.5
## [5] digest_0.6.27 evaluate_0.14 lifecycle_1.0.0 tibble_3.1.2
## [9] viridisLite_0.4.0 pkgconfig_2.0.3 rlang_0.4.11 DBI_1.1.1
## [13] rstudioapi_0.13 yaml_2.2.1 xfun_0.23 httr_1.4.2
## [17] stringr_1.4.0 dplyr_1.0.6 xml2_1.3.2 knitr_1.33
## [21] generics_0.1.0 vctrs_0.3.8 systemfonts_1.0.2 webshot_0.5.2
## [25] tidyselect_1.1.1 svglite_2.0.0 glue_1.4.2 R6_2.5.0
## [29] fansi_0.4.2 rmarkdown_2.8 purrr_0.3.4 tidyr_1.1.3
## [33] magrittr_2.0.1 scales_1.1.1 htmltools_0.5.1.1 ellipsis_0.3.2
## [37] assertthat_0.2.1 rvest_1.0.0 colorspace_2.0-1 utf8_1.2.1
## [41] stringi_1.6.2 munsell_0.5.0 crayon_1.4.1