From ede84679d705506c482b41d8a70b53a3dc5d2e4a Mon Sep 17 00:00:00 2001 From: Timon Date: Tue, 10 Feb 2026 11:34:29 +0100 Subject: [PATCH] code rabbit review stuff --- r_app/80_calculate_kpis.R | 2 +- r_app/90_CI_report_with_kpis_simple.Rmd | 39 ----------- r_app/91_CI_report_with_kpis_Angata.Rmd | 4 +- r_app/kpi_utils.R | 81 ++++++++++------------ webapps/data_validation_tool/index.html | 2 +- webapps/geojson_viewer/index.html | 8 ++- webapps/geojson_viewer/script.js | 44 +++--------- webapps/index.html | 4 +- webapps/polygon_analysis_editor/index.html | 2 +- webapps/sugar_mill_locator/index.html | 2 +- webapps/theme.css | 3 +- 11 files changed, 63 insertions(+), 128 deletions(-) diff --git a/r_app/80_calculate_kpis.R b/r_app/80_calculate_kpis.R index 3ad44c6..82add7a 100644 --- a/r_app/80_calculate_kpis.R +++ b/r_app/80_calculate_kpis.R @@ -807,7 +807,7 @@ main <- function() { total_acreage = sum(field_data$Acreage, na.rm = TRUE), mean_ci = round(mean(field_data$Mean_CI, na.rm = TRUE), 2), median_ci = round(median(field_data$Mean_CI, na.rm = TRUE), 2), - mean_cv = round(mean(field_data$CI_CV, na.rm = TRUE), 4), + mean_cv = round(mean(field_data$CV, na.rm = TRUE), 4), week = current_week, year = current_iso_year, date = as.character(end_date) diff --git a/r_app/90_CI_report_with_kpis_simple.Rmd b/r_app/90_CI_report_with_kpis_simple.Rmd index dbe8c9c..18a2829 100644 --- a/r_app/90_CI_report_with_kpis_simple.Rmd +++ b/r_app/90_CI_report_with_kpis_simple.Rmd @@ -610,45 +610,6 @@ if (exists("field_details_table") && !is.null(field_details_table)) { } ``` -```{r data, message=TRUE, warning=TRUE, include=FALSE} -# 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) -}) -``` ```{r calculate_difference_rasters, message=TRUE, warning=TRUE, include=FALSE} # Calculate difference rasters for comparisons diff --git a/r_app/91_CI_report_with_kpis_Angata.Rmd b/r_app/91_CI_report_with_kpis_Angata.Rmd index 9c74ba5..c370d8e 100644 --- a/r_app/91_CI_report_with_kpis_Angata.Rmd +++ b/r_app/91_CI_report_with_kpis_Angata.Rmd @@ -120,8 +120,8 @@ date_suffix <- format(as.Date(report_date), "%Y%m%d") # Calculate current week from report_date using ISO 8601 week numbering current_week <- as.numeric(format(as.Date(report_date), "%V")) -week_suffix <- paste0("week", current_week) - +current_iso_year <- as.numeric(format(as.Date(report_date), "%G")) +week_suffix <- paste0("week", sprintf("%02d", current_week), "_", current_iso_year) # Candidate filenames we expect (exact and common variants) expected_summary_names <- c( paste0(project_dir, "_kpi_summary_tables_", week_suffix, ".rds"), diff --git a/r_app/kpi_utils.R b/r_app/kpi_utils.R index 816d07d..6dc31af 100644 --- a/r_app/kpi_utils.R +++ b/r_app/kpi_utils.R @@ -80,7 +80,13 @@ load_weekly_ci_mosaic <- function(week_num, year, mosaic_dir) { tryCatch({ mosaic_raster <- terra::rast(week_path) - ci_raster <- mosaic_raster[[5]] # CI is the 5th band + # Extract CI band by name or position + if ("CI" %in% names(mosaic_raster)) { + ci_raster <- mosaic_raster[["CI"]] + } else { + # Fallback: assume last band is CI (after Red, Green, Blue, NIR) + ci_raster <- mosaic_raster[[nlyr(mosaic_raster)]] + } names(ci_raster) <- "CI" safe_log(paste("Loaded weekly mosaic:", week_file)) return(ci_raster) @@ -125,7 +131,7 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { field_boundaries_vect <- field_boundaries } - field_results <- data.frame() + field_results_list <- vector("list", nrow(field_boundaries)) for (i in seq_len(nrow(field_boundaries))) { field_name <- field_boundaries$field[i] @@ -144,7 +150,7 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { # If all valid values are 0 (cloud), fill with NA row if (length(valid_values) == 0 || all(valid_values == 0)) { - field_results <- rbind(field_results, data.frame( + field_results_list[[i]] <- data.frame( field = field_name, sub_field = sub_field_name, field_id = field_id, @@ -152,7 +158,7 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { uniformity_level = NA_character_, mean_ci = NA_real_, std_ci = NA_real_ - )) + ) } else if (length(valid_values) > 1) { # Calculate CV using existing function cv_value <- calculate_cv(valid_values) @@ -165,7 +171,7 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { TRUE ~ "Poor" ) - field_results <- rbind(field_results, data.frame( + field_results_list[[i]] <- data.frame( field = field_name, sub_field = sub_field_name, field_id = field_id, @@ -173,10 +179,10 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { uniformity_level = uniformity_level, mean_ci = mean(valid_values), std_ci = sd(valid_values) - )) + ) } else { # If only one valid value, fill with NA (not enough data for CV) - field_results <- rbind(field_results, data.frame( + field_results_list[[i]] <- data.frame( field = field_name, sub_field = sub_field_name, field_id = field_id, @@ -184,9 +190,11 @@ calculate_field_uniformity_kpi <- function(ci_raster, field_boundaries) { uniformity_level = NA_character_, mean_ci = mean(valid_values), std_ci = NA_real_ - )) + ) } } + + field_results <- do.call(rbind, field_results_list) # Create summary uniformity_summary <- field_results %>% @@ -671,8 +679,8 @@ calculate_weed_presence_kpi <- function(current_ci, previous_ci, field_boundarie safe_log("Previous week data not available for weed analysis", "WARNING") summary_result <- data.frame( weed_risk_level = c("Low", "Moderate", "High"), - field_count = c(35, 8, 3), - percent = c(76.1, 17.4, 6.5) + field_count = c(0, 0, 0), + percent = c(NA_real_, NA_real_, NA_real_) ) field_results <- data.frame( field = character(0), @@ -681,9 +689,7 @@ calculate_weed_presence_kpi <- function(current_ci, previous_ci, field_boundarie rapid_growth_pct = numeric(0), rapid_growth_pixels = numeric(0) ) - return(list(summary = summary_result, field_results = field_results)) - } - + return(list(summary = summary_result, field_results = field_results)) # Handle both sf and SpatVector inputs if (!inherits(field_boundaries, "SpatVector")) { field_boundaries_vect <- terra::vect(field_boundaries) @@ -967,8 +973,8 @@ create_field_detail_table <- function(kpi_results, field_boundaries_sf = NULL) { dplyr::rename(`Gap Score` = gap_score) field_details <- dplyr::left_join(field_details, gap_data, by = c("Field" = "field")) } else { - # Placeholder gap scores - field_details$`Gap Score` <- round(runif(nrow(field_details), 5, 25), 1) + # Gap score data unavailable - set to NA_real_ for deterministic handling + field_details$`Gap Score` <- NA_real_ } # Add growth decline risk from growth decline field results (aggregate by field) @@ -979,9 +985,8 @@ create_field_detail_table <- function(kpi_results, field_boundaries_sf = NULL) { dplyr::rename(`Decline Risk` = risk_level) field_details <- dplyr::left_join(field_details, decline_data, by = c("Field" = "field")) } else { - # Placeholder risk levels - field_details$`Decline Risk` <- sample(risk_levels, nrow(field_details), - prob = c(0.6, 0.25, 0.1, 0.05), replace = TRUE) + # Decline risk data unavailable - set to NA for deterministic handling + field_details$`Decline Risk` <- NA } # Add Moran's I spatial autocorrelation from growth decline field results (aggregate by field) @@ -992,9 +997,8 @@ create_field_detail_table <- function(kpi_results, field_boundaries_sf = NULL) { dplyr::rename(`Moran's I` = morans_i) field_details <- dplyr::left_join(field_details, moran_data, by = c("Field" = "field")) } else { - # Placeholder Moran's I values (typically range from -1 to 1) - set.seed(123) - field_details$`Moran's I` <- round(runif(nrow(field_details), -0.3, 0.8), 3) + # Moran's I data unavailable - set to NA_real_ for deterministic handling + field_details$`Moran's I` <- NA_real_ } # Add weed risk from weed presence field results (aggregate by field) @@ -1005,17 +1009,12 @@ create_field_detail_table <- function(kpi_results, field_boundaries_sf = NULL) { dplyr::rename(`Weed Risk` = weed_risk_level) field_details <- dplyr::left_join(field_details, weed_data, by = c("Field" = "field")) } else { - # Placeholder weed levels - field_details$`Weed Risk` <- sample(weed_levels, nrow(field_details), - prob = c(0.7, 0.2, 0.1), replace = TRUE) + # Weed risk data unavailable - set to NA for deterministic handling + field_details$`Weed Risk` <- NA } - # Fill any remaining NAs with defaults (but keep yield forecast as NA) - field_details$`Gap Score`[is.na(field_details$`Gap Score`)] <- 0.0 - field_details$`Decline Risk`[is.na(field_details$`Decline Risk`)] <- sample(risk_levels, sum(is.na(field_details$`Decline Risk`)), replace = TRUE, - prob = c(0.6, 0.25, 0.1, 0.05)) - field_details$`Weed Risk`[is.na(field_details$`Weed Risk`)] <- sample(weed_levels, sum(is.na(field_details$`Weed Risk`)), replace = TRUE, - prob = c(0.7, 0.2, 0.1)) + # Keep any remaining NAs as-is for all fields (NA indicates data unavailable) + # Do not fill with random values - let downstream code handle NA values deterministically # Reorder columns for better presentation field_details <- field_details %>% @@ -1204,19 +1203,16 @@ calculate_all_kpis <- function(report_date = Sys.Date(), # Calculate week numbers weeks <- calculate_week_numbers(report_date) + weeks <- calculate_week_numbers(report_date) + weeks <- calculate_week_numbers(report_date) safe_log(paste("Current week:", weeks$current_week, "Previous week:", weeks$previous_week)) # Load weekly mosaics - current_ci <- load_weekly_ci_mosaic(weeks$current_week, weeks$year, weekly_CI_mosaic) - previous_ci <- load_weekly_ci_mosaic(weeks$previous_week, weeks$year, weekly_CI_mosaic) + current_ci <- load_weekly_ci_mosaic(weeks$current_week, weeks$current_iso_year, weekly_CI_mosaic) + previous_ci <- load_weekly_ci_mosaic(weeks$previous_week, weeks$previous_iso_year, weekly_CI_mosaic) if (is.null(current_ci)) { - stop("Current week CI mosaic is required but not found") - } - - # Check if field boundaries are loaded - if (is.null(field_boundaries_sf)) { - stop("Field boundaries not loaded. Check parameters_project.R initialization.") + stop("Current week CI mosaic is required but not found") stop("Field boundaries not loaded. Check parameters_project.R initialization.") } # Calculate all KPIs @@ -1255,17 +1251,16 @@ calculate_all_kpis <- function(report_date = Sys.Date(), kpi_results$gap_filling_field_results <- gap_filling_result$field_results # Add metadata and field boundaries for later use + kpi_results$metadata <- list( + report_date = report_date, kpi_results$metadata <- list( report_date = report_date, current_week = weeks$current_week, previous_week = weeks$previous_week, - year = weeks$year, + year = weeks$current_iso_year, calculation_time = Sys.time(), total_fields = nrow(field_boundaries_sf) - ) - - # Store field_boundaries_sf for use in export_kpi_data - kpi_results$field_boundaries_sf <- field_boundaries_sf + ) kpi_results$field_boundaries_sf <- field_boundaries_sf # Save results if output directory specified if (!is.null(output_dir)) { diff --git a/webapps/data_validation_tool/index.html b/webapps/data_validation_tool/index.html index 6d59447..bd0b379 100644 --- a/webapps/data_validation_tool/index.html +++ b/webapps/data_validation_tool/index.html @@ -5,7 +5,7 @@ SmartCane Data Validation Tool - +