}) # Verify farm_health_data exists and has content if (!exists("farm_health_data") || nrow(farm_health_data) == 0) { safe_log("farm_health_data not found or empty, generating default data", "WARNING") # Create minimal fallback data tryCatch({ # Get fields from boundaries fields <- unique(AllPivots0$field) # Create basic data frame with just field names farm_health_data <- data.frame( field = fields, mean_ci = rep(NA, length(fields)), ci_change = rep(NA, length(fields)), ci_uniformity = rep(NA, length(fields)), status = rep("Unknown", length(fields)), anomaly_type = rep("Unknown", length(fields)), priority_level = rep(5, length(fields)), # Low priority age_weeks = rep(NA, length(fields)), harvest_readiness = rep("Unknown", length(fields)), stringsAsFactors = FALSE ) safe_log("Created fallback farm_health_data with basic field information") }, error = function(e) { safe_log(paste("Error creating fallback farm_health_data:", e$message), "ERROR") farm_health_data <<- data.frame( field = character(), mean_ci = numeric(), ci_change = numeric(), ci_uniformity = numeric(), status = character(), anomaly_type = character(), priority_level = numeric(), age_weeks = numeric(), harvest_readiness = character(), stringsAsFactors = FALSE ) }) } # Calculate farm health summary metrics tryCatch({ # Generate farm health summary data farm_health_data <- generate_farm_health_summary( field_boundaries = AllPivots0, ci_current = CI, ci_previous = CI_m1, harvesting_data = harvesting_data ) # Log the summary data safe_log(paste("Generated farm health summary with", nrow(farm_health_data), "fields")) }, error = function(e) { safe_log(paste("Error in farm health calculation:", e$message), "ERROR") # Create empty dataframe if calculation failed farm_health_data <- data.frame( field = character(), mean_ci = numeric(), ci_change = numeric(), ci_uniformity = numeric(), status = character(), anomaly_type = character(), priority_level = numeric(), age_weeks = numeric(), harvest_readiness = character(), stringsAsFactors = FALSE ) }) # Render the velocity and acceleration indicators tryCatch({ # Create and display the indicators using the imported utility function velocity_plot <- create_velocity_acceleration_indicator( health_data = farm_health_data, ci_current = CI, ci_prev1 = CI_m1, ci_prev2 = CI_m2, ci_prev3 = CI_m3, field_boundaries = AllPivots0 ) # Print the visualization print(velocity_plot) # Create a table of fields with significant velocity changes field_ci_metrics <- list() # Process each field to get metrics fields <- unique(AllPivots0$field) for (field_name in fields) { tryCatch({ # Get field boundary field_shape <- AllPivots0 %>% dplyr::filter(field == field_name) if (nrow(field_shape) == 0) next # Extract CI values ci_curr_values <- terra::extract(CI, field_shape) ci_prev1_values <- terra::extract(CI_m1, field_shape) # Calculate metrics mean_ci_curr <- mean(ci_curr_values$CI, na.rm = TRUE) mean_ci_prev1 <- mean(ci_prev1_values$CI, na.rm = TRUE) velocity <- mean_ci_curr - mean_ci_prev1 # Store in list field_ci_metrics[[field_name]] <- list( field = field_name, ci_current = mean_ci_curr, ci_prev1 = mean_ci_prev1, velocity = velocity ) }, error = function(e) { safe_log(paste("Error processing field", field_name, "for velocity table:", e$message), "WARNING") }) } # Convert list to data frame velocity_df <- do.call(rbind, lapply(field_ci_metrics, function(x) { data.frame( field = x$field, ci_current = round(x$ci_current, 2), ci_prev1 = round(x$ci_prev1, 2), velocity = round(x$velocity, 2), direction = ifelse(x$velocity >= 0, "Improving", "Declining") ) })) # Select top 5 positive and top 5 negative velocity fields top_positive <- velocity_df %>% dplyr::filter(velocity > 0) %>% dplyr::arrange(desc(velocity)) %>% dplyr::slice_head(n = 5) top_negative <- velocity_df %>% dplyr::filter(velocity < 0) %>% dplyr::arrange(velocity) %>% dplyr::slice_head(n = 5) # Display the tables if we have data if (nrow(top_positive) > 0) { cat("

Fields with Fastest Improvement

") knitr::kable(top_positive %>% dplyr::select(Field = field, `Current CI` = ci_current, `Previous CI` = ci_prev1, `Weekly Change` = velocity)) } if (nrow(top_negative) > 0) { cat("

