2.9 Percentage cover of zoanthids and gorgonians

Last updated

July 6, 2026

2.9 Percentage cover of zoanthids and gorgonians

On this page

This page aggregates the gorgonian and zoantharian components of the benthos into the groupings monitored by TCRMP and VINPS, then plots their percent cover through time at each survey site. Gorgonians (soft corals and sea fans) and zoanthids are recorded together here because both programs report them at the same coarse grouping. The page groups every survey record by gorgonian or zoanthid type and averages cover across replicate transects at each site and year. It produces the faceted cover-over-time figure (Figure 1) and a downloadable long-format cover table (s2pt9_benthicCoverZoanthidGorgonians) that feeds the downstream resilience and biodiversity pages.

Data sources

This page uses the reformatted benthic cover and cross-referenced benthic codes produced in sections 2.1 and 2.2 from the TCRMP and VINPS monitoring programs; CSUN does not enter this page. The benthic codes are filtered to the Gorgonian and Zoanthid categories, and the site master table orders facets by depth. TCRMP and VINPS both record replicate transects at each site, so their site-year means carry standard error, and VINPS begins in 1999, later than TCRMP, so the earliest years hold TCRMP sites only. The derived cover table produced here is available in the Downloads section below.

Load workspace and define variables

What happens here: the page loads the per-program benthic cover and the benthic-code cross-reference produced by the section 2.1 reformat and the section 2.2 cross-referencing step, then names the grouping variable and the output section tag used later for file naming.

Show code
load("benthicCoverXrefBenthicCodes.RData")

subfoldername names where the grouped cover products are written. groupingvar sets the taxonomic grouping for this page (zoanthidsGorgonians). section tags the output filenames (s2pt9).

Show code
subfoldername <- "benthicCoverGrouped"
groupingvar <- "zoanthidsGorgonians"
section <- "s2pt9" # for naming

Reorganize benthicDat into subgroupings of interest

The benthic-code cross-reference is filtered to the Gorgonian and Zoanthid categories, so the grouping below covers exactly the gorgonian and zoantharian types reported on this page.

Show code
benthicCodes <-
  benthicCodes[which(benthicCodes$tcrmp_Category %in% c("Gorgonian", "Zoanthid")), ]

The shared cross-reference include below matches every program’s benthic-data columns to their gorgonian or zoanthid group, builds one grouped cover table per program, merges TCRMP and VINPS, and melts the result to long format. Its UAGA guard warns if any program’s data column carries a code absent from benthicCodes, so a group cannot be silently dropped.

getBenthicDatColInds()

this is one of two functions that connect benthicDat to benthicCodes for all three programs.

getBenthicDatColInds() makes _columnInds that stores column indices of benthic codes corresponding to each item of zoanthidsGorgonians arguments:

  • benthicDat is benthic dataset of interest

  • codecolumn is the name of the column of benthic code containing the code for benthicdat

  • groupingcolumn is the name of the column of benthic codes where the grouping variable of interest is stored.

Show code
getBenthicDatColInds <-
  function(benthicDat, codecolumn, groupingcolumn) {
    codecolind <-
      which(colnames(benthicCodes) == codecolumn)
    groupingcolind <-
      which(colnames(benthicCodes) == groupingcolumn)
    genusdf <-
      data.frame(group =
                   unique(benthicCodes[, groupingcolind]),
                 colinds =
                   rep(0, length(unique(benthicCodes[, groupingcolind]))))
    for (i in 1:nrow(genusdf)) {
      codei <-
        benthicCodes[which(benthicCodes[, groupingcolind] == genusdf$group[i]), ]
      genusdf$colinds[i] <-
        list(which(colnames(benthicDat) %in% codei[, codecolind]))
    }
    # UAGA-guard: warn on benthicDat data columns whose code is absent from benthicCodes and is
    # therefore silently dropped (the footgun that lost VINPS Agaricia agaricites, code UAGA).
    .known <- benthicCodes[[codecolind]]; .known <- .known[nchar(.known) > 0]
    .meta_cols <- c("program","date","site","period","replicate","replicatetype","nopts",
                    "Year","Date","SiteFullName","year","month","percentCover_allCoral",
                    "PC","Check","Notes","Transect")
    .dropped <- setdiff(colnames(benthicDat), c(.known, .meta_cols))
    if (length(.dropped) > 0)
      warning("getBenthicDatColInds(", codecolumn, "): ", length(.dropped),
              " data column(s) have codes absent from benthicCodes and are DROPPED: ",
              paste(.dropped, collapse = ", "), " -- add them to benthicCodes if they are taxa.")
    return(genusdf)
  }

