Retrieve Taxonomic Data From WoRMS

WoRMS

The World Register of Marine Species (WoRMS) is a comprehensive database providing authoritative lists of marine organism names, managed by taxonomic experts. It combines data from the Aphia database and other sources like AlgaeBase and FishBase, offering species names, higher classifications, and additional data. WoRMS is continuously updated and maintained by taxonomists. In this tutorial, we source the R package worrms to access WoRMS data for our function. Please note that the authors of SHARK4R are not affiliated with WoRMS.

Getting Started

Installation

You can install the latest version of SHARK4R from CRAN using:

install.packages("SHARK4R")

Load the SHARK4R, dplyr and ggplot2 libraries:

library(SHARK4R)
library(dplyr)
library(ggplot2)

Retrieve Data Using SHARK4R

Retrieve Phytoplankton Data From SHARK

Phytoplankton data, including scientific names and AphiaIDs, are downloaded from SHARK. To see more download options, please visit the Retrieve Data From SHARK tutorial.

# Retrieve all phytoplankton data from April 2015
shark_data <- get_shark_data(fromYear = 2015,
                             toYear = 2015,
                             months = 4,
                             dataTypes = "Phytoplankton",
                             verbose = FALSE)

Match Taxa Names

Taxon names can be matched with the WoRMS API to retrieve Aphia IDs and corresponding taxonomic information. The match_worms_taxa() function incorporates retry logic to handle temporary failures, ensuring that all names are processed successfully.

# Find taxa without Aphia ID
no_aphia_id <- shark_data %>%
  filter(is.na(aphia_id))

# Randomly select taxa with missing aphia_id
taxa_names <- sample(unique(no_aphia_id$scientific_name),
                     size = 10,
                     replace = TRUE)

# Match taxa names with WoRMS
worms_records <- match_worms_taxa(unique(taxa_names),
                                  fuzzy = TRUE,
                                  best_match_only = TRUE,
                                  marine_only = TRUE,
                                  verbose = FALSE)

# Print result
print(worms_records)
## # A tibble: 4 × 29
##   name  AphiaID url   scientificname authority status unacceptreason taxonRankID
##   <chr>   <int> <chr> <chr>          <chr>     <chr>  <chr>                <int>
## 1 Cyli…  149004 http… Cylindrotheca… (Ehrenbe… accep… <NA>                   220
## 2 Unic…      NA <NA>  <NA>           <NA>      no co… <NA>                    NA
## 3 Dipl…  109515 http… Diplopsalis    R.S.Berg… accep… <NA>                   180
## 4 Scri…  109545 http… Scrippsiella   Balech e… accep… <NA>                   180
## # ℹ 21 more variables: rank <chr>, valid_AphiaID <int>, valid_name <chr>,
## #   valid_authority <chr>, parentNameUsageID <int>, originalNameUsageID <int>,
## #   kingdom <chr>, phylum <chr>, class <chr>, order <chr>, family <chr>,
## #   genus <chr>, citation <chr>, lsid <chr>, isMarine <int>, isBrackish <int>,
## #   isFreshwater <int>, isTerrestrial <int>, isExtinct <lgl>, match_type <chr>,
## #   modified <chr>

Get WoRMS records from AphiaID

Taxonomic records can also be retrieved using Aphia IDs, employing the same retry and error-handling logic as the match_worms_taxa() function.

# Randomly select ten Aphia IDs
aphia_ids <- sample(unique(shark_data$aphia_id),
                    size = 10)

# Remove NAs
aphia_ids <- aphia_ids[!is.na(aphia_ids)]

# Retrieve records
worms_records <- get_worms_records(aphia_ids,
                                   verbose = FALSE)

# Print result
print(worms_records)
## # A tibble: 10 × 28
##    AphiaID url        scientificname authority status unacceptreason taxonRankID
##      <int> <chr>      <chr>          <chr>     <chr>  <lgl>                <int>
##  1  160553 https://w… Dinobryon fac… (Willén)… accep… NA                     220
##  2  148985 https://w… Chaetoceros    C.G. Ehr… accep… NA                     180
##  3  118075 https://w… Telonema subt… Griessma… accep… NA                     220
##  4  160537 https://w… Melosira arct… Dickie, … unass… NA                     220
##  5  148912 https://w… Thalassiosira  P.T. Cle… accep… NA                     180
##  6  110321 https://w… Protoceratium… (Claparè… accep… NA                     220
##  7  341285 https://w… Centrales      <NA>      accep… NA                     100
##  8  109637 https://w… Dinophysis no… Claparèd… accep… NA                     220
##  9  110652 https://w… Eutreptiella … Throndse… accep… NA                     220
## 10  146677 https://w… Planktolyngbya Anagnost… accep… NA                     180
## # ℹ 21 more variables: rank <chr>, valid_AphiaID <int>, valid_name <chr>,
## #   valid_authority <chr>, parentNameUsageID <int>, originalNameUsageID <int>,
## #   kingdom <chr>, phylum <chr>, class <chr>, order <chr>, family <chr>,
## #   genus <chr>, citation <chr>, lsid <chr>, isMarine <int>, isBrackish <int>,
## #   isFreshwater <int>, isTerrestrial <int>, isExtinct <int>, match_type <chr>,
## #   modified <chr>

