From 60e4687fb237bc39514becb3bcc4264654805119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Zaba?= <153927231+tomaszaba@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:48:15 +0200 Subject: [PATCH 1/8] Closes #99 (#100) --- CITATION.cff | 8 ++++++-- DESCRIPTION | 4 ++-- R/data-wranglers.R | 6 +++--- R/module-data-wrangling.R | 12 ++++++------ R/satscan-configuration.R | 2 +- R/satscan-runner.R | 2 +- inst/WORDLIST | 1 + inst/app/ui.R | 2 +- man/ww_configure_satscan.Rd | 2 +- man/ww_run_satscan.Rd | 2 +- man/ww_wrangle_data.Rd | 6 +++--- tests/testthat/test-data-wranglers.R | 8 ++++---- tests/testthat/test-satscan-configuration.R | 2 +- tests/testthat/test-satscan-runner.R | 6 +++--- tests/testthat/test-utils.R | 2 +- vignettes/how-to-use-wowi.qmd | 6 +++--- 16 files changed, 38 insertions(+), 33 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 267f39b..7c81352 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -99,7 +99,7 @@ references: abstract: 'mwana: An Efficient Workflow for Plausibility Checks and Prevalence Analysis of Wasting in R' notes: Imports - url: https://nutriverse.io/mwana + url: https://mphimo.github.io/mwana/ authors: - family-names: Zaba given-names: Tomás @@ -111,7 +111,7 @@ references: - family-names: Myatt given-names: Mark year: '2025' - version: '>= 1.0.0' + version: '>= 0.2.3' - type: software title: withr abstract: 'withr: Run Code ''With'' Temporarily Modified Global State' @@ -193,6 +193,10 @@ references: given-names: Barret email: barret@posit.co orcid: https://orcid.org/0000-0001-9986-114X + - family-names: Aden-Buie + given-names: Garrick + email: garrick@adenbuie.com + orcid: https://orcid.org/0000-0002-7111-0077 - family-names: Xie given-names: Yihui email: yihui@posit.co diff --git a/DESCRIPTION b/DESCRIPTION index dc64f9e..5cadeea 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,7 +22,7 @@ Imports: dplyr (>= 1.1.4), rlang (>= 1.1.6), rsatscan (>= 1.0.9), - mwana (>= 1.0.0), + mwana (>= 0.2.3), withr (>= 3.0.2), stringr (>= 1.5.1), tibble (>= 3.3.0), @@ -41,7 +41,7 @@ Suggests: spelling (>= 2.3.1), testthat (>= 3.0.0) Remotes: - nutriverse/mwana + mphimo/mwana Config/testthat/edition: 3 Depends: R (>= 4.1.0) diff --git a/R/data-wranglers.R b/R/data-wranglers.R index c298b47..228ed11 100644 --- a/R/data-wranglers.R +++ b/R/data-wranglers.R @@ -59,7 +59,7 @@ wrangle_data <- function( #' readable by the software, and placed in a directory it can access. #' #' `ww_wrangle_data()` is a convenient function designed for this task. It -#' assumes that the input anthropometric data has been pre-processed using the +#' assumes that the input anthropometric data has been pre-processed using #' `{mwana}` data wrangling functions. #' #' @param .data A data frame object that has been wrangled using @@ -84,7 +84,7 @@ wrangle_data <- function( #' variable must be named "latitude". #' #' @returns -#' Three files are created and saved in the user-defined directory as specifiie +#' Three files are created and saved in the user-defined directory as specified #' in the `dir` argument: a `.cas` file for cases, a `.ctl` for controls, and #' a `.geo` file for geographical coordinates. The full filenames will incorporate #' the use-defined `filename` string. @@ -117,7 +117,7 @@ wrangle_data <- function( #' mwana::define_wasting( #' zscores = wfhz, #' .by = "zscores", -#' edema = oedema +#' oedema = oedema #' ) #' #' ## Apply the function ---- diff --git a/R/module-data-wrangling.R b/R/module-data-wrangling.R index d3b7203..d791d6c 100644 --- a/R/module-data-wrangling.R +++ b/R/module-data-wrangling.R @@ -134,7 +134,7 @@ module_server_wrangle_data <- function(id, data) { ), shiny::selectInput( inputId = ns("oedema"), - label = htmltools::tags$span("Oedema", + label = htmltools::tags$span("oedema", style = "font-size: 14px; font-weight: bold;" ), choices = c("", cols) @@ -174,7 +174,7 @@ module_server_wrangle_data <- function(id, data) { ), shiny::selectInput( inputId = ns("oedema"), - label = htmltools::tags$span("Oedema", + label = htmltools::tags$span("oedema", style = "font-size: 14px; font-weight: bold;" ), choices = c("", cols) @@ -234,7 +234,7 @@ module_server_wrangle_data <- function(id, data) { ), shiny::selectInput( inputId = ns("oedema"), - label = htmltools::tags$span("Oedema", + label = htmltools::tags$span("oedema", style = "font-size: 14px; font-weight: bold;" ), choices = c("", cols) @@ -303,7 +303,7 @@ module_server_wrangle_data <- function(id, data) { mwana::define_wasting( zscores = .data$wfhz, .by = "zscores", - edema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL + oedema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL ) }, "muac" = { @@ -332,7 +332,7 @@ module_server_wrangle_data <- function(id, data) { mwana::define_wasting( muac = .data$muac, .by = "muac", - edema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL + oedema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL ) }, "combined" = { @@ -372,7 +372,7 @@ module_server_wrangle_data <- function(id, data) { zscores = .data$wfhz, muac = .data$muac, .by = "combined", - edema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL + oedema = if (input$oedema != "") !!rlang::sym(input$oedema) else NULL ) } ) diff --git a/R/satscan-configuration.R b/R/satscan-configuration.R index 6cc8da3..2dc4dc8 100644 --- a/R/satscan-configuration.R +++ b/R/satscan-configuration.R @@ -51,7 +51,7 @@ #' mwana::define_wasting( #' zscores = wfhz, #' .by = "zscores", -#' edema = oedema +#' oedema = oedema #' ) #' #' ## Apply the function ---- diff --git a/R/satscan-runner.R b/R/satscan-runner.R index 63cc81b..1bb5ce7 100644 --- a/R/satscan-runner.R +++ b/R/satscan-runner.R @@ -94,7 +94,7 @@ #' mwana::define_wasting( #' zscores = wfhz, #' .by = "zscores", -#' edema = oedema +#' oedema = oedema #' ) #' #' #' ## Given a temporary directory ---- diff --git a/inst/WORDLIST b/inst/WORDLIST index 3368ca1..bf1a89f 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -19,4 +19,5 @@ muac satscan shapefiles tibble +walkthrough ️ diff --git a/inst/app/ui.R b/inst/app/ui.R index 14b2685..c9faf0b 100644 --- a/inst/app/ui.R +++ b/inst/app/ui.R @@ -43,7 +43,7 @@ ui <- tagList( ), ### Right side of the page navigation bar ---- - tags$span("v.1.0.1", + tags$span("v1.0.1", id = "app-version", style = "font-size: 12.5px; color: rgba(31, 42, 68, 0.58); position: fixed; top: 40px; right: 20px;" diff --git a/man/ww_configure_satscan.Rd b/man/ww_configure_satscan.Rd index 0e3cdb9..cbfa38a 100644 --- a/man/ww_configure_satscan.Rd +++ b/man/ww_configure_satscan.Rd @@ -58,7 +58,7 @@ x <- anthro |> mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ## Apply the function ---- diff --git a/man/ww_run_satscan.Rd b/man/ww_run_satscan.Rd index 7200bcb..a16f003 100644 --- a/man/ww_run_satscan.Rd +++ b/man/ww_run_satscan.Rd @@ -115,7 +115,7 @@ x <- anthro |> mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) #' ## Given a temporary directory ---- diff --git a/man/ww_wrangle_data.Rd b/man/ww_wrangle_data.Rd index e59aba2..1eb7466 100644 --- a/man/ww_wrangle_data.Rd +++ b/man/ww_wrangle_data.Rd @@ -37,7 +37,7 @@ are identified, and for which should be excluded from the analysis. Defaults to \code{wfhz}.} } \value{ -Three files are created and saved in the user-defined directory as specifiie +Three files are created and saved in the user-defined directory as specified in the \code{dir} argument: a \code{.cas} file for cases, a \code{.ctl} for controls, and a \code{.geo} file for geographical coordinates. The full filenames will incorporate the use-defined \code{filename} string. @@ -58,7 +58,7 @@ into cases, controls, and geographical coordinates files, then saved in a format readable by the software, and placed in a directory it can access. \code{ww_wrangle_data()} is a convenient function designed for this task. It -assumes that the input anthropometric data has been pre-processed using the +assumes that the input anthropometric data has been pre-processed using \code{{mwana}} data wrangling functions. } \examples{ @@ -79,7 +79,7 @@ x <- anthro |> mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ## Apply the function ---- diff --git a/tests/testthat/test-data-wranglers.R b/tests/testthat/test-data-wranglers.R index 393daa1..9409f05 100644 --- a/tests/testthat/test-data-wranglers.R +++ b/tests/testthat/test-data-wranglers.R @@ -24,7 +24,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ## Observed results ---- @@ -69,7 +69,7 @@ testthat::test_that( .to = "cm" ) |> dplyr::mutate(muac = mwana::recode_muac(muac, .to = "mm")) |> - mwana::define_wasting(muac = muac, .by = "muac", edema = oedema) + mwana::define_wasting(muac = muac, .by = "muac", oedema = oedema) ## Observed results ---- @@ -124,7 +124,7 @@ testthat::test_that( zscores = wfhz, muac = muac, .by = "combined", - edema = oedema + oedema = oedema ) ### Observed results ---- @@ -172,7 +172,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- diff --git a/tests/testthat/test-satscan-configuration.R b/tests/testthat/test-satscan-configuration.R index 3889189..d4b9fc0 100644 --- a/tests/testthat/test-satscan-configuration.R +++ b/tests/testthat/test-satscan-configuration.R @@ -24,7 +24,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- diff --git a/tests/testthat/test-satscan-runner.R b/tests/testthat/test-satscan-runner.R index a731397..e1f1b5d 100644 --- a/tests/testthat/test-satscan-runner.R +++ b/tests/testthat/test-satscan-runner.R @@ -26,7 +26,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- @@ -94,7 +94,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- @@ -166,7 +166,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 4e9e43c..a1f4a6c 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -23,7 +23,7 @@ testthat::test_that( mwana::define_wasting( zscores = wfhz, .by = "zscores", - edema = oedema + oedema = oedema ) ### Create a temporary directory ---- diff --git a/vignettes/how-to-use-wowi.qmd b/vignettes/how-to-use-wowi.qmd index 96f974e..d279643 100644 --- a/vignettes/how-to-use-wowi.qmd +++ b/vignettes/how-to-use-wowi.qmd @@ -63,7 +63,7 @@ The output described in point 4 offers an IPC Acute Malnutrition-related insight ## From data to clusters - the wowi analysis workflow -The analysis workflow with `wowi` begins with the standard anthropometric data processing steps - data wrangling and quality checks. For this purpose, wowi relies on the [`mwana`](https://nutriverse.io/mwana/dev/) package, which will be installed or updated automatically when you install `wowi`. Moreover, in the downstream analysis workflow, the `sf` package is required to generate shapefile-related outputs. Note that [`sf`](https://r-spatial.github.io/sf/) is not installed with wowi, therefore you must install it separately. +The analysis workflow with `wowi` begins with the standard anthropometric data processing steps - data wrangling and quality checks. For this purpose, wowi relies on the [`mwana`](https://https://mphimo.github.io/mwana/) package, which will be installed or updated automatically when you install `wowi`. Moreover, in the downstream analysis workflow, the `sf` package is required to generate shapefile-related outputs. Note that [`sf`](https://r-spatial.github.io/sf/) is not installed with wowi, therefore you must install it separately. ::: {.callout-note} @@ -106,7 +106,7 @@ a <- anthro |> ) |> define_wasting( zscores = wfhz, - edema = oedema, + oedema = oedema, .by = "zscores" ) |> dplyr::rename( @@ -115,7 +115,7 @@ a <- anthro |> ) ``` -Hereafter, you can check the quality of the data. Learn how to do so [here](https://nutriverse.io/mwana/dev/articles/plausibility.html). +Hereafter, you can check the quality of the data. Learn how to do so [here](https://https://mphimo.github.io/mwana/articles/plausibility.html). ### Running the spatial scan From d60412f8827624e43374ce660cde86845e04e2a8 Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Tue, 16 Dec 2025 22:21:11 +0200 Subject: [PATCH 2/8] Closes #61 --- R/utils.R | 107 ++++++++++++++++++++++-------------- man/parse_clusters.Rd | 15 +++++ tests/testthat/test-utils.R | 1 + 3 files changed, 83 insertions(+), 40 deletions(-) create mode 100644 man/parse_clusters.Rd diff --git a/R/utils.R b/R/utils.R index 6265f24..86c4cfa 100644 --- a/R/utils.R +++ b/R/utils.R @@ -2,58 +2,85 @@ #' #' @keywords internal #' +#' skip_if_no_satscan <- function(ss_path = "/Applications/SaTScan.app/Contents/app/satscan") { testthat::skip_if_not(file.exists(ss_path), message = "SaTScan is not installed or not found") } #' -#' +#' Extract results from SaTScan-text-based output +#' +#' @param file SaTScan-text-based output result given as "main" to be parsed +#' #' @keywords internal -#' -#' +#' +#' parse_clusters <- function(file) { - ## Access the txt-based results ---- + + ## Subset SaTScan-text-based output file ---- txt <- file$main - ## Find line indices with "Location IDs included" ---- + ## Find line indices for cluster starts and coordinates cluster_start <- stringr::str_which(txt, "^\\d+\\.Location IDs included\\.:") + coords <- stringr::str_which(txt, "^\\s+Coordinates / radius") + + ## Extract the name of the survey area ---- area_name <- stringr::str_which(txt, "^[Case File]+\\:") - ## Define line offsets to grab per cluster ---- - cluster_blocks <- lapply(cluster_start, function(start_idx) { - txt[start_idx:(start_idx + 10)] - }) - - ## Parse each cluster block ---- - parsed_clusters <- lapply(cluster_blocks, function(block) { - tibble::tibble( - survey_area = stringr::str_extract_all(basename(txt[[area_name]]), "^[^.]+") |> - as.character(), - nr_EAs = stringr::str_extract(txt[[18]], "\\d+") |> as.integer(), - total_children = stringr::str_extract(txt[[19]], "\\d+") |> as.integer(), - total_cases = stringr::str_extract(txt[[20]], "\\d+") |> as.integer(), - `%_cases` = stringr::str_extract(txt[[21]], "\\d+") |> as.double(), - location_ids = stringr::str_extract_all(block[1], "[0-9]+")[[1]][-1] |> - paste(collapse = ","), - geo = stringr::str_extract(block[2], "\\d+\\.\\d+\\s+\\w\\,\\s+\\d+\\.\\d+\\s+\\w"), - radius = stringr::str_extract(block[2], "\\d+\\.\\d+\\s*\\w+$"), - span = stringr::str_extract(block[3], "[0-9]+[.]+[0-9]+\\s+\\w+$"), - children = stringr::str_extract(block[4], "[0-9]+") |> as.integer(), - n_cases = stringr::str_extract(block[5], "[0-9]+") |> as.integer(), - expected_cases = stringr::str_extract(block[6], "[0-9]+[.]+[0-9]+") |> as.double(), - observedExpected = stringr::str_extract(block[7], "[0-9]+[.]+[0-9]+") |> as.double(), - relative_risk = stringr::str_extract(block[8], "[0-9]+\\.\\d+") |> as.double(), - `%_cases_in_area` = stringr::str_extract(block[9], "[0-9]+\\.\\d+") |> as.double(), - log_lik_ratio = stringr::str_extract(block[10], "[0-9]+\\.\\d+") |> as.double(), - pvalue = stringr::str_extract(block[11], "[0-9]+[.]+[0-9]+") |> as.double(), + ## Guard: align pairs if counts differ + n <- min(length(cluster_start), length(coords)) + if (n == 0) return(tibble::tibble()) + + out <- vector("list", n) + + for (j in seq_len(n)) { + idx <- cluster_start[j] + coord <- coords[j] + + ## Collect all lines containing IDs up to the coordinates line + id_block <- txt[idx:(coord - 1)] + ids_vec <- stringr::str_extract_all(id_block, "[0-9]+") |> unlist() + + ## Drop the leading cluster number (e.g., "1", "2") if present + location_ids <- if (length(ids_vec) > 1) { + paste(ids_vec[-1], collapse = ",") + } else { + NA_character_ + } + + ## Build tibble for this cluster (offsets are stable in SaTScan output) + out[[j]] <- tibble::tibble( + + ### Summary metadata (from fixed lines in your example) ---- + survey_area = as.character(stringr::str_extract_all(basename(txt[[area_name]]), "^[^.]+")), + nr_EAs = as.integer(stringr::str_extract(txt[18], "\\d+")), + total_children = as.integer(stringr::str_extract(txt[19], "\\d+")), + total_cases = as.integer(stringr::str_extract(txt[20], "\\d+")), + `%_cases` = as.double(stringr::str_extract(txt[21], "\\d+\\.?\\d*")), + + ### Cluster-specific ---- + location_ids = location_ids, + geo = stringr::str_extract(txt[coord], + "\\d+\\.\\d+\\s+\\w\\,\\s+\\d+\\.\\d+\\s+\\w"), + radius = stringr::str_extract(txt[coord],"[0-9]+\\.[0-9]+\\s*km"), + span = stringr::str_extract(txt[coord + 1], "[0-9]+\\.[0-9]+\\s*km"), + children = as.integer(stringr::str_extract(txt[coord + 2], "\\d+")), + n_cases = as.integer(stringr::str_extract(txt[coord + 3], "\\d+")), + expected_cases = as.double(stringr::str_extract(txt[coord + 4], "[0-9]+\\.[0-9]+")), + observedExpected = as.double(stringr::str_extract(txt[coord + 5], "[0-9]+\\.[0-9]+")), + relative_risk = as.double(stringr::str_extract(txt[coord + 6], "[0-9]+\\.[0-9]+")), + `%_cases_in_area` = as.double(stringr::str_extract(txt[coord + 7], "[0-9]+\\.?[0-9]*")), + log_lik_ratio = as.double(stringr::str_extract(txt[coord + 8], "[0-9]+\\.[0-9]+")), + pvalue = as.double(stringr::str_extract(txt[coord + 9], "[0-9]+\\.?[0-9]*")), + + ### Check if IPC AMN reqs for survey disaggregation is met ---- ipc_amn = ifelse( - test = length(strsplit(.data$location_ids, ",\\s*")[[1]]) >= 5 & as.numeric(.data$children) > 100, - yes = "yes", - no = "no" + length(strsplit(location_ids, ",\\s*")[[1]]) >= 5 & !is.na(children) & children >= 100, + "yes", "no" ) - ) - }) + ) + } - ## Combine all into one data frame ---- - dplyr::bind_rows(parsed_clusters) -} + ## Return binded results ---- + dplyr::bind_rows(out) +} \ No newline at end of file diff --git a/man/parse_clusters.Rd b/man/parse_clusters.Rd new file mode 100644 index 0000000..2542a3e --- /dev/null +++ b/man/parse_clusters.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{parse_clusters} +\alias{parse_clusters} +\title{Extract results from SaTScan-text-based output} +\usage{ +parse_clusters(file) +} +\arguments{ +\item{file}{SaTScan-text-based output result given as "main" to be parsed} +} +\description{ +Extract results from SaTScan-text-based output +} +\keyword{internal} diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index a1f4a6c..c0317a5 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -25,6 +25,7 @@ testthat::test_that( .by = "zscores", oedema = oedema ) + ### Create a temporary directory ---- tmp <- withr::local_tempdir() # ensures cleanup after test From 2d45e5d224e4039076bc6084b45c3099243e4f6f Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Tue, 16 Dec 2025 22:38:39 +0200 Subject: [PATCH 3/8] test check if parsed results == those in text-based output --- tests/testthat/test-utils.R | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index c0317a5..5706808 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -81,5 +81,22 @@ testthat::test_that( testthat::expect_true(is.double(dplyr::pull(r[[1]][16]))) testthat::expect_true(is.double(dplyr::pull(r[[1]][17]))) testthat::expect_true(is.character(dplyr::pull(r[[1]][18]))) + + ## Check if results are in the tibble are correct ---- + testthat::expect_equal(r$.df$nr_EAs[1], 36) + testthat::expect_equal(r$.df$total_cases[1], 26) + testthat::expect_equal(r$.df$"%_cases"[1], 7.8) + testthat::expect_equal(r$.df$location_ids[1], "10,9") + testthat::expect_equal(r$.df$geo[1], "34.113909 N, 3.087933 E") + testthat::expect_equal(r$.df$radius[1], "1.20 km") + testthat::expect_equal(r$.df$span[1], "1.20 km") + testthat::expect_equal(r$.df$children[1], 25) + testthat::expect_equal(r$.df$n_cases[1], 6) + testthat::expect_equal(r$.df$expected_cases[1], 1.95) + testthat::expect_equal(r$.df$observedExpected[1], 3.07) + testthat::expect_equal(r$.df$relative_risk[1], 3.70) + testthat::expect_equal(r$.df$"%_cases_in_area"[1], 24.0) + testthat::expect_equal(r$.df$log_lik_ratio[1], 3.458213) + testthat::expect_equal(r$.df$pvalue[1], 0.55) } ) From 46d0e80b419dfbcc3ef698e6f054a3f36f460089 Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Tue, 16 Dec 2025 22:41:41 +0200 Subject: [PATCH 4/8] Increment version number to 1.0.2 --- DESCRIPTION | 2 +- NEWS.md | 2 ++ inst/app/ui.R | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5cadeea..39bf72a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: wowi Title: Detect Spatial Clusters of High Acute Malnutrition Rates -Version: 1.0.1 +Version: 1.0.2 Authors@R: person(given = "Tomás", family = "Zaba", diff --git a/NEWS.md b/NEWS.md index 0108aff..3dbe536 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# wowi 1.0.2 + # wowi 1.0.1 ## General updates diff --git a/inst/app/ui.R b/inst/app/ui.R index c9faf0b..7d5d294 100644 --- a/inst/app/ui.R +++ b/inst/app/ui.R @@ -43,7 +43,7 @@ ui <- tagList( ), ### Right side of the page navigation bar ---- - tags$span("v1.0.1", + tags$span("v1.0.2", id = "app-version", style = "font-size: 12.5px; color: rgba(31, 42, 68, 0.58); position: fixed; top: 40px; right: 20px;" From f751a71432ad402f1ba54bd00f1e46c408aba3e6 Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Tue, 16 Dec 2025 22:48:28 +0200 Subject: [PATCH 5/8] update files following version increment; add app test status badge --- CITATION.cff | 4 ++-- README.md | 6 ++++-- README.qmd | 1 + inst/CITATION | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 7c81352..eb22df6 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,7 +8,7 @@ message: 'To cite package "wowi" in publications use:' type: software license: GPL-3.0-or-later title: 'wowi: Detect Spatial Clusters of High Acute Malnutrition Rates' -version: 1.0.1 +version: 1.0.2 abstract: Utilities for detecting statistically significant spatial clusters of high acute malnutrition rates using SaTScan's Bernoulli spatial-scan model. authors: @@ -23,7 +23,7 @@ preferred-citation: authors: - name: Tomás Zaba year: '2025' - notes: R package version 1.0.1 + notes: R package version 1.0.2 url: https://tiwowi.github.io/wowi/ repository-code: https://github.com/tiwowi/wowi url: https://tiwowi.github.io/wowi/ diff --git a/README.md b/README.md index 029ff80..e14bc89 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostat [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![R-CMD-check](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml) +[![Test +app](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/tiwowi/wowi/graph/badge.svg)](https://app.codecov.io/gh/tiwowi/wowi) @@ -107,7 +109,7 @@ citation("wowi") Tomás Zaba (2025). _wowi: Utilities for detecting statistically significant spatial clusters of high acute malnutrition rates using - SaTScan's Bernoulli spatial-scan model_. R package version 1.0.1, + SaTScan's Bernoulli spatial-scan model_. R package version 1.0.2, . A BibTeX entry for LaTeX users is @@ -116,7 +118,7 @@ citation("wowi") title = {wowi: Utilities for detecting statistically significant spatial clusters of high acute malnutrition rates using SaTScan's Bernoulli spatial-scan model}, author = {{Tomás Zaba}}, year = {2025}, - note = {R package version 1.0.1}, + note = {R package version 1.0.2}, url = {https://tiwowi.github.io/wowi/}, } diff --git a/README.qmd b/README.qmd index d22dfb0..2da606b 100644 --- a/README.qmd +++ b/README.qmd @@ -10,6 +10,7 @@ format: gfm [![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip) [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![R-CMD-check](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml) +[![Test app](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tiwowi/wowi/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/tiwowi/wowi/graph/badge.svg)](https://app.codecov.io/gh/tiwowi/wowi) diff --git a/inst/CITATION b/inst/CITATION index ea63582..a088d47 100644 --- a/inst/CITATION +++ b/inst/CITATION @@ -4,6 +4,6 @@ bibentry( title = "wowi: Utilities for detecting statistically significant spatial clusters of high acute malnutrition rates using SaTScan's Bernoulli spatial-scan model", author = person("Tomás Zaba"), year = 2025, - note = "R package version 1.0.1", + note = "R package version 1.0.2", url = "https://tiwowi.github.io/wowi/" ) From 5a9a88014b3cf932e54a4c49f57c711d00243ebb Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Wed, 17 Dec 2025 07:40:28 +0200 Subject: [PATCH 6/8] update news --- NEWS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3dbe536..e5564cd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ # wowi 1.0.2 +## Bug fixes + +* Resolved issue [#61](https://github.com/tiwowi/wowi/issues/61). +In the previous version, the regular expressions used to match text patterns into tables would break whenever the list of location IDs in a cluster wrapped onto a new line, altering the expected match order. This caused several columns to remain empty. The parser now handles these cases programmatically. + # wowi 1.0.1 ## General updates From 0235d43b103e1f68f23493a0c09ab24fd1a9865e Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Wed, 17 Dec 2025 11:18:16 +0200 Subject: [PATCH 7/8] re-factor test --- tests/testthat/test-utils.R | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 5706808..c736a40 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -82,21 +82,22 @@ testthat::test_that( testthat::expect_true(is.double(dplyr::pull(r[[1]][17]))) testthat::expect_true(is.character(dplyr::pull(r[[1]][18]))) - ## Check if results are in the tibble are correct ---- - testthat::expect_equal(r$.df$nr_EAs[1], 36) - testthat::expect_equal(r$.df$total_cases[1], 26) - testthat::expect_equal(r$.df$"%_cases"[1], 7.8) - testthat::expect_equal(r$.df$location_ids[1], "10,9") - testthat::expect_equal(r$.df$geo[1], "34.113909 N, 3.087933 E") - testthat::expect_equal(r$.df$radius[1], "1.20 km") - testthat::expect_equal(r$.df$span[1], "1.20 km") - testthat::expect_equal(r$.df$children[1], 25) - testthat::expect_equal(r$.df$n_cases[1], 6) - testthat::expect_equal(r$.df$expected_cases[1], 1.95) - testthat::expect_equal(r$.df$observedExpected[1], 3.07) - testthat::expect_equal(r$.df$relative_risk[1], 3.70) - testthat::expect_equal(r$.df$"%_cases_in_area"[1], 24.0) - testthat::expect_equal(r$.df$log_lik_ratio[1], 3.458213) - testthat::expect_equal(r$.df$pvalue[1], 0.55) + # ## Check if results are in the tibble are correct ---- + df <- r$.df + testthat::expect_equal(df$nr_EAs[1], 36) + testthat::expect_equal(df$total_cases[1], 26) + testthat::expect_equal(df$"%_cases"[1], 7.8) + testthat::expect_equal(df$location_ids[1], "10,9") + testthat::expect_equal(df$geo[1], "34.113909 N, 3.087933 E") + testthat::expect_equal(df$radius[1], "1.20 km") + testthat::expect_equal(df$span[1], "1.20 km") + testthat::expect_equal(df$children[1], 25) + testthat::expect_equal(df$n_cases[1], 6) + testthat::expect_equal(df$expected_cases[1], 1.95) + testthat::expect_equal(df$observedExpected[1], 3.07) + testthat::expect_equal(df$relative_risk[1], 3.70) + testthat::expect_equal(df$"%_cases_in_area"[1], 24.0) + testthat::expect_equal(df$log_lik_ratio[1], 3.458213) + testthat::expect_equal(df$pvalue[1], 0.55) } ) From d64ca71d623c9d9909fe864a0347a8488d3def0e Mon Sep 17 00:00:00 2001 From: tomaszaba Date: Wed, 17 Dec 2025 11:53:09 +0200 Subject: [PATCH 8/8] add 'nocov start' and 'nocov end' declaration to skip GitHub code cov test --- R/satscan-runner.R | 3 ++- R/utils.R | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/R/satscan-runner.R b/R/satscan-runner.R index 1bb5ce7..fbd3fd9 100644 --- a/R/satscan-runner.R +++ b/R/satscan-runner.R @@ -127,7 +127,8 @@ #' #' -# no# nocov start +# nocov start + ww_run_satscan <- function( .data, filename = NULL, diff --git a/R/utils.R b/R/utils.R index 86c4cfa..534e2e9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -15,6 +15,10 @@ skip_if_no_satscan <- function(ss_path = "/Applications/SaTScan.app/Contents/app #' @keywords internal #' #' + + +# nocov start + parse_clusters <- function(file) { ## Subset SaTScan-text-based output file ---- @@ -83,4 +87,6 @@ parse_clusters <- function(file) { ## Return binded results ---- dplyr::bind_rows(out) -} \ No newline at end of file +} + +# nocov end \ No newline at end of file