changes again

This commit is contained in:
Timon 2026-02-10 22:11:58 +01:00
parent a40b9c1dfe
commit 2d6f062c27
3 changed files with 40 additions and 54 deletions

View file

@ -24,8 +24,6 @@ library(tidyr)
library(readxl) library(readxl)
library(writexl) library(writexl)
library(spdep) library(spdep)
library(caret)
library(CAST)
# ============================================================================ # ============================================================================
# SHARED HELPER FUNCTIONS (NOW IN 80_UTILS_COMMON.R) # SHARED HELPER FUNCTIONS (NOW IN 80_UTILS_COMMON.R)
@ -81,27 +79,19 @@ prepare_predictions <- function(harvest_model, field_data, scenario = "optimisti
#' #'
#' @return Data frame with field_idx, cv_value, morans_i, uniformity_score, interpretation #' @return Data frame with field_idx, cv_value, morans_i, uniformity_score, interpretation
calculate_field_uniformity_kpi <- function(ci_pixels_by_field, field_boundaries_sf, ci_raster = NULL) { calculate_field_uniformity_kpi <- function(ci_pixels_by_field, field_boundaries_sf, ci_raster = NULL) {
result <- data.frame( results_list <- list()
field_idx = integer(),
cv_value = numeric(),
morans_i = numeric(),
uniformity_score = numeric(),
interpretation = character(),
stringsAsFactors = FALSE
)
for (field_idx in seq_len(nrow(field_boundaries_sf))) { for (field_idx in seq_len(nrow(field_boundaries_sf))) {
ci_pixels <- ci_pixels_by_field[[field_idx]] ci_pixels <- ci_pixels_by_field[[field_idx]]
if (is.null(ci_pixels) || length(ci_pixels) == 0) { if (is.null(ci_pixels) || length(ci_pixels) == 0) {
result <- rbind(result, data.frame( results_list[[length(results_list) + 1]] <- list(
field_idx = field_idx, field_idx = field_idx,
cv_value = NA_real_, cv_value = NA_real_,
morans_i = NA_real_, morans_i = NA_real_,
uniformity_score = NA_real_, uniformity_score = NA_real_,
interpretation = "No data", interpretation = "No data"
stringsAsFactors = FALSE )
))
next next
} }
@ -145,16 +135,18 @@ calculate_field_uniformity_kpi <- function(ci_pixels_by_field, field_boundaries_
interpretation <- "Very poor uniformity" interpretation <- "Very poor uniformity"
} }
result <- rbind(result, data.frame( results_list[[length(results_list) + 1]] <- list(
field_idx = field_idx, field_idx = field_idx,
cv_value = cv_val, cv_value = cv_val,
morans_i = morans_i, morans_i = morans_i,
uniformity_score = round(uniformity_score, 3), uniformity_score = round(uniformity_score, 3),
interpretation = interpretation, interpretation = interpretation
stringsAsFactors = FALSE )
))
} }
# Convert accumulated list to data frame in a single operation
result <- do.call(rbind, lapply(results_list, as.data.frame))
return(result) return(result)
} }
@ -222,19 +214,12 @@ calculate_tch_forecasted_kpi <- function(field_statistics, harvesting_data = NUL
next next
} }
ci_val <- result$mean_ci[i] if (is.na(result$mean_ci[i])) {
result$tch_forecasted[i] <- NA_real_
# Simple linear model result$tch_lower_bound[i] <- NA_real_
tch_est <- 50 + (ci_val * 10) result$tch_upper_bound[i] <- NA_real_
result$confidence[i] <- "No data"
# Confidence interval based on CI range }
tch_lower <- tch_est * 0.85
tch_upper <- tch_est * 1.15
result$tch_forecasted[i] <- round(tch_est, 2)
result$tch_lower_bound[i] <- round(tch_lower, 2)
result$tch_upper_bound[i] <- round(tch_upper, 2)
result$confidence[i] <- "Medium"
} }
return(result) return(result)
@ -365,13 +350,7 @@ calculate_gap_filling_kpi <- function(ci_raster, field_boundaries) {
field_boundaries_vect <- field_boundaries field_boundaries_vect <- field_boundaries
} }
field_results <- data.frame( results_list <- list()
field_idx = integer(),
gap_filling_success = numeric(),
na_percent_pre_interpolation = numeric(),
mean_ci = numeric(),
stringsAsFactors = FALSE
)
# Ensure field_boundaries_vect is valid and matches field_boundaries dimensions # Ensure field_boundaries_vect is valid and matches field_boundaries dimensions
n_fields_vect <- length(field_boundaries_vect) n_fields_vect <- length(field_boundaries_vect)
@ -395,25 +374,26 @@ calculate_gap_filling_kpi <- function(ci_raster, field_boundaries) {
gap_filling_success <- (valid_pixels / total_pixels) * 100 gap_filling_success <- (valid_pixels / total_pixels) * 100
na_percent <- ((total_pixels - valid_pixels) / total_pixels) * 100 na_percent <- ((total_pixels - valid_pixels) / total_pixels) * 100
field_results <- rbind(field_results, data.frame( results_list[[length(results_list) + 1]] <- list(
field_idx = i, field_idx = i,
gap_filling_success = round(gap_filling_success, 2), gap_filling_success = round(gap_filling_success, 2),
na_percent_pre_interpolation = round(na_percent, 2), na_percent_pre_interpolation = round(na_percent, 2),
mean_ci = round(mean(valid_values), 2), mean_ci = round(mean(valid_values), 2)
stringsAsFactors = FALSE )
))
} else { } else {
# Not enough valid data # Not enough valid data
field_results <- rbind(field_results, data.frame( results_list[[length(results_list) + 1]] <- list(
field_idx = i, field_idx = i,
gap_filling_success = NA_real_, gap_filling_success = NA_real_,
na_percent_pre_interpolation = NA_real_, na_percent_pre_interpolation = NA_real_,
mean_ci = NA_real_, mean_ci = NA_real_
stringsAsFactors = FALSE )
))
} }
} }
# Convert accumulated list to data frame in a single operation
field_results <- do.call(rbind, lapply(results_list, as.data.frame))
return(field_results) return(field_results)
} }
@ -653,9 +633,15 @@ export_kpi_data <- function(all_kpis, kpi_summary, project_dir, output_dir, week
} }
} }
# Fallback if name extraction didn't work # Ensure field_name is a character vector of appropriate length
if (any(is.na(field_name)) || length(field_name) != nrow(field_boundaries_sf)) { if (length(field_name) != nrow(field_boundaries_sf)) {
field_name <- paste0("Field_", 1:nrow(field_boundaries_sf)) field_name <- rep(NA_character_, nrow(field_boundaries_sf))
}
# Replace only NA elements with fallback names, keeping valid names intact
na_indices <- which(is.na(field_name))
if (length(na_indices) > 0) {
field_name[na_indices] <- paste0("Field_", na_indices)
} }
field_df <- data.frame( field_df <- data.frame(
@ -800,7 +786,7 @@ calculate_all_kpis <- function(
message("Calculating KPI 4: Growth Decline...") message("Calculating KPI 4: Growth Decline...")
growth_decline_kpi <- calculate_growth_decline_kpi( growth_decline_kpi <- calculate_growth_decline_kpi(
list(ci_pixels_by_field) # Would need historical data for real trend ci_pixels_by_field # Would need historical data for real trend
) )
message("Calculating KPI 5: Weed Presence...") message("Calculating KPI 5: Weed Presence...")

View file

@ -427,7 +427,7 @@ if (exists("summary_tables") && !is.null(summary_tables) && length(summary_table
```{r field_alerts_table, echo=FALSE, results='asis'} ```{r field_alerts_table, echo=FALSE, results='asis'}
# Generate alerts for all fields # Generate alerts for all fields
generate_field_alerts <- function(field_details_table) { generate_field_alerts <- function(field_details_table) {
if (!exists("field_details_table") || is.null(field_details_table) || nrow(field_details_table) == 0) { if (is.null(field_details_table) || nrow(field_details_table) == 0) {
return(NULL) # Return NULL to signal no data return(NULL) # Return NULL to signal no data
} }
@ -593,8 +593,8 @@ if (!exists("field_details_table") || is.null(field_details_table)) {
field_names <- AllPivots0$field field_names <- AllPivots0$field
# Try to calculate field sizes (area) from geometry if available # Try to calculate field sizes (area) from geometry if available
field_sizes <- if ("geometry" %in% names(AllPivots0)) { field_sizes <- if (!is.null(sf::st_geometry(AllPivots0)) && !all(sf::st_is_empty(sf::st_geometry(AllPivots0)))) {
sf::st_area(AllPivots0) / 10000 # Convert m² to hectares sf::st_area(sf::st_geometry(AllPivots0)) / 10000 # Convert m² to hectares
} else { } else {
rep(NA_real_, length(field_names)) rep(NA_real_, length(field_names))
} }

View file

@ -53,7 +53,7 @@ CLIENT_TYPE_MAP <- list(
get_client_type <- function(project_name) { get_client_type <- function(project_name) {
client_type <- CLIENT_TYPE_MAP[[project_name]] client_type <- CLIENT_TYPE_MAP[[project_name]]
if (is.null(client_type)) { if (is.null(client_type)) {
warning(paste("Project '", project_name, "' not found in CLIENT_TYPE_MAP. Defaulting to 'agronomic_support'.", sep="")) warning(paste0("Project '", project_name, "' not found in CLIENT_TYPE_MAP. Defaulting to 'agronomic_support'.", sep=""))
return("agronomic_support") # Default for all unlisted projects return("agronomic_support") # Default for all unlisted projects
} }
return(client_type) return(client_type)