Get WoRMS Taxonomy

SHARK sources taxonomic information from Dyntaxa, which is reflected in columns starting with taxon_xxxxx. Equivalent columns based on WoRMS can be retrieved using the add_worms_taxonomy() function.

# Retrieve taxonomic table
worms_taxonomy <- add_worms_taxonomy(aphia_ids,
                                     verbose = FALSE)

# Print result
print(worms_taxonomy)

# Enrich SHARK data with taxonomic data from WoRMS
shark_data_with_worms <- shark_data %>%
  left_join(worms_taxonomy, by = "aphia_id")
## # A tibble: 10 × 10
##    aphia_id worms_scientific_name     worms_kingdom worms_phylum     worms_class
##       <dbl> <chr>                     <chr>         <chr>            <chr>      
##  1   160553 Dinobryon faculiferum     Chromista     Ochrophyta       Chrysophyc…
##  2   148985 Chaetoceros               Chromista     Heterokontophyta Bacillario…
##  3   118075 Telonema subtile          Chromista     Cryptophyta      Telonemea  
##  4   160537 Melosira arctica          Chromista     Heterokontophyta Bacillario…
##  5   148912 Thalassiosira             Chromista     Heterokontophyta Bacillario…
##  6   110321 Protoceratium reticulatum Chromista     Myzozoa          Dinophyceae
##  7   341285 Centrales                 Chromista     Heterokontophyta Bacillario…
##  8   109637 Dinophysis norvegica      Chromista     Myzozoa          Dinophyceae
##  9   110652 Eutreptiella gymnastica   Protozoa      Euglenozoa       Euglenophy…
## 10   146677 Planktolyngbya            Bacteria      Cyanobacteria    Cyanophyce…
## # ℹ 5 more variables: worms_order <chr>, worms_family <chr>, worms_genus <chr>,
## #   worms_species <chr>, worms_hierarchy <chr>

Retrieve WoRMS Taxonomic Hierarchies

To explore the full hierarchical taxonomy records of your Aphia IDs, you can use the get_worms_taxonomy_tree() function. This function retrieves records for the entire taxonomic tree from WoRMS, including parent-child relationships, and can optionally fetch all descendants (e.g. species) under a genus or known synonyms.

# Retrieve taxonomic tree
worms_tree <- get_worms_taxonomy_tree(
  aphia_ids[1],                # use first id only in this example
  add_descendants = FALSE,     # only retrieve hierarchy for given AphiaIDs
  add_synonyms = FALSE,        # do not retrieve synonyms
  verbose = FALSE              # suppress progress messages
)

# Print result
print(worms_tree)
## # A tibble: 9 × 28
##   AphiaID url   scientificname authority status unacceptreason taxonRankID rank 
##     <int> <chr> <chr>          <chr>     <chr>  <lgl>                <int> <chr>
## 1       7 http… Chromista      <NA>      accep… NA                      10 King…
## 2  582419 http… Harosa         <NA>      accep… NA                      20 Subk…
## 3  368898 http… Heterokonta    <NA>      accep… NA                      25 Infr…
## 4  345465 http… Ochrophyta     Cavalier… accep… NA                      30 Phyl…
## 5  146230 http… Chrysophyceae  Pascher,… accep… NA                      60 Class
## 6  248107 http… Chromulinales  Pascher,… accep… NA                     100 Order
## 7  157239 http… Dinobryaceae   Ehrenber… accep… NA                     140 Fami…
## 8  157240 http… Dinobryon      Ehrenber… accep… NA                     180 Genus
## 9  160553 http… Dinobryon fac… (Willén)… accep… NA                     220 Spec…
## # ℹ 20 more variables: valid_AphiaID <int>, valid_name <chr>,
## #   valid_authority <chr>, parentNameUsageID <int>, originalNameUsageID <lgl>,
## #   kingdom <chr>, phylum <chr>, class <chr>, order <chr>, family <chr>,
## #   genus <chr>, citation <chr>, lsid <chr>, isMarine <int>, isBrackish <int>,
## #   isFreshwater <int>, isTerrestrial <int>, isExtinct <lgl>, match_type <chr>,
## #   modified <chr>

Assign Phytoplankton Groups

Phytoplankton data are often categorized into major groups such as Dinoflagellates, Diatoms, Cyanobacteria, and Others. This grouping can be achieved by referencing information from WoRMS and assigning taxa to these groups based on their taxonomic classification, as demonstrated in the example below.

