Package: algaeClassify

Title: Determine Phytoplankton Functional Groups Based on Functional Traits

Authors

Vijay Patil (ORCID: 0000-0002-9357-194X) U.S. Geological Survey - Alaska Science Center
Torsten Seltmann
Nico Salmaso
Orlane Anneville
Marc Lajeunesse
Dietmar Straile

Suggested Citation

Patil, V.P., Seltmann, T., Salmaso, N., Anneville, O., Lajeunesse, M., Straile, D., 2023. algaeClassify (ver 2.0.1, October 2023): U.S. Geological Survey software release, https://doi.org/10.5066/F7S46Q3F

Contact

Vijay Patil vpatil@usgs.gov - U.S. Geological Survey - Alaska Science Center; 4210 University Drive; Anchorage, Alaska 99508 USA; 907-786-7178 ascweb@usgs.gov

Software Requirements

Distribution

Package Overview

The goal of algaeClassify is to facilitate the analysis of taxonomic and functional trait data for phytoplankton.

Functions that facilitate the use of accepted taxonomic nomenclature, collection of functional trait data, and assignment of functional group classifications to phytoplankton species. Possible classifications include Morpho-functional group (MFG; [Salmaso et al. 2015] Salmaso, N., Naselli-Flores, L. and Padisak, J., 2015. Functional classifications and their application in phytoplankton ecology. Freshwater Biology, 60(4), pp.603-619.) and CSR, based on [Reynolds 1988] (Functional morphology and the adaptive strategies of phytoplankton. In C.D. Sandgren (ed). Growth and reproductive strategies of freshwater phytoplankton, 388-433. Cambridge University Press, New York) and [Reynolds 2006] https://doi.org/10.1017/CBO9780511542145.

Versions 2.0.0 and later includes new functions for querying the algaebase online taxonomic database (www.algaebase.org), however these functions require a valid API key that must be acquired from the algaebase admin. Note that none of the algaeClassify authors are affiliated with algaebase in any way. Taxonomic names can also be checked against a variety of taxonomic databases using the geographic name resolution service (GNRS) via wrapper functions for the R taxize package, with convenient output format and unlikely names for phytoplankton taxa removed. In addition, currently accepted and outdated synonyms, and higher taxonomy, can be extracted for lists of species from the ITIS database using wrapper functions for the R ritis package. The algaeClassify package is a product of the GEISHA (Global Evaluation of the Impacts of Storms on freshwater Habitat and Structure of phytoplankton Assemblages), funded by CESAB (Centre for Synthesis and Analysis of Biodiversity) and the USGS John Wesley Powell Center for Synthesis and Analysis, with data and other support provided by members of GLEON (Global Lake Ecology Observation Network).

Installation

To use the new algaebase search functions, you MUST install v2.0.0 or later from code.usgs.gov at https://doi.org/10.5066/F7S46Q3F. If you have git installed, you can also install the package through R with:

#the following will install the package from the code.usgs.gov 
#repository:
require(devtools)
install_git("https://code.usgs.gov/asc/algaeClassify",ref="main") 
#update packages if necessary, or choose 'none' 

Next, load the package and ensure you have the correct version installed.

library(algaeClassify)
citation("algaeClassify")

April 5, 2023: New functions for querying algaeBase

(www.algaebase.org)!!!! Algaebase search function examples

#check out the package
help(package="algaeClassify")

#View the new algaebase search functions:
help("algaebase_species_search")
help("algaebase_genus_search")
help("algaebase_search_df")

Using your API key

The Algaebase functions require an API key. You can obtain one from [Algaebase]https://www.algaebase.org/api.

There are several options for using your api key. 1) assigning it to an R object, and using it in function calls

apikey<- "asasdfasdfasdfasfd" #(not a real key)
algaebase_genus_search(genus="Anabaena",apikey=apikey)
  1. Saving it in a text file (e.g. “keyfile.txt”). You will need to give the filename and path using the api_file function argument.
algaebase_genus_search(genus="Anabaena",api_file="keyfile.txt")
  1. Finally, you can set your key as an environment variable. To do so, open or create a .Renviron text file in your home directory. One way to do this is by running the following line:
file.edit("~/.Renviron")

Add a line to the .Renviron file like the following, but use your actual key after the = symbol:

ALGAEBASE_APIKEY=yourKeyHere

Finally, save and close the file, then restart R for changes to take effect. Once the ALGAEBASE_APIKEY variable is defined, you do not need to specify it in the algaebase search functions.

Allowing international encodings and special characters

When reading in a phytplankton species list with read.csv, we recommend that you specify the character encoding. In the United States, using UTF-8 should correctly preserve umlautes, accents, and other special characters.

#example code. not a real file.
phyto.data<-read.csv('my_phytoplankton_species_list.csv',encoding="UTF-8")

