Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
rstudio
committed
Feb 5, 2015
1 parent
065d89c
commit 3a2e423
Showing
13 changed files
with
268 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
.git | ||
.gitignore | ||
inst/api | ||
^.*\.Rproj$ | ||
^\.Rproj\.user$ | ||
^\.travis\.yml$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Sample .travis.yml for R projects from https://github.com/craigcitro/r-travis | ||
|
||
language: c | ||
|
||
before_install: | ||
- curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh | ||
- chmod 755 ./travis-tool.sh | ||
- ./travis-tool.sh bootstrap | ||
|
||
install: | ||
- ./travis-tool.sh install_deps | ||
|
||
script: ./travis-tool.sh run_tests | ||
|
||
after_failure: | ||
- ./travis-tool.sh dump_logs | ||
|
||
env: | ||
- WARNINGS_ARE_ERRORS=1 | ||
|
||
notifications: | ||
email: | ||
on_success: change | ||
on_failure: change |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Generated by roxygen2 (4.1.0): do not edit by hand | ||
|
||
export(species_table) | ||
import(httr) | ||
import(stringr) | ||
import(tidyr) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,133 +1,9 @@ | ||
SERVER = "http://server.carlboettiger.info:4567" | ||
|
||
## Provide wrapper to work with species lists. | ||
#' @param species_list Takes a vector of scientific names (each element as "genus species"). | ||
#' if only one name is given in an element (no space), assumes it is the genus and returns | ||
#' all species matching that genus. | ||
#' @param verbose should the function give warnings? | ||
#' @return a data.frame with rows for species and columns for the fields returned by the query (FishBase 'species' table) | ||
#' @examples | ||
#' \donttest{ | ||
#' | ||
#' species_table(c("Oreochromis niloticus", "Bolbometopon muricatum")) | ||
#' # There are 5 species in this genus, so returns 5 rows: | ||
#' species_table("Labroides") | ||
#' } | ||
#' @export | ||
species_table <- function(species_list, verbose = TRUE, .limit = 50, .server = SERVER){ | ||
# Just wraps an lapply around the "per_species" function and combines the resulting data.frames. | ||
# .limit limits the number of returns in a single API call. As we are usually matching species, we expect | ||
# only one hit per call anyway so limit may as well be 1. If we are matching genus only, we can hit | ||
# several species and limit should justifiably be higher. | ||
do.call("rbind", lapply(species_list, per_species, verbose = verbose, limit = .limit, server = .server)) | ||
} | ||
|
||
|
||
|
||
#' @import httr stringr | ||
per_species <- function(species, verbose = TRUE, limit = 10, server = SERVER){ | ||
|
||
## parse scientific name (FIXME function should also do checks.) | ||
s <- parse_name(species) | ||
|
||
## Make the API call for the species requested | ||
args <- list(species = s$species, genus = s$genus, limit = limit) | ||
resp <- GET(paste0(server, "/species"), query = args) | ||
|
||
## check response for http errors | ||
stop_for_status(resp) | ||
|
||
## Parse the http response | ||
out <- content(resp) | ||
|
||
## Check for errors or other issues | ||
error_checks(out, verbose = verbose) | ||
|
||
## Combine into data.frame and tidy | ||
tidy_species_table(out$data) | ||
} | ||
|
||
|
||
|
||
|
||
## Family query is 2 api calls, one to look up FamCode. 1 call for subFamily | ||
## Higher taxonomy: less relevant? | ||
|
||
|
||
|
||
|
||
error_checks <- function(resp, verbose = TRUE){ | ||
## check for errors in the API query | ||
if(!is.null(out$error) && verbose) | ||
stop(out$error) | ||
|
||
## Comment if returns are incomplete. | ||
if(verbose && out$count > out$returned) | ||
warning(paste("Retruning first", out$returned, "matches out of", out$count, "matches.", | ||
"\n Increase limit or refine query for more results")) | ||
|
||
} | ||
|
||
|
||
## Metadata used by tidy_species_table | ||
#meta <- system.file("metadata", "species.csv", package="rfishbase") | ||
meta <- 'inst/metadata/species.csv' | ||
species_meta <- read.csv(meta) | ||
row.names(species_meta) <- species_meta$field | ||
|
||
|
||
#' @import tidyr | ||
tidy_species_table <- function(data) { | ||
L <- lapply(data, null_to_NA) | ||
df <- do.call(rbind.data.frame, L) | ||
# Convert columns to the appropriate class | ||
for(n in names(df)){ | ||
class <- as.character(species_meta[[n, "class"]]) | ||
if(class=="Date") | ||
df[,n] <- as.Date(as.character(df[,n])) | ||
else if(class=="logical") | ||
df[,n] <- as(as.numeric(df[,n]), class) | ||
else | ||
df[,n] <- as(as.character(df[,n]), class) | ||
} | ||
## Drop useless columns. Once reference table implemented, we may want to return those numbers. Same for expert ids. | ||
df <- df[,species_meta$keep] | ||
## Rename columns (pick names to indicate units on numeric values?) | ||
|
||
## Arrange columns | ||
|
||
df | ||
} | ||
|
||
# simple helper function | ||
null_to_NA <- function(x) { | ||
x[sapply(x, is.null)] <- NA | ||
return(x) | ||
} | ||
|
||
# resp <- GET("http://server.carlboettiger.info:4567/species/?genus=Labroides") | ||
# data <- content(resp)$data | ||
# tidy_species_table(data) | ||
|
||
# -1 is TRUE, 0 is FALSE | ||
|
||
|
||
|
||
# parse scientific name. FIXME stupid function, should do more check & error handling | ||
parse_name <- function(x){ | ||
x <- str_split(x, " ")[[1]] | ||
switch(length(x), | ||
list(genus = x[1]), | ||
list(genus = x[1], species = x[2])) | ||
} | ||
|
||
|
||
#' | ||
#' @import httr | ||
get_id <- function(genus, species, server = SERVER){ | ||
resp <- GET(paste0(server, "/species", "/?genus=", genus, "&species=", species, "&fields=speciesrefno,speccode")) | ||
sapply(content(resp)$data, `[[`, "speciesrefno") | ||
} | ||
|
||
|
||
#' @name rfishbase-package | ||
#' @aliases rfishbase | ||
#' @docType package | ||
#' @title The new R interface to Fishbase, v2.0 | ||
#' @author Carl Boettiger \email{carl@@ropensci.org} | ||
#' @author Scott Chamberlain \email{scott@@ropensci.org} | ||
#' @keywords package | ||
NULL | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Check that server is responding | ||
|
||
heartbeat <- function(server = SERVER) | ||
GET(paste0(server, "/heartbeat")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
SERVER = "http://server.carlboettiger.info:4567" | ||
|
||
#' species_table | ||
#' | ||
#' Provide wrapper to work with species lists. | ||
#' @param species_list Takes a vector of scientific names (each element as "genus species"). | ||
#' if only one name is given in an element (no space), assumes it is the genus and returns | ||
#' all species matching that genus. | ||
#' @param verbose should the function give warnings? | ||
#' @param limit The maximum number of matches from a single API call. (Applicable only when | ||
#' querying at genus level, typically only one #' record will match the scientific name and | ||
#' will try all names given.) Thus the default is almost always fine. | ||
#' @param server URL of the FishBase API server. | ||
#' @return a data.frame with rows for species and columns for the fields returned by the query (FishBase 'species' table) | ||
#' @details | ||
#' The Species table is the heart of FishBase. This function provides a convenient way to | ||
#' query, tidy, and assemble data from that table given an entire list of species. | ||
#' For details, see: http://www.fishbase.org/manual/english/fishbasethe_species_table.htm | ||
#' | ||
#' Species scientific names are defined according to fishbase taxonomy and nomenclature. | ||
#' | ||
#' @examples | ||
#' \donttest{ | ||
#' | ||
#' species_table(c("Oreochromis niloticus", "Bolbometopon muricatum")) | ||
#' # There are 5 species in this genus, so returns 5 rows: | ||
#' species_table("Labroides") | ||
#' } | ||
#' @import httr stringr tidyr | ||
#' @export | ||
species_table <- function(species_list, verbose = TRUE, limit = 50, server = SERVER){ | ||
# Just wraps an lapply around the "per_species" function and combines the resulting data.frames. | ||
# .limit limits the number of returns in a single API call. As we are usually matching species, we expect | ||
# only one hit per call anyway so limit may as well be 1. If we are matching genus only, we can hit | ||
# several species and limit should justifiably be higher. | ||
do.call("rbind", lapply(species_list, per_species, verbose = verbose, limit = limit, server = server)) | ||
} | ||
|
||
|
||
|
||
per_species <- function(species, verbose = TRUE, limit = 10, server = SERVER){ | ||
|
||
## parse scientific name (FIXME function should also do checks.) | ||
s <- parse_name(species) | ||
|
||
## Make the API call for the species requested | ||
args <- list(species = s$species, genus = s$genus, limit = limit) | ||
resp <- GET(paste0(server, "/species"), query = args) | ||
|
||
## check response for http errors | ||
stop_for_status(resp) | ||
|
||
## Parse the http response | ||
parsed <- content(resp) | ||
|
||
## Check for errors or other issues | ||
error_checks(parsed, verbose = verbose) | ||
|
||
## Combine into data.frame and tidy | ||
tidy_species_table(parsed$data) | ||
} | ||
|
||
|
||
|
||
|
||
## Family query is 2 api calls, one to look up FamCode. 1 call for subFamily | ||
## Higher taxonomy: less relevant? | ||
|
||
|
||
|
||
|
||
error_checks <- function(parsed, verbose = TRUE){ | ||
## check for errors in the API query | ||
if(!is.null(parsed$error) && verbose) | ||
stop(parsed$error) | ||
|
||
## Comment if returns are incomplete. | ||
if(verbose && parsed$count > parsed$returned) | ||
warning(paste("Retruning first", parsed$returned, "matches parsed of", parsed$count, "matches.", | ||
"\n Increase limit or refine query for more results")) | ||
|
||
} | ||
|
||
|
||
## Metadata used by tidy_species_table | ||
meta <- system.file("metadata", "species.csv", package="rfishbase") | ||
species_meta <- read.csv(meta) | ||
row.names(species_meta) <- species_meta$field | ||
|
||
|
||
## helper routine for tidying species data | ||
tidy_species_table <- function(data) { | ||
L <- lapply(data, null_to_NA) | ||
df <- do.call(rbind.data.frame, L) | ||
# Convert columns to the appropriate class | ||
for(n in names(df)){ | ||
class <- as.character(species_meta[[n, "class"]]) | ||
if(class=="Date") | ||
df[,n] <- as.Date(as.character(df[,n])) | ||
else if(class=="logical") | ||
df[,n] <- as(as.numeric(df[,n]), class) | ||
else | ||
df[,n] <- as(as.character(df[,n]), class) | ||
} | ||
## Drop useless columns. Once reference table implemented, we may want to return those numbers. Same for expert ids. | ||
df <- df[,species_meta$keep] | ||
## Rename columns (pick names to indicate units on numeric values?) | ||
|
||
## Arrange columns | ||
|
||
df | ||
} | ||
|
||
# simple helper function | ||
null_to_NA <- function(x) { | ||
x[sapply(x, is.null)] <- NA | ||
return(x) | ||
} | ||
|
||
# resp <- GET("http://server.carlboettiger.info:4567/species/?genus=Labroides") | ||
# data <- content(resp)$data | ||
# tidy_species_table(data) | ||
|
||
# -1 is TRUE, 0 is FALSE | ||
|
||
|
||
|
||
# parse scientific name. FIXME stupid function, should do more check & error handling | ||
parse_name <- function(x){ | ||
x <- str_split(x, " ")[[1]] | ||
switch(length(x), | ||
list(genus = x[1]), | ||
list(genus = x[1], species = x[2])) | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
% Generated by roxygen2 (4.1.0): do not edit by hand | ||
% Please edit documentation in R/fishbase.R | ||
\docType{package} | ||
\name{rfishbase-package} | ||
\alias{rfishbase} | ||
\alias{rfishbase-package} | ||
\title{The new R interface to Fishbase, v2.0} | ||
\description{ | ||
The new R interface to Fishbase, v2.0 | ||
} | ||
\author{ | ||
Carl Boettiger \email{carl@ropensci.org} | ||
|
||
Scott Chamberlain \email{scott@ropensci.org} | ||
} | ||
\keyword{package} | ||
|
Oops, something went wrong.