apply getBenthicDatColInds() to _benthicDat dataframes . preview tcrmp_columnInds

Show code
tcrmp_columnInds <-
  getBenthicDatColInds(tcrmp_benthicDat, "tcrmp_Code", "tcrmp_Meaning")
vinps_columnInds <-
  getBenthicDatColInds(vinps_benthicDat, "vinps_TaxonCode", "tcrmp_Meaning")

kbl(tcrmp_columnInds) |>
  kable_paper(full_width = F) |>
  kable_styling(
    fixed_thead = T,
    bootstrap_options = c("hover", "condensed"),
    font_size = 8
  ) |>
  scroll_box(width = "100%", height = "250px")
group colinds
Briareum asbestinum 70
Erythropodium caribaeorum 72
Encrusting Gorgonian 71
Sea fan 73
Gorgonian 74
Palythoa caribaeorum 87
Sea plume 75
Sea rod 76
Sea whip 77
Zoanthids 88
Zoanthus sociatus 89

makeGroupedBenthicDat()

this is the second function that connects benthicDat to benthicCodes for all three programs.

makeGroupedBenthicDat() extracts the column indices (colinds) from each row of *_columnInds.

If only one index in colinds , assigns the corresponding column from benthicdat to the i-th column of a data frame _groupedBenthicDat.

if more than one index in colinds, stores row sum of benthicDat[,colinds] in the i-th column of _groupedBenthicDat.

arguments:

  • benthicDat is benthic dataset of interest

  • columnInds is the output of getBenthicDatColInds() above that contains column indices of benthic codes for each benthic subgroup of interest

Show code
makeGroupedBenthicDat <- function(benthicDat, columnInds) {
  groupeddat <- data.frame(matrix(nrow = nrow(benthicDat),
                                  ncol = nrow(columnInds)))
  colnames(groupeddat) <- columnInds$group
   benthicDat <- benthicDat %>% dplyr::mutate(dplyr::across(dplyr::where(is.numeric), ~replace(.x, is.na(.x), 0))) 
  for (i in 1:nrow(columnInds)) {
    geni <- columnInds[i,]
    datcoli <- unlist(geni$colinds)
    if (length(datcoli) == 1) {
      groupeddat[, i] <- benthicDat[, datcoli]
    } else {
      groupeddat[, i] <- rowSums(benthicDat[, datcoli])
    }
  }
  groupeddat <- cbind(benthicDat[, 1:6], groupeddat)
  return(groupeddat)
}

apply makeGroupedBenthicDat() to _benthicDat and _columnInds . preview tcrmp_groupedBenthicDat.

Show code
tcrmp_groupedBenthicDat <-
  makeGroupedBenthicDat(tcrmp_benthicDat, tcrmp_columnInds)
vinps_groupedBenthicDat <-
  makeGroupedBenthicDat(vinps_benthicDat, vinps_columnInds)

kbl(head(tcrmp_groupedBenthicDat)) |>
  kable_paper(full_width = F) |>
  kable_styling(
    fixed_thead = T,
    bootstrap_options = c("hover", "condensed"),
    font_size = 8
  ) |>
  scroll_box(width = "100%", height = "250px")