#Can also set encoding for the R session.
#This can be specified to happen at startup.
options(encoding="UTF-8")

Algaebase search function examples:

You can search for a single genus

algaebase_genus_search(genus="Anabaena")

Or a genus and species name

algaebase_species_search("Anabaena","flos-aquae")

#There are several arguments for these functions.
#you can control whether to include higher taxonomy in the output
algaebase_genus_search(genus="Navicula",higher=TRUE)

#You can also choose to include the full species name with author and date in 
#output
algaebase_genus_search(genus="Navicula",higher=TRUE,long=TRUE)

#The default only returns exact matches and the most recent entry in algaebase,
#but you can override that behavior
algaebase_species_search(genus="Nitzschia",species="acicularis",
newest.only=FALSE,exact.matches.only=FALSE,long=TRUE)

It is also possible to include infraspecific names in searches. To do so, the species argument should be a character string containing the species name and infraspecific name, separated by a space.

algaebase_species_search(genus="Fragilaria",species="vaucheriae capitellata")

Algaebase_species_search will return an error for search terms that include infraspecific labels such as var., subsp., etc.

algaebase_species_search(genus="Fragilaria",
                         species="vaucheriae var. capitellata")

If desired, you can view the raw output in JSON format

algaebase_genus_search(genus="Cyclotella",higher=TRUE,print.full.json=TRUE)

Preprocessing data with genus_species_extract()

The genus_species_extract function can be used to process a list of binomial names before submitting an algaebase search. This function accepts a data.frame containing a column of character strings with binomial names, and appends columns for genus and species. If infraspecific names are present, The species column will contain both the species and infraspecific names, with any infraspecific labels or label abbreviations removed. Genus_species_extract() will also convert any input character encodings to UTF-8 to ensure consistent search behavior when special characters are present.

test.df<-data.frame(phyto_name="Fragilaria vaucheriae var. capitellata")
test.df<-genus_species_extract(test.df,phyto.name='phyto_name')
#view the new dataframe with genus and species columns, formatted for 
#algaebase search.
head(test.df)

In all cases, the output will return the currently accepted name, as well as the name that was supplied by the user. There are columns indicating whether the input name is currently accepted and whether an exact match was found.

Submit a list of names to Algaebase.

You can submit a data.frame of phytoplankton names to algaebase. The data frame must have columns named genus and species. We recommend using the genus_species_extract() function to create properly formatted columns of genus and species names.

This will only return 1 result per name. If there are no exact matches it will return NA by default. You can set exact.matches.only =FALSE for partial matching, but this may result in more than one match returned per submitted name. If there is no match for genus+species it will search for a genus-only match or you can specify genus.only searches for the entire dataset.

data(lakegeneva) #load small example dataset
head(lakegeneva) #view example dataset

lakegeneva<-genus_species_extract(lakegeneva,phyto.name="phyto_name")
lakegeneva<-lakegeneva[!duplicated(lakegeneva$phyto_name),]

lakegeneva.algaebase<-algaebase_search_df(lakegeneva,higher=TRUE,
genus.name="genus",species.name="species")

head(lakegeneva.algaebase)

##partial matching for an incorrectly-spelled name:
genus<-"Terpsinoe" # should be Terpsinoë
species<-"musica"

umlaut.test.df<-data.frame(genus,species)

algaebase_search_df(umlaut.test.df) #no match

algaebase_search_df(umlaut.test.df,exact.matches.only=FALSE) 
#no species match, but the function tries a genus-only search next, and 
finds the correct genus name as a partial match when exact.matches.only = FALSE.

Other taxonomic search functions

Version 2.0.0 includes functions for searching the ITIS database and for using the Global Names Resolver (GNR). These functions are based on the ritis and taxize packages, respectively.

#ITIS
genus_search_itis(genus="Mougeotia",higher=TRUE)

species_search_itis(genspp="Anabaena flos-aquae")
#This does not return a match in ITIS, but Anabaena flosaquae

#GNR (Global Names Resolver)
#GNR/taxize use fuzzy/partial matching, and search multiple databases.
#If you do not find a hit in algaebase or ITIS, you can try searching for a 
#partial match via GNR

name<-"Anabaena flos-aquae"
gnr_simple(name=name,sourceid=3) #Search ITIS
gnr_simple(name=name,sourceid=NULL) #search for matches from any source

species_search_itis(genspp="Anabaena flosaquae") #check itis f0r gnr best match.

Functional group classifications

AlgaeClassify can also be used to assist users in classifying species into one of several morphological/functional classifications: Morpho- functional groups (MFG) [Salmaso et al. 2015] or the C-S-R framework as described for freshwater systems [Reynolds 1988; Reynolds 2006]