Fields with Fastest Decline

") knitr::kable(top_negative %>% dplyr::select(Field = field, `Current CI` = ci_current, `Previous CI` = ci_prev1, `Weekly Change` = velocity)) } }, error = function(e) { safe_log(paste("Error rendering velocity visualization:", e$message), "ERROR") cat("
Error generating velocity visualization.
") }) # Generate anomaly timeline visualization tryCatch({ # Use the imported function to create the anomaly timeline anomaly_timeline <- create_anomaly_timeline( field_boundaries = AllPivots0, ci_data = CI_quadrant, days_to_include = 90 # Show last 90 days of data ) # Display the timeline print(anomaly_timeline) }, error = function(e) { safe_log(paste("Error generating anomaly timeline:", e$message), "ERROR") cat("
Error generating anomaly timeline visualization.
") }) # Verify farm_health_data exists and has content if (!exists("farm_health_data") || nrow(farm_health_data) == 0) { safe_log("farm_health_data not found or empty, generating default data", "WARNING") # Create minimal fallback data tryCatch({ # Get fields from boundaries fields <- unique(AllPivots0$field) # Create basic data frame with just field names farm_health_data <- data.frame( field = fields, mean_ci = rep(NA, length(fields)), ci_change = rep(NA, length(fields)), ci_uniformity = rep(NA, length(fields)), status = rep("Unknown", length(fields)), anomaly_type = rep("Unknown", length(fields)), priority_level = rep(5, length(fields)), # Low priority age_weeks = rep(NA, length(fields)), harvest_readiness = rep("Unknown", length(fields)), stringsAsFactors = FALSE ) safe_log("Created fallback farm_health_data with basic field information") }, error = function(e) { safe_log(paste("Error creating fallback farm_health_data:", e$message), "ERROR") farm_health_data <<- data.frame( field = character(), mean_ci = numeric(), ci_change = numeric(), ci_uniformity = numeric(), status = character(), anomaly_type = character(), priority_level = numeric(), age_weeks = numeric(), harvest_readiness = character(), stringsAsFactors = FALSE ) }) } # ADVANCED ANALYTICS FUNCTIONS # Note: These functions are now imported from executive_report_utils.R # The utility file contains functions for velocity/acceleration indicators, # anomaly timeline creation, age cohort mapping, and cohort performance charts safe_log("Using analytics functions from executive_report_utils.R") # Chunk 1: setup_parameters # Set up basic report parameters from input values report_date <- params$report_date mail_day <- params$mail_day borders <- params$borders use_breaks <- params$use_breaks # Whether to use breaks or continuous spectrum in visualizations # Environment setup notes (commented out) # # Activeer de renv omgeving # renv::activate() # renv::deactivate() # # Optioneel: Herstel de omgeving als dat nodig is # # Je kunt dit commentaar geven als je het normaal niet wilt uitvoeren # renv::restore() # Chunk 2: load_libraries # Configure knitr options knitr::opts_chunk$set(warning = FALSE, message = FALSE) # Path management library(here) # Spatial data libraries library(sf) library(terra) library(exactextractr) # library(raster) - Removed as it's no longer maintained # Data manipulation and visualization library(tidyverse) # Includes dplyr, ggplot2, etc. library(tmap) library(lubridate) library(zoo) # Machine learning library(rsample) library(caret) library(randomForest) library(CAST) # Load custom utility functions tryCatch({ source("report_utils.R") }, error = function(e) { message(paste("Error loading report_utils.R:", e$message)) # Try alternative path if the first one fails tryCatch({ source(here::here("r_app", "report_utils.R")) }, error = function(e) { stop("Could not load report_utils.R from either location: ", e$message) }) }) # Load executive report utilities tryCatch({ source("executive_report_utils.R") }, error = function(e) { message(paste("Error loading executive_report_utils.R:", e$message)) # Try alternative path if the first one fails tryCatch({ source(here::here("r_app", "executive_report_utils.R")) }, error = function(e) { stop("Could not load executive_report_utils.R from either location: ", e$message) }) }) # Chunk 1: setup_parameters # Set up basic report parameters from input values report_date <- params$report_date mail_day <- params$mail_day borders <- params$borders use_breaks <- params$use_breaks # Whether to use breaks or continuous spectrum in visualizations # Environment setup notes (commented out) # # Activeer de renv omgeving # renv::activate() # renv::deactivate() # # Optioneel: Herstel de omgeving als dat nodig is # # Je kunt dit commentaar geven als je het normaal niet wilt uitvoeren # renv::restore() # Chunk 2: load_libraries # Configure knitr options knitr::opts_chunk$set(warning = FALSE, message = FALSE) # Path management library(here) # Spatial data libraries library(sf) library(terra) library(exactextractr) # library(raster) - Removed as it's no longer maintained # Data manipulation and visualization library(tidyverse) # Includes dplyr, ggplot2, etc. library(tmap) library(lubridate) library(zoo) # Machine learning library(rsample) library(caret) library(randomForest) library(CAST) # Load custom utility functions tryCatch({ source("report_utils.R") }, error = function(e) { message(paste("Error loading report_utils.R:", e$message)) # Try alternative path if the first one fails tryCatch({ source(here::here("r_app", "report_utils.R")) }, error = function(e) { stop("Could not load report_utils.R from either location: ", e$message) }) }) # Load executive report utilities tryCatch({ source("executive_report_utils.R") }, error = function(e) { message(paste("Error loading executive_report_utils.R:", e$message)) # Try alternative path if the first one fails tryCatch({ source(here::here("r_app", "executive_report_utils.R")) }, error = function(e) { stop("Could not load executive_report_utils.R from either location: ", e$message) }) }) # Chunk 1: setup_parameters # Set up basic report parameters from input values report_date <- params$report_date mail_day <- params$mail_day borders <- params$borders use_breaks <- params$use_breaks # Whether to use breaks or continuous spectrum in visualizations # Environment setup notes (commented out) # # Activeer de renv omgeving # renv::activate() # renv::deactivate() # # Optioneel: Herstel de omgeving als dat nodig is # # Je kunt dit commentaar geven als je het normaal niet wilt uitvoeren # renv::restore() # Chunk 2: load_libraries # Configure knitr options knitr::opts_chunk$set(warning = FALSE, message = FALSE) # Path management library(here) # Spatial data libraries library(sf) library(terra) library(exactextractr) # library(raster) - Removed as it's no longer maintained # Data manipulation and visualization library(tidyverse) # Includes dplyr, ggplot2, etc. library(tmap) library(lubridate) library(zoo) # Machine learning library(rsample) library(caret) library(randomForest) library(CAST) # Load custom utility functions # tryCatch({ # source("report_utils.R") # }, error = function(e) { # message(paste("Error loading report_utils.R:", e$message)) # # Try alternative path if the first one fails # tryCatch({ source(here::here("r_app", "report_utils.R")) # }, error = function(e) { # stop("Could not load report_utils.R from either location: ", e$message) # }) # }) # Load executive report utilities # tryCatch({ # source("executive_report_utils.R") # }, error = function(e) { # message(paste("Error loading executive_report_utils.R:", e$message)) # # Try alternative path if the first one fails # tryCatch({ source(here::here("r_app", "executive_report_utils.R")) # Chunk 1: setup_parameters # Set up basic report parameters from input values report_date <- params$report_date mail_day <- params$mail_day borders <- params$borders use_breaks <- params$use_breaks # Whether to use breaks or continuous spectrum in visualizations # Environment setup notes (commented out) # # Activeer de renv omgeving # renv::activate() # renv::deactivate() # # Optioneel: Herstel de omgeving als dat nodig is # # Je kunt dit commentaar geven als je het normaal niet wilt uitvoeren # renv::restore() # Chunk 2: load_libraries # Configure knitr options knitr::opts_chunk$set(warning = FALSE, message = FALSE) # Path management library(here) # Spatial data libraries library(sf) library(terra) library(exactextractr) # library(raster) - Removed as it's no longer maintained # Data manipulation and visualization library(tidyverse) # Includes dplyr, ggplot2, etc. library(tmap) library(lubridate) library(zoo) # Machine learning library(rsample) library(caret) library(randomForest) library(CAST) # Load custom utility functions # tryCatch({ # source("report_utils.R") # }, error = function(e) { # message(paste("Error loading report_utils.R:", e$message)) # # Try alternative path if the first one fails # tryCatch({ source(here::here("r_app", "report_utils.R")) # }, error = function(e) { # stop("Could not load report_utils.R from either location: ", e$message) # }) # }) # Load executive report utilities # tryCatch({ # source("executive_report_utils.R") # }, error = function(e) { # message(paste("Error loading executive_report_utils.R:", e$message)) # # Try alternative path if the first one fails # tryCatch({ source(here::here("r_app", "exec_dashboard", "executive_report_utils.R")) # }, error = function(e) { # stop("Could not load executive_report_utils.R from either location: ", e$message) # }) # }) # Chunk 3: initialize_project_config # Set the project directory from parameters project_dir <- params$data_dir # Source project parameters with error handling # tryCatch({ source(here::here("r_app", "parameters_project.R")) # }, error = function(e) { # stop("Error loading parameters_project.R: ", e$message) # }) # Log initial configuration safe_log("Starting the R Markdown script") safe_log(paste("mail_day params:", params$mail_day)) safe_log(paste("report_date params:", params$report_date)) safe_log(paste("mail_day variable:", mail_day)) # Set locale for consistent date formatting Sys.setlocale("LC_TIME", "C") # Initialize date variables from parameters today <- as.character(report_date) mail_day_as_character <- as.character(mail_day) # Calculate week days report_date_as_week_day <- weekdays(lubridate::ymd(today)) days_of_week <- c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday") # Calculate initial week number week <- lubridate::week(today) safe_log(paste("Initial week calculation:", week, "today:", today)) # Calculate previous dates for comparisons today_minus_1 <- as.character(lubridate::ymd(today) - 7) today_minus_2 <- as.character(lubridate::ymd(today) - 14) today_minus_3 <- as.character(lubridate::ymd(today) - 21) # Log the weekday calculations for debugging safe_log(paste("Report date weekday:", report_date_as_week_day)) safe_log(paste("Weekday index:", which(days_of_week == report_date_as_week_day))) safe_log(paste("Mail day:", mail_day_as_character)) safe_log(paste("Mail day index:", which(days_of_week == mail_day_as_character))) # Adjust week calculation based on mail day if (which(days_of_week == report_date_as_week_day) > which(days_of_week == mail_day_as_character)) { safe_log("Adjusting weeks because of mail day") week <- lubridate::week(today) + 1 today_minus_1 <- as.character(lubridate::ymd(today)) today_minus_2 <- as.character(lubridate::ymd(today) - 7) today_minus_3 <- as.character(lubridate::ymd(today) - 14) } # Generate subtitle for report subtitle_var <- paste("Report generated on", Sys.Date()) # Calculate week numbers for previous weeks week_minus_1 <- week - 1 week_minus_2 <- week - 2 week_minus_3 <- week - 3 # Format current week with leading zeros week <- sprintf("%02d", week) # Get years for each date year <- lubridate::year(today) year_1 <- lubridate::year(today_minus_1) year_2 <- lubridate::year(today_minus_2) year_3 <- lubridate::year(today_minus_3) # Load CI index data with error handling tryCatch({ CI_quadrant <- readRDS(here::here(cumulative_CI_vals_dir, "All_pivots_Cumulative_CI_quadrant_year_v2.rds")) safe_log("Successfully loaded CI quadrant data") }, error = function(e) { stop("Error loading CI quadrant data: ", e$message) }) # Get file paths for different weeks using the utility function tryCatch({ path_to_week_current = get_week_path(weekly_CI_mosaic, today, 0) path_to_week_minus_1 = get_week_path(weekly_CI_mosaic, today, -1) path_to_week_minus_2 = get_week_path(weekly_CI_mosaic, today, -2) path_to_week_minus_3 = get_week_path(weekly_CI_mosaic, today, -3) # Log the calculated paths safe_log("Required mosaic paths:") safe_log(paste("Path to current week:", path_to_week_current)) safe_log(paste("Path to week minus 1:", path_to_week_minus_1)) safe_log(paste("Path to week minus 2:", path_to_week_minus_2)) safe_log(paste("Path to week minus 3:", path_to_week_minus_3)) # Validate that files exist if (!file.exists(path_to_week_current)) warning("Current week mosaic file does not exist: ", path_to_week_current) if (!file.exists(path_to_week_minus_1)) warning("Week minus 1 mosaic file does not exist: ", path_to_week_minus_1) if (!file.exists(path_to_week_minus_2)) warning("Week minus 2 mosaic file does not exist: ", path_to_week_minus_2) if (!file.exists(path_to_week_minus_3)) warning("Week minus 3 mosaic file does not exist: ", path_to_week_minus_3) # Load raster data with terra functions CI <- terra::rast(path_to_week_current)$CI CI_m1 <- terra::rast(path_to_week_minus_1)$CI CI_m2 <- terra::rast(path_to_week_minus_2)$CI CI_m3 <- terra::rast(path_to_week_minus_3)$CI }, error = function(e) { stop("Error loading raster data: ", e$message) })