program date site period replicate replicatetype Briareum asbestinum Erythropodium caribaeorum Encrusting Gorgonian Sea fan Gorgonian Palythoa caribaeorum Sea plume Sea rod Sea whip Zoanthids Zoanthus sociatus
TCRMP 2001-04-25 Cane Bay Annual 1 transect 0 0 0 0 0.00 0 0 0 0 0 0
TCRMP 2001-04-25 Cane Bay Annual 2 transect 0 0 0 0 2.34 0 0 0 0 0 0
TCRMP 2001-04-25 Cane Bay Annual 3 transect 0 0 0 0 2.71 0 0 0 0 0 0
TCRMP 2001-04-25 Cane Bay Annual 4 transect 0 0 0 0 2.90 0 0 0 0 0 0
TCRMP 2001-04-25 Cane Bay Annual 5 transect 0 0 0 0 0.39 0 0 0 0 0 0
TCRMP 2001-04-25 Cane Bay Annual 6 transect 0 0 0 0 0.38 0 0 0 0 0 0

merge the benthicDat from three programs

now have three _groupedBenthicDat, need to merge them, start by comparing the column names, because some are missing from csun.

make sure each _groupedBenthicDat has the same column names

  • get unique column names across all data frames
Show code
all_columns <-
  unique(c(
    colnames(tcrmp_groupedBenthicDat),
    colnames(vinps_groupedBenthicDat)
    ))
  • identify missing columns in each data frame
Show code
missing_columns_tcrmp <-
  setdiff(all_columns, colnames(tcrmp_groupedBenthicDat))
missing_columns_vinps <-
  setdiff(all_columns, colnames(vinps_groupedBenthicDat))
  • add missing column with NAs.
Show code
for (col in missing_columns_tcrmp) {
  tcrmp_groupedBenthicDat[[col]] <- NA
}
for (col in missing_columns_vinps) {
  vinps_groupedBenthicDat[[col]] <- NA
}
  • reorder columns to match unique column order
Show code
tcrmp_groupedBenthicDat <- tcrmp_groupedBenthicDat[, all_columns]
vinps_groupedBenthicDat <- vinps_groupedBenthicDat[, all_columns]
  • combine the modified data frames using rbind to make groupedBenthicDat.
Show code
groupedBenthicDat <-
  rbind(tcrmp_groupedBenthicDat,
        vinps_groupedBenthicDat)
  • add column year
Show code
groupedBenthicDat <-
  cbind(year = lubridate::year(groupedBenthicDat$date),
        groupedBenthicDat)
  • melt groupedBenthicDat into long format.
Show code
groupedBenthicDat <- groupedBenthicDat |>
  tidyr::gather(!!groupingvar, "perccover", 8:ncol(groupedBenthicDat))

groupedBenthicDat <- groupedBenthicDat |>
  filter(!is.na(perccover))
  • make column pres to indicate whether zoanthidsGorgonians was present or absent
Show code
groupedBenthicDat$pres <- rep(0, nrow(groupedBenthicDat))
groupedBenthicDat$pres[groupedBenthicDat$perccover > 0] <- 1

Summarize and plot

For TCRMP and VINPS, the page calculates annual transect-averaged percent cover of gorgonian and zoantharian types at each site. Total cover is summed within each transect first, then averaged across transects with standard error, so the black total-cover points and their linerange reflect site-year replication.

Annual percentage total cover

Show code
totaldatCovSum <- groupedBenthicDat |>
  dplyr::group_by(year, date, program, site, period, replicate) |>
  dplyr::summarise(perccover = sum(perccover))

totaldatCovSum <- totaldatCovSum |>
  dplyr::group_by(year, date, program, site) |>
  dplyr::summarise(
    meancov = mean(perccover),
    sdcov = sd(perccover),
    secov = sd(perccover) / (sqrt(length(perccover))),
    n = length(perccover)
  )

totaldatCovSum <- totaldatCovSum %>% dplyr::mutate(dplyr::across(dplyr::where(is.numeric), ~replace(.x, is.na(.x), 0)))

