Nothing
# Author: Robert J. Hijmans
# Date : December 2009-2011
# Version 1.0
# Licence GPL v3
# 2011-12-04
# implemented trycatch to deal with poor response from GBIF server
# suggestion and changed code provided by John Baumgartner
# 2013-01-15
# translate ISO2 codes to full country names
# add "cloc"
#2014-03-08
# new version, using the json API
.frbind <- function(x, ...) {
if (! inherits(x, 'data.frame') ) {
x <- data.frame(x)
}
d <- list(...)
if (length(d) == 0) { return(x) }
for (i in 1:length(d)) {
dd <- d[[i]]
if (! inherits(dd, 'data.frame')) {
dd <- data.frame(dd)
}
cnx <- colnames(x)
cnd <- colnames(dd)
e <- cnx[(cnx %in% cnd)]
for (j in e) {
if (!all(class(x[,j]) == class(dd[,j]))) {
x[,j] <- as.character(x[,j])
dd[,j] <- as.character(dd[,j])
}
}
a <- which(!cnd %in% cnx)
if (length(a) > 0) {
zz <- dd[NULL, a, drop=FALSE]
zz[1:nrow(x),] <- NA
x <- cbind(x, zz)
}
b <- which(!cnx %in% cnd)
if (length(b) > 0) {
zz <- x[NULL, b, drop=FALSE]
zz[1:nrow(dd),] <- NA
dd <- cbind(dd, zz)
}
x <- rbind(x, dd)
}
x
}
.ccodes <- function() {
path <- system.file(package="geodata")
readRDS(file.path(path, "ex/countries.rds"))
}
.getExtGBIF <- function(ext) {
if (!is.null(ext)) {
e <- round(ext(ext), 5)
global <- ext(-180,180,-90,90)
ex <- intersect(e, global)
if (!is.null(ex)) {
ex <- paste0('&decimalLatitude=', ymin(e),',', ymax(e), '&decimalLongitude=', xmin(e), ',', xmax(e))
} else {
warning('invalid extent')
}
} else {
ex <- NULL
}
return(ex)
}
.fixNameGBIF <- function(genus, species) {
genus <- trimws(genus)
species <- trimws(species)
gensp <- paste(genus, species)
spec <- gsub(" ", " ", species)
spec <- gsub(" ", " ", spec)
spec <- gsub(" ", "%20", spec) # for genus species var. xxx
spec <- paste(genus, '+', spec, sep='')
return(spec)
}
sp_genus <- function(genus, simple=TRUE, ...) {
gurl <- paste0("https://api.gbif.org/v1/species/match?name=", genus)
tmpfile <- tempfile()
if (!.downloadDirect(gurl, tmpfile, quiet=TRUE, ...)) return(NULL)
json <- scan(tmpfile, what="character", quiet=TRUE, sep="\n", encoding = "UTF-8")
try(file.remove(tmpfile), silent=TRUE)
json <- chartr("\a\v", " ", json)
x <- jsonlite::fromJSON(json)
x <- as.data.frame(x)
key <- x[(tolower(x$rank)) == "genus", "genusKey"]
res <- list()
off <- 0
i <- 1
while (TRUE) {
surl <- paste0("https://api.gbif.org/v1/species/search?rank=SPECIES&highertaxon_key=", key, "&offset=", off, "&limit=1000")
tmpfile <- tempfile()
if (!.downloadDirect(surl, tmpfile, quiet=TRUE, ...)) return(NULL)
json <- scan(tmpfile, what="character", quiet=TRUE, sep="\n", encoding = "UTF-8")
try(file.remove(tmpfile), silent=TRUE)
x <- jsonlite::fromJSON(json)
res[[i]] <- as.data.frame(x$results)
if ( x$endOfRecords ) break;
i <- i + 1;
off <- off + 1000
}
res <- do.call(rbind, res)
if (simple) {
return(sort(unique(res$species)))
}
res$higherClassificationMap <- NULL
res$nomenclaturalStatus <- NULL
res$descriptions <- NULL
res$numOccurrences <- NULL
# res$descriptions <- sapply(res$descriptions, function(i) paste(unlist(i), collapse="; "))
res$habitats <- sapply(res$habitats, function(i) paste(unlist(i), collapse="; "))
res$threatStatuses <- sapply(res$threatStatuses, function(i) paste(unlist(i), collapse="; "))
res$vernacularNames <- sapply(res$vernacularNames, function(i) {
if (ncol(i) > 0) {
paste(sort(unique(i[,1])), collapse="; ")
} else {
""
}
}
)
res
}
sp_occurrence <- function(genus, species="", ext=NULL, args=NULL, geo=TRUE, removeZeros=FALSE, download=TRUE, ntries=5, nrecs=300, start=1, end=Inf, fixnames=TRUE, ...) {
if (! requireNamespace("jsonlite")) { stop("You need to install the jsonlite package to use this function") }
tmpfile <- paste0(tempfile(), ".json")
ex <- .getExtGBIF(ext)
spec <- .fixNameGBIF(genus, species)
if (geo) { cds <- "&hasCoordinate=true" } else { cds <- "" }
base <- "https://api.gbif.org/v1/occurrence/search?"
if (!is.null(args)) {
args <- trimws(as.character(args))
args <- gsub(" ", "%20", args)
args <- paste0("&", paste(args, collapse="&"))
}
ntries <- min(max(ntries, 1), 100)
url1 <- paste(base, "scientificname=", spec, "&limit=1", cds, ex, args, sep="")
if (!.downloadDirect(url1, tmpfile, quiet=TRUE, ...)) return(NULL)
json <- scan(tmpfile, what="character", quiet=TRUE, sep="\n", encoding = "UTF-8")
try(file.remove(tmpfile), silent=TRUE)
x <- jsonlite::fromJSON(json)
if (!download) {
if (is.null(x$count)) {
return(0)
} else {
return(x$count)
}
}
ntot <- ifelse(is.null(x$count), 0, x$count)
if (ntot == 0) {
message("no records found")
return(NULL)
}
start <- max(1, start)
end <- min(end, ntot)
stopifnot(start <= end)
if (end > 100000) {
stop("GBIF does not allow using this service for record numbers that are > 100,000")
}
ntot <- (end-start)+1
message(ntot, " records found")
if (ntot <= 0) {
return(NULL)
}
if (ntot > 100000) {
stop("The number of records is larger than the maximum for download via this service (100,000)")
}
nrecs <- min(max(nrecs, 1), 300)
url1 <- paste(base, "scientificname=", spec, "&limit=", format(nrecs, scientific=FALSE), cds, ex, args, sep="")
g <- list()
breakout <- FALSE
np <- i <- 1
while (TRUE) {
if (start+nrecs >= end) {
nrecs <- end - start + 1
url1 <- paste(base, "scientificname=", spec, "&limit=", format(nrecs, scientific=FALSE), cds, ex, args, sep="")
breakout <- TRUE
}
aurl <- paste(url1, "&offset=", format(start-1, scientific=FALSE), sep="")
if (np > 20) {
np <- 1
message("")
}
message(paste(format(start-1, scientific=FALSE), "-", sep=""), appendLF = FALSE)
utils::flush.console()
tries <- 0
np <- np + 1
#======= if download fails due to server problems, keep trying =======#
while (TRUE) {
tries <- tries + 1
if (tries > ntries) {
warning("GBIF did not return the data in ", ntries, " tries for:")
print(aurl)
breakout <- TRUE
break
}
if (!.downloadDirect(aurl, tmpfile, quiet=TRUE, ...)) return(NULL)
json <- scan(tmpfile, what="character", quiet=TRUE, sep="\n", encoding = "UTF-8")
try(file.remove(tmpfile), silent=TRUE)
json <- chartr("\a\v", " ", json)
x <- jsonlite::fromJSON(json)
if (is.null(x$count)) {
x$count <- 0
if (i == 1) {
warning("no records found")
break
} else {
break
}
}
r <- x$results
ok <- !(sapply(r, function(i) class(i)[1]) %in% c("data.frame", "list"))
r <- r[, ok]
rownames(r) <- NULL
g[[i]] <- r
break
}
start <- start + nrecs
i <- i + 1
if (breakout) break
if (x$endOfRecords) break
}
message(end)
message(min(end, x$count), " records downloaded")
if (length(g) == 0) {
return(NULL)
} else if (length(g) == 1) {
z <- g[[1]]
} else {
z <- do.call(.frbind, g)
}
lat <- "decimalLatitude"
lon <- "decimalLongitude"
cn <- colnames(z)
if ((lat %in% cn) & (lon %in% cn)) {
z[,lon] <- gsub(",", ".", z[,lon])
z[,lat] <- gsub(",", ".", z[,lat])
z[,lon] <- as.numeric(z[,lon])
z[,lat] <- as.numeric(z[,lat])
k <- apply(z[ ,c(lon, lat)], 1, function(x) isTRUE(any(x==0)))
if (removeZeros) {
if (geo) {
z <- z[!k, ]
} else {
z[k, c(lat, lon)] <- NA
}
} else {
z[k, c(lat, lon)] <- NA
}
}
if (fixnames && (nrow(z) > 0)) {
cn <- gsub("decimalLatitude", "lat", cn)
cn <- gsub("decimalLongitude", "lon", cn)
cn <- gsub("stateProvince", "adm1", cn)
cn <- gsub("county", "adm2", cn)
cn <- gsub("countryCode", "ISO2", cn)
colnames(z) <- cn
if ("ISO2" %in% cn) {
z$fullCountry <- z$country
iso <- .ccodes()
i <- match(z$ISO2, iso[, "ISO2"])
z$country <- iso[i, 1]
z$country[is.na(z$ISO2)] <- NA
}
vrs <- c("locality", "stateProvince", "county", "country", "continent")
vrs <- vrs[vrs %in% colnames(z)]
if (length(vrs) > 0) {
fullloc <- trimws(as.matrix(z[, vrs]))
fullloc <- apply(fullloc, 1, function(x) paste(x, collapse=", "))
fullloc <- gsub("NA, ", "", fullloc)
fullloc <- gsub(", NA", "", fullloc)
fullloc <- gsub("\"", "", fullloc)
z$cloc <- fullloc
} else {
z$cloc <- NA
}
}
z <- z[, sort(colnames(z))]
d <- as.Date(Sys.time())
z <- cbind(z, downloadDate=d)
return(z)
}
#p <- sp_occurrence("solanum", "cantense")
#pp <- sp_occurrence("solanum", "cantense", fix=F)
#sa <- gbif("solanum", "*")
#sa <- gbif("solanum", "acaule*")
#sa <- gbif("solanum", "acaule var acaule")
.run_sp_occurrence_batch <- function(genus, species="", path=".", ext=c(-180,180,-90,90), args=NULL, geo=TRUE, removeZeros=FALSE, ntries=5, nrecs=300, fixnames=TRUE, prefix=NULL, ...) {
dir.create("gbif", FALSE, FALSE)
r <- rast(nrow=2, ncol=2, extent=ext)
p <- as.polygons(r)
for (i in 1:nrow(p)) {
itr <- paste0(prefix, i)
fit <- file.path(path, "gbif", paste0(itr, ".rds"))
if (!file.exists(fit)) {
ep <- ext(p[i])
obs <- geodata::sp_occurrence(genus, species, download=FALSE, ext=ep)
if (obs >= 50000) {
message(paste0(itr, ": split (", obs, ")")); utils::flush.console()
d <- .run_sp_occurrence_batch(genus, species, ext=ep, args=args, geo=geo, removeZeros=removeZeros, ntries=ntries, nrecs=nrecs, fixnames=fixnames, prefix=itr)
} else if (obs > 0) {
message(paste0(itr, ":")); utils::flush.console()
d <- NULL
d <- geodata::sp_occurrence(genus, species, download=TRUE, ext=ep, args=args,
geo=geo, removeZeros=removeZeros, ntries=ntries, nrecs=nrecs,
fixnames=fixnames, ...)
if (!is.null(d)) {
saveRDS(d, fit)
}
} else {
message(paste0(itr, ": no records")); utils::flush.console()
}
} else {
message(paste0(itr, ": exists")); utils::flush.console()
}
}
}
sp_occurrence_split <- function(genus, species="", path=".", ext=c(-180,180,-90,90), args=NULL, geo=TRUE, removeZeros=FALSE, ntries=5, nrecs=300, fixnames=TRUE, prefix=NULL, ...) {
if (is.null(prefix)) {
prefix <- tolower(paste0(genus, "_", species, "_"))
fout <- file.path(path, "gbif", paste0(genus, "_", species, ".rds"))
} else {
fout <- file.path(path, "gbif", paste0(prefix, ".rds"))
}
if (file.exists(fout)) {
message("using existing file")
out <- readRDS(fout)
return(out)
}
.run_sp_occurrence_batch(genus, species, path=path, ext=ext, args=args, geo=geo, removeZeros=removeZeros, ntries=ntries, nrecs=nrecs, fixnames=fixnames, prefix=prefix, ...)
message("combining")
ff <- list.files("gbif", pattern=paste0("^", genus, "_", species), full.names=TRUE)
out <- lapply(ff, readRDS)
i <- sapply(out, is.null)
if (any(i)) out <- out[[!i]]
out <- do.call(.frbind, out)
out <- unique(out)
saveRDS(out, fout)
return(out)
}
#x = sp_occurrence_batch("Anas", "acuta")
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.