Set Up

Average Shrub Cover

calculate_uncovered_cm <- function(data, transect_length = 3000) {
  # Filter out rows where start or end is NA or both are zero
  data <- data %>%
    filter(!is.na(Line_Start), !is.na(Line_End)) %>%
    filter(!(Line_Start == 0 & Line_End == 0))
  
  # If no valid shrubs, entire transect is uncovered
  if (nrow(data) == 0) {
    return(transect_length)
  }
  
  # Sort by Line_Start
  data <- data[order(data$Line_Start, data$Line_End), ]
  
  # Create merged list
  merged <- list()
  current <- data[1, ]
  
  for (i in 2:nrow(data)) {
    next_row <- data[i, ]
    
    # If current and next overlap, merge them
    if (!is.na(next_row$Line_Start) && !is.na(current$Line_End) &&
        next_row$Line_Start <= current$Line_End) {
      current$Line_End <- max(current$Line_End, next_row$Line_End, na.rm = TRUE)
    } else {
      merged <- append(merged, list(current))
      current <- next_row
    }
  }
  merged <- append(merged, list(current))
  
  # Total covered length
  total_covered <- sum(sapply(merged, function(x) x$Line_End - x$Line_Start), na.rm = TRUE)
  
  # Uncovered length
  uncovered <- transect_length - total_covered
  return(uncovered)
}


no_shrub_cover <- shrub_data %>%
  group_by(Plot) %>%
  summarise(No_Shrub_Cover_cm = calculate_uncovered_cm(cur_data())) %>%
  ungroup()
## Warning: There was 1 warning in `summarise()`.
## ℹ In argument: `No_Shrub_Cover_cm = calculate_uncovered_cm(cur_data())`.
## ℹ In group 1: `Plot = "BI200"`.
## Caused by warning:
## ! `cur_data()` was deprecated in dplyr 1.1.0.
## ℹ Please use `pick()` instead.

Herbaceous Height