# Subset data from one national monitoring station
nat_stations <- shark_data %>%
  filter(station_name %in% c("BY5 BORNHOLMSDJ"))

# Randomly select one sample from the nat_stations
sample <- sample(unique(nat_stations$shark_sample_id_md5), 1)

# Subset the random sample
shark_data_subset <- shark_data %>%
  filter(shark_sample_id_md5 == sample)

# Assign groups by providing both scientific name and Aphia ID
plankton_groups <- assign_phytoplankton_group(
  scientific_names = shark_data_subset$scientific_name,
  aphia_ids = shark_data_subset$aphia_id,
  verbose = FALSE)

# Print result
distinct(plankton_groups)

# Add plankton groups to data and summarize abundance results
plankton_group_sum <- shark_data_subset %>%
  mutate(plankton_group = plankton_groups$plankton_group) %>%
  filter(parameter == "Abundance") %>%
  group_by(plankton_group) %>%
  summarise(sum_plankton_groups = sum(value, na.rm = TRUE))

# Plot a pie chart
ggplot(plankton_group_sum,
       aes(x = "", y = sum_plankton_groups, fill = plankton_group)) +
  geom_col(width = 1) +
  coord_polar(theta = "y") +
  labs(
    title = "Phytoplankton Groups",
    subtitle = paste(unique(shark_data_subset$station_name),
                     unique(shark_data_subset$sample_date)),
    fill = "Plankton Group"
  ) +
  theme_void() +
  theme(plot.background = element_rect(fill = "white", color = NA))
## # A tibble: 23 × 2
##    scientific_name      plankton_group 
##    <chr>                <chr>          
##  1 Pauliella taeniata   Diatoms        
##  2 Amylax triacantha    Dinoflagellates
##  3 Aphanocapsa          Cyanobacteria  
##  4 Aphanothece          Cyanobacteria  
##  5 Chaetoceros similis  Diatoms        
##  6 Dinobryon balticum   Other          
##  7 Dinophysis acuminata Dinoflagellates
##  8 Dinophysis norvegica Dinoflagellates
##  9 Gymnodinium          Dinoflagellates
## 10 Protodinium simplex  Other          
## # ℹ 13 more rows

Assign Custom Phytoplankton Groups

You can add custom plankton groups by using the custom_groups parameter, allowing flexibility to categorize plankton based on specific taxonomic criteria. Please note that the order of the list matters: taxa are assigned to the last matching group. For example: Mesodinium rubrum will be excluded from the Ciliates group because it appears after Ciliates in the list in the example below.

# Define custom plankton groups using a named list
custom_groups <- list(
  "Cryptophytes" = list(class = "Cryptophyceae"),
  "Green Algae" = list(class = c("Trebouxiophyceae",
                                 "Chlorophyceae",
                                 "Pyramimonadophyceae"),
                       phylum = "Chlorophyta"),
  "Ciliates" = list(phylum = "Ciliophora"),
  "Mesodinium rubrum" = list(scientific_name = "Mesodinium rubrum"),
  "Dinophysis" = list(genus = "Dinophysis")
)

# Assign groups by providing scientific name only, and adding custom groups
plankton_groups <- assign_phytoplankton_group(
  scientific_names = shark_data_subset$scientific_name,
  custom_groups = custom_groups,
  verbose = FALSE)

# Add new plankton groups to data and summarize abundance results
plankton_custom_group_sum <- shark_data_subset %>%
  mutate(plankton_group = plankton_groups$plankton_group) %>%
  filter(parameter == "Abundance") %>%
  group_by(plankton_group) %>%
  summarise(sum_plankton_groups = sum(value, na.rm = TRUE))

# Plot a new pie chart, including the custom groups
ggplot(plankton_custom_group_sum,
       aes(x = "", y = sum_plankton_groups, fill = plankton_group)) +
  geom_col(width = 1) +
  coord_polar(theta = "y") +
  labs(
    title = "Phytoplankton Custom Groups",
    subtitle = paste(unique(shark_data_subset$station_name),
                     unique(shark_data_subset$sample_date)),
    fill = "Plankton Group"
  ) +
  theme_void() +
  theme(plot.background = element_rect(fill = "white", color = NA))


Citation

## To cite package 'SHARK4R' in publications use:
## 
##   Lindh, M. and Torstensson, A. (2026). SHARK4R: Accessing and
##   Validating Marine Environmental Data from 'SHARK' and Related
##   Databases. R package version 1.2.0.
##   https://CRAN.R-project.org/package=SHARK4R
## 
## A BibTeX entry for LaTeX users is
## 
##   @Manual{,
##     title = {SHARK4R: Accessing and Validating Marine Environmental Data from 'SHARK' and Related Databases},
##     author = {Markus Lindh and Anders Torstensson},
##     year = {2026},
##     note = {R package version 1.2.0},
##     url = {https://CRAN.R-project.org/package=SHARK4R},
##   }