Annual percentage cover of gorgonian/zoanthid types

Show code
groupedBenthicDatCovSum <- groupedBenthicDat |>
  dplyr::group_by(year, date, program, site, zoanthidsGorgonians) |>
  dplyr::summarise(
    meancov = mean(perccover),
    sdcov = sd(perccover),
    secov = sd(perccover) / (sqrt(length(perccover))),
    n = length(perccover)
  )
groupedBenthicDatCovSum <- groupedBenthicDatCovSum %>% dplyr::mutate(dplyr::across(dplyr::where(is.numeric), ~replace(.x, is.na(.x), 0)))

Plot

Figure 1 shows how each gorgonian and zoanthid type’s cover changes through time at every TCRMP and VINPS site, with facets ordered shallow to deep so depth patterns read down the panel. Stacked areas give each type’s contribution, and the black points with linerange give total cover with standard error.

Show code
#add site info so can plot according to increasing depth
groupedBenthicDatCovSum <-
  merge(groupedBenthicDatCovSum, sitedat, by = "site")
groupedBenthicDatCovSum <-
  groupedBenthicDatCovSum[order(groupedBenthicDatCovSum$depth), ]
groupedBenthicDatCovSum$site <- factor(groupedBenthicDatCovSum$site,
                                       levels = unique(groupedBenthicDatCovSum$site))

#add site info so can plot according to increasing depth
totaldatCovSum <-
  merge(totaldatCovSum, sitedat, by = "site")
totaldatCovSum <-
  totaldatCovSum[order(totaldatCovSum$depth), ]
totaldatCovSum$site <- factor(totaldatCovSum$site,
                              levels = unique(totaldatCovSum$site))

stack <- ggplot() +
  geom_area(
    data = groupedBenthicDatCovSum,
    aes(x = year, y = meancov, fill = zoanthidsGorgonians),
    position = 'stack'
  ) +
  # geom_line(data = totaldatCovSum, aes(x=year, y= meancov),color="black")+
  geom_point(
    data = totaldatCovSum,
    aes(x = year, y = meancov),
    color = "black",
    size = 0.5
  ) +
  geom_linerange(
    data = totaldatCovSum,
    aes(
      x = year,
      ymin = meancov - secov,
      ymax = meancov + secov
    ),
    color = "black",
    linewidth = 0.5
  ) +
  facet_wrap( ~ site, scales = "free_x") +
  ylab("percent cover") +
  scale_y_continuous(expand = c(0, 0)) +
  scale_x_continuous(
    expand = expansion(mult = 0.04),
    breaks = seq(minyear, maxyear, by = 1),
    labels = function(x)
        ifelse(x %% 5 == 0, paste0("'", substr(x, 3, 4)), "")
    ) +
  geom_vline(
    xintercept = 2005,
    color = "gray50",
    alpha = 0.5,
    lty = "dashed"
  ) +
  theme_bw() +
  theme(strip.text = element_text(size = 10)) +
  theme(legend.position = "bottom") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())

stack

# svg(filename="gorgzo.svg", width = 10, height =8)
# stack
# dev.off()
Sec 2.9 Figure 1: Percent cover of gorgonians and zoantharians over time at each site, separated by type. Sites are ordered from shallow to deep. Black points show average total cover +- SE. The dashed line marks the 2005 bleaching event.
TipKey result

Gorgonians and zoanthids occupy a modest share of benthic cover relative to coral and algae, so the stacked areas stay low across most sites. The site facets show which types are present at each depth and how their total cover shifts through the record, with TCRMP sites carrying the earliest years before VINPS surveys begin in 1999.

Downloads

What happens here: the page writes the long-format gorgonian and zoanthid cover table and its metadata to the shared outputs folder, then offers both plus the page source for download.

The gorgonian and zoanthid cover table (s2pt9_benthicCoverZoanthidGorgonians), its metadata, and this page’s .qmd source download below.


version 1.0.0 • in-review • data ≤ 2023