It is possible to derive MFG and CSR classifications by supplying trait values. Relevant traits are surface area, volume and maximum linear dimension for CSR, or presence/absence of flagella, colonies, filamentous growth forms, and other traits for MFG, as described in Salmaso et al. 2015.

We hope to add additional functional classifications in future versions, such as the Reynolds Functional Group classification system. Please send suggestions to vpatil@usgs.gov!

traits_to_csr(sav=0.2,msv=10,traitrange=traitranges)

traits_to_mfg(flagella = 1,size = "large",colonial = 1,filament = 0,
              centric = NA,gelatinous = 0,aerotopes = 0,
              class = "Euglenophyceae",order = "Euglenales")

Users may be able to retrieve relevant trait data from published sources. For convenience, algaeClassify has included tables of MFG and CSR trait values for common European species, extracted from [Rimet et al. 2018]. doi:10.1051/limn/2018009.

data("csrTraits")
data("mfgTraits")
head(csrTraits)
head(mfgTraits)

Alternatively, the user may be able to match species to a library of species:MFG classifications derived via expert assessment as part of the GEISHA John Wesley Powell Center fellowship. https://www.usgs.gov/centers/john-wesley-powell-center-for-analysis-and-synthesis/science/global-evaluation-impacts

This library can be used to classify lists of species or single species names. However, many morphofunctional traits are plastic and MFG classifications may vary for a single species depending on location and environment. Use with caution!

data("species_mfg_library")
head(species_mfg_library)

species_to_mfg('Scenedesmus','bijuga')

data(lakegeneva)
lakegeneva<-genus_species_extract(lakegeneva,phyto.name='phyto_name')
lakegeneva.mfg<-species_to_mfg_df(lakegeneva)

head(lakegeneva.mfg)

If desired, species_to_mfg_df() can be run with a user-supplied library of species:MFG matches based on their own research, using the mfgDbase argument.

help("specis_to_mfg_df")

Finally, the user can crosswalk MFG and CSR classifications, based on [Salmaso et al. 2015] and [Reynolds 1988].

data(mfg_csr_library)
mfg_csr_convert(mfg="11a-NakeChlor")

Visualizing and manipulating long-term phytoplankton datasets

This is a basic example which shows you how to use algaeClassify to 1) identify anomalies in atime-series of phytoplankton species 2) calculate aggregate abundance at a higher taxonomic level (genus) 3) re-plot species accumulation curves to see if the taxonomic standardization and aggregation to higher taxonomy have resolved the anomalies.

phyto_ts_aggregate() can be used to aggregate phytoplankton timeseries based on abundance and grouping variables (genus, MFG, station id, etc.). If no abundance var is given, will aggregate to presence/absence.

date_mat() is used to transform long-term data into a matrix of abundance or presence/absence, organized by taxa/group and date (day, month, or year). This simplifies the process of formatting data for ordinations or other plots of abundance change over time.

accum() compares observed change in total species richness over time to simulated curves based on random draws with replacement from a list of all unique species in the dataset. step discontinuities in the observed curve & departures from the simulated range may signal sudden ecological or methodological changes (including changes in taxonomic standards, personnel, or equipment).


data(lakegeneva) #load the demonstration dataset

accum(lakegeneva,phyto_name='phyto_name',column='biovol_um3_ml',n=100,
      datename='date_dd_mm_yy',dateformat='%d-%m-%y')

#clean up binomial names and extract genus and species to new columns
lakegeneva<-genus_species_extract(lakegeneva,phyto.name='phyto_name')

#aggregate abundance data to genus level
lakegeneva.genus<-phyto_ts_aggregate(lakegeneva,SummaryType='abundance',
                                      AbundanceVar='biovol_um3_ml',
                                      GroupingVar1='genus')
#plot accumulation curve again, but at genus level
accum(lakegeneva.genus,phyto_name='genus',column='biovol_um3_ml',n=100,
      datename='date_dd_mm_yy',dateformat='%Y-%m-%d')

#classify taxa to CSR and visualize relative abundance of CSR groups by month
data(lakegeneva)

lakegeneva<-genus_species_extract(lakegeneva,phyto.name='phyto_name')
lakegeneva<-species_to_mfg_df(lakegeneva)
lakegeneva<-mfg_csr_convert_df(lakegeneva,mfg='MFG')
csrAbundance.by.month<-date_mat(lakegeneva,abundance.var='biovol_um3_ml',
                                taxa.name='CSR',time.agg='month')

#make a simple heatmap of mean daily csr group abundance by month
#In this example dataset, Stress-tolerant taxa dominate for a short time in 
#mid summer, followed by Ruderal-disturbance tolerant species that thrive during
#fall overturn. In winter, spring, and summer, small and fast-reproducing 
#(C)ompetitors are most abundant.
stats::heatmap(csrAbundance.by.month,Rowv=NA,Colv=NA,
xlab='CSR group',ylab='Month')