R/downto.tree.R

Defines functions downto.tree

Documented in downto.tree

#' Phylogenetic tree from a taxon down to a lower rank
#'
#' Expands a higher taxon to all of its descendants at a chosen rank using
#' \code{\link[taxize]{downstream}}, then builds the corresponding Open Tree
#' of Life subtree via \code{\link{taxa.tree}}.
#'
#' @param taxon A single higher taxon name (e.g. a family or genus).
#' @param downto Target lower rank to expand down to, e.g. \code{"species"}
#'   or \code{"genus"}. Must be lower than \code{taxon}'s rank.
#' @param db Taxonomic database used for the downstream expansion. Default
#'   \code{"ncbi"}. \code{"gbif"} and \code{"itis"} are also supported and
#'   need no API key; prefer them if you hit NCBI rate limits.
#' @param key NCBI Entrez API key (relevant when \code{db = "ncbi"}). When
#'   supplied it is exported as the \code{ENTREZ_KEY} environment variable for
#'   the duration of the call, so both the \code{get_uid} and \code{downstream}
#'   requests use it; the previous value is restored on exit. Create a key with
#'   \code{\link[taxize]{use_entrez}}. Alternatively, set \code{ENTREZ_KEY}
#'   yourself (e.g. in \code{.Renviron}) and leave this \code{NULL}. Without a
#'   key NCBI throttles requests to 3 per second (10 with one).
#' @param source Tree source passed to \code{\link{taxa.tree}}: \code{"otl"}
#'   (default) or \code{"fish"}.
#' @param plot Logical; plot the resulting tree(s). Default \code{TRUE}.
#' @param verbose Logical; print progress messages. Default \code{TRUE}.
#'
#' @return Invisibly, the list returned by \code{\link{taxa.tree}}
#'   (\code{trees}, \code{unmatched}). Because descendants of a taxon may span
#'   more than one phylum, \code{trees} can contain more than one element.
#'
#' @details Only the taxon-expansion step uses \pkg{taxize}; the tree itself
#'   comes from Open Tree of Life, so descendants that are absent from the
#'   Open Tree synthesis are dropped and reported in \code{unmatched}.
#'
#' @seealso \code{\link{taxa.tree}}
#'
#' @importFrom taxize get_uid downstream
#' @examples
#' \dontrun{
#' # All species in the deer family:
#' downto.tree("Cervidae", downto = "species")
#' }
#' @export
downto.tree <- function(taxon, downto, db = "ncbi", key = NULL,
                        source = c("otl", "fish"),
                        plot = TRUE, verbose = TRUE) {
  source <- match.arg(source)
  if (length(taxon) != 1L || !is.character(taxon) || !nzchar(trimws(taxon))) {
    stop("'taxon' must be a single non-empty taxon name.", call. = FALSE)
  }

  # Expose an explicit key via ENTREZ_KEY for the duration of the call so that
  # every taxize NCBI request (get_uid *and* downstream) picks it up, then
  # restore whatever was there before (unset it if it was previously unset).
  if (!is.null(key) && nzchar(key)) {
    old_key <- Sys.getenv("ENTREZ_KEY", unset = NA_character_)
    Sys.setenv(ENTREZ_KEY = key)
    on.exit(
      if (is.na(old_key)) Sys.unsetenv("ENTREZ_KEY") else Sys.setenv(ENTREZ_KEY = old_key),
      add = TRUE
    )
  }

  if (identical(db, "ncbi")) {
    # Resolve the name to a UID once. ask = FALSE keeps this non-interactive
    # (safe inside scripts / R CMD check); the first best match is used.
    # The key is read from ENTREZ_KEY (set above), so it is not passed here.
    id <- taxize::get_uid(taxon, messages = verbose, ask = FALSE)
    if (is.na(id)) {
      stop("Could not resolve '", taxon, "' on NCBI.", call. = FALSE)
    }
    dn <- taxize::downstream(id, downto = downto, db = "ncbi")
  } else {
    dn <- taxize::downstream(taxon, downto = downto, db = db)
  }

  # downstream() returns a named list keyed by the query; take the first
  # (and only) element and pull the child-taxon names.
  children <- dn[[1]]$childtaxa_name
  if (is.null(children) || !length(children)) {
    stop("No descendants found for '", taxon, "' at rank '", downto, "'.",
         call. = FALSE)
  }

  if (verbose) {
    message("Retrieved ", length(children), " '", downto, "' taxa under '",
            taxon, "'.")
  }

  taxa.tree(children, source = source, plot = plot, verbose = verbose)
}

Try the aptg package in your browser

Any scripts or data that you put into this service are public.

aptg documentation built on July 19, 2026, 9:07 a.m.