herbaceous_height <- fuel_data %>%
  mutate(Height = as.numeric(Height)) %>%   # Convert to numeric
  filter(!is.na(Height)) %>%                # Remove NA heights
  group_by(Plot) %>%
  summarise(Avg_Height = mean(Height, na.rm = TRUE)) %>%
  ungroup()
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Height = as.numeric(Height)`.
## Caused by warning:
## ! NAs introduced by coercion

Herbacous Height by Status

# 25th, 50th, and 75th percentiles of height by invasion status
Herb_height_status <- herbaceous_height %>%
  left_join(fuel_data %>% select(Plot, Status) %>% distinct(), by = "Plot") %>%
  group_by(Status) %>%
  summarise(
    Height_25th = quantile(Avg_Height, 0.25, na.rm = TRUE),
    Height_50th = quantile(Avg_Height, 0.50, na.rm = TRUE),
    Height_75th = quantile(Avg_Height, 0.75, na.rm = TRUE)
  ) %>%
  ungroup()

print(Herb_height_status)
## # A tibble: 2 × 4
##   Status      Height_25th Height_50th Height_75th
##   <chr>             <dbl>       <dbl>       <dbl>
## 1 Invaded            68.2        83.8       103. 
## 2 Non_Invaded        15          21.3        33.7

Shrub Percentile

no_shrub_cover <- no_shrub_cover %>%
  mutate(Percent_Shrub_Cover = 100 * (1 - No_Shrub_Cover_cm / 3000))

fuel_bed_data <- no_shrub_cover %>%
  left_join(fuel_data %>% select(Plot, Status) %>% distinct(), by = "Plot")

# Shrub percentile by status
shrub_percentile <- fuel_bed_data %>%
  group_by(Status) %>%
  summarise(
    Shrub_25th = quantile(Percent_Shrub_Cover, 0.25, na.rm = TRUE),
    Shrub_50th = quantile(Percent_Shrub_Cover, 0.50, na.rm = TRUE),
    Shrub_75th = quantile(Percent_Shrub_Cover, 0.75, na.rm = TRUE)
  ) %>%
  ungroup()

print(shrub_percentile)
## # A tibble: 2 × 4
##   Status      Shrub_25th Shrub_50th Shrub_75th
##   <chr>            <dbl>      <dbl>      <dbl>
## 1 Invaded           25.7       47.2       77.6
## 2 Non_Invaded       39.3       72.4       92.1

Option 2: Binned Quantiles

herb_status_joined <- herbaceous_height %>%
  left_join(fuel_data %>% select(Plot, Status) %>% distinct(), by = "Plot")

quantile_thresholds <- herb_status_joined %>%
  group_by(Status) %>%
  summarise(
    Q25 = quantile(Avg_Height, 0.25, na.rm = TRUE),
    Q50 = quantile(Avg_Height, 0.50, na.rm = TRUE),
    Q75 = quantile(Avg_Height, 0.75, na.rm = TRUE),
    .groups = "drop"
  )

# Bin to nearest quantile
herbaceous_height_bins <- herb_status_joined %>%
  left_join(quantile_thresholds, by = "Status") %>%
  rowwise() %>%
  mutate(
    Height_Class = c("Q25", "Q50", "Q75")[which.min(
      c(abs(Avg_Height - Q25), abs(Avg_Height - Q50), abs(Avg_Height - Q75))
    )]
  ) %>%
  ungroup() %>%
  select(Plot, Status, Avg_Height, Height_Class)

print(herbaceous_height_bins)
## # A tibble: 159 × 4
##    Plot  Status      Avg_Height Height_Class
##    <chr> <chr>            <dbl> <chr>       
##  1 BI200 Invaded          64.3  Q25         
##  2 BI201 Invaded          65.3  Q25         
##  3 BI202 Invaded          80.3  Q50         
##  4 BI97  Invaded          90    Q50         
##  5 BI99  Invaded          68    Q25         
##  6 BN210 Non_Invaded      13.3  Q25         
##  7 BN211 Non_Invaded      15.3  Q25         
##  8 BN212 Non_Invaded      27.3  Q50         
##  9 BN96  Non_Invaded      33.7  Q75         
## 10 BN98  Non_Invaded       8.33 Q25         
## # ℹ 149 more rows
# Average height in each bin
average_height_bins <- herbaceous_height_bins %>%
  group_by(Status, Height_Class) %>%
  summarise(
    Avg_Height = mean(Avg_Height, na.rm = TRUE),
    .groups = "drop"
  )

Shrub Cover by Height Bin

fuel_bed_Q <- no_shrub_cover %>%
  left_join(herbaceous_height_bins %>% select(Plot, Status, Height_Class, Avg_Height) %>% distinct(), by = "Plot")


# Calculate average shrub cover per height bin (and status)
shrub_cover_by_height_bin <- fuel_bed_Q %>%
  group_by(Status, Height_Class) %>%
  summarise(
    Avg_Height = mean(Avg_Height, na.rm = TRUE),
    Avg_Shrub_Cover = mean(Percent_Shrub_Cover, na.rm = TRUE),
    Count = n(),
    .groups = "drop"
  )

print(shrub_cover_by_height_bin)
## # A tibble: 6 × 5
##   Status      Height_Class Avg_Height Avg_Shrub_Cover Count
##   <chr>       <chr>             <dbl>           <dbl> <int>
## 1 Invaded     Q25                59.8            66.9    27
## 2 Invaded     Q50                84.1            49.8    21
## 3 Invaded     Q75               110.             33.8    30
## 4 Non_Invaded Q25                11.6            65.7    30
## 5 Non_Invaded Q50                21.8            64.1    17
## 6 Non_Invaded Q75                40.9            64.2    34
kable(shrub_cover_by_height_bin, caption = "Average Shrub Cover by Height Bin and Status", format = "html", table.attr = "class='table table-striped'")
Average Shrub Cover by Height Bin and Status
Status Height_Class Avg_Height Avg_Shrub_Cover Count
Invaded Q25 59.84691 66.91852 27
Invaded Q50 84.12698 49.75397 21
Invaded Q75 109.51111 33.79778 30
Non_Invaded Q25 11.55000 65.73778 30
Non_Invaded Q50 21.82353 64.05686 17
Non_Invaded Q75 40.88235 64.15196 34