Nothing
# Declare global variables to avoid R CMD check warnings
utils::globalVariables(c("Hcbh", "Hdepth", "Hdepth1", "Hdist", "Hdist1",
"cbh", "cbh1", "depth", "depth1", "dist1",
"gap", "index1", "last_cbh", "last_nonzero_Hdist",
"max_dist", "temp_Hdepth", "temp_depth",
"total_depth", "total_dist"))
#' Effective fuel layers depth
#' @description This function recalculates fuel layers depth after considering distances greater than the actual height bin step.
#' @usage get_real_depths (effective_fbh, step=1, min_height=1.5, verbose=TRUE)
#' @param effective_fbh tree metrics with the recalculated base height of fuel layers after considering distances greater than any number of height bin steps
#' (output of [get_real_fbh()] function).An object of the class text.
#' @param step Numeric value for the actual height bin step (in meters).
#' @param min_height Numeric value for the actual minimum base height (in meters).
#' @param verbose Logical, indicating whether to display informational messages (default is TRUE).
#' @return A data frame giving new fuel layers depth after considering distances greater than the actual height bin step.
#' @author Olga Viedma, Carlos Silva, JM Moreno and A.T. Hudak
#'
#' @details
#' # List of tree metrics:
#' \itemize{
#' \item treeID: tree ID with strings and numeric values
#' \item treeID1: tree ID with only numeric values
#' \item dist: Distance between consecutive fuel layers (m)
#' \item Hdist - Height of the distance between consecutive fuel layers (m)
#' \item Hcbh - Base height of each fuel separated by a distance greater than the certain number of steps
#' \item dptf - Depth of fuel layers (m) after considering distances greater than the actual height bin step
#' \item Hdptf - Height of the depth of fuel layers (m) after considering distances greater than the actual height bin step
#' \item max_height - Maximum height of the tree profile
#' }
#' @examples
#' library(magrittr)
#' library(tidyr)
#' library(dplyr)
#'
#' # Before running this example, make sure to run get_real_fbh().
#' if (interactive()) {
#' effective_fbh <- get_real_fbh()
#' LadderFuelsR::effective_fbh$treeID <- factor(LadderFuelsR::effective_fbh$treeID)
#'
#' trees_name1 <- as.character(effective_fbh$treeID)
#' trees_name2 <- factor(unique(trees_name1))
#'
#' depth_metrics_corr_list <- list()
#'
#' for (i in levels(trees_name2)){
#' # Filter data for each tree
#' tree3 <- effective_fbh |> dplyr::filter(treeID == i)
#' # Get real depths for each tree
#' depth_metrics_corr <- get_real_depths(tree3, step=1, min_height=1.5,verbose=TRUE)
#' depth_metrics_corr_list[[i]] <- depth_metrics_corr
#' }
#'
#' # Combine depth values for all trees
#' effective_depth <- dplyr::bind_rows(depth_metrics_corr_list)
#'
#' # Reorder columns
#' original_column_names <- colnames(effective_depth)
#'
#' # Specify prefixes
#' desired_order <- c("treeID", "Hcbh", "dptf", "dist", "Hdist", "Hdptf", "max_height")
#'
#' # Identify unique prefixes
#' prefixes <- unique(sub("^([a-zA-Z]+).*", "\\1", original_column_names))
#' # Initialize vector to store new order
#' new_order <- c()
#'
#' # Loop over desired order of prefixes
#' for (prefix in desired_order) {
#' # Find column names matching the current prefix
#' matching_columns <- grep(paste0("^", prefix), original_column_names, value = TRUE)
#' # Append to the new order
#' new_order <- c(new_order, matching_columns)
#' }
#' effective_depth <- effective_depth[, new_order]
#' }
#' @importFrom dplyr select_if group_by summarise summarize mutate arrange rename rename_with filter slice slice_tail ungroup distinct
#' across matches row_number all_of vars bind_cols case_when left_join mutate if_else lag n_distinct
#' @importFrom segmented segmented seg.control
#' @importFrom magrittr %>%
#' @importFrom stats ave dist lm na.omit predict quantile setNames smooth.spline
#' @importFrom utils tail
#' @importFrom tidyselect starts_with everything one_of
#' @importFrom stringr str_extract str_match str_detect str_remove_all
#' @importFrom tibble tibble
#' @importFrom tidyr pivot_longer fill pivot_wider replace_na
#' @importFrom gdata startsWith
#' @importFrom ggplot2 aes geom_line geom_path geom_point geom_polygon geom_text geom_vline ggtitle coord_flip theme_bw
#' theme element_text xlab ylab ggplot xlim
#' @seealso \code{\link{get_renamed0_df}}
#' @seealso \code{\link{get_real_fbh}}
#' @export
get_real_depths <- function (effective_fbh, step=1, min_height=1.5, verbose=TRUE) {
if(min_height==0){
min_height <-0.5
}
#remove the columns from the dataframe df2a which contain only NA values.
df<- effective_fbh
df2a <- df[, colSums(!is.na(df)) > 0]
if (verbose) {
message("Unique treeIDs:", paste(unique(df2a$treeID), collapse = ", "))
}
# Rename cbh columns to Hcbh with their numeric suffixes
names(df2a) <- gsub("^cbh", "Hcbh", names(df2a))
##check if the first "dist" column has a value greater than 1. If this is true, then it will remove depth0 in computation
# Identify the "dist" and "depth" column names
dist_cols <- grep("^dist", colnames(df2a), value = TRUE)
if (length(dist_cols) == 0) {
df2a$dist1 <- 0
}
if (length(dist_cols) == 1 && all(df2a$Hcbh1 <= min_height)) {
df2a$dist1 <- 0
df2a$Hdist1 <- min_height
}
if (length(dist_cols) == 1 && all(df2a$Hcbh1 > min_height) && all(df2a$Hcbh1 > step)) {
df2a$Hdist1 <- abs(df2a$Hcbh1 - step)
df2a$dist1 <- floor(df2a$Hcbh1 - step)
}
if (length(dist_cols) == 1 && all(df2a$Hcbh1 > min_height) && all(df2a$Hcbh1 == step)) {
df2a$Hdist1 <- df2a$Hcbh1
df2a$dist1 <- df2a$Hdist1
}
if (all(df2a$Hcbh1 > min_height) && all(df2a$Hcbh1 > step)) {
df2a$Hdist1 <- abs(df2a$Hcbh1 - step)
df2a$dist1 <- floor(df2a$Hcbh1 - step)
}
if (all(df2a$Hcbh1 > min_height) && all(df2a$Hcbh1 == step)) {
df2a$Hdist1 <- df2a$Hcbh1
df2a$dist1 <- df2a$Hdist1
}
if (all(df2a$Hcbh1 <= min_height)) {
df2a$dist1 <- 0
df2a$Hdist1 <- min_height
}
if (all(df2a$Hcbh1 <= min_height) && all(df2a$Hdepth1 == 0)) {
df2a$dist1 <- 0
df2a$Hdist1 <- min_height
df2a$Hdepth1 <- min_height
}
df4 <- df2a
# Function to extract prefix and suffix
extract_prefix_suffix <- function(colname) {
match <- regexpr("\\d+$", colname)
if (match == -1) {
prefix <- colname
suffix <- NA
} else {
prefix <- substr(colname, 1, match - 1)
suffix <- as.integer(substr(colname, match, nchar(colname)))
}
list(prefix = prefix, suffix = suffix)
}
# Apply the function to the column names
col_info <- sapply(names(df2a), extract_prefix_suffix, simplify = FALSE)
# Convert to a dataframe for better readability
col_info_df <- do.call(rbind, lapply(col_info, as.data.frame))
col_info_df <- cbind(col_name = names(df2a), col_info_df)
rownames(col_info_df) <- NULL
col_info_df$colname <- names(df2a)
# Ordenar por prefijo y luego por sufijo numérico
col_info_df <- col_info_df[order(col_info_df$prefix, col_info_df$suffix), ]
# Reordenar las columnas del dataframe original segĂșn el orden calculado
df4 <- df4[, col_info_df$colname]
#########################################################3
# Identify Hcbh and Hdepth columns
Hcbh_cols <- grep("^Hcbh", names(df4), value = TRUE)
Hdepth_cols <- grep("^Hdepth", names(df4), value = TRUE)
depth_cols <- grep("^depth", names(df4), value = TRUE)
# Check if more Hcbh columns than Hdepth columns
if (length(Hcbh_cols) > length(Hdepth_cols)) {
# Calculate how many new Hdepth columns to create
num_new_Hdepth <- length(Hcbh_cols) - length(Hdepth_cols)
# Get the values from the last existing Hdepth column
last_Hdepth_col <- df4[[tail(Hdepth_cols, 1)]]
# Create new Hdepth columns with the values from the last existing column
for (i in seq_len(num_new_Hdepth)) {
new_col_name <- paste0("Hdepth", length(Hdepth_cols) + i)
df4[[new_col_name]] <- last_Hdepth_col
}
}
# Check if more Hcbh columns than depth columns
if (length(Hcbh_cols) > length(depth_cols)) {
# Calculate how many new depth columns to create
num_new_depth <- length(Hcbh_cols) - length(depth_cols)
# Get the values from the last existing depth column
last_depth_col <- df4[[tail(depth_cols, 1)]]
# Create new depth columns with the values from the last existing column
for (i in seq_len(num_new_depth)) {
new_col_name <- paste0("depth", length(depth_cols) + i)
df4[[new_col_name]] <- last_depth_col
}
}
#######################################3
# Identify the "dist" and "depth" column names
dist_cols <- grep("^dist", colnames(df4), value = TRUE)
depth_cols <- grep("^depth", colnames(df4), value = TRUE)
Hdepth_cols <- grep("^Hdepth", colnames(df4), value = TRUE)
Hcbh_cols <- grep("^Hcbh", colnames(df4), value = TRUE)
cols_to_transpose <- colnames(df4)
# Exclude both treeID and treeID1 columns from transposition
cols_to_transpose <- setdiff(cols_to_transpose, c("treeID", "treeID1","treeID2", "max1", "max_height"))
# Transpose the dataframe excluding treeID and treeID1 columns
df_transposed0 <- df4 %>%
dplyr::select(all_of(cols_to_transpose)) %>%
pivot_longer(cols = everything(), names_to = c(".value", "index"), names_pattern = "(\\D+)(\\d+)?")
index<-df_transposed0$index
df_transposed0 <- df_transposed0 %>%
dplyr::arrange(as.numeric(index))
Hdepth<- df_transposed0$Hdepth
###############################################
df_transposed <- df_transposed0
# Define a function to update depth based on conditions
update_depth_if_needed <- function(df) {
for (i in seq_len(nrow(df))) {
if (is.na(df$depth[i]) && !is.na(df$Hdepth[i])) {
df$depth[i] <- abs(df$Hdepth[i] - df$Hcbh[i])
}
}
return(df)
}
df_transposed <- update_depth_if_needed(df_transposed)
#####################################
# Function to move Hdepth values based on Hdist condition
move_Hdepth <- function(df) {
# Identify the Hdepth values to move and their original indices
Hdepth_values <- df$Hdepth[df$Hdepth > 0 & !is.na(df$Hdepth)]
original_indices <- which(df$Hdepth > 0 & !is.na(df$Hdepth))
# Identify the indices where Hdist > 0 and are not NA
Hdist_indices <- which(df$Hdist > 0 & !is.na(df$Hdist))
# Ensure there are enough indices to move Hdepth values to
num_to_move <- min(length(Hdepth_values), length(Hdist_indices))
# Create a new vector to store the moved Hdepth values
new_Hdepth <- df$Hdepth
# Move each Hdepth value to the corresponding row where Hdist > 0
for (i in seq_len(num_to_move)) {
new_Hdepth[Hdist_indices[i]] <- Hdepth_values[i]
}
# Assign the updated Hdepth values back to the dataframe
df$Hdepth <- new_Hdepth
# Convert Hdepth values to NA where Hdist is 0 or NA
df$Hdepth <- if_else(df$Hdist == 0 | is.na(df$Hdist), NA_real_, df$Hdepth)
return(df)
}
# Apply the function
df_transposed_updated <- move_Hdepth(df_transposed)
########################################
move_depth <- function(df) {
# Identify the depth values to move and their original indices
depth_values <- df$depth[df$depth > 0 & !is.na(df$depth)]
original_indices <- which(df$depth > 0 & !is.na(df$depth))
# Identify the indices where Hdist > 0 and are not NA
Hdist_indices <- which(df$Hdist > 0 & !is.na(df$Hdist))
# Ensure there are enough indices to move depth values to
num_to_move <- min(length(depth_values), length(Hdist_indices))
# Create a new vector to store the moved depth values
new_depth <- df$depth
# Move each depth value to the corresponding row where Hdist > 0
for (i in seq_len(num_to_move)) {
new_depth[Hdist_indices[i]] <- depth_values[i]
}
# Assign the updated depth values back to the dataframe
df$depth <- new_depth
# Convert depth values to NA where Hdist is 0 or NA
df$depth <- if_else(df$Hdist == 0 | is.na(df$Hdist), NA_real_, df$depth)
return(df)
}
# Apply the function
df_transposed_updated1 <- move_depth(df_transposed_updated)
########################################
# Convert NA values in Hdist to 0
df_transposed_updated1 <- df_transposed_updated1 %>%
dplyr::mutate(Hdist = replace_na(Hdist, 0))
# Propagate last non-NA Hcbh value into NA rows
df_transposed_updated1 <- df_transposed_updated1 %>%
dplyr::mutate(Hcbh = if_else(is.na(Hcbh), lag(Hcbh, default = Hcbh[1]), Hcbh))
########################################
# Propagate the last depth value > 0 into NA or 0 values
df_transposed_updated1 <- df_transposed_updated1 %>%
group_by(Hcbh) %>%
mutate(temp_depth = if_else(depth > 0, depth, NA_real_)) %>%
fill(temp_depth, .direction = "down") %>%
mutate(depth = if_else(is.na(depth) | depth == 0, temp_depth, depth)) %>%
dplyr::select(-temp_depth) %>%
ungroup()
# Propagate the last Hdist value > 0
df_transposed_updated1 <- df_transposed_updated1 %>%
dplyr::group_by(Hcbh) %>%
dplyr::mutate(last_nonzero_Hdist = last(na.omit(Hdist[Hdist > 0]), default = dplyr::first(na.omit(Hdist[Hdist > 0]))),
Hdist = if_else(is.na(Hdist) | Hdist == 0, last_nonzero_Hdist, Hdist)) %>%
dplyr::select(-last_nonzero_Hdist) %>%
dplyr::ungroup()
# Propagate the last Hdepth value > 0
df_transposed_updated1 <- df_transposed_updated1 %>%
dplyr::group_by(Hcbh) %>%
dplyr::mutate(temp_Hdepth = if_else(Hdepth > 0, Hdepth, lag(Hdepth, default = Hdepth[1]))) %>%
fill(temp_Hdepth, .direction = "down") %>%
dplyr::mutate(Hdepth = if_else(is.na(Hdepth) | Hdepth == 0, temp_Hdepth, Hdepth)) %>%
dplyr::select(-temp_Hdepth) %>%
dplyr::ungroup()
# Keep only the last row of duplicated Hcbh values and retain maximum dist
# Assign the maximum dist value to all rows in groups before filtering
# Compute the maximum dist for each Hcbh group
max_dist_per_Hcbh <- df_transposed_updated1 %>%
dplyr::group_by(Hcbh) %>%
dplyr::summarize(max_dist = max(dist), .groups = 'drop')
# Join the max dist back to the original dataframe and update dist
df_transposed_updated1 <- df_transposed_updated1 %>%
left_join(max_dist_per_Hcbh, by = "Hcbh") %>%
dplyr::mutate(dist = if_else(Hcbh %in% Hcbh[duplicated(Hcbh)], max_dist, dist)) %>%
dplyr::select(-max_dist)
#########################################
# Filter to keep rows with max Hdepth for each unique Hcbh, avoiding NA values in Hdepth
df_transposed_updated1 <- df_transposed_updated1 %>%
group_by(Hcbh) %>%
dplyr::filter(
!is.na(Hdepth) & Hdepth == max(Hdepth, na.rm = TRUE)) %>%
ungroup()
#########################################
# Check if all Hdist values are non-NA and greater than 0
if (all(!is.na(df_transposed_updated1$Hdist)) && all(df_transposed_updated1$Hdist > 0)) {
# Summarize dist and depth for duplicated Hcbh values
df_transposed_summarized <- df_transposed_updated1 %>%
dplyr::group_by(Hcbh) %>%
dplyr::summarize(
total_depth = sum(depth) + sum(dist[-dplyr::n()]), # sum of all depth + sum of dist excluding last
total_dist = sum(dist),
Hdepth = max(Hdepth),
Hdist = max(Hdist),
.groups = 'drop'
) %>%
dplyr::ungroup() %>%
dplyr::mutate(index = row_number()) %>%
dplyr::select(index, total_depth, total_dist, Hcbh, Hdepth, Hdist) %>%
dplyr::rename(depth = total_depth, dist = total_dist)
# #print the summarized dataframe
#print(df_transposed_summarized)
} else {
#print("Not all Hdist values are non-NA and greater than 0.")
}
if (exists ("df_transposed_summarized")) {
df_transposed_updated1 <-df_transposed_summarized
} else {
df_transposed_updated1 <-df_transposed_updated1
}
#########################################
# Filter to keep rows with max Hdepth for each unique Hcbh, avoiding NA values in Hdepth
df_transposed_updated1 <- df_transposed_updated1 %>%
group_by(Hcbh) %>%
dplyr::filter(
!is.na(Hdepth) & Hdepth == max(Hdepth, na.rm = TRUE)) %>%
ungroup()
# Keep only the first row with duplicated values in all variables
df_transposed_updated1 <- df_transposed_updated1 %>%
distinct(depth, Hcbh, Hdepth, Hdist, .keep_all = TRUE)
update_hdist <- function(df) {
# Check if dataframe has exactly one row
if (nrow(df) == 1) {
# Check if Hdist > Hcbh
if (df$Hdist > df$Hcbh) {
# Update Hdist to be equal to Hcbh
df$Hdist <- df$Hcbh -step
}
}
return(df)
}
df_transposed_updated1 <- update_hdist(df_transposed_updated1)
all_equal<- n_distinct(df_transposed_updated1$Hcbh) == 1
if (nrow(df_transposed_updated1) ==2 && all_equal) {
# Loop to Hdist > Hcbh with the previous non-NA value
for (i in 1:nrow(df_transposed_updated1)) {
df_transposed_updated1$depth[i] <- round(df_transposed_updated1$dist[i + 1] + df_transposed_updated1$dist [i] + df_transposed_updated1$depth [i + 1] + df_transposed_updated1$depth [i], 0)
}
df_transposed_updated1 <- df_transposed_updated1 %>%
group_by(Hdist) %>%
summarise(
dist = max(dist),
Hcbh = max(Hcbh),
depth = max(depth, na.rm =T),
Hdepth = max(Hdepth)
)
}
##########################################33
cols_to_transpose <- grep("^Hdepth", colnames(df_transposed_updated1), value = TRUE)
df_transposed_updated1$index <- 1:nrow(df_transposed_updated1)
df_wide <- df_transposed_updated1 %>%
pivot_wider(names_from = index, values_from = c(all_of(cols_to_transpose), dist, depth, Hcbh,Hdist))
df_single1 <- df_wide %>%
dplyr::summarize(across(everything(), ~na.omit(.x)[1]))
df_single1 <- df_single1 %>%
dplyr::select_if(~!any(is.na(.)))
df5b<-cbind.data.frame(df_single1)
df5b <- df5b %>%
dplyr::rename_with(~gsub("^Hdepth", "Hdptf", .), starts_with("Hdepth"))
df5b <- df5b %>%
dplyr::rename_with(~gsub("^depth", "dptf", .), starts_with("depth"))
# Remove underscores from column names
df5b <- df5b %>%
rename_with(~ str_remove_all(., "_"), everything())
#######################################
update_hdepth <- function(df) {
# Get column names of Hdepth and Hcbh
hdepth_cols <- grep("^Hdptf\\d+$", names(df), value = TRUE)
hcbh_cols <- grep("^Hcbh\\d+$", names(df), value = TRUE)
# Iterate over each pair of columns
for (i in seq_along(hdepth_cols)) {
hdepth_col <- hdepth_cols[i]
hcbh_col <- hcbh_cols[i]
# Update Hdepth column where Hdepth < Hcbh
df[[hdepth_col]] <- pmax(df[[hdepth_col]], df[[hcbh_col]])
}
return(df)
}
df5b <- update_hdepth(df5b)
################### rename columns
# Extract unique prefixes
prefixes <- unique(gsub("([a-zA-Z]+).*", "\\1", names(df5b)))
# Rename the columns based on the extracted prefixes
for (prefix in prefixes) {
# Identify columns with the current prefix
cols <- grep(paste0("^", prefix), names(df5b))
# Generate new column names with consecutive suffixes
new_names <- paste0(prefix, 1:length(cols))
# Assign new names to the columns
names(df5b)[cols] <- new_names
}
if (df5b$Hcbh1 == min_height) {
df5b$Hdist1 <- min_height
df5b$dist1 <- 0
}
######### CORRECT DPTF ##################################################
correct_dptf <- function(df) {
# Get column names related to Hcbh and Hdist
hcbh_cols <- grep("^Hcbh", names(df), value = TRUE)
hdptf_cols <- grep("^Hdptf", names(df), value = TRUE)
# Initialize a vector to store new dptf column names
new_dptf_cols <- character(0)
# Iterate over each pair of Hcbh and Hdist columns
for (i in seq_along(hcbh_cols)) {
hcbh_col <- hcbh_cols[i]
hdptf_col <- hdptf_cols[i]
# Update dptf values based on the formula: dptf = hdptf - hcbh
index <- sub("^Hcbh_", "", hcbh_col)
dptf_col <- paste0("dptf", index)
df[[dptf_col]] <- df[[hdptf_col]] - df[[hcbh_col]]
# Store the new dptf column name
new_dptf_cols <- c(new_dptf_cols, dptf_col)
}
# Remove old dptf columns that have corresponding Hdptf columns
for (dptf_col in new_dptf_cols) {
hdptf_col <- gsub("^dptf", "Hdptf", dptf_col)
if (hdptf_col %in% colnames(df)) {
df[[dptf_col]] <- df[[dptf_col]]
df[[dptf_col]] <- NULL
}
}
# Update dptf columns with the values of dptfHcbh columns
dptfHcbh_cols <- grep("^dptfHcbh", names(df), value = TRUE)
for (dptfHcbh_col in dptfHcbh_cols) {
dptf_col <- gsub("^dptfHcbh", "dptf", dptfHcbh_col)
df[[dptf_col]] <- df[[dptfHcbh_col]]
}
# Remove dptfHcbh columns
df <- df[, !grepl("^dptfHcbh", names(df))]
# #print the updated dataframe
##print(df)
}
# Apply the function to your dataframe (replace df5b with your dataframe name)
df5b <- correct_dptf(df5b)
# Replace 0 values with 1 in dptf columns
df5b <- df5b %>%
dplyr::mutate(across(starts_with("dptf"), ~ ifelse(. == 0, 1, .)))
############################################
treeID<-unique(factor(df$treeID))
if(!"treeID" %in% colnames(df5b)) {
df5b <- cbind(df[c("treeID","treeID1")],df5b )
}
max_height<-data.frame(df$max_height)
names(max_height)<-"max_height"
if(!"max_height" %in% colnames(df5b)) {
df5b <- cbind(df5b,df[c("max_height")])
}
effective_depth<-df5b
dptf_cols <- grep("^dptf", colnames(effective_depth), value = TRUE)
# Apply floor to all identified columns
effective_depth <- effective_depth %>%
mutate(across(all_of(dptf_cols), ceiling))
return (effective_depth)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.