From ebac3daf14161981995520818d552a8c894faa21 Mon Sep 17 00:00:00 2001 From: Emmanouil Sifakis Date: Thu, 19 Feb 2026 18:27:35 +0100 Subject: [PATCH] Fix AUTO NA handling in ER/HER2 subgroup counts (na.rm=TRUE) (closes #127) --- NEWS.md | 5 ++--- R/Utilities.R | 27 +++++++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 146ff5c..9f9df9e 100755 --- a/NEWS.md +++ b/NEWS.md @@ -25,15 +25,14 @@ - Readiness uses the same minimums used by AUTO (sourced programmatically; no duplicated thresholds). - **Shorter notifications.**\ -Routine toasts (e.g., "Step 1 complete. Proceed to Step 2.") now auto-dismiss sooner to reduce UI clutter. -- **Phenodata normalization (Mapping):** Accepts flexible ER/HER2/TN encodings and -normalizes to canonical forms (`ER+/ER-`, `HER2+/HER2-`, `TN/nonTN`). -Ambiguous `HER2="2+"` remains as-is and raises a warning. +- **Phenodata normalization (Mapping):** Accepts flexible ER/HER2/TN encodings and normalizes to canonical forms (`ER+/ER-`, `HER2+/HER2-`, `TN/nonTN`). Ambiguous `HER2="2+"` remains as-is and raises a warning. ### Bug fixes - **TN cohorts + ssBC**: `BS_Multi()` now respects TN cohorts when methods are specified manually; `ssBC`/`ssBC.v2` switch to `s = "TN"` / `"TN.v2"` when a `TN` column indicates a TN cohort. Falls back to `s = "ER"` / `"ER.v2"` otherwise. +- **AUTO**: Fixed a crash in BS_Multi(methods="AUTO") when ER and/or HER2 contained missing values (NA). - **AUTO internals**: fixed variable name typo (`samples_ERHER2.icd`). - **Mapping():** Robust ENTREZID coercion (from `as.character()` to `as.integer()` with suppressed warnings). - **cIHC.itr**: `outList$distances` now returned as numeric matrix. diff --git a/R/Utilities.R b/R/Utilities.R index ad21399..e5bf9a5 100755 --- a/R/Utilities.R +++ b/R/Utilities.R @@ -342,16 +342,27 @@ get_methods <- function(pheno) { } else if (!all(c("ER", "HER2") %in% colnames(pheno))) { stop("The 'AUTO' mode requires both 'ER' and 'HER2' columns in the 'pheno' dataframe.") } else { + + pheno <- .normalize_er_her2_tn(pheno) + + # Detect missing receptor annotations (optional) + n_na_ER <- sum(is.na(pheno$ER)) + n_na_HER2 <- sum(is.na(pheno$HER2)) + if (n_na_ER > 0L || n_na_HER2 > 0L) { + .msg("AUTO: missing ER/HER2 values detected (ER NA=%d, HER2 NA=%d). These samples are excluded from subgroup counts.", + n_na_ER, n_na_HER2, origin = "AUTO") + } + # Calculate sample sizes sample_counts <- with(pheno, table(ER, HER2)) # (kept for future debugging) - n_ERpos <- sum(pheno$ER == "ER+") - n_ERneg <- sum(pheno$ER == "ER-") - - n_ERnegHER2pos <- sum(pheno$ER == "ER-" & pheno$HER2 == "HER2+") - n_ERnegHER2neg <- sum(pheno$ER == "ER-" & pheno$HER2 == "HER2-") - n_ERposHER2pos <- sum(pheno$ER == "ER+" & pheno$HER2 == "HER2+") - n_ERposHER2neg <- sum(pheno$ER == "ER+" & pheno$HER2 == "HER2-") - + n_ERpos <- sum(pheno$ER == "ER+", na.rm = TRUE) + n_ERneg <- sum(pheno$ER == "ER-", na.rm = TRUE) + + n_ERnegHER2pos <- sum(pheno$ER == "ER-" & pheno$HER2 == "HER2+", na.rm = TRUE) + n_ERnegHER2neg <- sum(pheno$ER == "ER-" & pheno$HER2 == "HER2-", na.rm = TRUE) + n_ERposHER2pos <- sum(pheno$ER == "ER+" & pheno$HER2 == "HER2+", na.rm = TRUE) + n_ERposHER2neg <- sum(pheno$ER == "ER+" & pheno$HER2 == "HER2-", na.rm = TRUE) + # Set thresholds n_ERpos_threshold <- 15 # simulation-based cut-off n_ERneg_threshold <- 18 # simulation-based cut-off