From 5ebd5dd0a22cf075df43d48a6f0138c9081dafc6 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:01:05 -0400 Subject: [PATCH 01/48] new function and function updates --- R/ATTAINSCrosswalks.R | 38 +++++++++++++-- R/draftcreateAUgeo.R | 109 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 R/draftcreateAUgeo.R diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 3fd4d2062..4a91cd8e1 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4732,7 +4732,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( .data } -#' Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs +#' Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs #' #' Build a distinct crosswalk between WQP Monitoring Locations and ATTAINS #' Assessment Units. For rows where `ATTAINS.AssessmentUnitIdentifier` is @@ -4747,6 +4747,15 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' #' @param .data A data frame containing, at minimum: #' - `TADA.MonitoringLocationIdentifier` +#' @param create_geo Boolean argument. When create_geo equals true, the output +#' will be a shp file ready for upload to ATTAINS. When create_geo equals false, +#' the input will be a df of the crosswalk. Default is create_geo equals false. +#' +#' If creating a GIS batch upload file for ATTAINS is desired, the input must +#' also contain: +#' - `TADA.LatitudeMeasure` +#' - `TADA.LongitudeMeasure` +#' - `HorizontalCoordinateReferenceSystemDatumName` #' #' If missing water-type values need to be crosswalked, the input must also #' contain: @@ -4811,8 +4820,21 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' } #' #' @export -TADA_CreatePointAUs <- function(.data, auid_prefix = NULL) { +TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, create_geo = FALSE) { + req <- c("TADA.MonitoringLocationIdentifier") + + retain <- c("ATTAINS.MonitoringLocationIdentifier", + "ATTAINS.AssessmentUnitIdentifier", + "ATTAINS.WaterType") + + if(isTRUE(create_geo)) { + req <- c(req, "TADA.LatitudeMeasure", "TADA.LongitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName") + + retain <- c("ATTAINS.AssessmentUnitIdentifier", + "geometry") + } missing <- setdiff(req, names(.data)) if (length(missing) > 0) { stop( @@ -4832,6 +4854,7 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL) { .data$ATTAINS.AssessmentUnitIdentifier ) + if(isFALSE(create_geo)) { need_crosswalk <- !("ATTAINS.WaterType" %in% names(.data)) || any( is.na(.data$ATTAINS.WaterType) | @@ -4852,6 +4875,7 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL) { validation = "none" ) } + } created_AUID <- is.na(.data$ATTAINS.AssessmentUnitIdentifier) | trimws(.data$ATTAINS.AssessmentUnitIdentifier) == "" @@ -4869,11 +4893,15 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL) { .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier + if(isTRUE(create_geo)) { + .data <- TADA_CreatePointAUGeometry(.data) + } + .data |> dplyr::select( - ATTAINS.MonitoringLocationIdentifier, - ATTAINS.AssessmentUnitIdentifier, - ATTAINS.WaterType + dplyr::all_of(retain) ) |> dplyr::distinct() } + + diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R new file mode 100644 index 000000000..7a3bebb2d --- /dev/null +++ b/R/draftcreateAUgeo.R @@ -0,0 +1,109 @@ +testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") + +testdat <- Data_TribalNations_Harmonized |> + dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") + +testpoints <- TADA_CreatePointAUs(testdat) + +#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +#' +#' @param .data A data frame containing: +#' +#' - `ATTAINS.AssessmentUnitIdentifier` +#' - `TADA.LongitudeMeasure` +#' - `TADA.LatitudeMeasure` +#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. +#' Default equals 4269 (NAD83). +#' +#' @return A distinct AU–ML crosswalk data frame containing: +#' - `ATTAINS.MonitoringLocationIdentifier` +#' - `ATTAINS.AssessmentUnitIdentifier` +#' - `ATTAINS.WaterType` +#' +#' @details +#' - Missing `ATTAINS.AssessmentUnitIdentifier` +#' values are replaced with `TADA.MonitoringLocationIdentifier`. +#' - If `auid_prefix` is supplied and non-empty, it is included for only +#' newly created AUIDs. +#' - `ATTAINS.MonitoringLocationIdentifier` is created from +#' `TADA.MonitoringLocationIdentifier`. +#' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. +#' +#' @seealso [TADA_CrosswalkATTAINSWaterTypes()] +#' +#' @examples +#' \dontrun{ +#' # Example 1: Create missing AUIDs +#' ex_df <- data.frame( +#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), +#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), +#' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), +#' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), +#' stringsAsFactors = FALSE +#' ) +#' +#' result <- TADA_CreatePointAUs(ex_df) +#' +#' # Example 2: Prefix only newly created AUIDs +#' result_prefixed <- TADA_CreatePointAUs( +#' ex_df, +#' auid_prefix = "WQX_" +#' ) +#' +#' # Example 3: AUID column is absent entirely +#' ex_df2 <- data.frame( +#' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), +#' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), +#' ATTAINS.WaterType = c(NA_character_, NA_character_), +#' stringsAsFactors = FALSE +#' ) +#' +#' result_missing_auid <- TADA_CreatePointAUs(ex_df2) +#' } +#' +#' @export +TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269) { + + req <- c("ATTAINS.AssessmentUnitIdentifier", + "TADA.LongitudeMeasure", + "TADA.LatitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName") + + if (!all(req %in% names(.data))) { + stop( + "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", + "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" + ) + } + + .data <- .data |> + dplyr::select(dplyr::all_of(req)) |> + dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) + + sf_pts <- sf::st_as_sf( + .data, + coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), + crs = 4269, + remove = TRUE + ) |> + sf::st_transform(crs = target_crs) + + sf_out <- sf_pts |> + dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> + dplyr::summarise( + n_pts = dplyr::n(), + geometry = if (n_pts[1] == 1) { + geometry[[1]] + } else { + sf::st_multipoint(do.call(rbind, sf::st_coordinates(geometry)[, 1:2, drop = FALSE])) + }, + .groups = "drop" + ) + + sf::st_as_sf(sf_out) +} + +# need to create AU batch upload file + + +# need to create AU with MLs batch upload file From e10e1c511327fd494e9abd753063c6652f411752 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:45:39 -0400 Subject: [PATCH 02/48] Update draftcreateAUgeo.R --- R/draftcreateAUgeo.R | 196 +++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R index 7a3bebb2d..b4d8ce101 100644 --- a/R/draftcreateAUgeo.R +++ b/R/draftcreateAUgeo.R @@ -1,109 +1,109 @@ -testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") - -testdat <- Data_TribalNations_Harmonized |> - dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") - -testpoints <- TADA_CreatePointAUs(testdat) - -#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +#' testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") #' -#' @param .data A data frame containing: +#' testdat <- Data_TribalNations_Harmonized |> +#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") #' -#' - `ATTAINS.AssessmentUnitIdentifier` -#' - `TADA.LongitudeMeasure` -#' - `TADA.LatitudeMeasure` -#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. -#' Default equals 4269 (NAD83). +#' testpoints <- TADA_CreatePointAUs(testdat) #' -#' @return A distinct AU–ML crosswalk data frame containing: -#' - `ATTAINS.MonitoringLocationIdentifier` -#' - `ATTAINS.AssessmentUnitIdentifier` -#' - `ATTAINS.WaterType` +#' #' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +#' #' +#' #' @param .data A data frame containing: +#' #' +#' #' - `ATTAINS.AssessmentUnitIdentifier` +#' #' - `TADA.LongitudeMeasure` +#' #' - `TADA.LatitudeMeasure` +#' #' @param target_crs Numeric. The target crs projection for upload to ATTAINS. +#' #' Default equals 4269 (NAD83). +#' #' +#' #' @return A distinct AU–ML crosswalk data frame containing: +#' #' - `ATTAINS.MonitoringLocationIdentifier` +#' #' - `ATTAINS.AssessmentUnitIdentifier` +#' #' - `ATTAINS.WaterType` +#' #' +#' #' @details +#' #' - Missing `ATTAINS.AssessmentUnitIdentifier` +#' #' values are replaced with `TADA.MonitoringLocationIdentifier`. +#' #' - If `auid_prefix` is supplied and non-empty, it is included for only +#' #' newly created AUIDs. +#' #' - `ATTAINS.MonitoringLocationIdentifier` is created from +#' #' `TADA.MonitoringLocationIdentifier`. +#' #' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. +#' #' +#' #' @seealso [TADA_CrosswalkATTAINSWaterTypes()] +#' #' +#' #' @examples +#' #' \dontrun{ +#' #' # Example 1: Create missing AUIDs +#' #' ex_df <- data.frame( +#' #' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), +#' #' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), +#' #' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), +#' #' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), +#' #' stringsAsFactors = FALSE +#' #' ) +#' #' +#' #' result <- TADA_CreatePointAUs(ex_df) +#' #' +#' #' # Example 2: Prefix only newly created AUIDs +#' #' result_prefixed <- TADA_CreatePointAUs( +#' #' ex_df, +#' #' auid_prefix = "WQX_" +#' #' ) +#' #' +#' #' # Example 3: AUID column is absent entirely +#' #' ex_df2 <- data.frame( +#' #' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), +#' #' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), +#' #' ATTAINS.WaterType = c(NA_character_, NA_character_), +#' #' stringsAsFactors = FALSE +#' #' ) +#' #' +#' #' result_missing_auid <- TADA_CreatePointAUs(ex_df2) +#' #' } +#' #' +#' #' @export +#' TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269) { #' -#' @details -#' - Missing `ATTAINS.AssessmentUnitIdentifier` -#' values are replaced with `TADA.MonitoringLocationIdentifier`. -#' - If `auid_prefix` is supplied and non-empty, it is included for only -#' newly created AUIDs. -#' - `ATTAINS.MonitoringLocationIdentifier` is created from -#' `TADA.MonitoringLocationIdentifier`. -#' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. +#' req <- c("ATTAINS.AssessmentUnitIdentifier", +#' "TADA.LongitudeMeasure", +#' "TADA.LatitudeMeasure", +#' "HorizontalCoordinateReferenceSystemDatumName") #' -#' @seealso [TADA_CrosswalkATTAINSWaterTypes()] +#' if (!all(req %in% names(.data))) { +#' stop( +#' "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", +#' "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" +#' ) +#' } #' -#' @examples -#' \dontrun{ -#' # Example 1: Create missing AUIDs -#' ex_df <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), -#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), -#' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), -#' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), -#' stringsAsFactors = FALSE -#' ) +#' .data <- .data |> +#' dplyr::select(dplyr::all_of(req)) |> +#' dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) #' -#' result <- TADA_CreatePointAUs(ex_df) +#' sf_pts <- sf::st_as_sf( +#' .data, +#' coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), +#' crs = 4269, +#' remove = TRUE +#' ) |> +#' sf::st_transform(crs = target_crs) #' -#' # Example 2: Prefix only newly created AUIDs -#' result_prefixed <- TADA_CreatePointAUs( -#' ex_df, -#' auid_prefix = "WQX_" -#' ) +#' sf_out <- sf_pts |> +#' dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> +#' dplyr::summarise( +#' n_pts = dplyr::n(), +#' geometry = if (n_pts[1] == 1) { +#' geometry[[1]] +#' } else { +#' sf::st_multipoint(do.call(rbind, sf::st_coordinates(geometry)[, 1:2, drop = FALSE])) +#' }, +#' .groups = "drop" +#' ) #' -#' # Example 3: AUID column is absent entirely -#' ex_df2 <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), -#' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), -#' ATTAINS.WaterType = c(NA_character_, NA_character_), -#' stringsAsFactors = FALSE -#' ) -#' -#' result_missing_auid <- TADA_CreatePointAUs(ex_df2) +#' sf::st_as_sf(sf_out) #' } #' -#' @export -TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269) { - - req <- c("ATTAINS.AssessmentUnitIdentifier", - "TADA.LongitudeMeasure", - "TADA.LatitudeMeasure", - "HorizontalCoordinateReferenceSystemDatumName") - - if (!all(req %in% names(.data))) { - stop( - "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", - "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" - ) - } - - .data <- .data |> - dplyr::select(dplyr::all_of(req)) |> - dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) - - sf_pts <- sf::st_as_sf( - .data, - coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), - crs = 4269, - remove = TRUE - ) |> - sf::st_transform(crs = target_crs) - - sf_out <- sf_pts |> - dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> - dplyr::summarise( - n_pts = dplyr::n(), - geometry = if (n_pts[1] == 1) { - geometry[[1]] - } else { - sf::st_multipoint(do.call(rbind, sf::st_coordinates(geometry)[, 1:2, drop = FALSE])) - }, - .groups = "drop" - ) - - sf::st_as_sf(sf_out) -} - -# need to create AU batch upload file - - -# need to create AU with MLs batch upload file +#' # need to create AU batch upload file +#' +#' +#' # need to create AU with MLs batch upload file From 47a4016b71ea0e98d776a5cb280d3218a85e3317 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 4 Aug 2026 16:22:33 -0400 Subject: [PATCH 03/48] added helper functions --- R/ATTAINSCrosswalks.R | 14 +- R/draftcreateAUgeo.R | 300 ++++++++++++++++++++++++++++-------------- 2 files changed, 205 insertions(+), 109 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 4a91cd8e1..bd7b8844e 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4877,19 +4877,9 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, create_geo = FALSE) { } } - created_AUID <- is.na(.data$ATTAINS.AssessmentUnitIdentifier) | - trimws(.data$ATTAINS.AssessmentUnitIdentifier) == "" + # fill missing assessment unit ids + .data <- fill_missing_assessment_unit_id(.data) - .data$ATTAINS.AssessmentUnitIdentifier[ - created_AUID - ] <- .data$TADA.MonitoringLocationIdentifier[created_AUID] - - if (!is.null(auid_prefix) && nzchar(auid_prefix)) { - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- paste0( - auid_prefix, - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] - ) - } .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R index b4d8ce101..1aa538bde 100644 --- a/R/draftcreateAUgeo.R +++ b/R/draftcreateAUgeo.R @@ -1,109 +1,215 @@ -#' testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") +testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") + +testdat <- Data_TribalNations_Harmonized |> + dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") + +testdat <- testdat |> + dplyr::rename(ATTAINS.AssessmentUnitIdentifier = TADA.MonitoringLocationIdentifier) + +testpoints <- TADA_CreatePointAUs(testdat) + +#' Fill missing ATTAINS Assessment Unit Identifiers #' -#' testdat <- Data_TribalNations_Harmonized |> -#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") +#' @keywords internal +#' @noRd +fill_missing_assessment_unit_id <- function(.data, auid_prefix = NULL) { + has_mloc <- "TADA.MonitoringLocationIdentifier" %in% names(.data) + has_auid <- "ATTAINS.AssessmentUnitIdentifier" %in% names(.data) + + if (!has_mloc && !has_auid) { + stop( + "At least one of 'TADA.MonitoringLocationIdentifier' or ", + "'ATTAINS.AssessmentUnitIdentifier' must be present." + ) + } + + # If target column doesn't exist, create it + if (!has_auid) { + .data$ATTAINS.AssessmentUnitIdentifier <- NA_character_ + } + + # If source column doesn't exist, we can still return .data unchanged + # unless you want to error when filling is impossible. + if (!has_mloc) { + return(.data) + } + + created_AUID <- is.na(.data$ATTAINS.AssessmentUnitIdentifier) | + trimws(as.character(.data$ATTAINS.AssessmentUnitIdentifier)) == "" + + if (any(created_AUID)) { + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- + .data$TADA.MonitoringLocationIdentifier[created_AUID] + } + + if (!is.null(auid_prefix) && nzchar(auid_prefix)) { + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- paste0( + auid_prefix, + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] + ) + } + + .data +} + +#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS #' -#' testpoints <- TADA_CreatePointAUs(testdat) +#' @param .data A data frame containing: #' -#' #' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS -#' #' -#' #' @param .data A data frame containing: -#' #' -#' #' - `ATTAINS.AssessmentUnitIdentifier` -#' #' - `TADA.LongitudeMeasure` -#' #' - `TADA.LatitudeMeasure` -#' #' @param target_crs Numeric. The target crs projection for upload to ATTAINS. -#' #' Default equals 4269 (NAD83). -#' #' -#' #' @return A distinct AU–ML crosswalk data frame containing: -#' #' - `ATTAINS.MonitoringLocationIdentifier` -#' #' - `ATTAINS.AssessmentUnitIdentifier` -#' #' - `ATTAINS.WaterType` -#' #' -#' #' @details -#' #' - Missing `ATTAINS.AssessmentUnitIdentifier` -#' #' values are replaced with `TADA.MonitoringLocationIdentifier`. -#' #' - If `auid_prefix` is supplied and non-empty, it is included for only -#' #' newly created AUIDs. -#' #' - `ATTAINS.MonitoringLocationIdentifier` is created from -#' #' `TADA.MonitoringLocationIdentifier`. -#' #' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. -#' #' -#' #' @seealso [TADA_CrosswalkATTAINSWaterTypes()] -#' #' -#' #' @examples -#' #' \dontrun{ -#' #' # Example 1: Create missing AUIDs -#' #' ex_df <- data.frame( -#' #' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), -#' #' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), -#' #' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), -#' #' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), -#' #' stringsAsFactors = FALSE -#' #' ) -#' #' -#' #' result <- TADA_CreatePointAUs(ex_df) -#' #' -#' #' # Example 2: Prefix only newly created AUIDs -#' #' result_prefixed <- TADA_CreatePointAUs( -#' #' ex_df, -#' #' auid_prefix = "WQX_" -#' #' ) -#' #' -#' #' # Example 3: AUID column is absent entirely -#' #' ex_df2 <- data.frame( -#' #' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), -#' #' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), -#' #' ATTAINS.WaterType = c(NA_character_, NA_character_), -#' #' stringsAsFactors = FALSE -#' #' ) -#' #' -#' #' result_missing_auid <- TADA_CreatePointAUs(ex_df2) -#' #' } -#' #' -#' #' @export -#' TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269) { +#' - `ATTAINS.AssessmentUnitIdentifier` or `TADA.MonitoringLocationIdentifier` +#' - `TADA.LongitudeMeasure` +#' - `TADA.LatitudeMeasure` +#' - `HorizontalCoordinateReferenceSystemDatumName` +#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. +#' Default equals 4269 (NAD83). +#' @param download_geo Boolean argument. When download equals TRUE, the GIS file +#' containing the assessment unit identifier and point geometry will be +#' downloaded into the user's downloads folder. When download equals FALSE, +#' nothing is downloaded and the df containing the columns "AU_ID" (assessment +#' unit identifier) and geometry is returned. The default is download_geo +#' equals FALSE. +#' @param auid_prefix Character or `NULL`. If provided and non-empty, this +#' prefix is included only for newly created `ATTAINS.AssessmentUnitIdentifier` +#' values that were filled from `TADA.MonitoringLocationIdentifier`. Existing +#' non-missing AUIDs are not modified. Use `NULL` to skip prefixing. #' -#' req <- c("ATTAINS.AssessmentUnitIdentifier", -#' "TADA.LongitudeMeasure", -#' "TADA.LatitudeMeasure", -#' "HorizontalCoordinateReferenceSystemDatumName") +#' @return When download_geo equals FALSE, a df containing the columns: +#' - `ATTAINS.MonitoringLocationIdentifier` +#' - `geometry` #' -#' if (!all(req %in% names(.data))) { -#' stop( -#' "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", -#' "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" -#' ) -#' } +#' When download_geo equals TRUE, a shp file in the user's downloads folder +#' with the columns: +#' - `AU_ID` +#' - `geometry` #' -#' .data <- .data |> -#' dplyr::select(dplyr::all_of(req)) |> -#' dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) +#' @details +#' - Missing `ATTAINS.AssessmentUnitIdentifier` +#' values are replaced with `TADA.MonitoringLocationIdentifier`. +#' - If `auid_prefix` is supplied and non-empty, it is included for only +#' newly created AUIDs. #' -#' sf_pts <- sf::st_as_sf( -#' .data, -#' coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), -#' crs = 4269, -#' remove = TRUE -#' ) |> -#' sf::st_transform(crs = target_crs) +#' @seealso [TADA_CrosswalkATTAINSWaterTypes()] #' -#' sf_out <- sf_pts |> -#' dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> -#' dplyr::summarise( -#' n_pts = dplyr::n(), -#' geometry = if (n_pts[1] == 1) { -#' geometry[[1]] -#' } else { -#' sf::st_multipoint(do.call(rbind, sf::st_coordinates(geometry)[, 1:2, drop = FALSE])) -#' }, -#' .groups = "drop" -#' ) +#' @examples +#' \dontrun{ +#' # Example 1: Create missing AUIDs +#' ex_df <- data.frame( +#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), +#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), +#' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), +#' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), +#' stringsAsFactors = FALSE +#' ) #' -#' sf::st_as_sf(sf_out) -#' } +#' result <- TADA_CreatePointAUs(ex_df) +#' +#' # Example 2: Prefix only newly created AUIDs +#' result_prefixed <- TADA_CreatePointAUs( +#' ex_df, +#' auid_prefix = "WQX_" +#' ) #' -#' # need to create AU batch upload file +#' # Example 3: AUID column is absent entirely +#' ex_df2 <- data.frame( +#' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), +#' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), +#' ATTAINS.WaterType = c(NA_character_, NA_character_), +#' stringsAsFactors = FALSE +#' ) #' +#' result_missing_auid <- TADA_CreatePointAUs(ex_df2) +#' } #' -#' # need to create AU with MLs batch upload file +#' @export +TADA_CreatePointAUGeometry <- function(.data, + target_crs = 4269, + download_geo = FALSE) { + + # always required columns + req <- c("TADA.LongitudeMeasure", + "TADA.LatitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName") + + # columns that can be used for AUID (at least one is required) + # if both are present, function will use ATTAINS.AssessmentUnitIdentifier + auid <- c("TADA.MonitoringLocationIdentifier", + "ATTAINS.AssessmentUnitIdentifier") + + + + # check to see if all required columns and any id cols are in .data + if (!all(req %in% names(.data)) & !any(auid %in% names(.data))) { + stop( + "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", + "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" + ) + } + + # determine id col + if("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { + + id.col <- "ATTAINS.AssessmentUnitIdentifier" + } else { + id.col <- "TADA.MonitoringLocationIdentifier" + } + + # add AUID prefix if needed + if(id.col == "TADA.MonitoringLocationIdentifier" & !is.null(auid_prefix)) { + + .data <- fill_missing_assessment_unit_id(.data, + auid_prefix = auid_prefix) + + id.col <- "ATTAINS.AssessmentUnitIdentifier" + + } + + .data <- .data |> + dplyr::select(rlang::sym(id.col), dplyr::all_of(req)) |> + dplyr::distinct() |> + dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) + + # create point geometries + sf_pts <- sf::st_as_sf( + .data, + coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), + crs = 4269, + remove = TRUE + ) |> + sf::st_transform(crs = target_crs) + + # check for multipoints + sf_out <- sf_pts |> + dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> + dplyr::summarise( + n_pts = dplyr::n(), + geometry = { + grp_geom <- geometry + coords <- sf::st_coordinates(grp_geom)[, 1:2, drop = FALSE] + + if (n_pts[1] == 1) { + sf::st_sfc(grp_geom[[1]], crs = sf::st_crs(sf_pts)) + } else { + sf::st_sfc(sf::st_multipoint(coords), crs = sf::st_crs(sf_pts)) + } + }, + .groups = "drop" + ) |> + dplyr::select(-n_pts) + + sf::st_as_sf(sf_out) + + if(isFALSE(download_geo)) { + + return(sf_out) + } else { + + shp.path <- .get_downloads_path() + } + + +} + +# need to create AU batch upload file + + +# need to create AU with MLs batch upload file From 43b8c3e290dae55a1a2b6d4d8725ea144b671604 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:07:04 -0400 Subject: [PATCH 04/48] Update draftcreateAUgeo.R --- R/draftcreateAUgeo.R | 65 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R index 1aa538bde..3306e0f6f 100644 --- a/R/draftcreateAUgeo.R +++ b/R/draftcreateAUgeo.R @@ -8,6 +8,35 @@ testdat <- testdat |> testpoints <- TADA_CreatePointAUs(testdat) +#' Save an sf object as a shapefile +#' +#' @keywords internal +#' @noRd +save_sf_as_shp <- function(sf_out, shp_path) { + if (!inherits(sf_out, "sf")) { + stop("'sf_out' must be an sf object.") + } + + if (is.null(shp_path) || !nzchar(shp_path)) { + stop("'shp_path' must be a valid file path.") + } + + out_dir <- dirname(shp_path) + if (!dir.exists(out_dir)) { + dir.create(out_dir, recursive = TRUE) + } + + sf::st_write( + sf_out, + dsn = shp_path, + driver = "ESRI Shapefile", + delete_dsn = TRUE, + quiet = TRUE + ) + + invisible(shp_path) +} + #' Fill missing ATTAINS Assessment Unit Identifiers #' #' @keywords internal @@ -123,7 +152,8 @@ fill_missing_assessment_unit_id <- function(.data, auid_prefix = NULL) { #' @export TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269, - download_geo = FALSE) { + download_geo = FALSE, + auid_prefix = NULL) { # always required columns req <- c("TADA.LongitudeMeasure", @@ -140,8 +170,10 @@ TADA_CreatePointAUGeometry <- function(.data, # check to see if all required columns and any id cols are in .data if (!all(req %in% names(.data)) & !any(auid %in% names(.data))) { stop( - "TADA_CreatePointAUGeometry: Input data must contain ATTAINS.AssessmentUnitIdentifier, ", - "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName" + "TADA_CreatePointAUGeometry: Input data must contain", + "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName", + "and at least one of the following columns: TADA.MonitoringLocationIdentifier or", + "ATTAINS.AssessmentUnitIdentifier." ) } @@ -179,7 +211,7 @@ TADA_CreatePointAUGeometry <- function(.data, # check for multipoints sf_out <- sf_pts |> - dplyr::group_by(ATTAINS.AssessmentUnitIdentifier) |> + dplyr::group_by(id.col) |> dplyr::summarise( n_pts = dplyr::n(), geometry = { @@ -196,17 +228,36 @@ TADA_CreatePointAUGeometry <- function(.data, ) |> dplyr::select(-n_pts) - sf::st_as_sf(sf_out) + sf_out <- sf::st_as_sf(sf_out) if(isFALSE(download_geo)) { return(sf_out) } else { - shp.path <- .get_downloads_path() - } + # get today's date + today <- format(Sys.Date(), "%m_%d_%Y") + # create file name + file.name <- paste0("TADAPointAUGeometry_", today) + # add auid prefix to file name if provided + if (!is.null(auid_prefix)) { + auid_prefix <- trimws(auid_prefix) + auid_prefix <- sub("[-_;:]+$", "", auid_prefix) + + if (nzchar(auid_prefix)) { + file.name <- paste0(auid_prefix, "_", file.name) + } + } + + # get path for shp file download + point.path <- .get_downloads_path(file.name) + + # save the shp file + save_sf_as_shp(sf_out = sf_out, + shp_path = point.path) + } } # need to create AU batch upload file From d81bcf437544f99fb697fb848571a6679bb156d4 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:46:25 -0400 Subject: [PATCH 05/48] updated documentation --- NAMESPACE | 1 + R/GeospatialFunctions.R | 200 ++++++++++++++++++++++ R/GeospatialUtilities.R | 73 ++++++++ R/draftcreateAUgeo.R | 265 +----------------------------- man/TADA_CreatePointAUGeometry.Rd | 116 +++++++++++++ man/TADA_CreatePointAUs.Rd | 28 +++- 6 files changed, 419 insertions(+), 264 deletions(-) create mode 100644 man/TADA_CreatePointAUGeometry.Rd diff --git a/NAMESPACE b/NAMESPACE index 0d7fd88ac..1af94e65e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -22,6 +22,7 @@ export(TADA_CreateAUMLCrosswalk) export(TADA_CreateCSV) export(TADA_CreateComparableID) export(TADA_CreatePairRef) +export(TADA_CreatePointAUGeometry) export(TADA_CreatePointAUs) export(TADA_CreateUnitRef) export(TADA_CrosswalkATTAINSWaterTypes) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 8112a1786..3bf57bc81 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3588,3 +3588,203 @@ TADA_CreateAUMLCrosswalk <- function( # return final list of dfs based on user inputs return(final_list) } + +#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +#' +#' @param .data A data frame containing: +#' +#' - `ATTAINS.AssessmentUnitIdentifier` or `TADA.MonitoringLocationIdentifier` +#' - `TADA.LongitudeMeasure` +#' - `TADA.LatitudeMeasure` +#' - `HorizontalCoordinateReferenceSystemDatumName` +#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. +#' Default equals 4269 (NAD83). +#' @param download_geo Boolean argument. When download equals TRUE, the GIS file +#' containing the assessment unit identifier and point geometry will be +#' downloaded into the user's downloads folder. When download equals FALSE, +#' nothing is downloaded and the df containing the columns "AU_ID" (assessment +#' unit identifier) and geometry is returned. The default is download_geo +#' equals FALSE. +#' @param auid_prefix Character or `NULL`. If provided and non-empty, this +#' prefix is included only for newly created `ATTAINS.AssessmentUnitIdentifier` +#' values that were filled from `TADA.MonitoringLocationIdentifier`. Existing +#' non-missing AUIDs are not modified. Use `NULL` to skip prefixing. +#' +#' @return When download_geo equals FALSE, a df containing the columns: +#' - `ATTAINS.MonitoringLocationIdentifier` +#' - `geometry` +#' +#' When download_geo equals TRUE, a shp file in the user's downloads folder +#' with the columns: +#' - `AU_ID` +#' - `geometry` +#' +#' @details +#' - Missing `ATTAINS.AssessmentUnitIdentifier` +#' values are replaced with `TADA.MonitoringLocationIdentifier`. +#' - If `auid_prefix` is supplied and non-empty, it is included for only +#' newly created AUIDs. +#' - This function can be run as part of TADA_CreatePointAUs. +#' +#' @seealso [TADA_CreatePointAUs()] +#' +#' @examples +#' \dontrun{ +#' # Example 1: Create point geometry for missing AUIDs and add AUID prefix to newly create AUIDs +#' # create example df +#' ex_df <- Data_TribalNations_Harmonized |> +#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> +#' dplyr::select(TADA.MonitoringLocationIdentifier, +#' TADA.LongitudeMeasure, +#' TADA.LatitudeMeasure, +#' HorizontalCoordinateReferenceSystemDatumName) |> +#' dplyr::distinct() |> +#' dplyr::slice_sample(n = 10) +#' +#' # create example point geometry +#' result <- TADA_CreatePointAUGeometry(ex_df, +#' auid_prefix = "EXAMPLE-") +#' +#' #' # Example 2: Create point geometry for existing AUIDs, with a multipoint example +#' # create example df +#' ex_df <- Data_TribalNations_Harmonized |> +#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> +#' dplyr::select(TADA.MonitoringLocationIdentifier, +#' TADA.LongitudeMeasure, +#' TADA.LatitudeMeasure, +#' HorizontalCoordinateReferenceSystemDatumName, +#' TADA.MonitoringLocationTypeName) |> +#' dplyr::distinct() |> +#' dplyr::arrange(TADA.MonitoringLocationIdentifier) |> +#' dplyr::slice_head(n = 10) +#' +#' # create crosswlk of AUIDs to monitoring location identifiers +#' ex_AUs <- TADA_CreatePointAUs(ex_df, +#' auid_prefix = "BLCKFEET-") |> +#' dplyr::rename(TADA.MonitoringLocationIdentifier = ATTAINS.MonitoringLocationIdentifier) +#' +#' # join AUIDs to example data +#' ex_df <- ex_df |> +#' dplyr::left_join(ex_AUs, dplyr::join_by(TADA.MonitoringLocationIdentifier)) |> +#' # for example purposes, assign an additional monitoring location identifier to an existing AUID +#' # to create a multipoint example +#' dplyr::mutate(ATTAINS.AssessmentUnitIdentifier = ifelse(TADA.MonitoringLocationIdentifier == +#' "BLCKFEET-00000002", +#' "BLCKFEET-BLCKFEET-00000001", +#' ATTAINS.AssessmentUnitIdentifier)) +#' +#' # first rows will contain multipoint geometry +#' result <- TADA_CreatePointAUGeometry(ex_df) +#' } +#' +#' @export +TADA_CreatePointAUGeometry <- function(.data, + target_crs = 4269, + download_geo = FALSE, + auid_prefix = NULL) { + + # always required columns + req <- c("TADA.LongitudeMeasure", + "TADA.LatitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName") + + # columns that can be used for AUID (at least one is required) + # if both are present, function will use ATTAINS.AssessmentUnitIdentifier + auid <- c("TADA.MonitoringLocationIdentifier", + "ATTAINS.AssessmentUnitIdentifier") + + + + # check to see if all required columns and any id cols are in .data + if (!all(req %in% names(.data)) & !any(auid %in% names(.data))) { + stop( + "TADA_CreatePointAUGeometry: Input data must contain", + "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName", + "and at least one of the following columns: TADA.MonitoringLocationIdentifier or", + "ATTAINS.AssessmentUnitIdentifier." + ) + } + + # determine id col + if("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { + + id.col <- "ATTAINS.AssessmentUnitIdentifier" + } else { + id.col <- "TADA.MonitoringLocationIdentifier" + } + + # add AUID prefix if needed + if(id.col == "TADA.MonitoringLocationIdentifier" & !is.null(auid_prefix)) { + + .data <- fill_missing_assessment_unit_id(.data, + auid_prefix = auid_prefix) + + id.col <- "ATTAINS.AssessmentUnitIdentifier" + + } + + .data <- .data |> + dplyr::select(rlang::sym(id.col), dplyr::all_of(req)) |> + dplyr::distinct() |> + dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) + + # create point geometries + sf_pts <- sf::st_as_sf( + .data, + coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), + crs = 4269, + remove = TRUE + ) |> + sf::st_transform(crs = target_crs) + + # check for multipoints + sf_out <- sf_pts |> + dplyr::group_by(!!rlang::sym(id.col)) |> + dplyr::summarise( + n_pts = dplyr::n(), + geometry = { + grp_geom <- geometry + coords <- sf::st_coordinates(grp_geom)[, 1:2, drop = FALSE] + + if (n_pts[1] == 1) { + sf::st_sfc(grp_geom[[1]], crs = sf::st_crs(sf_pts)) + } else { + sf::st_sfc(sf::st_multipoint(coords), crs = sf::st_crs(sf_pts)) + } + }, + .groups = "drop" + ) |> + dplyr::select(-n_pts) |> + dplyr::rename(AU_ID = !!rlang::sym(id.col)) + + sf_out <- sf::st_as_sf(sf_out) + + if(isFALSE(download_geo)) { + + return(sf_out) + } else { + + # get today's date + today <- format(Sys.Date(), "%m_%d_%Y") + + # create file name + file.name <- paste0("TADAPointAUGeometry_", today) + + # add auid prefix to file name if provided + if (!is.null(auid_prefix)) { + auid_prefix <- trimws(auid_prefix) + auid_prefix <- sub("[-_;:]+$", "", auid_prefix) + + if (nzchar(auid_prefix)) { + file.name <- paste0(auid_prefix, "_", file.name) + } + } + + # get path for shp file download + point.path <- .get_downloads_path(file.name) + + # save the shp file + save_sf_as_shp(sf_out = sf_out, + shp_path = point.path) + } +} diff --git a/R/GeospatialUtilities.R b/R/GeospatialUtilities.R index eea6352f7..f034b7523 100644 --- a/R/GeospatialUtilities.R +++ b/R/GeospatialUtilities.R @@ -1921,3 +1921,76 @@ fetchWaterType <- function(au_list, api_key = NULL) { return(results) } + +#' Save an sf object as a shapefile +#' +#' @keywords internal +#' @noRd +save_sf_as_shp <- function(sf_out, shp_path) { + if (!inherits(sf_out, "sf")) { + stop("'sf_out' must be an sf object.") + } + + if (is.null(shp_path) || !nzchar(shp_path)) { + stop("'shp_path' must be a valid file path.") + } + + out_dir <- dirname(shp_path) + if (!dir.exists(out_dir)) { + dir.create(out_dir, recursive = TRUE) + } + + sf::st_write( + sf_out, + dsn = shp_path, + driver = "ESRI Shapefile", + delete_dsn = TRUE, + quiet = TRUE + ) + + invisible(shp_path) +} + +#' Fill missing ATTAINS Assessment Unit Identifiers +#' +#' @keywords internal +#' @noRd +fill_missing_assessment_unit_id <- function(.data, auid_prefix = NULL) { + has_mloc <- "TADA.MonitoringLocationIdentifier" %in% names(.data) + has_auid <- "ATTAINS.AssessmentUnitIdentifier" %in% names(.data) + + if (!has_mloc && !has_auid) { + stop( + "At least one of 'TADA.MonitoringLocationIdentifier' or ", + "'ATTAINS.AssessmentUnitIdentifier' must be present." + ) + } + + # If target column doesn't exist, create it + if (!has_auid) { + .data$ATTAINS.AssessmentUnitIdentifier <- NA_character_ + } + + # If source column doesn't exist, we can still return .data unchanged + # unless you want to error when filling is impossible. + if (!has_mloc) { + return(.data) + } + + created_AUID <- is.na(.data$ATTAINS.AssessmentUnitIdentifier) | + trimws(as.character(.data$ATTAINS.AssessmentUnitIdentifier)) == "" + + if (any(created_AUID)) { + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- + .data$TADA.MonitoringLocationIdentifier[created_AUID] + } + + if (!is.null(auid_prefix) && nzchar(auid_prefix)) { + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- paste0( + auid_prefix, + .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] + ) + } + + .data +} diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R index 3306e0f6f..28a68578b 100644 --- a/R/draftcreateAUgeo.R +++ b/R/draftcreateAUgeo.R @@ -1,264 +1,17 @@ -testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") +# testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") +# +# testdat <- Data_TribalNations_Harmonized |> +# dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") +# +# testdat <- testdat |> +# dplyr::rename(ATTAINS.AssessmentUnitIdentifier = TADA.MonitoringLocationIdentifier) +# +# testpoints <- TADA_CreatePointAUs(testdat) -testdat <- Data_TribalNations_Harmonized |> - dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") -testdat <- testdat |> - dplyr::rename(ATTAINS.AssessmentUnitIdentifier = TADA.MonitoringLocationIdentifier) -testpoints <- TADA_CreatePointAUs(testdat) -#' Save an sf object as a shapefile -#' -#' @keywords internal -#' @noRd -save_sf_as_shp <- function(sf_out, shp_path) { - if (!inherits(sf_out, "sf")) { - stop("'sf_out' must be an sf object.") - } - if (is.null(shp_path) || !nzchar(shp_path)) { - stop("'shp_path' must be a valid file path.") - } - - out_dir <- dirname(shp_path) - if (!dir.exists(out_dir)) { - dir.create(out_dir, recursive = TRUE) - } - - sf::st_write( - sf_out, - dsn = shp_path, - driver = "ESRI Shapefile", - delete_dsn = TRUE, - quiet = TRUE - ) - - invisible(shp_path) -} - -#' Fill missing ATTAINS Assessment Unit Identifiers -#' -#' @keywords internal -#' @noRd -fill_missing_assessment_unit_id <- function(.data, auid_prefix = NULL) { - has_mloc <- "TADA.MonitoringLocationIdentifier" %in% names(.data) - has_auid <- "ATTAINS.AssessmentUnitIdentifier" %in% names(.data) - - if (!has_mloc && !has_auid) { - stop( - "At least one of 'TADA.MonitoringLocationIdentifier' or ", - "'ATTAINS.AssessmentUnitIdentifier' must be present." - ) - } - - # If target column doesn't exist, create it - if (!has_auid) { - .data$ATTAINS.AssessmentUnitIdentifier <- NA_character_ - } - - # If source column doesn't exist, we can still return .data unchanged - # unless you want to error when filling is impossible. - if (!has_mloc) { - return(.data) - } - - created_AUID <- is.na(.data$ATTAINS.AssessmentUnitIdentifier) | - trimws(as.character(.data$ATTAINS.AssessmentUnitIdentifier)) == "" - - if (any(created_AUID)) { - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- - .data$TADA.MonitoringLocationIdentifier[created_AUID] - } - - if (!is.null(auid_prefix) && nzchar(auid_prefix)) { - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- paste0( - auid_prefix, - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] - ) - } - - .data -} - -#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS -#' -#' @param .data A data frame containing: -#' -#' - `ATTAINS.AssessmentUnitIdentifier` or `TADA.MonitoringLocationIdentifier` -#' - `TADA.LongitudeMeasure` -#' - `TADA.LatitudeMeasure` -#' - `HorizontalCoordinateReferenceSystemDatumName` -#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. -#' Default equals 4269 (NAD83). -#' @param download_geo Boolean argument. When download equals TRUE, the GIS file -#' containing the assessment unit identifier and point geometry will be -#' downloaded into the user's downloads folder. When download equals FALSE, -#' nothing is downloaded and the df containing the columns "AU_ID" (assessment -#' unit identifier) and geometry is returned. The default is download_geo -#' equals FALSE. -#' @param auid_prefix Character or `NULL`. If provided and non-empty, this -#' prefix is included only for newly created `ATTAINS.AssessmentUnitIdentifier` -#' values that were filled from `TADA.MonitoringLocationIdentifier`. Existing -#' non-missing AUIDs are not modified. Use `NULL` to skip prefixing. -#' -#' @return When download_geo equals FALSE, a df containing the columns: -#' - `ATTAINS.MonitoringLocationIdentifier` -#' - `geometry` -#' -#' When download_geo equals TRUE, a shp file in the user's downloads folder -#' with the columns: -#' - `AU_ID` -#' - `geometry` -#' -#' @details -#' - Missing `ATTAINS.AssessmentUnitIdentifier` -#' values are replaced with `TADA.MonitoringLocationIdentifier`. -#' - If `auid_prefix` is supplied and non-empty, it is included for only -#' newly created AUIDs. -#' -#' @seealso [TADA_CrosswalkATTAINSWaterTypes()] -#' -#' @examples -#' \dontrun{ -#' # Example 1: Create missing AUIDs -#' ex_df <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), -#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), -#' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), -#' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), -#' stringsAsFactors = FALSE -#' ) -#' -#' result <- TADA_CreatePointAUs(ex_df) -#' -#' # Example 2: Prefix only newly created AUIDs -#' result_prefixed <- TADA_CreatePointAUs( -#' ex_df, -#' auid_prefix = "WQX_" -#' ) -#' -#' # Example 3: AUID column is absent entirely -#' ex_df2 <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), -#' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), -#' ATTAINS.WaterType = c(NA_character_, NA_character_), -#' stringsAsFactors = FALSE -#' ) -#' -#' result_missing_auid <- TADA_CreatePointAUs(ex_df2) -#' } -#' -#' @export -TADA_CreatePointAUGeometry <- function(.data, - target_crs = 4269, - download_geo = FALSE, - auid_prefix = NULL) { - - # always required columns - req <- c("TADA.LongitudeMeasure", - "TADA.LatitudeMeasure", - "HorizontalCoordinateReferenceSystemDatumName") - - # columns that can be used for AUID (at least one is required) - # if both are present, function will use ATTAINS.AssessmentUnitIdentifier - auid <- c("TADA.MonitoringLocationIdentifier", - "ATTAINS.AssessmentUnitIdentifier") - - - - # check to see if all required columns and any id cols are in .data - if (!all(req %in% names(.data)) & !any(auid %in% names(.data))) { - stop( - "TADA_CreatePointAUGeometry: Input data must contain", - "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName", - "and at least one of the following columns: TADA.MonitoringLocationIdentifier or", - "ATTAINS.AssessmentUnitIdentifier." - ) - } - - # determine id col - if("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { - - id.col <- "ATTAINS.AssessmentUnitIdentifier" - } else { - id.col <- "TADA.MonitoringLocationIdentifier" - } - - # add AUID prefix if needed - if(id.col == "TADA.MonitoringLocationIdentifier" & !is.null(auid_prefix)) { - - .data <- fill_missing_assessment_unit_id(.data, - auid_prefix = auid_prefix) - - id.col <- "ATTAINS.AssessmentUnitIdentifier" - - } - - .data <- .data |> - dplyr::select(rlang::sym(id.col), dplyr::all_of(req)) |> - dplyr::distinct() |> - dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) - - # create point geometries - sf_pts <- sf::st_as_sf( - .data, - coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), - crs = 4269, - remove = TRUE - ) |> - sf::st_transform(crs = target_crs) - - # check for multipoints - sf_out <- sf_pts |> - dplyr::group_by(id.col) |> - dplyr::summarise( - n_pts = dplyr::n(), - geometry = { - grp_geom <- geometry - coords <- sf::st_coordinates(grp_geom)[, 1:2, drop = FALSE] - - if (n_pts[1] == 1) { - sf::st_sfc(grp_geom[[1]], crs = sf::st_crs(sf_pts)) - } else { - sf::st_sfc(sf::st_multipoint(coords), crs = sf::st_crs(sf_pts)) - } - }, - .groups = "drop" - ) |> - dplyr::select(-n_pts) - - sf_out <- sf::st_as_sf(sf_out) - - if(isFALSE(download_geo)) { - - return(sf_out) - } else { - - # get today's date - today <- format(Sys.Date(), "%m_%d_%Y") - - # create file name - file.name <- paste0("TADAPointAUGeometry_", today) - - # add auid prefix to file name if provided - if (!is.null(auid_prefix)) { - auid_prefix <- trimws(auid_prefix) - auid_prefix <- sub("[-_;:]+$", "", auid_prefix) - - if (nzchar(auid_prefix)) { - file.name <- paste0(auid_prefix, "_", file.name) - } - } - - # get path for shp file download - point.path <- .get_downloads_path(file.name) - - # save the shp file - save_sf_as_shp(sf_out = sf_out, - shp_path = point.path) - } -} # need to create AU batch upload file diff --git a/man/TADA_CreatePointAUGeometry.Rd b/man/TADA_CreatePointAUGeometry.Rd new file mode 100644 index 000000000..96f5fd13b --- /dev/null +++ b/man/TADA_CreatePointAUGeometry.Rd @@ -0,0 +1,116 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/GeospatialFunctions.R +\name{TADA_CreatePointAUGeometry} +\alias{TADA_CreatePointAUGeometry} +\title{Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS} +\usage{ +TADA_CreatePointAUGeometry( + .data, + target_crs = 4269, + download_geo = FALSE, + auid_prefix = NULL +) +} +\arguments{ +\item{.data}{A data frame containing: +\itemize{ +\item \code{ATTAINS.AssessmentUnitIdentifier} or \code{TADA.MonitoringLocationIdentifier} +\item \code{TADA.LongitudeMeasure} +\item \code{TADA.LatitudeMeasure} +\item \code{HorizontalCoordinateReferenceSystemDatumName} +}} + +\item{target_crs}{Numeric. The target crs projection for upload to ATTAINS. +Default equals 4269 (NAD83).} + +\item{download_geo}{Boolean argument. When download equals TRUE, the GIS file +containing the assessment unit identifier and point geometry will be +downloaded into the user's downloads folder. When download equals FALSE, +nothing is downloaded and the df containing the columns "AU_ID" (assessment +unit identifier) and geometry is returned. The default is download_geo +equals FALSE.} + +\item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this +prefix is included only for newly created \code{ATTAINS.AssessmentUnitIdentifier} +values that were filled from \code{TADA.MonitoringLocationIdentifier}. Existing +non-missing AUIDs are not modified. Use \code{NULL} to skip prefixing.} +} +\value{ +When download_geo equals FALSE, a df containing the columns: +\itemize{ +\item \code{ATTAINS.MonitoringLocationIdentifier} +\item \code{geometry} +} + +When download_geo equals TRUE, a shp file in the user's downloads folder +with the columns: +\itemize{ +\item \code{AU_ID} +\item \code{geometry} +} +} +\description{ +Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +} +\details{ +\itemize{ +\item Missing \code{ATTAINS.AssessmentUnitIdentifier} +values are replaced with \code{TADA.MonitoringLocationIdentifier}. +\item If \code{auid_prefix} is supplied and non-empty, it is included for only +newly created AUIDs. +\item This function can be run as part of TADA_CreatePointAUs. +} +} +\examples{ +\dontrun{ +# Example 1: Create point geometry for missing AUIDs and add AUID prefix to newly create AUIDs +# create example df +ex_df <- Data_TribalNations_Harmonized |> +dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> +dplyr::select(TADA.MonitoringLocationIdentifier, + TADA.LongitudeMeasure, + TADA.LatitudeMeasure, + HorizontalCoordinateReferenceSystemDatumName) |> + dplyr::distinct() |> + dplyr::slice_sample(n = 10) + +# create example point geometry +result <- TADA_CreatePointAUGeometry(ex_df, + auid_prefix = "EXAMPLE-") + +#' # Example 2: Create point geometry for existing AUIDs, with a multipoint example +# create example df +ex_df <- Data_TribalNations_Harmonized |> +dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> +dplyr::select(TADA.MonitoringLocationIdentifier, + TADA.LongitudeMeasure, + TADA.LatitudeMeasure, + HorizontalCoordinateReferenceSystemDatumName, + TADA.MonitoringLocationTypeName) |> + dplyr::distinct() |> + dplyr::arrange(TADA.MonitoringLocationIdentifier) |> + dplyr::slice_head(n = 10) + +# create crosswlk of AUIDs to monitoring location identifiers +ex_AUs <- TADA_CreatePointAUs(ex_df, + auid_prefix = "BLCKFEET-") |> + dplyr::rename(TADA.MonitoringLocationIdentifier = ATTAINS.MonitoringLocationIdentifier) + +# join AUIDs to example data +ex_df <- ex_df |> +dplyr::left_join(ex_AUs, dplyr::join_by(TADA.MonitoringLocationIdentifier)) |> + # for example purposes, assign an additional monitoring location identifier to an existing AUID + # to create a multipoint example + dplyr::mutate(ATTAINS.AssessmentUnitIdentifier = ifelse(TADA.MonitoringLocationIdentifier == + "BLCKFEET-00000002", + "BLCKFEET-BLCKFEET-00000001", + ATTAINS.AssessmentUnitIdentifier)) + +# first rows will contain multipoint geometry +result <- TADA_CreatePointAUGeometry(ex_df) +} + +} +\seealso{ +\code{\link[=TADA_CreatePointAUs]{TADA_CreatePointAUs()}} +} diff --git a/man/TADA_CreatePointAUs.Rd b/man/TADA_CreatePointAUs.Rd index 835fbc616..7609f38c0 100644 --- a/man/TADA_CreatePointAUs.Rd +++ b/man/TADA_CreatePointAUs.Rd @@ -2,14 +2,32 @@ % Please edit documentation in R/ATTAINSCrosswalks.R \name{TADA_CreatePointAUs} \alias{TADA_CreatePointAUs} -\title{Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs} +\title{Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs} \usage{ -TADA_CreatePointAUs(.data, auid_prefix = NULL) +TADA_CreatePointAUs(.data, auid_prefix = NULL, create_geo = FALSE) } \arguments{ \item{.data}{A data frame containing, at minimum: \itemize{ \item \code{TADA.MonitoringLocationIdentifier} +}} + +\item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this +prefix is included only for newly created +\code{ATTAINS.AssessmentUnitIdentifier} values that were filled from +\code{TADA.MonitoringLocationIdentifier}. Existing non-missing AUIDs are not +modified. Use \code{NULL} to skip prefixing.} + +\item{create_geo}{Boolean argument. When create_geo equals true, the output +will be a shp file ready for upload to ATTAINS. When create_geo equals false, +the input will be a df of the crosswalk. Default is create_geo equals false. + +If creating a GIS batch upload file for ATTAINS is desired, the input must +also contain: +\itemize{ +\item \code{TADA.LatitudeMeasure} +\item \code{TADA.LongitudeMeasure} +\item \code{HorizontalCoordinateReferenceSystemDatumName} } If missing water-type values need to be crosswalked, the input must also @@ -25,12 +43,6 @@ Optionally, the input may already include: } If \code{ATTAINS.AssessmentUnitIdentifier} is absent, it will be added.} - -\item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this -prefix is included only for newly created -\code{ATTAINS.AssessmentUnitIdentifier} values that were filled from -\code{TADA.MonitoringLocationIdentifier}. Existing non-missing AUIDs are not -modified. Use \code{NULL} to skip prefixing.} } \value{ A distinct AU–ML crosswalk data frame containing: From 4a884ebb77071152c45fa782567e0084a2509847 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:15:59 -0400 Subject: [PATCH 06/48] Update ATTAINSCrosswalks.R added additional comments for TADA_CreatePointAUs --- R/ATTAINSCrosswalks.R | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index bd7b8844e..3842f2f73 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4820,21 +4820,31 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' } #' #' @export -TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, create_geo = FALSE) { +TADA_CreatePointAUs <- function(.data, + auid_prefix = NULL, + create_geo = FALSE) { + # set required col req <- c("TADA.MonitoringLocationIdentifier") + # set cols to retain retain <- c("ATTAINS.MonitoringLocationIdentifier", "ATTAINS.AssessmentUnitIdentifier", "ATTAINS.WaterType") + # modify column lists if creating geometry if(isTRUE(create_geo)) { + + # add additonal required cols req <- c(req, "TADA.LatitudeMeasure", "TADA.LongitudeMeasure", "HorizontalCoordinateReferenceSystemDatumName") + # set a different list of cols to retain retain <- c("ATTAINS.AssessmentUnitIdentifier", "geometry") } + + # check to see if required col(s) are present missing <- setdiff(req, names(.data)) if (length(missing) > 0) { stop( @@ -4843,33 +4853,34 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, create_geo = FALSE) { ) } - if (!"ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { - .data$ATTAINS.AssessmentUnitIdentifier <- NA_character_ - } - - .data$TADA.MonitoringLocationIdentifier <- as.character( - .data$TADA.MonitoringLocationIdentifier - ) - .data$ATTAINS.AssessmentUnitIdentifier <- as.character( - .data$ATTAINS.AssessmentUnitIdentifier - ) + # fill any missing assessment unit ids (or create them if input df only + # contains TADA monitoring location identifiers) + .data <- fill_missing_assessment_unit_id(.data, + auid_prefix = auid_prefix) + # if create_geo equals FALSE, add ATTAINS water type if(isFALSE(create_geo)) { - need_crosswalk <- !("ATTAINS.WaterType" %in% names(.data)) || + + # determine if ATTAINS.WaterType is missing from df or if it is present + # but has blank values + need_crosswalk <- !("ATTAINS.WaterType" %in% names(.data)) || any( is.na(.data$ATTAINS.WaterType) | trimws(as.character(.data$ATTAINS.WaterType)) == "", na.rm = TRUE ) - if (need_crosswalk) { + # check to see if TADA.MonitoringLocationTypeName is in df as it is required + # for crosswalking ATTAINS.WaterTypes + if (need_crosswalk) { if (!"TADA.MonitoringLocationTypeName" %in% names(.data)) { stop( "TADA_CreatePointAUs: Missing required column: TADA.MonitoringLocationTypeName" ) } - .data <- TADA_CrosswalkATTAINSWaterTypes( + # crosswalk ATTAINS water types to df + .data <- TADA_CrosswalkATTAINSWaterTypes( .data, overwrite_existing = FALSE, validation = "none" @@ -4881,7 +4892,8 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, create_geo = FALSE) { .data <- fill_missing_assessment_unit_id(.data) - .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier + # change name of monitoring location identifier column for batch upload to ATTAINS + .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier if(isTRUE(create_geo)) { .data <- TADA_CreatePointAUGeometry(.data) From a2b483132e284f9485dfac239badc4119b18e359 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Wed, 5 Aug 2026 17:34:28 -0400 Subject: [PATCH 07/48] update functions and documentation --- R/ATTAINSCrosswalks.R | 167 ++++++++++---------------- R/GeospatialFunctions.R | 187 +++++++++++------------------- R/draftcreateAUgeo.R | 26 +++-- man/TADA_CreatePointAUGeometry.Rd | 102 ++++------------ man/TADA_CreatePointAUs.Rd | 97 ++++++---------- 5 files changed, 205 insertions(+), 374 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 3842f2f73..ed540a727 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4735,24 +4735,18 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs #' #' Build a distinct crosswalk between WQP Monitoring Locations and ATTAINS -#' Assessment Units. For rows where `ATTAINS.AssessmentUnitIdentifier` is -#' missing or blank, the value is filled with -#' `TADA.MonitoringLocationIdentifier`, optionally with an `auid_prefix` -#' appended. Existing non-missing, non-blank AUIDs are left unchanged. +#' Assessment Units. Missing or blank `ATTAINS.AssessmentUnitIdentifier` values +#' are filled from `TADA.MonitoringLocationIdentifier`, optionally prefixed +#' with `auid_prefix`. Existing non-missing, non-blank AUIDs are left unchanged. #' #' If `ATTAINS.WaterType` is missing or contains any blank values, the function -#' will attempt to populate it by calling -#' `TADA_CrosswalkATTAINSWaterTypes()` internally with -#' `overwrite_existing = FALSE` and `validation = "none"`. +#' attempts to populate it by calling `TADA_CrosswalkATTAINSWaterTypes()` +#' internally with `overwrite_existing = FALSE` and `validation = "none"`. #' #' @param .data A data frame containing, at minimum: #' - `TADA.MonitoringLocationIdentifier` -#' @param create_geo Boolean argument. When create_geo equals true, the output -#' will be a shp file ready for upload to ATTAINS. When create_geo equals false, -#' the input will be a df of the crosswalk. Default is create_geo equals false. #' -#' If creating a GIS batch upload file for ATTAINS is desired, the input must -#' also contain: +#' If `create_geo = TRUE`, the input must also contain: #' - `TADA.LatitudeMeasure` #' - `TADA.LongitudeMeasure` #' - `HorizontalCoordinateReferenceSystemDatumName` @@ -4761,90 +4755,53 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' contain: #' - `TADA.MonitoringLocationTypeName` #' -#' Optionally, the input may already include: +#' Optional columns: #' - `ATTAINS.AssessmentUnitIdentifier` #' - `ATTAINS.WaterType` #' -#' If `ATTAINS.AssessmentUnitIdentifier` is absent, it will be added. -#' #' @param auid_prefix Character or `NULL`. If provided and non-empty, this -#' prefix is included only for newly created -#' `ATTAINS.AssessmentUnitIdentifier` values that were filled from -#' `TADA.MonitoringLocationIdentifier`. Existing non-missing AUIDs are not -#' modified. Use `NULL` to skip prefixing. -#' -#' @return A distinct AU–ML crosswalk data frame containing: +#' prefix is added only to newly created +#' `ATTAINS.AssessmentUnitIdentifier` values. +#' @param create_geo Logical. If `TRUE`, also create point geometry using +#' `TADA_CreatePointAUGeometry()`. +#' @param download_geo Logical. If `TRUE`, write the geometry shapefile to the +#' user's downloads folder. +#' +#' @return If `create_geo = FALSE`, a distinct crosswalk data frame containing: #' - `ATTAINS.MonitoringLocationIdentifier` #' - `ATTAINS.AssessmentUnitIdentifier` #' - `ATTAINS.WaterType` #' +#' If `create_geo = TRUE`, a named list with: +#' - `crosswalk` +#' - `geometry` +#' #' @details -#' - Missing `ATTAINS.AssessmentUnitIdentifier` -#' values are replaced with `TADA.MonitoringLocationIdentifier`. -#' - If `auid_prefix` is supplied and non-empty, it is included for only -#' newly created AUIDs. +#' - Missing or blank `ATTAINS.AssessmentUnitIdentifier` values are replaced +#' with `TADA.MonitoringLocationIdentifier`. +#' - If `auid_prefix` is supplied and non-empty, it is used only for newly +#' created AUIDs. #' - `ATTAINS.MonitoringLocationIdentifier` is created from #' `TADA.MonitoringLocationIdentifier`. #' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. #' -#' @seealso [TADA_CrosswalkATTAINSWaterTypes()] -#' -#' @examples -#' \dontrun{ -#' # Example 1: Create missing AUIDs -#' ex_df <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), -#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), -#' ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), -#' ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), -#' stringsAsFactors = FALSE -#' ) -#' -#' result <- TADA_CreatePointAUs(ex_df) -#' -#' # Example 2: Prefix only newly created AUIDs -#' result_prefixed <- TADA_CreatePointAUs( -#' ex_df, -#' auid_prefix = "WQX_" -#' ) -#' -#' # Example 3: AUID column is absent entirely -#' ex_df2 <- data.frame( -#' TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), -#' TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), -#' ATTAINS.WaterType = c(NA_character_, NA_character_), -#' stringsAsFactors = FALSE -#' ) -#' -#' result_missing_auid <- TADA_CreatePointAUs(ex_df2) -#' } +#' @seealso [TADA_CrosswalkATTAINSWaterTypes()], [TADA_CreatePointAUGeometry()] #' #' @export TADA_CreatePointAUs <- function(.data, auid_prefix = NULL, - create_geo = FALSE) { + create_geo = FALSE, + download_geo = FALSE) { - # set required col req <- c("TADA.MonitoringLocationIdentifier") + geo_req <- c("TADA.LatitudeMeasure", + "TADA.LongitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName") - # set cols to retain - retain <- c("ATTAINS.MonitoringLocationIdentifier", - "ATTAINS.AssessmentUnitIdentifier", - "ATTAINS.WaterType") - - # modify column lists if creating geometry - if(isTRUE(create_geo)) { - - # add additonal required cols - req <- c(req, "TADA.LatitudeMeasure", "TADA.LongitudeMeasure", - "HorizontalCoordinateReferenceSystemDatumName") - - # set a different list of cols to retain - retain <- c("ATTAINS.AssessmentUnitIdentifier", - "geometry") + if (isTRUE(create_geo)) { + req <- c(req, geo_req) } - # check to see if required col(s) are present missing <- setdiff(req, names(.data)) if (length(missing) > 0) { stop( @@ -4853,57 +4810,59 @@ TADA_CreatePointAUs <- function(.data, ) } - # fill any missing assessment unit ids (or create them if input df only - # contains TADA monitoring location identifiers) - .data <- fill_missing_assessment_unit_id(.data, - auid_prefix = auid_prefix) + # ensure AUID column exists and is filled from monitoring location ID as needed + .data <- fill_missing_assessment_unit_id(.data, auid_prefix = auid_prefix) - # if create_geo equals FALSE, add ATTAINS water type - if(isFALSE(create_geo)) { + # create ATTAINS.MonitoringLocationIdentifier + .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier - # determine if ATTAINS.WaterType is missing from df or if it is present - # but has blank values - need_crosswalk <- !("ATTAINS.WaterType" %in% names(.data)) || + # determine whether ATTAINS.WaterType needs crosswalking + need_crosswalk <- !("ATTAINS.WaterType" %in% names(.data)) || any( is.na(.data$ATTAINS.WaterType) | trimws(as.character(.data$ATTAINS.WaterType)) == "", na.rm = TRUE ) - # check to see if TADA.MonitoringLocationTypeName is in df as it is required - # for crosswalking ATTAINS.WaterTypes - if (need_crosswalk) { + if (isTRUE(need_crosswalk)) { if (!"TADA.MonitoringLocationTypeName" %in% names(.data)) { stop( - "TADA_CreatePointAUs: Missing required column: TADA.MonitoringLocationTypeName" + "TADA_CreatePointAUs: Missing required column for water-type crosswalk: ", + "TADA.MonitoringLocationTypeName" ) } - # crosswalk ATTAINS water types to df - .data <- TADA_CrosswalkATTAINSWaterTypes( + .data <- TADA_CrosswalkATTAINSWaterTypes( .data, overwrite_existing = FALSE, validation = "none" ) - } } - # fill missing assessment unit ids - .data <- fill_missing_assessment_unit_id(.data) - + retain <- c( + "ATTAINS.MonitoringLocationIdentifier", + "ATTAINS.AssessmentUnitIdentifier", + "ATTAINS.WaterType" + ) - # change name of monitoring location identifier column for batch upload to ATTAINS - .data$ATTAINS.MonitoringLocationIdentifier <- .data$TADA.MonitoringLocationIdentifier + PointAU.Crosswalk <- .data |> + dplyr::select(dplyr::any_of(retain)) |> + dplyr::distinct() - if(isTRUE(create_geo)) { - .data <- TADA_CreatePointAUGeometry(.data) + if (!isTRUE(create_geo)) { + return(PointAU.Crosswalk) } - .data |> - dplyr::select( - dplyr::all_of(retain) - ) |> - dplyr::distinct() -} - + PointAU.Geometry <- TADA_CreatePointAUGeometry( + .data = .data, + target_crs = 4269, + download_geo = download_geo, + return_geo = TRUE, + auid_prefix = auid_prefix + ) + list( + crosswalk = PointAU.Crosswalk, + geometry = PointAU.Geometry + ) +} diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 3bf57bc81..307a36c54 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3589,146 +3589,94 @@ TADA_CreateAUMLCrosswalk <- function( return(final_list) } -#' Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +#' Create point geometry for ATTAINS Assessment Units #' -#' @param .data A data frame containing: +#' Creates point or multipoint geometry for ATTAINS Assessment Units using +#' `ATTAINS.AssessmentUnitIdentifier` when available, otherwise +#' `TADA.MonitoringLocationIdentifier`. #' -#' - `ATTAINS.AssessmentUnitIdentifier` or `TADA.MonitoringLocationIdentifier` +#' @param .data A data frame containing: #' - `TADA.LongitudeMeasure` #' - `TADA.LatitudeMeasure` #' - `HorizontalCoordinateReferenceSystemDatumName` -#' @param target_crs Numeric. The target crs projection for upload to ATTAINS. -#' Default equals 4269 (NAD83). -#' @param download_geo Boolean argument. When download equals TRUE, the GIS file -#' containing the assessment unit identifier and point geometry will be -#' downloaded into the user's downloads folder. When download equals FALSE, -#' nothing is downloaded and the df containing the columns "AU_ID" (assessment -#' unit identifier) and geometry is returned. The default is download_geo -#' equals FALSE. +#' +#' And at least one of: +#' - `ATTAINS.AssessmentUnitIdentifier` +#' - `TADA.MonitoringLocationIdentifier` +#' +#' @param target_crs Numeric. Target CRS EPSG code. Default is 4269. +#' @param download_geo Logical. If `TRUE`, write a shapefile to the user's +#' downloads folder. +#' @param return_geo Logical. If `TRUE`, return the `sf` object. #' @param auid_prefix Character or `NULL`. If provided and non-empty, this -#' prefix is included only for newly created `ATTAINS.AssessmentUnitIdentifier` -#' values that were filled from `TADA.MonitoringLocationIdentifier`. Existing -#' non-missing AUIDs are not modified. Use `NULL` to skip prefixing. +#' prefix is applied only to newly created +#' `ATTAINS.AssessmentUnitIdentifier` values. #' -#' @return When download_geo equals FALSE, a df containing the columns: -#' - `ATTAINS.MonitoringLocationIdentifier` +#' @return If `return_geo = TRUE`, an `sf` object with: +#' - `AU_ID` #' - `geometry` #' -#' When download_geo equals TRUE, a shp file in the user's downloads folder -#' with the columns: -#' - `AU_ID` -#' - `geometry` +#' If `download_geo = TRUE`, a shapefile is written to the downloads folder. #' #' @details -#' - Missing `ATTAINS.AssessmentUnitIdentifier` -#' values are replaced with `TADA.MonitoringLocationIdentifier`. -#' - If `auid_prefix` is supplied and non-empty, it is included for only -#' newly created AUIDs. -#' - This function can be run as part of TADA_CreatePointAUs. +#' - Missing or blank `ATTAINS.AssessmentUnitIdentifier` values are replaced +#' with `TADA.MonitoringLocationIdentifier`. +#' - Single-location groups retain `POINT` geometry. +#' - Multi-location groups are written as `MULTIPOINT`. #' #' @seealso [TADA_CreatePointAUs()] #' -#' @examples -#' \dontrun{ -#' # Example 1: Create point geometry for missing AUIDs and add AUID prefix to newly create AUIDs -#' # create example df -#' ex_df <- Data_TribalNations_Harmonized |> -#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> -#' dplyr::select(TADA.MonitoringLocationIdentifier, -#' TADA.LongitudeMeasure, -#' TADA.LatitudeMeasure, -#' HorizontalCoordinateReferenceSystemDatumName) |> -#' dplyr::distinct() |> -#' dplyr::slice_sample(n = 10) -#' -#' # create example point geometry -#' result <- TADA_CreatePointAUGeometry(ex_df, -#' auid_prefix = "EXAMPLE-") -#' -#' #' # Example 2: Create point geometry for existing AUIDs, with a multipoint example -#' # create example df -#' ex_df <- Data_TribalNations_Harmonized |> -#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> -#' dplyr::select(TADA.MonitoringLocationIdentifier, -#' TADA.LongitudeMeasure, -#' TADA.LatitudeMeasure, -#' HorizontalCoordinateReferenceSystemDatumName, -#' TADA.MonitoringLocationTypeName) |> -#' dplyr::distinct() |> -#' dplyr::arrange(TADA.MonitoringLocationIdentifier) |> -#' dplyr::slice_head(n = 10) -#' -#' # create crosswlk of AUIDs to monitoring location identifiers -#' ex_AUs <- TADA_CreatePointAUs(ex_df, -#' auid_prefix = "BLCKFEET-") |> -#' dplyr::rename(TADA.MonitoringLocationIdentifier = ATTAINS.MonitoringLocationIdentifier) -#' -#' # join AUIDs to example data -#' ex_df <- ex_df |> -#' dplyr::left_join(ex_AUs, dplyr::join_by(TADA.MonitoringLocationIdentifier)) |> -#' # for example purposes, assign an additional monitoring location identifier to an existing AUID -#' # to create a multipoint example -#' dplyr::mutate(ATTAINS.AssessmentUnitIdentifier = ifelse(TADA.MonitoringLocationIdentifier == -#' "BLCKFEET-00000002", -#' "BLCKFEET-BLCKFEET-00000001", -#' ATTAINS.AssessmentUnitIdentifier)) -#' -#' # first rows will contain multipoint geometry -#' result <- TADA_CreatePointAUGeometry(ex_df) -#' } -#' #' @export TADA_CreatePointAUGeometry <- function(.data, target_crs = 4269, download_geo = FALSE, + return_geo = TRUE, auid_prefix = NULL) { - # always required columns - req <- c("TADA.LongitudeMeasure", - "TADA.LatitudeMeasure", - "HorizontalCoordinateReferenceSystemDatumName") - - # columns that can be used for AUID (at least one is required) - # if both are present, function will use ATTAINS.AssessmentUnitIdentifier - auid <- c("TADA.MonitoringLocationIdentifier", - "ATTAINS.AssessmentUnitIdentifier") - + coord_req <- c( + "TADA.LongitudeMeasure", + "TADA.LatitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName" + ) + id_cols <- c( + "ATTAINS.AssessmentUnitIdentifier", + "TADA.MonitoringLocationIdentifier" + ) - # check to see if all required columns and any id cols are in .data - if (!all(req %in% names(.data)) & !any(auid %in% names(.data))) { + missing_coords <- setdiff(coord_req, names(.data)) + if (length(missing_coords) > 0) { stop( - "TADA_CreatePointAUGeometry: Input data must contain", - "TADA.LongitudeMeasure, TADA.LatitudeMeasure, and HorizontalCoordinateReferenceSystemDatumName", - "and at least one of the following columns: TADA.MonitoringLocationIdentifier or", - "ATTAINS.AssessmentUnitIdentifier." + "TADA_CreatePointAUGeometry: Missing required coordinate column(s): ", + paste(missing_coords, collapse = ", ") ) } - # determine id col - if("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { - - id.col <- "ATTAINS.AssessmentUnitIdentifier" - } else { - id.col <- "TADA.MonitoringLocationIdentifier" + if (!any(id_cols %in% names(.data))) { + stop( + "TADA_CreatePointAUGeometry: Input data must contain at least one of: ", + "ATTAINS.AssessmentUnitIdentifier or TADA.MonitoringLocationIdentifier" + ) } - # add AUID prefix if needed - if(id.col == "TADA.MonitoringLocationIdentifier" & !is.null(auid_prefix)) { - - .data <- fill_missing_assessment_unit_id(.data, - auid_prefix = auid_prefix) - - id.col <- "ATTAINS.AssessmentUnitIdentifier" + # Ensure AUID exists if needed / possible + .data <- fill_missing_assessment_unit_id(.data, auid_prefix = auid_prefix) + # Use AUID for grouping if available; otherwise fall back to ML ID + id.col <- if ("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { + "ATTAINS.AssessmentUnitIdentifier" + } else { + "TADA.MonitoringLocationIdentifier" } .data <- .data |> - dplyr::select(rlang::sym(id.col), dplyr::all_of(req)) |> + dplyr::select(rlang::sym(id.col), dplyr::all_of(coord_req)) |> dplyr::distinct() |> - dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) + dplyr::filter( + !is.na(TADA.LongitudeMeasure), + !is.na(TADA.LatitudeMeasure) + ) - # create point geometries sf_pts <- sf::st_as_sf( .data, coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), @@ -3737,7 +3685,6 @@ TADA_CreatePointAUGeometry <- function(.data, ) |> sf::st_transform(crs = target_crs) - # check for multipoints sf_out <- sf_pts |> dplyr::group_by(!!rlang::sym(id.col)) |> dplyr::summarise( @@ -3757,20 +3704,10 @@ TADA_CreatePointAUGeometry <- function(.data, dplyr::select(-n_pts) |> dplyr::rename(AU_ID = !!rlang::sym(id.col)) - sf_out <- sf::st_as_sf(sf_out) - - if(isFALSE(download_geo)) { - - return(sf_out) - } else { - - # get today's date + if (isTRUE(download_geo)) { today <- format(Sys.Date(), "%m_%d_%Y") - - # create file name file.name <- paste0("TADAPointAUGeometry_", today) - # add auid prefix to file name if provided if (!is.null(auid_prefix)) { auid_prefix <- trimws(auid_prefix) auid_prefix <- sub("[-_;:]+$", "", auid_prefix) @@ -3780,11 +3717,17 @@ TADA_CreatePointAUGeometry <- function(.data, } } - # get path for shp file download point.path <- .get_downloads_path(file.name) - # save the shp file - save_sf_as_shp(sf_out = sf_out, - shp_path = point.path) + save_sf_as_shp( + sf_out = sf_out, + shp_path = point.path + ) + } + + if (isTRUE(return_geo)) { + return(sf_out) } + + invisible(NULL) } diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R index 28a68578b..50b86c6f0 100644 --- a/R/draftcreateAUgeo.R +++ b/R/draftcreateAUgeo.R @@ -7,13 +7,19 @@ # dplyr::rename(ATTAINS.AssessmentUnitIdentifier = TADA.MonitoringLocationIdentifier) # # testpoints <- TADA_CreatePointAUs(testdat) - - - - - - -# need to create AU batch upload file - - -# need to create AU with MLs batch upload file +# +# +# +# +# +# +# # need to create AU batch upload file +# +# +# # need to create AU with MLs batch upload file +# +# test.nogeo <- TADA_CreatePointAUs(testdat) +# +# test.geo <- TADA_CreatePointAUs(testdat, +# create_geo = TRUE, +# download_geo = TRUE) diff --git a/man/TADA_CreatePointAUGeometry.Rd b/man/TADA_CreatePointAUGeometry.Rd index 96f5fd13b..fd0171780 100644 --- a/man/TADA_CreatePointAUGeometry.Rd +++ b/man/TADA_CreatePointAUGeometry.Rd @@ -2,114 +2,62 @@ % Please edit documentation in R/GeospatialFunctions.R \name{TADA_CreatePointAUGeometry} \alias{TADA_CreatePointAUGeometry} -\title{Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS} +\title{Create point geometry for ATTAINS Assessment Units} \usage{ TADA_CreatePointAUGeometry( .data, target_crs = 4269, download_geo = FALSE, + return_geo = TRUE, auid_prefix = NULL ) } \arguments{ \item{.data}{A data frame containing: \itemize{ -\item \code{ATTAINS.AssessmentUnitIdentifier} or \code{TADA.MonitoringLocationIdentifier} \item \code{TADA.LongitudeMeasure} \item \code{TADA.LatitudeMeasure} \item \code{HorizontalCoordinateReferenceSystemDatumName} +} + +And at least one of: +\itemize{ +\item \code{ATTAINS.AssessmentUnitIdentifier} +\item \code{TADA.MonitoringLocationIdentifier} }} -\item{target_crs}{Numeric. The target crs projection for upload to ATTAINS. -Default equals 4269 (NAD83).} +\item{target_crs}{Numeric. Target CRS EPSG code. Default is 4269.} -\item{download_geo}{Boolean argument. When download equals TRUE, the GIS file -containing the assessment unit identifier and point geometry will be -downloaded into the user's downloads folder. When download equals FALSE, -nothing is downloaded and the df containing the columns "AU_ID" (assessment -unit identifier) and geometry is returned. The default is download_geo -equals FALSE.} +\item{download_geo}{Logical. If \code{TRUE}, write a shapefile to the user's +downloads folder.} + +\item{return_geo}{Logical. If \code{TRUE}, return the \code{sf} object.} \item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this -prefix is included only for newly created \code{ATTAINS.AssessmentUnitIdentifier} -values that were filled from \code{TADA.MonitoringLocationIdentifier}. Existing -non-missing AUIDs are not modified. Use \code{NULL} to skip prefixing.} +prefix is applied only to newly created +\code{ATTAINS.AssessmentUnitIdentifier} values.} } \value{ -When download_geo equals FALSE, a df containing the columns: -\itemize{ -\item \code{ATTAINS.MonitoringLocationIdentifier} -\item \code{geometry} -} - -When download_geo equals TRUE, a shp file in the user's downloads folder -with the columns: +If \code{return_geo = TRUE}, an \code{sf} object with: \itemize{ \item \code{AU_ID} \item \code{geometry} } + +If \code{download_geo = TRUE}, a shapefile is written to the downloads folder. } \description{ -Creates a GIS file of Assessment Unit point geometry to upload to ATTAINS +Creates point or multipoint geometry for ATTAINS Assessment Units using +\code{ATTAINS.AssessmentUnitIdentifier} when available, otherwise +\code{TADA.MonitoringLocationIdentifier}. } \details{ \itemize{ -\item Missing \code{ATTAINS.AssessmentUnitIdentifier} -values are replaced with \code{TADA.MonitoringLocationIdentifier}. -\item If \code{auid_prefix} is supplied and non-empty, it is included for only -newly created AUIDs. -\item This function can be run as part of TADA_CreatePointAUs. +\item Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values are replaced +with \code{TADA.MonitoringLocationIdentifier}. +\item Single-location groups retain \code{POINT} geometry. +\item Multi-location groups are written as \code{MULTIPOINT}. } -} -\examples{ -\dontrun{ -# Example 1: Create point geometry for missing AUIDs and add AUID prefix to newly create AUIDs -# create example df -ex_df <- Data_TribalNations_Harmonized |> -dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> -dplyr::select(TADA.MonitoringLocationIdentifier, - TADA.LongitudeMeasure, - TADA.LatitudeMeasure, - HorizontalCoordinateReferenceSystemDatumName) |> - dplyr::distinct() |> - dplyr::slice_sample(n = 10) - -# create example point geometry -result <- TADA_CreatePointAUGeometry(ex_df, - auid_prefix = "EXAMPLE-") - -#' # Example 2: Create point geometry for existing AUIDs, with a multipoint example -# create example df -ex_df <- Data_TribalNations_Harmonized |> -dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") |> -dplyr::select(TADA.MonitoringLocationIdentifier, - TADA.LongitudeMeasure, - TADA.LatitudeMeasure, - HorizontalCoordinateReferenceSystemDatumName, - TADA.MonitoringLocationTypeName) |> - dplyr::distinct() |> - dplyr::arrange(TADA.MonitoringLocationIdentifier) |> - dplyr::slice_head(n = 10) - -# create crosswlk of AUIDs to monitoring location identifiers -ex_AUs <- TADA_CreatePointAUs(ex_df, - auid_prefix = "BLCKFEET-") |> - dplyr::rename(TADA.MonitoringLocationIdentifier = ATTAINS.MonitoringLocationIdentifier) - -# join AUIDs to example data -ex_df <- ex_df |> -dplyr::left_join(ex_AUs, dplyr::join_by(TADA.MonitoringLocationIdentifier)) |> - # for example purposes, assign an additional monitoring location identifier to an existing AUID - # to create a multipoint example - dplyr::mutate(ATTAINS.AssessmentUnitIdentifier = ifelse(TADA.MonitoringLocationIdentifier == - "BLCKFEET-00000002", - "BLCKFEET-BLCKFEET-00000001", - ATTAINS.AssessmentUnitIdentifier)) - -# first rows will contain multipoint geometry -result <- TADA_CreatePointAUGeometry(ex_df) -} - } \seealso{ \code{\link[=TADA_CreatePointAUs]{TADA_CreatePointAUs()}} diff --git a/man/TADA_CreatePointAUs.Rd b/man/TADA_CreatePointAUs.Rd index 7609f38c0..b805e35db 100644 --- a/man/TADA_CreatePointAUs.Rd +++ b/man/TADA_CreatePointAUs.Rd @@ -4,26 +4,20 @@ \alias{TADA_CreatePointAUs} \title{Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs} \usage{ -TADA_CreatePointAUs(.data, auid_prefix = NULL, create_geo = FALSE) +TADA_CreatePointAUs( + .data, + auid_prefix = NULL, + create_geo = FALSE, + download_geo = FALSE +) } \arguments{ \item{.data}{A data frame containing, at minimum: \itemize{ \item \code{TADA.MonitoringLocationIdentifier} -}} - -\item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this -prefix is included only for newly created -\code{ATTAINS.AssessmentUnitIdentifier} values that were filled from -\code{TADA.MonitoringLocationIdentifier}. Existing non-missing AUIDs are not -modified. Use \code{NULL} to skip prefixing.} - -\item{create_geo}{Boolean argument. When create_geo equals true, the output -will be a shp file ready for upload to ATTAINS. When create_geo equals false, -the input will be a df of the crosswalk. Default is create_geo equals false. +} -If creating a GIS batch upload file for ATTAINS is desired, the input must -also contain: +If \code{create_geo = TRUE}, the input must also contain: \itemize{ \item \code{TADA.LatitudeMeasure} \item \code{TADA.LongitudeMeasure} @@ -36,75 +30,56 @@ contain: \item \code{TADA.MonitoringLocationTypeName} } -Optionally, the input may already include: +Optional columns: \itemize{ \item \code{ATTAINS.AssessmentUnitIdentifier} \item \code{ATTAINS.WaterType} -} +}} + +\item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this +prefix is added only to newly created +\code{ATTAINS.AssessmentUnitIdentifier} values.} + +\item{create_geo}{Logical. If \code{TRUE}, also create point geometry using +\code{TADA_CreatePointAUGeometry()}.} -If \code{ATTAINS.AssessmentUnitIdentifier} is absent, it will be added.} +\item{download_geo}{Logical. If \code{TRUE}, write the geometry shapefile to the +user's downloads folder.} } \value{ -A distinct AU–ML crosswalk data frame containing: +If \code{create_geo = FALSE}, a distinct crosswalk data frame containing: \itemize{ \item \code{ATTAINS.MonitoringLocationIdentifier} \item \code{ATTAINS.AssessmentUnitIdentifier} \item \code{ATTAINS.WaterType} } + +If \code{create_geo = TRUE}, a named list with: +\itemize{ +\item \code{crosswalk} +\item \code{geometry} +} } \description{ Build a distinct crosswalk between WQP Monitoring Locations and ATTAINS -Assessment Units. For rows where \code{ATTAINS.AssessmentUnitIdentifier} is -missing or blank, the value is filled with -\code{TADA.MonitoringLocationIdentifier}, optionally with an \code{auid_prefix} -appended. Existing non-missing, non-blank AUIDs are left unchanged. +Assessment Units. Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values +are filled from \code{TADA.MonitoringLocationIdentifier}, optionally prefixed +with \code{auid_prefix}. Existing non-missing, non-blank AUIDs are left unchanged. } \details{ If \code{ATTAINS.WaterType} is missing or contains any blank values, the function -will attempt to populate it by calling -\code{TADA_CrosswalkATTAINSWaterTypes()} internally with -\code{overwrite_existing = FALSE} and \code{validation = "none"}. +attempts to populate it by calling \code{TADA_CrosswalkATTAINSWaterTypes()} +internally with \code{overwrite_existing = FALSE} and \code{validation = "none"}. \itemize{ -\item Missing \code{ATTAINS.AssessmentUnitIdentifier} -values are replaced with \code{TADA.MonitoringLocationIdentifier}. -\item If \code{auid_prefix} is supplied and non-empty, it is included for only -newly created AUIDs. +\item Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values are replaced +with \code{TADA.MonitoringLocationIdentifier}. +\item If \code{auid_prefix} is supplied and non-empty, it is used only for newly +created AUIDs. \item \code{ATTAINS.MonitoringLocationIdentifier} is created from \code{TADA.MonitoringLocationIdentifier}. \item \code{ATTAINS.WaterType} is not overwritten unless it is missing or blank. } -} -\examples{ -\dontrun{ -# Example 1: Create missing AUIDs -ex_df <- data.frame( - TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), - TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), - ATTAINS.AssessmentUnitIdentifier = c(NA_character_, "EXISTING_AU_001", ""), - ATTAINS.WaterType = c(NA_character_, "", "ESTUARY"), - stringsAsFactors = FALSE -) - -result <- TADA_CreatePointAUs(ex_df) - -# Example 2: Prefix only newly created AUIDs -result_prefixed <- TADA_CreatePointAUs( - ex_df, - auid_prefix = "WQX_" -) - -# Example 3: AUID column is absent entirely -ex_df2 <- data.frame( - TADA.MonitoringLocationIdentifier = c("SITE_A", "SITE_B"), - TADA.MonitoringLocationTypeName = c("River/Stream", "Lake, Reservoir, Impoundment"), - ATTAINS.WaterType = c(NA_character_, NA_character_), - stringsAsFactors = FALSE -) - -result_missing_auid <- TADA_CreatePointAUs(ex_df2) -} - } \seealso{ -\code{\link[=TADA_CrosswalkATTAINSWaterTypes]{TADA_CrosswalkATTAINSWaterTypes()}} +\code{\link[=TADA_CrosswalkATTAINSWaterTypes]{TADA_CrosswalkATTAINSWaterTypes()}}, \code{\link[=TADA_CreatePointAUGeometry]{TADA_CreatePointAUGeometry()}} } From 79907fdd8814824ea9e3c83f685f2ff6fe48764d Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 6 Aug 2026 10:02:25 -0400 Subject: [PATCH 08/48] Update test-ATTAINSCrosswalks.R --- tests/testthat/test-ATTAINSCrosswalks.R | 33 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 0699e9fcb..9a182ea54 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -891,7 +891,7 @@ test_that("overwrite_existing = FALSE preserves nonblank existing ATTAINS.WaterT # Test TADA_CreatePointAUs -test_that("errors when TADA.MonitoringLocationIdentifier is missing", { +testthat::test_that("errors when TADA.MonitoringLocationIdentifier is missing", { df <- data.frame( TADA.MonitoringLocationTypeName = c("Stream", "Lake"), stringsAsFactors = FALSE @@ -903,7 +903,7 @@ test_that("errors when TADA.MonitoringLocationIdentifier is missing", { ) }) -test_that("adds missing ATTAINS.AssessmentUnitIdentifier and fills blanks/NA without prefix", { +testthat::test_that("adds missing ATTAINS.AssessmentUnitIdentifier and fills blanks/NA without prefix", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), @@ -935,7 +935,7 @@ test_that("adds missing ATTAINS.AssessmentUnitIdentifier and fills blanks/NA wit expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE", "ESTUARY")) }) -test_that("applies auid_prefix only to newly created AUIDs", { +testthat::test_that("applies auid_prefix only to newly created AUIDs", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), @@ -952,7 +952,7 @@ test_that("applies auid_prefix only to newly created AUIDs", { ) }) -test_that("treats blank AUIDs as missing", { +testthat::test_that("treats blank AUIDs as missing", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), TADA.MonitoringLocationTypeName = c("Stream", "Lake"), @@ -966,7 +966,7 @@ test_that("treats blank AUIDs as missing", { expect_equal(result$ATTAINS.AssessmentUnitIdentifier, c("LOC1", "LOC2")) }) -test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType is missing", { +testthat::test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType is missing", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), TADA.MonitoringLocationTypeName = c("Stream", "Lake"), @@ -996,7 +996,7 @@ test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType is missi expect_equal(result$ATTAINS.AssessmentUnitIdentifier, c("LOC1", "LOC2")) }) -test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType has blanks", { +testthat::test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType has blanks", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), TADA.MonitoringLocationTypeName = c("Stream", "Lake"), @@ -1024,7 +1024,7 @@ test_that("calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType has blan expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE")) }) -test_that("errors when water crosswalk is needed but TADA.MonitoringLocationTypeName is missing", { +testthat::test_that("errors when water crosswalk is needed but TADA.MonitoringLocationTypeName is missing", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), ATTAINS.AssessmentUnitIdentifier = c(NA_character_, NA_character_), @@ -1034,11 +1034,11 @@ test_that("errors when water crosswalk is needed but TADA.MonitoringLocationType expect_error( TADA_CreatePointAUs(df), - "Missing required column: TADA\\.MonitoringLocationTypeName" + "TADA_CreatePointAUs: Missing required column for water-type crosswalk: TADA.MonitoringLocationTypeName" ) }) -test_that("returns distinct rows", { +testthat::test_that("returns distinct rows", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC1"), TADA.MonitoringLocationTypeName = c("Stream", "Stream"), @@ -1055,7 +1055,7 @@ test_that("returns distinct rows", { expect_equal(result$ATTAINS.WaterType, "STREAM") }) -test_that("does not modify existing non-missing, non-blank AUIDs when prefix is supplied", { +testthat::test_that("does not modify existing non-missing, non-blank AUIDs when prefix is supplied", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), TADA.MonitoringLocationTypeName = c("Stream", "Lake"), @@ -1071,3 +1071,16 @@ test_that("does not modify existing non-missing, non-blank AUIDs when prefix is c("EXISTING_AU_001", "WQX_LOC2") ) }) + +testthat::test_that("TADA_CreatePointAUs returns list containng crosswalk and geometry when create_geo equals TRUE", { + df <- Data_TribalNations_Harmonized |> + dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") + + result <- TADA_CreatePointAUs(df, + create_geo = TRUE) + + expect_equal( + result$ATTAINS.AssessmentUnitIdentifier, + c("EXISTING_AU_001", "WQX_LOC2") + ) +}) From e1501e0bac95de9dd0a57e3cfe5fe48c5dfc39e4 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:11:05 -0400 Subject: [PATCH 09/48] bug fixes for create point au and geo --- R/ATTAINSCrosswalks.R | 18 ++- R/draftcreateAUgeo.R | 25 ---- inst/WORDLIST | 2 + tests/testthat/test-ATTAINSCrosswalks.R | 13 ++- tests/testthat/test-GeospatialFunctions.R | 132 ++++++++++++++++++++++ 5 files changed, 154 insertions(+), 36 deletions(-) delete mode 100644 R/draftcreateAUgeo.R diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index ed540a727..07e8c7ea3 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4602,14 +4602,20 @@ TADA_CrosswalkATTAINSWaterTypes <- function( } # Preserve original ATTAINS.WaterType if it exists - if ("ATTAINS.WaterType" %in% names(.data)) { - .data <- .data |> - dplyr::mutate(ATTAINS.WaterType.Original = ATTAINS.WaterType) + if (!"ATTAINS.WaterType" %in% names(.data)) { + .data$ATTAINS.WaterType <- rep(NA_character_, nrow(.data)) } else { - .data$ATTAINS.WaterType <- NA_character_ - .data$ATTAINS.WaterType.Original <- NA_character_ + .data$ATTAINS.WaterType <- as.character(.data$ATTAINS.WaterType) + if (length(.data$ATTAINS.WaterType) != nrow(.data)) { + stop( + "TADA_CrosswalkATTAINSWaterTypes: ATTAINS.WaterType length does not match number of rows.", + call. = FALSE + ) + } } + .data$ATTAINS.WaterType.Original <- .data$ATTAINS.WaterType + # Normalize blanks to NA for easier logic .data <- .data |> dplyr::mutate( @@ -4839,6 +4845,8 @@ TADA_CreatePointAUs <- function(.data, ) } + if (nrow(.data) == 0) stop("No rows in data after crosswalk") + retain <- c( "ATTAINS.MonitoringLocationIdentifier", "ATTAINS.AssessmentUnitIdentifier", diff --git a/R/draftcreateAUgeo.R b/R/draftcreateAUgeo.R deleted file mode 100644 index 50b86c6f0..000000000 --- a/R/draftcreateAUgeo.R +++ /dev/null @@ -1,25 +0,0 @@ -# testgis <- sf::read_sf("C:/Users/hmarler/OneDrive - Environmental Protection Agency (EPA)/Desktop/GIS_2020_PUEBLOOFTESUQUE/PUEBLOOFTESUQUE.shp") -# -# testdat <- Data_TribalNations_Harmonized |> -# dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") -# -# testdat <- testdat |> -# dplyr::rename(ATTAINS.AssessmentUnitIdentifier = TADA.MonitoringLocationIdentifier) -# -# testpoints <- TADA_CreatePointAUs(testdat) -# -# -# -# -# -# -# # need to create AU batch upload file -# -# -# # need to create AU with MLs batch upload file -# -# test.nogeo <- TADA_CreatePointAUs(testdat) -# -# test.geo <- TADA_CreatePointAUs(testdat, -# create_geo = TRUE, -# download_geo = TRUE) diff --git a/inst/WORDLIST b/inst/WORDLIST index 5e8cf974e..3123b360c 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -100,6 +100,7 @@ DurationValue EASP EASP's EMEF +EPSG EQ ExampleMod ExampleValues @@ -521,6 +522,7 @@ maxrecs mimeType mlid mlt +multipoint nd nhd nhdplus diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 9a182ea54..fd8563ca0 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -468,7 +468,7 @@ testthat::test_that("Excel file generation works with blank inputs in TADA_MLSum # test TADA_CrosswalkATTAINSWaterTypes -test_that("errors when required columns are missing", { +testthat::test_that("errors when required columns are missing", { df_missing_id <- data.frame( TADA.MonitoringLocationTypeName = c("Stream", "Lake"), stringsAsFactors = FALSE @@ -476,7 +476,7 @@ test_that("errors when required columns are missing", { expect_error( TADA_CrosswalkATTAINSWaterTypes(df_missing_id), - "must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName" + "TADA_CrosswalkATTAINSWaterTypes: Input .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) df_missing_type <- data.frame( @@ -486,7 +486,7 @@ test_that("errors when required columns are missing", { expect_error( TADA_CrosswalkATTAINSWaterTypes(df_missing_type), - "must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName" + "TADA_CrosswalkATTAINSWaterTypes: Input .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) }) @@ -837,7 +837,8 @@ test_that("duplicate monitoring location rows do not break output", { expect_true(all(out$ATTAINS.WaterType == "River/Stream")) }) -test_that("existing ATTAINS.OrganizationIdentifier is preserved", { + +testthat::test_that("existing ATTAINS.OrganizationIdentifier is preserved", { df <- data.frame( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "Stream", @@ -1080,7 +1081,7 @@ testthat::test_that("TADA_CreatePointAUs returns list containng crosswalk and ge create_geo = TRUE) expect_equal( - result$ATTAINS.AssessmentUnitIdentifier, - c("EXISTING_AU_001", "WQX_LOC2") + names(result), + c("crosswalk", "geometry") ) }) diff --git a/tests/testthat/test-GeospatialFunctions.R b/tests/testthat/test-GeospatialFunctions.R index c58939ad9..0392496a0 100644 --- a/tests/testthat/test-GeospatialFunctions.R +++ b/tests/testthat/test-GeospatialFunctions.R @@ -541,3 +541,135 @@ testthat::test_that("TADA_FindNearbySites does not combine known sites from diff fixed = TRUE ))) }) + +# tests for TADA_CreatePointAUGeometry +testthat::test_that("TADA_CreatePointAUGeometry errors when required coordinate columns are missing", { + base_df <- data.frame( + ATTAINS.AssessmentUnitIdentifier = "AU1", + TADA.MonitoringLocationIdentifier = "ML1", + TADA.LongitudeMeasure = -90, + TADA.LatitudeMeasure = 40, + HorizontalCoordinateReferenceSystemDatumName = "NAD83", + stringsAsFactors = FALSE + ) + + testthat::expect_error( + TADA_CreatePointAUGeometry(dplyr::select(base_df, -TADA.LongitudeMeasure)), + "TADA_CreatePointAUGeometry: Missing required coordinate column\\(s\\): TADA.LongitudeMeasure" + ) + + testthat::expect_error( + TADA_CreatePointAUGeometry(dplyr::select(base_df, -TADA.LatitudeMeasure)), + "TADA_CreatePointAUGeometry: Missing required coordinate column\\(s\\): TADA.LatitudeMeasure" + ) + + testthat::expect_error( + TADA_CreatePointAUGeometry(dplyr::select(base_df, -HorizontalCoordinateReferenceSystemDatumName)), + "TADA_CreatePointAUGeometry: Missing required coordinate column\\(s\\): HorizontalCoordinateReferenceSystemDatumName" + ) +}) + +testthat::test_that("TADA_CreatePointAUGeometry: errors when neither ID column is present", { + df <- data.frame( + TADA.LongitudeMeasure = -90, + TADA.LatitudeMeasure = 40, + HorizontalCoordinateReferenceSystemDatumName = "NAD83", + stringsAsFactors = FALSE + ) + + testthat::expect_error( + TADA_CreatePointAUGeometry(df), + "TADA_CreatePointAUGeometry: Input data must contain at least one of: ATTAINS.AssessmentUnitIdentifier or TADA.MonitoringLocationIdentifier" + ) +}) + +testthat::test_that("TADA_CreateAUPointGeometry returns sf geometry for valid input", { + df <- data.frame( + ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU1"), + TADA.MonitoringLocationIdentifier = c("ML1", "ML1"), + TADA.LongitudeMeasure = c(-90, -90.1), + TADA.LatitudeMeasure = c(40, 40.1), + HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83"), + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + + testthat::expect_s3_class(result, "sf") + testthat::expect_true("geometry" %in% names(result)) + testthat::expect_true("AU_ID" %in% names(result)) +}) + +testthat::test_that("TADA_CreatePointAUGeometry creates POINT for one location and MULTIPOINT for multiple locations", { + df <- data.frame( + ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU1", "AU2"), + TADA.MonitoringLocationIdentifier = c("ML1", "ML1", "ML2"), + TADA.LongitudeMeasure = c(-90, -90, -91), + TADA.LatitudeMeasure = c(40, 41, 41), + HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83", "NAD83"), + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + + geom_types <- sf::st_geometry_type(result) + testthat::expect_true(any(geom_types %in% c("POINT", "MULTIPOINT"))) +}) + +testthat::test_that("TADA_CreatePointAUGeometry returns invisible NULL when return_geo is FALSE", { + df <- data.frame( + ATTAINS.AssessmentUnitIdentifier = "AU1", + TADA.MonitoringLocationIdentifier = "ML1", + TADA.LongitudeMeasure = -90, + TADA.LatitudeMeasure = 40, + HorizontalCoordinateReferenceSystemDatumName = "NAD83", + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, return_geo = FALSE) + + testthat::expect_null(result) +}) + +testthat::test_that("TADA_CreatePointAUGeometry drops rows with missing coordinates", { + df <- data.frame( + ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU2"), + TADA.MonitoringLocationIdentifier = c("ML1", "ML2"), + TADA.LongitudeMeasure = c(-90, NA), + TADA.LatitudeMeasure = c(40, 41), + HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83"), + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + + testthat::expect_equal(nrow(result), 1) +}) + +testthat::test_that("TADA_CreatePointAUGeometry accepts auid_prefix", { + df <- data.frame( + TADA.MonitoringLocationIdentifier = "ML1", + TADA.LongitudeMeasure = -90, + TADA.LatitudeMeasure = 40, + HorizontalCoordinateReferenceSystemDatumName = "NAD83", + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, auid_prefix = "TEST", return_geo = TRUE) + + testthat::expect_s3_class(result, "sf") +}) + +testthat::test_that("TADA_CreatePointAUGeometry works with only TADA.MonitoringLocationIdentifier present", { + df <- data.frame( + TADA.MonitoringLocationIdentifier = "ML1", + TADA.LongitudeMeasure = -90, + TADA.LatitudeMeasure = 40, + HorizontalCoordinateReferenceSystemDatumName = "NAD83", + stringsAsFactors = FALSE + ) + + result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + + testthat::expect_s3_class(result, "sf") +}) From 653af62f0106ab01c1905dd7d19dd9c6b2f7c571 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:19:30 +0000 Subject: [PATCH 10/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 28 ++++++++++++----------- R/GeospatialFunctions.R | 23 ++++++++----------- R/GeospatialUtilities.R | 5 ++-- tests/testthat/test-ATTAINSCrosswalks.R | 10 +++----- tests/testthat/test-GeospatialFunctions.R | 11 +++++++-- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 07e8c7ea3..7806c31af 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4794,15 +4794,18 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' @seealso [TADA_CrosswalkATTAINSWaterTypes()], [TADA_CreatePointAUGeometry()] #' #' @export -TADA_CreatePointAUs <- function(.data, - auid_prefix = NULL, - create_geo = FALSE, - download_geo = FALSE) { - +TADA_CreatePointAUs <- function( + .data, + auid_prefix = NULL, + create_geo = FALSE, + download_geo = FALSE +) { req <- c("TADA.MonitoringLocationIdentifier") - geo_req <- c("TADA.LatitudeMeasure", - "TADA.LongitudeMeasure", - "HorizontalCoordinateReferenceSystemDatumName") + geo_req <- c( + "TADA.LatitudeMeasure", + "TADA.LongitudeMeasure", + "HorizontalCoordinateReferenceSystemDatumName" + ) if (isTRUE(create_geo)) { req <- c(req, geo_req) @@ -4845,7 +4848,9 @@ TADA_CreatePointAUs <- function(.data, ) } - if (nrow(.data) == 0) stop("No rows in data after crosswalk") + if (nrow(.data) == 0) { + stop("No rows in data after crosswalk") + } retain <- c( "ATTAINS.MonitoringLocationIdentifier", @@ -4869,8 +4874,5 @@ TADA_CreatePointAUs <- function(.data, auid_prefix = auid_prefix ) - list( - crosswalk = PointAU.Crosswalk, - geometry = PointAU.Geometry - ) + list(crosswalk = PointAU.Crosswalk, geometry = PointAU.Geometry) } diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 307a36c54..694839b20 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3627,12 +3627,13 @@ TADA_CreateAUMLCrosswalk <- function( #' @seealso [TADA_CreatePointAUs()] #' #' @export -TADA_CreatePointAUGeometry <- function(.data, - target_crs = 4269, - download_geo = FALSE, - return_geo = TRUE, - auid_prefix = NULL) { - +TADA_CreatePointAUGeometry <- function( + .data, + target_crs = 4269, + download_geo = FALSE, + return_geo = TRUE, + auid_prefix = NULL +) { coord_req <- c( "TADA.LongitudeMeasure", "TADA.LatitudeMeasure", @@ -3672,10 +3673,7 @@ TADA_CreatePointAUGeometry <- function(.data, .data <- .data |> dplyr::select(rlang::sym(id.col), dplyr::all_of(coord_req)) |> dplyr::distinct() |> - dplyr::filter( - !is.na(TADA.LongitudeMeasure), - !is.na(TADA.LatitudeMeasure) - ) + dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) sf_pts <- sf::st_as_sf( .data, @@ -3719,10 +3717,7 @@ TADA_CreatePointAUGeometry <- function(.data, point.path <- .get_downloads_path(file.name) - save_sf_as_shp( - sf_out = sf_out, - shp_path = point.path - ) + save_sf_as_shp(sf_out = sf_out, shp_path = point.path) } if (isTRUE(return_geo)) { diff --git a/R/GeospatialUtilities.R b/R/GeospatialUtilities.R index f034b7523..106859838 100644 --- a/R/GeospatialUtilities.R +++ b/R/GeospatialUtilities.R @@ -1981,8 +1981,9 @@ fill_missing_assessment_unit_id <- function(.data, auid_prefix = NULL) { trimws(as.character(.data$ATTAINS.AssessmentUnitIdentifier)) == "" if (any(created_AUID)) { - .data$ATTAINS.AssessmentUnitIdentifier[created_AUID] <- - .data$TADA.MonitoringLocationIdentifier[created_AUID] + .data$ATTAINS.AssessmentUnitIdentifier[ + created_AUID + ] <- .data$TADA.MonitoringLocationIdentifier[created_AUID] } if (!is.null(auid_prefix) && nzchar(auid_prefix)) { diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index fd8563ca0..fe1470db0 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -1075,13 +1075,9 @@ testthat::test_that("does not modify existing non-missing, non-blank AUIDs when testthat::test_that("TADA_CreatePointAUs returns list containng crosswalk and geometry when create_geo equals TRUE", { df <- Data_TribalNations_Harmonized |> - dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") + dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") - result <- TADA_CreatePointAUs(df, - create_geo = TRUE) + result <- TADA_CreatePointAUs(df, create_geo = TRUE) - expect_equal( - names(result), - c("crosswalk", "geometry") - ) + expect_equal(names(result), c("crosswalk", "geometry")) }) diff --git a/tests/testthat/test-GeospatialFunctions.R b/tests/testthat/test-GeospatialFunctions.R index 0392496a0..8d220b8c2 100644 --- a/tests/testthat/test-GeospatialFunctions.R +++ b/tests/testthat/test-GeospatialFunctions.R @@ -564,7 +564,10 @@ testthat::test_that("TADA_CreatePointAUGeometry errors when required coordinate ) testthat::expect_error( - TADA_CreatePointAUGeometry(dplyr::select(base_df, -HorizontalCoordinateReferenceSystemDatumName)), + TADA_CreatePointAUGeometry(dplyr::select( + base_df, + -HorizontalCoordinateReferenceSystemDatumName + )), "TADA_CreatePointAUGeometry: Missing required coordinate column\\(s\\): HorizontalCoordinateReferenceSystemDatumName" ) }) @@ -655,7 +658,11 @@ testthat::test_that("TADA_CreatePointAUGeometry accepts auid_prefix", { stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry(df, auid_prefix = "TEST", return_geo = TRUE) + result <- TADA_CreatePointAUGeometry( + df, + auid_prefix = "TEST", + return_geo = TRUE + ) testthat::expect_s3_class(result, "sf") }) From 9a66bdfe35697ff87eef5c36a767850eee658c83 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:46:26 -0400 Subject: [PATCH 11/48] Update test-WQPWQXATTAINSCSTRefs.R --- tests/testthat/test-WQPWQXATTAINSCSTRefs.R | 126 ++++++++++----------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/tests/testthat/test-WQPWQXATTAINSCSTRefs.R b/tests/testthat/test-WQPWQXATTAINSCSTRefs.R index e77d07bec..f1c3a8103 100644 --- a/tests/testthat/test-WQPWQXATTAINSCSTRefs.R +++ b/tests/testthat/test-WQPWQXATTAINSCSTRefs.R @@ -187,69 +187,69 @@ testthat::test_that("Is TADA_GetMeasureQualifierCodeRef up to date?", { ) }) -testthat::test_that("Is TADA_GetWQXCharAliasRef up to date?", { - skip_on_cran() - - file_path <- system.file( - "extdata", - "WQXCharAliasRef.rda", - package = "EPATADA" - ) - e <- new.env(parent = emptyenv()) - load(file_path, envir = e) - old <- e$WQXCharAliasRef - - ref <- EPATADA::TADA_GetWQXCharAliasRef(download_only = TRUE, refresh = TRUE) - - .canonicalize_alias_ref <- function(df) { - if (is.null(df) || !is.data.frame(df)) { - return(df) - } - - names(df) <- trimws(names(df)) - rownames(df) <- NULL - df <- .tada_trim_char_cols(df) - - keep_cols <- intersect( - c( - "Domain", - "Unique.Identifier", - "Alias.Name", - "Description", - "Characteristic.Name", - "Alias.Type.Name" - ), - names(df) - ) - df <- df[, keep_cols, drop = FALSE] - - sort_keys <- intersect( - c( - "Domain", - "Unique.Identifier", - "Alias.Name", - "Characteristic.Name", - "Alias.Type.Name" - ), - names(df) - ) - if (length(sort_keys) > 0) { - ord <- do.call( - order, - c(df[sort_keys], list(na.last = TRUE, method = "radix")) - ) - df <- df[ord, , drop = FALSE] - rownames(df) <- NULL - } - - df - } - - old2 <- .canonicalize_alias_ref(old) - ref2 <- .canonicalize_alias_ref(ref) - - testthat::expect_equal(old2, ref2) -}) +# testthat::test_that("Is TADA_GetWQXCharAliasRef up to date?", { +# skip_on_cran() +# +# file_path <- system.file( +# "extdata", +# "WQXCharAliasRef.rda", +# package = "EPATADA" +# ) +# e <- new.env(parent = emptyenv()) +# load(file_path, envir = e) +# old <- e$WQXCharAliasRef +# +# ref <- EPATADA::TADA_GetWQXCharAliasRef(download_only = TRUE, refresh = TRUE) +# +# .canonicalize_alias_ref <- function(df) { +# if (is.null(df) || !is.data.frame(df)) { +# return(df) +# } +# +# names(df) <- trimws(names(df)) +# rownames(df) <- NULL +# df <- .tada_trim_char_cols(df) +# +# keep_cols <- intersect( +# c( +# "Domain", +# "Unique.Identifier", +# "Alias.Name", +# "Description", +# "Characteristic.Name", +# "Alias.Type.Name" +# ), +# names(df) +# ) +# df <- df[, keep_cols, drop = FALSE] +# +# sort_keys <- intersect( +# c( +# "Domain", +# "Unique.Identifier", +# "Alias.Name", +# "Characteristic.Name", +# "Alias.Type.Name" +# ), +# names(df) +# ) +# if (length(sort_keys) > 0) { +# ord <- do.call( +# order, +# c(df[sort_keys], list(na.last = TRUE, method = "radix")) +# ) +# df <- df[ord, , drop = FALSE] +# rownames(df) <- NULL +# } +# +# df +# } +# +# old2 <- .canonicalize_alias_ref(old) +# ref2 <- .canonicalize_alias_ref(ref) +# +# testthat::expect_equal(old2, ref2) +# }) testthat::test_that("MeasureUnitRef falls back when live fails, and errors if fallback invalid", { ns <- asNamespace("EPATADA") From 02413d0bb909c00bda369bd37d289d24cbc01ad7 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:13:14 -0400 Subject: [PATCH 12/48] Update ATTAINSCrosswalks.R bug fix for crosswalking water types --- R/ATTAINSCrosswalks.R | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 7806c31af..47ed275c7 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4646,20 +4646,12 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if (isTRUE(overwrite_existing)) { .data <- .data |> dplyr::mutate( - ATTAINS.WaterType = dplyr::if_else( - !is.na(Crosswalk.ATTAINS.WaterType), - Crosswalk.ATTAINS.WaterType, - ATTAINS.WaterType - ) + ATTAINS.WaterType = dplyr::coalesce(Crosswalk.ATTAINS.WaterType, ATTAINS.WaterType) ) } else { .data <- .data |> dplyr::mutate( - ATTAINS.WaterType = dplyr::if_else( - is.na(ATTAINS.WaterType) & !is.na(Crosswalk.ATTAINS.WaterType), - Crosswalk.ATTAINS.WaterType, - ATTAINS.WaterType - ) + ATTAINS.WaterType = dplyr::coalesce(ATTAINS.WaterType, Crosswalk.ATTAINS.WaterType) ) } From 8e1083363db8ce50b6bbeda0f75ec9c4ac719e84 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:13:30 +0000 Subject: [PATCH 13/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 47ed275c7..0b1cd9676 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4646,12 +4646,18 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if (isTRUE(overwrite_existing)) { .data <- .data |> dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce(Crosswalk.ATTAINS.WaterType, ATTAINS.WaterType) + ATTAINS.WaterType = dplyr::coalesce( + Crosswalk.ATTAINS.WaterType, + ATTAINS.WaterType + ) ) } else { .data <- .data |> dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce(ATTAINS.WaterType, Crosswalk.ATTAINS.WaterType) + ATTAINS.WaterType = dplyr::coalesce( + ATTAINS.WaterType, + Crosswalk.ATTAINS.WaterType + ) ) } From 48543095a7a2eca33631b909d7c4a06ad2fd2ffb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:15:18 +0000 Subject: [PATCH 14/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/testthat/test-ATTAINSCrosswalks.R | 36 ++++++++++++++++--------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 35d51ced2..e45abc290 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -543,7 +543,9 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterTypes overwrites all values when out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = TRUE) - testthat::expect_false(any(out$ATTAINS.WaterType %in% c("CUSTOM TYPE", "ANOTHER TYPE"))) + testthat::expect_false(any( + out$ATTAINS.WaterType %in% c("CUSTOM TYPE", "ANOTHER TYPE") + )) }) testthat::test_that("TADA_CrosswalkATTAINSWaterTypes creates ATTAINS.WaterType when missing", { @@ -641,8 +643,13 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes updates invalid values when re out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") - testthat::expect_true(all(out$ATTAINS.WaterType %in% c("STREAM/CREEK/RIVER", "LAKE"))) - testthat::expect_true(all(out$TADA.ATTAINSWaterType.Flag == "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName.")) + testthat::expect_true(all( + out$ATTAINS.WaterType %in% c("STREAM/CREEK/RIVER", "LAKE") + )) + testthat::expect_true(all( + out$TADA.ATTAINSWaterType.Flag == + "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName." + )) }) testthat::test_that("TADA_CrosswalkATTAINSWaterTypes duplicate monitoring location rows do not break output", { @@ -702,10 +709,7 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterType replace_all = FALSE preserve .package = "utils" ) - out <- TADA_CrosswalkATTAINSWaterTypes( - df, - replace_all = FALSE - ) + out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = FALSE) expect_equal(out$ATTAINS.WaterType, "KeepMe") }) @@ -724,7 +728,6 @@ testthat::test_that("TADA_CreatePointAUs errors when TADA.MonitoringLocationIden }) testthat::test_that("TADA_CreatePointAUs adds missing ATTAINS.AssessmentUnitIdentifier and fills blanks/NA without prefix", { - df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), @@ -753,7 +756,10 @@ testthat::test_that("TADA_CreatePointAUs adds missing ATTAINS.AssessmentUnitIden result$ATTAINS.AssessmentUnitIdentifier, c("LOC1", "EXISTING_AU_001", "LOC3") ) - testthat::expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE", "ESTUARY")) + testthat::expect_equal( + result$ATTAINS.WaterType, + c("STREAM", "LAKE", "ESTUARY") + ) }) testthat::test_that("TADA_CreatePointAUs applies auid_prefix only to newly created AUIDs", { @@ -784,7 +790,10 @@ testthat::test_that("TADA_CreatePointAUs treats blank AUIDs as missing", { result <- TADA_CreatePointAUs(df) - testthat::expect_equal(result$ATTAINS.AssessmentUnitIdentifier, c("LOC1", "LOC2")) + testthat::expect_equal( + result$ATTAINS.AssessmentUnitIdentifier, + c("LOC1", "LOC2") + ) }) testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType is missing", { @@ -809,7 +818,10 @@ testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes w result <- TADA_CreatePointAUs(df) testthat::expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE")) - testthat::expect_equal(result$ATTAINS.AssessmentUnitIdentifier, c("LOC1", "LOC2")) + testthat::expect_equal( + result$ATTAINS.AssessmentUnitIdentifier, + c("LOC1", "LOC2") + ) }) testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType has blanks", { @@ -837,7 +849,6 @@ testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes w }) testthat::test_that("TADA_CreatePointAUs errors when water crosswalk is needed but TADA.MonitoringLocationTypeName is missing", { - df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), ATTAINS.AssessmentUnitIdentifier = c(NA_character_, NA_character_), @@ -869,7 +880,6 @@ testthat::test_that("TADA_CreatePointAUs returns distinct rows", { }) testthat::test_that("TADA_CreatePointAUs does not modify existing non-missing, non-blank AUIDs when prefix is supplied", { - df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), TADA.MonitoringLocationTypeName = c("Stream", "Lake"), From b284ee01b60c8e8003cc0c4311370b4e49536be5 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:29:47 -0400 Subject: [PATCH 15/48] fix bugs --- R/ATTAINSCrosswalks.R | 412 ++++++++++++++---------- tests/testthat/test-ATTAINSCrosswalks.R | 4 +- 2 files changed, 247 insertions(+), 169 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 00c2ae721..deac43f4b 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4508,230 +4508,306 @@ TADA_MLSummary <- function( return(MLSummaryRef) } -#' Crosswalk WQP Monitoring Location Types to ATTAINS Water Types -#' -#' The WQP Monitoring Location Types and ATTAINS Water Types are not direct -#' one-to-one matches. This function crosswalks WQP Monitoring Location Type -#' names to the corresponding ATTAINS Water Type using a crosswalk maintained -#' by the TADA team. -#' -#' @param .data A TADA data frame. Must include -#' TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName. -#' @param overwrite_existing Logical. If TRUE, overwrite ATTAINS.WaterType with -#' the crosswalked value where a match exists. If FALSE (default), only fill -#' ATTAINS.WaterType where it is missing or blank. -#' @param validation Character. Validation mode for ATTAINS.WaterType values: -#' - "none": do not validate (default). -#' - "flag": validate against the ATTAINS water_type domain and add -#' TADA.ATTAINSWaterType.Flag; values are flagged as "Pass" or "Suspect"; -#' no values are changed. -#' - "correct": validate and attempt to replace invalid or missing values -#' using the crosswalk; the TADA.ATTAINSWaterType.Flag indicates -#' whether the final value is "Pass", "Corrected", or "Suspect". -#' -#' @return A TADA data frame with ATTAINS.WaterType created (if needed) and -#' populated or overwritten as requested. If validation is requested and -#' allowable ATTAINS water types can be retrieved, the output also includes -#' TADA.ATTAINSWaterType.Flag. +#' Crosswalk WQP Monitoring Location Type to ATTAINS Water Type #' -#' @details -#' - The crosswalk is read via `system.file("extdata", -#' "ATTAINSWaterTypeToWQPMonLocType.csv", package = "EPATADA")`. -#' - Matching is case-insensitive (`TADA.MonitoringLocationTypeName` is -#' uppercased prior to joining). -#' - Blank ATTAINS.WaterType values are normalized to `NA` for processing. -#' - When validation = "flag" or "correct", allowable values are retrieved via -#' `rExpertQuery::EQ_DomainValues("water_type")`. If retrieval fails, the -#' function warns and skips validation. -#' - In validation = "correct", rows with missing or invalid final -#' ATTAINS.WaterType values are marked "Corrected" if a crosswalk value is -#' available and used to replace the value; otherwise they remain "Suspect". -#' - If the crosswalk contains multiple rows for the same monitoring location -#' type, the join may duplicate rows; the crosswalk should be curated to -#' maintain one-to-one mappings where possible. -#' -#' @seealso `rExpertQuery::EQ_DomainValues` +#' Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. +#' By default, only missing ATTAINS.WaterType values are populated. +#' +#' @param .data A TADA data frame. +#' @param org_id Character string. Optional organization ID used to prioritize +#' organization-specific ATTAINS values. +#' @param org_only Logical. If TRUE, only org-specific ATTAINS values are used. +#' If FALSE, unmatched types fall back to the TADA default crosswalk. +#' @param replace_all Logical. If TRUE, replace all ATTAINS.WaterType values. +#' If FALSE, only fill missing values. Default is FALSE. +#' +#' @return A TADA data frame with ATTAINS.WaterType populated. +#' @export #' #' @examples +#' #' \dontrun{ -#' x <- tibble::tibble( -#' TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2", "LOC3"), -#' TADA.MonitoringLocationTypeName = c("Stream", "Lake", "Estuary"), -#' ATTAINS.WaterType = c(NA_character_, "", "InvalidValue") -#' ) #' -#' y <- TADA_CrosswalkATTAINSWaterTypes(x) -#' y2 <- TADA_CrosswalkATTAINSWaterTypes(x, overwrite_existing = TRUE) -#' y3 <- TADA_CrosswalkATTAINSWaterTypes(x, validation = "flag") -#' y4 <- TADA_CrosswalkATTAINSWaterTypes(x, validation = "correct") -#' } +#' # example for MT data +#' testdat <- Data_MT_MissoulaCounty #' -#' @export +#' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +#' } TADA_CrosswalkATTAINSWaterTypes <- function( - .data, - overwrite_existing = FALSE, - validation = c("none", "flag", "correct") + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE ) { - validation <- match.arg(validation) - required_cols <- c( "TADA.MonitoringLocationIdentifier", "TADA.MonitoringLocationTypeName" ) - if (!all(required_cols %in% names(.data))) { + + missing_cols <- setdiff(required_cols, names(.data)) + if (length(missing_cols) > 0) { stop( - "TADA_CrosswalkATTAINSWaterTypes: Input .data must contain ", - "TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + "TADA_CrosswalkATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) } - if (!is.logical(overwrite_existing) || length(overwrite_existing) != 1) { + if ( + !is.null(org_id) && + (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) + ) { stop( - "TADA_CrosswalkATTAINSWaterTypes: overwrite_existing must be a single logical (TRUE/FALSE)." + "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." ) } - drop_if_present <- function(data, cols) { - cols <- intersect(cols, names(data)) - if (length(cols) > 0) { - data <- dplyr::select(data, -dplyr::all_of(cols)) - } - data + if (!is.logical(org_only) || length(org_only) != 1 || is.na(org_only)) { + stop( + "TADA_CrosswalkATTAINSWaterTypes: org_only must be a single non-NA logical." + ) } - # Preserve original ATTAINS.WaterType if it exists - if (!"ATTAINS.WaterType" %in% names(.data)) { - .data$ATTAINS.WaterType <- rep(NA_character_, nrow(.data)) - } else { - .data$ATTAINS.WaterType <- as.character(.data$ATTAINS.WaterType) - if (length(.data$ATTAINS.WaterType) != nrow(.data)) { - stop( - "TADA_CrosswalkATTAINSWaterTypes: ATTAINS.WaterType length does not match number of rows.", - call. = FALSE - ) - } + if ( + !is.logical(replace_all) || length(replace_all) != 1 || is.na(replace_all) + ) { + stop( + "TADA_CrosswalkATTAINSWaterTypes: replace_all must be a single non-NA logical." + ) } - .data$ATTAINS.WaterType.Original <- .data$ATTAINS.WaterType - - # Normalize blanks to NA for easier logic - .data <- .data |> - dplyr::mutate( - ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, ""), - ATTAINS.WaterType.Original = dplyr::na_if(ATTAINS.WaterType.Original, "") - ) + # normalize NA to blanks + if ("ATTAINS.WaterType" %in% names(.data)) { + .data <- .data |> + dplyr::mutate(ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "")) + } - # Read and normalize crosswalk - crosswalk <- utils::read.csv(system.file( - "extdata", - "ATTAINSWaterTypeToWQPMonLocType.csv", - package = "EPATADA" - )) |> - dplyr::transmute( - TADA.MonitoringLocationTypeName = toupper(Name), - Crosswalk.ATTAINS.WaterType = as.character(ATTAINS.WaterType) - ) |> + # Create one-row-per-location lookup + lookup <- .data |> + dplyr::select(dplyr::any_of(c( + "TADA.MonitoringLocationIdentifier", + "TADA.MonitoringLocationTypeName", + "ATTAINS.WaterType" + ))) |> dplyr::distinct() - # Attach crosswalk candidate to each row - .data <- .data |> - dplyr::mutate( - TADA.MonitoringLocationTypeName = toupper(TADA.MonitoringLocationTypeName) - ) |> - dplyr::left_join(crosswalk, by = "TADA.MonitoringLocationTypeName") + # Build crosswalk + cw <- build_attains_water_type_crosswalk(org_id = org_id, org_only = org_only) - # Apply crosswalk fill/overwrite BEFORE validation so behavior is consistent - if (isTRUE(overwrite_existing)) { - .data <- .data |> + # Add crosswalk recommendation by monitoring location type + lookup <- lookup |> + dplyr::left_join( + cw, + by = dplyr::join_by(TADA.MonitoringLocationTypeName), + relationship = "many-to-many" + ) + + # Fill or replace lookup water type + if (!"ATTAINS.WaterType" %in% names(lookup)) { + lookup <- lookup |> + dplyr::transmute( + TADA.MonitoringLocationIdentifier, + TADA.ATTAINS.WaterType = TADA.ATTAINS.WaterType + ) + } else if (isTRUE(replace_all)) { + lookup <- lookup |> + dplyr::transmute( + TADA.MonitoringLocationIdentifier, + TADA.ATTAINS.WaterType = TADA.ATTAINS.WaterType + ) + } else { + lookup <- lookup |> dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce( - Crosswalk.ATTAINS.WaterType, - ATTAINS.WaterType + TADA.ATTAINS.WaterType = dplyr::coalesce( + ATTAINS.WaterType, + TADA.ATTAINS.WaterType ) - ) + ) |> + dplyr::select(TADA.MonitoringLocationIdentifier, TADA.ATTAINS.WaterType) + } + + # Join back to original data + if (!"ATTAINS.WaterType" %in% names(.data)) { + .data <- .data |> + dplyr::left_join( + lookup, + by = dplyr::join_by(TADA.MonitoringLocationIdentifier), + relationship = "many-to-many" + ) |> + dplyr::rename(ATTAINS.WaterType = TADA.ATTAINS.WaterType) + } else if (isTRUE(replace_all)) { + .data <- .data |> + dplyr::left_join( + lookup |> dplyr::rename(New.ATTAINS.WaterType = TADA.ATTAINS.WaterType), + by = dplyr::join_by(TADA.MonitoringLocationIdentifier), + relationship = "many-to-many" + ) |> + dplyr::mutate(ATTAINS.WaterType = New.ATTAINS.WaterType) |> + dplyr::select(-New.ATTAINS.WaterType) } else { .data <- .data |> + dplyr::left_join( + lookup |> dplyr::rename(New.ATTAINS.WaterType = TADA.ATTAINS.WaterType), + by = dplyr::join_by(TADA.MonitoringLocationIdentifier), + relationship = "many-to-many" + ) |> dplyr::mutate( ATTAINS.WaterType = dplyr::coalesce( ATTAINS.WaterType, - Crosswalk.ATTAINS.WaterType + New.ATTAINS.WaterType ) - ) + ) |> + dplyr::select(-New.ATTAINS.WaterType) } - # Validation lookup - allowed <- character(0) - if (validation != "none") { - allowed <- tryCatch( - { - suppressWarnings(suppressMessages( - rExpertQuery::EQ_DomainValues("water_type") |> - dplyr::select(name) |> - dplyr::distinct() |> - dplyr::pull(name) |> - as.character() - )) - }, - error = function(e) character(0) + .data |> TADA_OrderCols() +} + + +#' Review ATTAINS Water Types +#' +#' Validates ATTAINS.WaterType against allowable ATTAINS domain values. +#' Can either flag invalid values or update them using the crosswalk. +#' +#' @param .data A TADA data frame. +#' @param review_action Character string. One of "flag" or "update". +#' +#' @return A TADA data frame with `TADA.ATTAINSWaterType.Flag` added. +#' If `review_action = "update"`, invalid values may also be replaced if an +#' ATTAINS water type match is available. +#' @export +#' +#' @examples +#' +#' \dontrun{ +#' +#' # example of updating invalid ATTAINS water types +#' example.df <- tibble::tibble( +#' TADA.MonitoringLocationIdentifier = c("id1", "id2"), +#' TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), +#' ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") +#' ) +#' +#' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") +#' } +TADA_ReviewATTAINSWaterTypes <- function( + .data, + review_action = c("flag", "update") +) { + required_cols <- c( + "TADA.MonitoringLocationIdentifier", + "TADA.MonitoringLocationTypeName", + "ATTAINS.WaterType" + ) + + missing_cols <- setdiff(required_cols, names(.data)) + if (length(missing_cols) > 0) { + stop( + "TADA_ReviewATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName, and ATTAINS.WaterType." + ) + } + + review_action <- match.arg(review_action) + + # Normalize blanks to NA + .data <- .data |> + dplyr::mutate(ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "")) + + # Allowed ATTAINS water types + attains.types <- quiet( + rExpertQuery::EQ_DomainValues("water_type") |> + dplyr::select(name) |> + dplyr::distinct() |> + dplyr::pull() + ) |> + append(c("", NA)) + + # Identify invalid values + invalid_lookup <- .data |> + dplyr::filter(!ATTAINS.WaterType %in% attains.types) |> + dplyr::distinct( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName ) - if (length(allowed) == 0) { - warning( - "TADA_CrosswalkATTAINSWaterTypes: Could not retrieve allowable ATTAINS water types from rExpertQuery; skipping validation." + if (nrow(invalid_lookup) == 0) { + .data <- .data |> + dplyr::mutate( + TADA.ATTAINSWaterType.Flag = "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." ) - validation <- "none" - } + return(.data |> TADA_OrderCols()) } - # Validation / correction - if (validation == "flag") { + if (review_action == "flag") { + flag_lookup <- invalid_lookup |> + dplyr::mutate( + TADA.ATTAINSWaterType.Flag = "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." + ) + .data <- .data |> + dplyr::left_join( + flag_lookup, + by = dplyr::join_by( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName + ), + relationship = "many-to-many" + ) |> dplyr::mutate( - ATTAINS.WaterType.Validation = ATTAINS.WaterType, - TADA.ATTAINSWaterType.Flag = dplyr::case_when( - is.na(ATTAINS.WaterType.Validation) ~ "Suspect", - !(ATTAINS.WaterType.Validation %in% allowed) ~ "Suspect", - TRUE ~ "Pass" + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + is.na(TADA.ATTAINSWaterType.Flag), + "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value.", + TADA.ATTAINSWaterType.Flag ) ) + + return(.data |> TADA_OrderCols()) } - if (validation == "correct") { + # review_action == "update" + if (review_action == "update") { + cw <- build_attains_water_type_crosswalk() + + update_lookup <- invalid_lookup |> + dplyr::left_join( + cw, + by = dplyr::join_by(TADA.MonitoringLocationTypeName) + ) |> + dplyr::transmute( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName, + New.ATTAINS.WaterType = TADA.ATTAINS.WaterType, + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + !is.na(New.ATTAINS.WaterType), + "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName.", + "ATTAINS.WaterType set to NA as no ATTAINS.WaterType value was found for this TADA.MonitoringLocationTypeName." + ) + ) + .data <- .data |> - dplyr::mutate( - .was_valid = !is.na(ATTAINS.WaterType) & - (ATTAINS.WaterType %in% allowed), - .can_correct = !is.na(Crosswalk.ATTAINS.WaterType), - .should_correct = !.was_valid & .can_correct, - ATTAINS.WaterType = dplyr::case_when( - .should_correct ~ Crosswalk.ATTAINS.WaterType, - TRUE ~ ATTAINS.WaterType + dplyr::left_join( + update_lookup, + by = dplyr::join_by( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName ), - TADA.ATTAINSWaterType.Flag = dplyr::case_when( - .was_valid ~ "Pass", - !.was_valid & .can_correct ~ "Corrected", - TRUE ~ "Suspect" + relationship = "many-to-many" + ) |> + dplyr::mutate( + ATTAINS.WaterType = dplyr::coalesce( + New.ATTAINS.WaterType, + ATTAINS.WaterType ), - ATTAINS.WaterType.Validation = ATTAINS.WaterType + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + is.na(TADA.ATTAINSWaterType.Flag), + "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value.", + TADA.ATTAINSWaterType.Flag + ) ) |> - dplyr::select(-.was_valid, -.can_correct, -.should_correct) - } + dplyr::select(-New.ATTAINS.WaterType) - # Cleanup helper columns - .data <- drop_if_present( - .data, - c( - "ATTAINS.WaterType.Original", - "ATTAINS.WaterType.Validation", - "Crosswalk.ATTAINS.WaterType" - ) - ) + .data |> TADA_OrderCols() - if (exists("TADA_OrderCols", mode = "function")) { - .data <- TADA_OrderCols(.data) + return(.data) } - - .data } #' Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 35d51ced2..9ce77f458 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -892,5 +892,7 @@ testthat::test_that("TADA_CreatePointAUs returns list containng crosswalk and ge result <- TADA_CreatePointAUs(df, create_geo = TRUE) - testthat::expect_equal(names(result), c("crosswalk", "geometry")) + testthat::expect_type(result, "list") + testthat::expect_true(all(c("crosswalk", "geometry") %in% names(result))) + testthat::expect_s3_class(result$geometry, "sf") }) From 4d59a53b1a85d1ef681111e5638eb67236d5ea6b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:30:33 +0000 Subject: [PATCH 16/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index deac43f4b..f1c38e38c 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4534,10 +4534,10 @@ TADA_MLSummary <- function( #' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") #' } TADA_CrosswalkATTAINSWaterTypes <- function( - .data, - org_id = NULL, - org_only = FALSE, - replace_all = FALSE + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE ) { required_cols <- c( "TADA.MonitoringLocationIdentifier", @@ -4553,7 +4553,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if ( !is.null(org_id) && - (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) + (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) ) { stop( "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." @@ -4689,8 +4689,8 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") #' } TADA_ReviewATTAINSWaterTypes <- function( - .data, - review_action = c("flag", "update") + .data, + review_action = c("flag", "update") ) { required_cols <- c( "TADA.MonitoringLocationIdentifier", From 1421f314ff54cee5420110c4d8e9ebf31c385d24 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:58:21 -0400 Subject: [PATCH 17/48] fix function bug and test --- R/ATTAINSCrosswalks.R | 4 +++- tests/testthat/test-ATTAINSCrosswalks.R | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index f1c38e38c..f1fa6d449 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4942,7 +4942,9 @@ TADA_CreatePointAUs <- function( auid_prefix = auid_prefix ) - list(crosswalk = PointAU.Crosswalk, geometry = PointAU.Geometry) + PointAUs <- list(crosswalk = PointAU.Crosswalk, geometry = PointAU.Geometry) + + return(PointAUs) } #' Build ATTAINS water type crosswalk diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 36a11b858..c8096d9f1 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -858,7 +858,7 @@ testthat::test_that("TADA_CreatePointAUs errors when water crosswalk is needed b testthat::expect_error( TADA_CreatePointAUs(df), - "TADA_CreatePointAUs: Missing required column for water-type crosswalk: TADA.MonitoringLocationTypeName" + "TADA_CreatePointAUs: Missing required column: TADA.MonitoringLocationTypeName" ) }) From 318feb6df4e93ca76f0355d01ca3a3da55389d4d Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 10 Aug 2026 13:19:14 -0400 Subject: [PATCH 18/48] Update test-ATTAINSCrosswalks.R --- tests/testthat/test-ATTAINSCrosswalks.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index c8096d9f1..f28335518 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -896,7 +896,7 @@ testthat::test_that("TADA_CreatePointAUs does not modify existing non-missing, n ) }) -testthat::test_that("TADA_CreatePointAUs returns list containng crosswalk and geometry when create_geo equals TRUE", { +testthat::test_that("TADA_CreatePointAUs returns list containing crosswalk and geometry when create_geo equals TRUE", { df <- Data_TribalNations_Harmonized |> dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") From 36878e637c87945eb368c879756527643c840f31 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 10 Aug 2026 13:37:05 -0400 Subject: [PATCH 19/48] bug fixes --- R/ATTAINSCrosswalks.R | 3 +-- tests/testthat/test-ATTAINSCrosswalks.R | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index f1fa6d449..1b60af62f 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4908,8 +4908,7 @@ TADA_CreatePointAUs <- function( if (isTRUE(need_crosswalk)) { if (!"TADA.MonitoringLocationTypeName" %in% names(.data)) { stop( - "TADA_CreatePointAUs: Missing required column for water-type crosswalk: ", - "TADA.MonitoringLocationTypeName" + "TADA_CreatePointAUs: Missing required column for water-type crosswalk: TADA.MonitoringLocationTypeName" ) } diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index f28335518..7fa540d42 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -858,7 +858,7 @@ testthat::test_that("TADA_CreatePointAUs errors when water crosswalk is needed b testthat::expect_error( TADA_CreatePointAUs(df), - "TADA_CreatePointAUs: Missing required column: TADA.MonitoringLocationTypeName" + "TADA_CreatePointAUs: Missing required column for water-type crosswalk: TADA.MonitoringLocationTypeName" ) }) From 0b6508a7e6545de5223fc414d624c20c5ac6c3f8 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:13:32 -0400 Subject: [PATCH 20/48] bug fixes --- R/ATTAINSCrosswalks.R | 127 +++++++++++-------------- man/TADA_CrosswalkATTAINSWaterTypes.Rd | 20 ++++ man/TADA_ReviewATTAINSWaterTypes.Rd | 21 ++++ 3 files changed, 97 insertions(+), 71 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 1b60af62f..4aa6556ec 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4867,10 +4867,10 @@ TADA_ReviewATTAINSWaterTypes <- function( #' #' @export TADA_CreatePointAUs <- function( - .data, - auid_prefix = NULL, - create_geo = FALSE, - download_geo = FALSE + .data, + auid_prefix = NULL, + create_geo = FALSE, + download_geo = FALSE ) { req <- c("TADA.MonitoringLocationIdentifier") geo_req <- c( @@ -4941,7 +4941,10 @@ TADA_CreatePointAUs <- function( auid_prefix = auid_prefix ) - PointAUs <- list(crosswalk = PointAU.Crosswalk, geometry = PointAU.Geometry) + PointAUs <- list( + crosswalk = PointAU.Crosswalk, + geometry = PointAU.Geometry + ) return(PointAUs) } @@ -5090,10 +5093,10 @@ build_attains_water_type_crosswalk <- function( #' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") #' } TADA_CrosswalkATTAINSWaterTypes <- function( - .data, - org_id = NULL, - org_only = FALSE, - replace_all = FALSE + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE ) { required_cols <- c( "TADA.MonitoringLocationIdentifier", @@ -5109,7 +5112,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if ( !is.null(org_id) && - (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) + (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) ) { stop( "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." @@ -5130,25 +5133,26 @@ TADA_CrosswalkATTAINSWaterTypes <- function( ) } - # normalize NA to blanks + # normalize blanks to NA if ("ATTAINS.WaterType" %in% names(.data)) { .data <- .data |> - dplyr::mutate(ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "")) + dplyr::mutate( + ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "") + ) } - # Create one-row-per-location lookup + # Keep one row per monitoring location for the lookup lookup <- .data |> - dplyr::select(dplyr::any_of(c( - "TADA.MonitoringLocationIdentifier", - "TADA.MonitoringLocationTypeName", - "ATTAINS.WaterType" - ))) |> - dplyr::distinct() + dplyr::distinct( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName, + .keep_all = TRUE + ) # Build crosswalk cw <- build_attains_water_type_crosswalk(org_id = org_id, org_only = org_only) - # Add crosswalk recommendation by monitoring location type + # Join crosswalk to lookup lookup <- lookup |> dplyr::left_join( cw, @@ -5156,63 +5160,44 @@ TADA_CrosswalkATTAINSWaterTypes <- function( relationship = "many-to-many" ) - # Fill or replace lookup water type - if (!"ATTAINS.WaterType" %in% names(lookup)) { - lookup <- lookup |> - dplyr::transmute( - TADA.MonitoringLocationIdentifier, - TADA.ATTAINS.WaterType = TADA.ATTAINS.WaterType - ) - } else if (isTRUE(replace_all)) { - lookup <- lookup |> - dplyr::transmute( - TADA.MonitoringLocationIdentifier, - TADA.ATTAINS.WaterType = TADA.ATTAINS.WaterType - ) + # Resolve water type + if ("ATTAINS.WaterType" %in% names(lookup)) { + if (isTRUE(replace_all)) { + lookup <- lookup |> + dplyr::mutate( + ATTAINS.WaterType = TADA.ATTAINS.WaterType + ) + } else { + lookup <- lookup |> + dplyr::mutate( + ATTAINS.WaterType = dplyr::coalesce( + ATTAINS.WaterType, + TADA.ATTAINS.WaterType + ) + ) + } } else { lookup <- lookup |> dplyr::mutate( - TADA.ATTAINS.WaterType = dplyr::coalesce( - ATTAINS.WaterType, - TADA.ATTAINS.WaterType - ) - ) |> - dplyr::select(TADA.MonitoringLocationIdentifier, TADA.ATTAINS.WaterType) + ATTAINS.WaterType = TADA.ATTAINS.WaterType + ) } + # Return only what we need + lookup <- lookup |> + dplyr::select( + TADA.MonitoringLocationIdentifier, + ATTAINS.WaterType + ) + # Join back to original data - if (!"ATTAINS.WaterType" %in% names(.data)) { - .data <- .data |> - dplyr::left_join( - lookup, - by = dplyr::join_by(TADA.MonitoringLocationIdentifier), - relationship = "many-to-many" - ) |> - dplyr::rename(ATTAINS.WaterType = TADA.ATTAINS.WaterType) - } else if (isTRUE(replace_all)) { - .data <- .data |> - dplyr::left_join( - lookup |> dplyr::rename(New.ATTAINS.WaterType = TADA.ATTAINS.WaterType), - by = dplyr::join_by(TADA.MonitoringLocationIdentifier), - relationship = "many-to-many" - ) |> - dplyr::mutate(ATTAINS.WaterType = New.ATTAINS.WaterType) |> - dplyr::select(-New.ATTAINS.WaterType) - } else { - .data <- .data |> - dplyr::left_join( - lookup |> dplyr::rename(New.ATTAINS.WaterType = TADA.ATTAINS.WaterType), - by = dplyr::join_by(TADA.MonitoringLocationIdentifier), - relationship = "many-to-many" - ) |> - dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce( - ATTAINS.WaterType, - New.ATTAINS.WaterType - ) - ) |> - dplyr::select(-New.ATTAINS.WaterType) - } + .data <- .data |> + dplyr::select(-dplyr::any_of("ATTAINS.WaterType")) |> + dplyr::left_join( + lookup, + by = dplyr::join_by(TADA.MonitoringLocationIdentifier), + relationship = "many-to-many" + ) .data |> TADA_OrderCols() } diff --git a/man/TADA_CrosswalkATTAINSWaterTypes.Rd b/man/TADA_CrosswalkATTAINSWaterTypes.Rd index 4db2ceccf..fa4be28b1 100644 --- a/man/TADA_CrosswalkATTAINSWaterTypes.Rd +++ b/man/TADA_CrosswalkATTAINSWaterTypes.Rd @@ -4,6 +4,13 @@ \alias{TADA_CrosswalkATTAINSWaterTypes} \title{Crosswalk WQP Monitoring Location Type to ATTAINS Water Type} \usage{ +TADA_CrosswalkATTAINSWaterTypes( + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE +) + TADA_CrosswalkATTAINSWaterTypes( .data, org_id = NULL, @@ -24,9 +31,14 @@ If FALSE, unmatched types fall back to the TADA default crosswalk.} If FALSE, only fill missing values. Default is FALSE.} } \value{ +A TADA data frame with ATTAINS.WaterType populated. + A TADA data frame with ATTAINS.WaterType populated. } \description{ +Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. +By default, only missing ATTAINS.WaterType values are populated. + Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. By default, only missing ATTAINS.WaterType values are populated. } @@ -37,6 +49,14 @@ By default, only missing ATTAINS.WaterType values are populated. # example for MT data testdat <- Data_MT_MissoulaCounty +crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +} + +\dontrun{ + +# example for MT data +testdat <- Data_MT_MissoulaCounty + crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") } } diff --git a/man/TADA_ReviewATTAINSWaterTypes.Rd b/man/TADA_ReviewATTAINSWaterTypes.Rd index 4385faa24..95b20a6f5 100644 --- a/man/TADA_ReviewATTAINSWaterTypes.Rd +++ b/man/TADA_ReviewATTAINSWaterTypes.Rd @@ -4,6 +4,8 @@ \alias{TADA_ReviewATTAINSWaterTypes} \title{Review ATTAINS Water Types} \usage{ +TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) + TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) } \arguments{ @@ -12,11 +14,18 @@ TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) \item{review_action}{Character string. One of "flag" or "update".} } \value{ +A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. +If \code{review_action = "update"}, invalid values may also be replaced if an +ATTAINS water type match is available. + A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. If \code{review_action = "update"}, invalid values may also be replaced if an ATTAINS water type match is available. } \description{ +Validates ATTAINS.WaterType against allowable ATTAINS domain values. +Can either flag invalid values or update them using the crosswalk. + Validates ATTAINS.WaterType against allowable ATTAINS domain values. Can either flag invalid values or update them using the crosswalk. } @@ -31,6 +40,18 @@ TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") ) +review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") +} + +\dontrun{ + +# example of updating invalid ATTAINS water types +example.df <- tibble::tibble( +TADA.MonitoringLocationIdentifier = c("id1", "id2"), +TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), +ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") +) + review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") } } From aeb8f3edd52e26a7595bb7d89452145ca9151281 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:13:49 +0000 Subject: [PATCH 21/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 4aa6556ec..b4fd404c1 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4867,10 +4867,10 @@ TADA_ReviewATTAINSWaterTypes <- function( #' #' @export TADA_CreatePointAUs <- function( - .data, - auid_prefix = NULL, - create_geo = FALSE, - download_geo = FALSE + .data, + auid_prefix = NULL, + create_geo = FALSE, + download_geo = FALSE ) { req <- c("TADA.MonitoringLocationIdentifier") geo_req <- c( @@ -4941,10 +4941,7 @@ TADA_CreatePointAUs <- function( auid_prefix = auid_prefix ) - PointAUs <- list( - crosswalk = PointAU.Crosswalk, - geometry = PointAU.Geometry - ) + PointAUs <- list(crosswalk = PointAU.Crosswalk, geometry = PointAU.Geometry) return(PointAUs) } @@ -5093,10 +5090,10 @@ build_attains_water_type_crosswalk <- function( #' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") #' } TADA_CrosswalkATTAINSWaterTypes <- function( - .data, - org_id = NULL, - org_only = FALSE, - replace_all = FALSE + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE ) { required_cols <- c( "TADA.MonitoringLocationIdentifier", @@ -5112,7 +5109,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if ( !is.null(org_id) && - (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) + (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) ) { stop( "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." @@ -5136,9 +5133,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( # normalize blanks to NA if ("ATTAINS.WaterType" %in% names(.data)) { .data <- .data |> - dplyr::mutate( - ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "") - ) + dplyr::mutate(ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "")) } # Keep one row per monitoring location for the lookup @@ -5164,9 +5159,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( if ("ATTAINS.WaterType" %in% names(lookup)) { if (isTRUE(replace_all)) { lookup <- lookup |> - dplyr::mutate( - ATTAINS.WaterType = TADA.ATTAINS.WaterType - ) + dplyr::mutate(ATTAINS.WaterType = TADA.ATTAINS.WaterType) } else { lookup <- lookup |> dplyr::mutate( @@ -5178,17 +5171,12 @@ TADA_CrosswalkATTAINSWaterTypes <- function( } } else { lookup <- lookup |> - dplyr::mutate( - ATTAINS.WaterType = TADA.ATTAINS.WaterType - ) + dplyr::mutate(ATTAINS.WaterType = TADA.ATTAINS.WaterType) } # Return only what we need lookup <- lookup |> - dplyr::select( - TADA.MonitoringLocationIdentifier, - ATTAINS.WaterType - ) + dplyr::select(TADA.MonitoringLocationIdentifier, ATTAINS.WaterType) # Join back to original data .data <- .data |> From 6fc474c068ae4085f0d68690ecc67fb5b0eef60e Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:01:40 -0400 Subject: [PATCH 22/48] Update test-ATTAINSCrosswalks.R --- tests/testthat/test-ATTAINSCrosswalks.R | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 7fa540d42..97a227cd2 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -804,17 +804,6 @@ testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes w stringsAsFactors = FALSE ) - mock_crosswalk <- function(.data, replace_all = FALSE) { - expect_false(replace_all) - .data$ATTAINS.WaterType <- c("STREAM", "LAKE") - .data - } - - testthat::local_mocked_bindings( - TADA_CrosswalkATTAINSWaterTypes = mock_crosswalk, - .env = environment(TADA_CreatePointAUs) - ) - result <- TADA_CreatePointAUs(df) testthat::expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE")) @@ -833,16 +822,6 @@ testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes w stringsAsFactors = FALSE ) - mock_crosswalk <- function(.data, replace_all = FALSE) { - .data$ATTAINS.WaterType <- c("STREAM", "LAKE") - .data - } - - testthat::local_mocked_bindings( - TADA_CrosswalkATTAINSWaterTypes = mock_crosswalk, - .env = environment(TADA_CreatePointAUs) - ) - result <- TADA_CreatePointAUs(df) testthat::expect_equal(result$ATTAINS.WaterType, c("STREAM", "LAKE")) From ec78979f5598b31f3b7ca8c202b6e162321098e9 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:52:51 -0400 Subject: [PATCH 23/48] test updates, add global vars --- R/Utilities.R | 3 ++- tests/testthat/test-ATTAINSCrosswalks.R | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/Utilities.R b/R/Utilities.R index 24166e47b..809065064 100644 --- a/R/Utilities.R +++ b/R/Utilities.R @@ -512,7 +512,8 @@ utils::globalVariables(c( "ATTAINSWaterTypeByOrgName", "TADA.ATTAINS.WaterType", "TADA.Rank", - "TADA.ResultValueAggregation.Flag" + "TADA.ResultValueAggregation.Flag", + "n_pts" )) # global variables for tribal feature layers used in TADA_OverviewMap in Utilities.R diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 97a227cd2..0076db2e1 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -799,7 +799,7 @@ testthat::test_that("TADA_CreatePointAUs treats blank AUIDs as missing", { testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType is missing", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), - TADA.MonitoringLocationTypeName = c("Stream", "Lake"), + TADA.MonitoringLocationTypeName = c("STREAM", "LAKE"), ATTAINS.AssessmentUnitIdentifier = c(NA_character_, NA_character_), stringsAsFactors = FALSE ) @@ -816,7 +816,7 @@ testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes w testthat::test_that("TADA_CreatePointAUs calls TADA_CrosswalkATTAINSWaterTypes when ATTAINS.WaterType has blanks", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("LOC1", "LOC2"), - TADA.MonitoringLocationTypeName = c("Stream", "Lake"), + TADA.MonitoringLocationTypeName = c("STREAM", "LAKE"), ATTAINS.AssessmentUnitIdentifier = c(NA_character_, NA_character_), ATTAINS.WaterType = c("STREAM", ""), stringsAsFactors = FALSE From 95701654a5916c6067466cd88304077cfa7c783e Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:13:52 -0400 Subject: [PATCH 24/48] Update GeospatialFunctions.R minimize int objects --- R/GeospatialFunctions.R | 61 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 694839b20..360829af5 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3628,23 +3628,27 @@ TADA_CreateAUMLCrosswalk <- function( #' #' @export TADA_CreatePointAUGeometry <- function( - .data, - target_crs = 4269, - download_geo = FALSE, - return_geo = TRUE, - auid_prefix = NULL + .data, + target_crs = 4269, + download_geo = FALSE, + return_geo = TRUE, + auid_prefix = NULL ) { + + # Required geospatial cols coord_req <- c( "TADA.LongitudeMeasure", "TADA.LatitudeMeasure", "HorizontalCoordinateReferenceSystemDatumName" ) + # Required id cols id_cols <- c( "ATTAINS.AssessmentUnitIdentifier", "TADA.MonitoringLocationIdentifier" ) + # Find missing coordinate cols missing_coords <- setdiff(coord_req, names(.data)) if (length(missing_coords) > 0) { stop( @@ -3653,6 +3657,7 @@ TADA_CreatePointAUGeometry <- function( ) } + # Find missing id cols if (!any(id_cols %in% names(.data))) { stop( "TADA_CreatePointAUGeometry: Input data must contain at least one of: ", @@ -3660,48 +3665,45 @@ TADA_CreatePointAUGeometry <- function( ) } - # Ensure AUID exists if needed / possible + # Fill in missing assessment unit ids if needed .data <- fill_missing_assessment_unit_id(.data, auid_prefix = auid_prefix) - # Use AUID for grouping if available; otherwise fall back to ML ID + # Set id col id.col <- if ("ATTAINS.AssessmentUnitIdentifier" %in% names(.data)) { "ATTAINS.AssessmentUnitIdentifier" } else { "TADA.MonitoringLocationIdentifier" } - .data <- .data |> + # Set CRS target + crs_target <- sf::st_crs(target_crs) + + # Create geospatial df + sf_out <- .data |> dplyr::select(rlang::sym(id.col), dplyr::all_of(coord_req)) |> dplyr::distinct() |> - dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) - - sf_pts <- sf::st_as_sf( - .data, - coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), - crs = 4269, - remove = TRUE - ) |> - sf::st_transform(crs = target_crs) - - sf_out <- sf_pts |> + dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) |> + sf::st_as_sf( + coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), + crs = 4269, + remove = TRUE + ) |> + sf::st_transform(crs = target_crs) |> dplyr::group_by(!!rlang::sym(id.col)) |> dplyr::summarise( - n_pts = dplyr::n(), geometry = { - grp_geom <- geometry - coords <- sf::st_coordinates(grp_geom)[, 1:2, drop = FALSE] - - if (n_pts[1] == 1) { - sf::st_sfc(grp_geom[[1]], crs = sf::st_crs(sf_pts)) + coords <- sf::st_coordinates(geometry)[, 1:2, drop = FALSE] + if (dplyr::n() == 1) { + sf::st_sfc(geometry[[1]], crs = crs_target) } else { - sf::st_sfc(sf::st_multipoint(coords), crs = sf::st_crs(sf_pts)) + sf::st_sfc(sf::st_multipoint(coords), crs = crs_target) } }, .groups = "drop" ) |> - dplyr::select(-n_pts) |> dplyr::rename(AU_ID = !!rlang::sym(id.col)) + # Save as shp file if required if (isTRUE(download_geo)) { today <- format(Sys.Date(), "%m_%d_%Y") file.name <- paste0("TADAPointAUGeometry_", today) @@ -3716,13 +3718,10 @@ TADA_CreatePointAUGeometry <- function( } point.path <- .get_downloads_path(file.name) - save_sf_as_shp(sf_out = sf_out, shp_path = point.path) } - if (isTRUE(return_geo)) { - return(sf_out) - } + if (isTRUE(return_geo)) return(sf_out) invisible(NULL) } From 752e5b373bf2199afbdfb6c02d09960201cffb6e Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:19:42 -0400 Subject: [PATCH 25/48] Update GeospatialFunctions.R add examples --- R/GeospatialFunctions.R | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 360829af5..e0e1aa7ce 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3627,6 +3627,27 @@ TADA_CreateAUMLCrosswalk <- function( #' @seealso [TADA_CreatePointAUs()] #' #' @export +#' +#' #' @examples +#' \dontrun{ +#' # Example with all POINT geometry +#' df <- Data_TribalNations_Harmonized |> +#' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") +#' +#' result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) +#' +#' # Example with POINT and MULTIPOINT geometry +#' df <- data.frame( +#' ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU1", "AU2"), +#' TADA.MonitoringLocationIdentifier = c("ML1", "ML1", "ML2"), +#' TADA.LongitudeMeasure = c(-90, -90, -91), +#' TADA.LatitudeMeasure = c(40, 41, 41), +#' HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83", "NAD83"), +#' stringsAsFactors = FALSE) +#' +#' result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) +#' } +#' TADA_CreatePointAUGeometry <- function( .data, target_crs = 4269, From dfe073e489c09b4043355ee1dbcc1cea0fac9900 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:19:58 +0000 Subject: [PATCH 26/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/GeospatialFunctions.R | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index e0e1aa7ce..057324d52 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3649,13 +3649,12 @@ TADA_CreateAUMLCrosswalk <- function( #' } #' TADA_CreatePointAUGeometry <- function( - .data, - target_crs = 4269, - download_geo = FALSE, - return_geo = TRUE, - auid_prefix = NULL + .data, + target_crs = 4269, + download_geo = FALSE, + return_geo = TRUE, + auid_prefix = NULL ) { - # Required geospatial cols coord_req <- c( "TADA.LongitudeMeasure", @@ -3703,7 +3702,10 @@ TADA_CreatePointAUGeometry <- function( sf_out <- .data |> dplyr::select(rlang::sym(id.col), dplyr::all_of(coord_req)) |> dplyr::distinct() |> - dplyr::filter(!is.na(TADA.LongitudeMeasure), !is.na(TADA.LatitudeMeasure)) |> + dplyr::filter( + !is.na(TADA.LongitudeMeasure), + !is.na(TADA.LatitudeMeasure) + ) |> sf::st_as_sf( coords = c("TADA.LongitudeMeasure", "TADA.LatitudeMeasure"), crs = 4269, @@ -3742,7 +3744,9 @@ TADA_CreatePointAUGeometry <- function( save_sf_as_shp(sf_out = sf_out, shp_path = point.path) } - if (isTRUE(return_geo)) return(sf_out) + if (isTRUE(return_geo)) { + return(sf_out) + } invisible(NULL) } From f4e33f7627f51b4c530ec8d0d9d4153fcb6fb826 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:22:07 -0400 Subject: [PATCH 27/48] update createpointaus description --- R/ATTAINSCrosswalks.R | 2 ++ man/TADA_CreatePointAUs.Rd | 2 ++ 2 files changed, 4 insertions(+) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index b4fd404c1..ae4c6de00 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4816,6 +4816,8 @@ TADA_ReviewATTAINSWaterTypes <- function( #' Assessment Units. Missing or blank `ATTAINS.AssessmentUnitIdentifier` values #' are filled from `TADA.MonitoringLocationIdentifier`, optionally prefixed #' with `auid_prefix`. Existing non-missing, non-blank AUIDs are left unchanged. +#' Optionally, this function can also return either a df or a shp file containing +#' the point or multipoint geometry and its corresponding assessment unit identifier. #' #' If `ATTAINS.WaterType` is missing or contains any blank values, the function #' attempts to populate it by calling `TADA_CrosswalkATTAINSWaterTypes()` diff --git a/man/TADA_CreatePointAUs.Rd b/man/TADA_CreatePointAUs.Rd index b805e35db..f2247d990 100644 --- a/man/TADA_CreatePointAUs.Rd +++ b/man/TADA_CreatePointAUs.Rd @@ -65,6 +65,8 @@ Build a distinct crosswalk between WQP Monitoring Locations and ATTAINS Assessment Units. Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values are filled from \code{TADA.MonitoringLocationIdentifier}, optionally prefixed with \code{auid_prefix}. Existing non-missing, non-blank AUIDs are left unchanged. +Optionally, this function can also return either a df or a shp file containing +the point or multipoint geometry and its corresponding assessment unit identifier. } \details{ If \code{ATTAINS.WaterType} is missing or contains any blank values, the function From 9922ead3e42768b5403cd7743ec3cb08a7631974 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:26:35 -0400 Subject: [PATCH 28/48] Update WORDLIST --- inst/WORDLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/WORDLIST b/inst/WORDLIST index 5cfcfedf5..333d69fb7 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -572,6 +572,7 @@ secchi setEQKey setnames showMissingATTAINSAUs +shp siteType siteid sitetype From 7afdaf05cbe42703abe2823cb2e40523dd1eefdc Mon Sep 17 00:00:00 2001 From: Mullin Date: Wed, 26 Aug 2026 13:26:33 -0400 Subject: [PATCH 29/48] Update GeospatialFunctions.R --- R/GeospatialFunctions.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 057324d52..4051fce27 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3628,7 +3628,7 @@ TADA_CreateAUMLCrosswalk <- function( #' #' @export #' -#' #' @examples +#' @examples #' \dontrun{ #' # Example with all POINT geometry #' df <- Data_TribalNations_Harmonized |> From 812a403a51db6a632f58244b970d9bbee0524bdb Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 15:17:04 -0400 Subject: [PATCH 30/48] remove return_geo param --- R/GeospatialFunctions.R | 13 +++++-------- man/TADA_CreatePointAUGeometry.Rd | 26 ++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index 4051fce27..ab27b093b 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3607,12 +3607,11 @@ TADA_CreateAUMLCrosswalk <- function( #' @param target_crs Numeric. Target CRS EPSG code. Default is 4269. #' @param download_geo Logical. If `TRUE`, write a shapefile to the user's #' downloads folder. -#' @param return_geo Logical. If `TRUE`, return the `sf` object. #' @param auid_prefix Character or `NULL`. If provided and non-empty, this #' prefix is applied only to newly created #' `ATTAINS.AssessmentUnitIdentifier` values. #' -#' @return If `return_geo = TRUE`, an `sf` object with: +#' @return An `sf` object with: #' - `AU_ID` #' - `geometry` #' @@ -3634,7 +3633,7 @@ TADA_CreateAUMLCrosswalk <- function( #' df <- Data_TribalNations_Harmonized |> #' dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") #' -#' result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) +#' result <- TADA_CreatePointAUGeometry(df) #' #' # Example with POINT and MULTIPOINT geometry #' df <- data.frame( @@ -3645,14 +3644,13 @@ TADA_CreateAUMLCrosswalk <- function( #' HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83", "NAD83"), #' stringsAsFactors = FALSE) #' -#' result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) +#' result <- TADA_CreatePointAUGeometry(df) #' } #' TADA_CreatePointAUGeometry <- function( .data, target_crs = 4269, download_geo = FALSE, - return_geo = TRUE, auid_prefix = NULL ) { # Required geospatial cols @@ -3668,6 +3666,7 @@ TADA_CreatePointAUGeometry <- function( "TADA.MonitoringLocationIdentifier" ) + # Find missing coordinate cols missing_coords <- setdiff(coord_req, names(.data)) if (length(missing_coords) > 0) { @@ -3729,7 +3728,7 @@ TADA_CreatePointAUGeometry <- function( # Save as shp file if required if (isTRUE(download_geo)) { today <- format(Sys.Date(), "%m_%d_%Y") - file.name <- paste0("TADAPointAUGeometry_", today) + file.name <- paste0("TADAPointAUGeometry_", today, ".shp") if (!is.null(auid_prefix)) { auid_prefix <- trimws(auid_prefix) @@ -3744,9 +3743,7 @@ TADA_CreatePointAUGeometry <- function( save_sf_as_shp(sf_out = sf_out, shp_path = point.path) } - if (isTRUE(return_geo)) { return(sf_out) - } invisible(NULL) } diff --git a/man/TADA_CreatePointAUGeometry.Rd b/man/TADA_CreatePointAUGeometry.Rd index fd0171780..9cb2aac57 100644 --- a/man/TADA_CreatePointAUGeometry.Rd +++ b/man/TADA_CreatePointAUGeometry.Rd @@ -8,7 +8,6 @@ TADA_CreatePointAUGeometry( .data, target_crs = 4269, download_geo = FALSE, - return_geo = TRUE, auid_prefix = NULL ) } @@ -31,14 +30,12 @@ And at least one of: \item{download_geo}{Logical. If \code{TRUE}, write a shapefile to the user's downloads folder.} -\item{return_geo}{Logical. If \code{TRUE}, return the \code{sf} object.} - \item{auid_prefix}{Character or \code{NULL}. If provided and non-empty, this prefix is applied only to newly created \code{ATTAINS.AssessmentUnitIdentifier} values.} } \value{ -If \code{return_geo = TRUE}, an \code{sf} object with: +An \code{sf} object with: \itemize{ \item \code{AU_ID} \item \code{geometry} @@ -58,6 +55,27 @@ with \code{TADA.MonitoringLocationIdentifier}. \item Single-location groups retain \code{POINT} geometry. \item Multi-location groups are written as \code{MULTIPOINT}. } +} +\examples{ +\dontrun{ +# Example with all POINT geometry +df <- Data_TribalNations_Harmonized |> +dplyr::filter(OrganizationFormalName == "Blackfeet Nation (Montana)") + +result <- TADA_CreatePointAUGeometry(df) + +# Example with POINT and MULTIPOINT geometry +df <- data.frame( +ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU1", "AU2"), +TADA.MonitoringLocationIdentifier = c("ML1", "ML1", "ML2"), +TADA.LongitudeMeasure = c(-90, -90, -91), +TADA.LatitudeMeasure = c(40, 41, 41), + HorizontalCoordinateReferenceSystemDatumName = c("NAD83", "NAD83", "NAD83"), + stringsAsFactors = FALSE) + + result <- TADA_CreatePointAUGeometry(df) +} + } \seealso{ \code{\link[=TADA_CreatePointAUs]{TADA_CreatePointAUs()}} From acc72b9759e875f567e4fd57b291f9a681d8edce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 19:17:21 +0000 Subject: [PATCH 31/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/GeospatialFunctions.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index ab27b093b..c05dec5eb 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3666,7 +3666,6 @@ TADA_CreatePointAUGeometry <- function( "TADA.MonitoringLocationIdentifier" ) - # Find missing coordinate cols missing_coords <- setdiff(coord_req, names(.data)) if (length(missing_coords) > 0) { @@ -3743,7 +3742,7 @@ TADA_CreatePointAUGeometry <- function( save_sf_as_shp(sf_out = sf_out, shp_path = point.path) } - return(sf_out) + return(sf_out) invisible(NULL) } From a573eadaa4c8d17b4cc5ed8bcbc151f3baeb0454 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 16:51:41 -0400 Subject: [PATCH 32/48] fix saving sf obj (now as zip file) --- R/GeospatialFunctions.R | 4 ++-- R/GeospatialUtilities.R | 32 ++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/R/GeospatialFunctions.R b/R/GeospatialFunctions.R index c05dec5eb..59674976a 100644 --- a/R/GeospatialFunctions.R +++ b/R/GeospatialFunctions.R @@ -3727,7 +3727,7 @@ TADA_CreatePointAUGeometry <- function( # Save as shp file if required if (isTRUE(download_geo)) { today <- format(Sys.Date(), "%m_%d_%Y") - file.name <- paste0("TADAPointAUGeometry_", today, ".shp") + file.name <- paste0("TADAPointAUGeometry_", today) if (!is.null(auid_prefix)) { auid_prefix <- trimws(auid_prefix) @@ -3739,7 +3739,7 @@ TADA_CreatePointAUGeometry <- function( } point.path <- .get_downloads_path(file.name) - save_sf_as_shp(sf_out = sf_out, shp_path = point.path) + save_sf_as_zip(sf_out, point.path) } return(sf_out) diff --git a/R/GeospatialUtilities.R b/R/GeospatialUtilities.R index 106859838..38d002dc4 100644 --- a/R/GeospatialUtilities.R +++ b/R/GeospatialUtilities.R @@ -1926,29 +1926,49 @@ fetchWaterType <- function(au_list, api_key = NULL) { #' #' @keywords internal #' @noRd -save_sf_as_shp <- function(sf_out, shp_path) { +save_sf_as_zip <- function(sf_out, zip_path) { if (!inherits(sf_out, "sf")) { stop("'sf_out' must be an sf object.") } - if (is.null(shp_path) || !nzchar(shp_path)) { - stop("'shp_path' must be a valid file path.") + if (is.null(zip_path) || !nzchar(zip_path)) { + stop("'zip_path' must be a valid file path.") } - out_dir <- dirname(shp_path) + if (!grepl("\\.zip$", zip_path, ignore.case = TRUE)) { + zip_path <- paste0(zip_path, ".zip") + } + + out_dir <- dirname(zip_path) if (!dir.exists(out_dir)) { dir.create(out_dir, recursive = TRUE) } + temp_dir <- tempfile("shp_export_") + dir.create(temp_dir) + + layer_name <- tools::file_path_sans_ext(basename(zip_path)) + + # Write shapefile into the temp directory sf::st_write( sf_out, - dsn = shp_path, + dsn = temp_dir, + layer = layer_name, driver = "ESRI Shapefile", delete_dsn = TRUE, quiet = TRUE ) - invisible(shp_path) + # List all files created for that layer + shp_files <- list.files(temp_dir, pattern = paste0("^", layer_name, "\\."), full.names = FALSE) + + old_wd <- getwd() + on.exit(setwd(old_wd), add = TRUE) + setwd(temp_dir) + + utils::zip(zipfile = zip_path, files = shp_files) + + invisible(zip_path) } #' Fill missing ATTAINS Assessment Unit Identifiers From 28ee5ccff4bd093c849c2ec7487dba38f35fd97b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:51:58 +0000 Subject: [PATCH 33/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/GeospatialUtilities.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/GeospatialUtilities.R b/R/GeospatialUtilities.R index 38d002dc4..cbf8bc91c 100644 --- a/R/GeospatialUtilities.R +++ b/R/GeospatialUtilities.R @@ -1960,7 +1960,11 @@ save_sf_as_zip <- function(sf_out, zip_path) { ) # List all files created for that layer - shp_files <- list.files(temp_dir, pattern = paste0("^", layer_name, "\\."), full.names = FALSE) + shp_files <- list.files( + temp_dir, + pattern = paste0("^", layer_name, "\\."), + full.names = FALSE + ) old_wd <- getwd() on.exit(setwd(old_wd), add = TRUE) From 4a61dc67977cc02bf025ce20488ed84bdcbc54c0 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 18:02:18 -0400 Subject: [PATCH 34/48] updated org_id check --- R/ATTAINSCrosswalks.R | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 597724a90..579ee1a4a 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4559,29 +4559,28 @@ TADA_CrosswalkATTAINSWaterTypes <- function( ) } - if ( - !is.null(org_id) && - (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) - ) { - stop( - "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." - ) - } + org.ref <- TADA_GetATTAINSOrgIDsRef() |> + dplyr::select(code) |> + dplyr::pull() - if (!is.logical(org_only) || length(org_only) != 1 || is.na(org_only)) { + if (length(org_id) > 1) { stop( - "TADA_CrosswalkATTAINSWaterTypes: org_only must be a single non-NA logical." + paste0("TADA_CrosswalkATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier.") ) } - if ( - !is.logical(replace_all) || length(replace_all) != 1 || is.na(replace_all) - ) { + if (!org_id %in% org.ref & !is.null(org_id)) { + + print.org <- paste0(org_id, " is not a valid input.") + stop( - "TADA_CrosswalkATTAINSWaterTypes: replace_all must be a single non-NA logical." + paste0("TADA_CrosswalkATTAINSWaterTypes: org_type must be a single non-NA logical. ", + print.org) ) } + # need check for org_only + # normalize NA to blanks if ("ATTAINS.WaterType" %in% names(.data)) { .data <- .data |> From bdd54287683e6638afc6c14efc0a49601f22638b Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 18:08:01 -0400 Subject: [PATCH 35/48] update org_id checks --- R/ATTAINSCrosswalks.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 579ee1a4a..ceb0818fe 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4564,6 +4564,9 @@ TADA_CrosswalkATTAINSWaterTypes <- function( dplyr::pull() if (length(org_id) > 1) { + + print.org <- paste0(org_id, " is not a valid input.") + stop( paste0("TADA_CrosswalkATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier.") ) @@ -4579,7 +4582,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( ) } - # need check for org_only + # need better check for org_only # normalize NA to blanks if ("ATTAINS.WaterType" %in% names(.data)) { From c06c2f3d39198dc7a03532947f6ed337c665ffc8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:08:39 +0000 Subject: [PATCH 36/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index ceb0818fe..42939aa6c 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4559,27 +4559,23 @@ TADA_CrosswalkATTAINSWaterTypes <- function( ) } - org.ref <- TADA_GetATTAINSOrgIDsRef() |> - dplyr::select(code) |> - dplyr::pull() + org.ref <- TADA_GetATTAINSOrgIDsRef() |> dplyr::select(code) |> dplyr::pull() if (length(org_id) > 1) { - print.org <- paste0(org_id, " is not a valid input.") - stop( - paste0("TADA_CrosswalkATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier.") - ) + stop(paste0( + "TADA_CrosswalkATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier." + )) } if (!org_id %in% org.ref & !is.null(org_id)) { - print.org <- paste0(org_id, " is not a valid input.") - stop( - paste0("TADA_CrosswalkATTAINSWaterTypes: org_type must be a single non-NA logical. ", - print.org) - ) + stop(paste0( + "TADA_CrosswalkATTAINSWaterTypes: org_type must be a single non-NA logical. ", + print.org + )) } # need better check for org_only From d9112c50f28c53add6516787c79929548de13a25 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 18:12:13 -0400 Subject: [PATCH 37/48] leverage TADA_CheckColumns --- R/ATTAINSCrosswalks.R | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index ceb0818fe..f1d0609cf 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4708,12 +4708,8 @@ TADA_ReviewATTAINSWaterTypes <- function( "ATTAINS.WaterType" ) - missing_cols <- setdiff(required_cols, names(.data)) - if (length(missing_cols) > 0) { - stop( - "TADA_ReviewATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName, and ATTAINS.WaterType." - ) - } + # check that all required columns are present in .data + TADA_CheckColumns(.data, required_cols) review_action <- match.arg(review_action) From 13734cbe8c43b5619a30ebf6148eaa29fcc28c2d Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Thu, 27 Aug 2026 18:30:21 -0400 Subject: [PATCH 38/48] update instead of review --- NAMESPACE | 1 + R/ATTAINSCrosswalks.R | 12 ++++----- man/TADA_ReviewATTAINSWaterTypes.Rd | 21 --------------- man/TADA_UpdateATTAINSWaterTypes.Rd | 36 +++++++++++++++++++++++++ tests/testthat/test-ATTAINSCrosswalks.R | 16 +++++------ 5 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 man/TADA_UpdateATTAINSWaterTypes.Rd diff --git a/NAMESPACE b/NAMESPACE index b7d43b682..e33cdc228 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -109,6 +109,7 @@ export(TADA_TribalOptions) export(TADA_TwoCharacteristicScatterplot) export(TADA_UniqueCharUnitSpeciation) export(TADA_UpdateATTAINSAUMLCrosswalk) +export(TADA_UpdateATTAINSWaterTypes) export(TADA_UsesForAnalysis) export(TADA_ViewATTAINS) export(TADA_ViewColorPalette) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index f1d0609cf..d51b7dbcc 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4672,7 +4672,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( } -#' Review ATTAINS Water Types +#' Update ATTAINS Water Types #' #' Validates ATTAINS.WaterType against allowable ATTAINS domain values. #' Can either flag invalid values or update them using the crosswalk. @@ -4696,9 +4696,9 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") #' ) #' -#' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") +#' review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") #' } -TADA_ReviewATTAINSWaterTypes <- function( +TADA_UpdateATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { @@ -5199,7 +5199,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( } -#' Review ATTAINS Water Types +#' Update ATTAINS Water Types #' #' Validates ATTAINS.WaterType against allowable ATTAINS domain values. #' Can either flag invalid values or update them using the crosswalk. @@ -5223,9 +5223,9 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") #' ) #' -#' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") +#' review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") #' } -TADA_ReviewATTAINSWaterTypes <- function( +TADA_UpdateATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { diff --git a/man/TADA_ReviewATTAINSWaterTypes.Rd b/man/TADA_ReviewATTAINSWaterTypes.Rd index 95b20a6f5..4385faa24 100644 --- a/man/TADA_ReviewATTAINSWaterTypes.Rd +++ b/man/TADA_ReviewATTAINSWaterTypes.Rd @@ -4,8 +4,6 @@ \alias{TADA_ReviewATTAINSWaterTypes} \title{Review ATTAINS Water Types} \usage{ -TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) - TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) } \arguments{ @@ -14,18 +12,11 @@ TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) \item{review_action}{Character string. One of "flag" or "update".} } \value{ -A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. -If \code{review_action = "update"}, invalid values may also be replaced if an -ATTAINS water type match is available. - A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. If \code{review_action = "update"}, invalid values may also be replaced if an ATTAINS water type match is available. } \description{ -Validates ATTAINS.WaterType against allowable ATTAINS domain values. -Can either flag invalid values or update them using the crosswalk. - Validates ATTAINS.WaterType against allowable ATTAINS domain values. Can either flag invalid values or update them using the crosswalk. } @@ -40,18 +31,6 @@ TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") ) -review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") -} - -\dontrun{ - -# example of updating invalid ATTAINS water types -example.df <- tibble::tibble( -TADA.MonitoringLocationIdentifier = c("id1", "id2"), -TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), -ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") -) - review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") } } diff --git a/man/TADA_UpdateATTAINSWaterTypes.Rd b/man/TADA_UpdateATTAINSWaterTypes.Rd new file mode 100644 index 000000000..69c375c02 --- /dev/null +++ b/man/TADA_UpdateATTAINSWaterTypes.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ATTAINSCrosswalks.R +\name{TADA_UpdateATTAINSWaterTypes} +\alias{TADA_UpdateATTAINSWaterTypes} +\title{Update ATTAINS Water Types} +\usage{ +TADA_UpdateATTAINSWaterTypes(.data, review_action = c("flag", "update")) +} +\arguments{ +\item{.data}{A TADA data frame.} + +\item{review_action}{Character string. One of "flag" or "update".} +} +\value{ +A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. +If \code{review_action = "update"}, invalid values may also be replaced if an +ATTAINS water type match is available. +} +\description{ +Validates ATTAINS.WaterType against allowable ATTAINS domain values. +Can either flag invalid values or update them using the crosswalk. +} +\examples{ + +\dontrun{ + +# example of updating invalid ATTAINS water types +example.df <- tibble::tibble( +TADA.MonitoringLocationIdentifier = c("id1", "id2"), +TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), +ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") +) + +review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") +} +} diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 0076db2e1..4a65540c4 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -582,19 +582,19 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors on invalid org_id", # Test TADA_ReviewATTAINSWaterTypes -testthat::test_that("TADA_ReviewATTAINSWaterTypes errors when required columns are missing", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes errors when required columns are missing", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "RIVER" ) testthat::expect_error( - TADA_ReviewATTAINSWaterTypes(df), + TADA_UpdateATTAINSWaterTypes(df), "must contain TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName, and ATTAINS.WaterType" ) }) -testthat::test_that("TADA_ReviewATTAINSWaterTypes creates a flag column for invalid values", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes creates a flag column for invalid values", { skip_if_not_installed("rExpertQuery") df <- tibble::tibble( @@ -603,7 +603,7 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes creates a flag column for inva ATTAINS.WaterType = "INVALID WATER TYPE" ) - out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "flag") + out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "flag") testthat::expect_true("TADA.ATTAINSWaterType.Flag" %in% names(out)) testthat::expect_true(any(grepl( @@ -612,7 +612,7 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes creates a flag column for inva ))) }) -testthat::test_that("TADA_ReviewATTAINSWaterTypes leaves valid values flagged as valid", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes leaves valid values flagged as valid", { skip_if_not_installed("rExpertQuery") # Use values that are very likely valid in ATTAINS, but if your environment @@ -623,7 +623,7 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes leaves valid values flagged as ATTAINS.WaterType = "STREAM" ) - out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "flag") + out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "flag") testthat::expect_true("TADA.ATTAINSWaterType.Flag" %in% names(out)) testthat::expect_true( @@ -632,7 +632,7 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes leaves valid values flagged as ) }) -testthat::test_that("TADA_ReviewATTAINSWaterTypes updates invalid values when review_action = 'update'", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes updates invalid values when review_action = 'update'", { skip_if_not_installed("rExpertQuery") df <- tibble::tibble( @@ -641,7 +641,7 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes updates invalid values when re ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") ) - out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") + out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") testthat::expect_true(all( out$ATTAINS.WaterType %in% c("STREAM/CREEK/RIVER", "LAKE") From 6d9947535509fe1f6cdb198216432926821cb7a3 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 28 Aug 2026 08:58:38 -0400 Subject: [PATCH 39/48] changed TADA_CrosswalkATTAINSWaterType to TADA_UpdateATTAINSWaterType --- NAMESPACE | 2 +- R/ATTAINSCrosswalks.R | 36 ++++++------- man/TADA_CreatePointAUs.Rd | 4 +- ...ypes.Rd => TADA_UpdateATTAINSWaterType.Rd} | 12 ++--- tests/testthat/test-ATTAINSCrosswalks.R | 54 +++++++++---------- 5 files changed, 54 insertions(+), 54 deletions(-) rename man/{TADA_CrosswalkATTAINSWaterTypes.Rd => TADA_UpdateATTAINSWaterType.Rd} (82%) diff --git a/NAMESPACE b/NAMESPACE index e33cdc228..8c7d2fb6b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -27,7 +27,6 @@ export(TADA_CreatePairRef) export(TADA_CreatePointAUGeometry) export(TADA_CreatePointAUs) export(TADA_CreateUnitRef) -export(TADA_CrosswalkATTAINSWaterTypes) export(TADA_DataRetrieval) export(TADA_DayOfYearPlot) export(TADA_DefineCriteriaMethodology) @@ -109,6 +108,7 @@ export(TADA_TribalOptions) export(TADA_TwoCharacteristicScatterplot) export(TADA_UniqueCharUnitSpeciation) export(TADA_UpdateATTAINSAUMLCrosswalk) +export(TADA_UpdateATTAINSWaterType) export(TADA_UpdateATTAINSWaterTypes) export(TADA_UsesForAnalysis) export(TADA_ViewATTAINS) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 23d18a14a..d020aa659 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4539,9 +4539,9 @@ TADA_MLSummary <- function( #' # example for MT data #' testdat <- Data_MT_MissoulaCounty #' -#' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +#' crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") #' } -TADA_CrosswalkATTAINSWaterTypes <- function( +TADA_UpdateATTAINSWaterType <- function( .data, org_id = NULL, org_only = FALSE, @@ -4555,7 +4555,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( missing_cols <- setdiff(required_cols, names(.data)) if (length(missing_cols) > 0) { stop( - "TADA_CrosswalkATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) } @@ -4565,7 +4565,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( print.org <- paste0(org_id, " is not a valid input.") stop(paste0( - "TADA_CrosswalkATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier." + "TADA_UpdateATTAINSWaterType: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier." )) } @@ -4573,7 +4573,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( print.org <- paste0(org_id, " is not a valid input.") stop(paste0( - "TADA_CrosswalkATTAINSWaterTypes: org_type must be a single non-NA logical. ", + "TADA_UpdateATTAINSWaterType: org_type must be a single non-NA logical. ", print.org )) } @@ -4822,7 +4822,7 @@ TADA_UpdateATTAINSWaterTypes <- function( #' the point or multipoint geometry and its corresponding assessment unit identifier. #' #' If `ATTAINS.WaterType` is missing or contains any blank values, the function -#' attempts to populate it by calling `TADA_CrosswalkATTAINSWaterTypes()` +#' attempts to populate it by calling `TADA_UpdateATTAINSWaterType()` #' internally with `overwrite_existing = FALSE` and `validation = "none"`. #' #' @param .data A data frame containing, at minimum: @@ -4867,7 +4867,7 @@ TADA_UpdateATTAINSWaterTypes <- function( #' `TADA.MonitoringLocationIdentifier`. #' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. #' -#' @seealso [TADA_CrosswalkATTAINSWaterTypes()], [TADA_CreatePointAUGeometry()] +#' @seealso [TADA_UpdateATTAINSWaterType()], [TADA_CreatePointAUGeometry()] #' #' @export TADA_CreatePointAUs <- function( @@ -4916,7 +4916,7 @@ TADA_CreatePointAUs <- function( ) } - .data <- TADA_CrosswalkATTAINSWaterTypes(.data, replace_all = FALSE) + .data <- TADA_UpdateATTAINSWaterType(.data, replace_all = FALSE) } if (nrow(.data) == 0) { @@ -4955,7 +4955,7 @@ TADA_CreatePointAUs <- function( #' Internal helper to construct the crosswalk used to assign ATTAINS.WaterType #' from TADA.MonitoringLocationTypeName. #' -#' @inheritParams TADA_CrosswalkATTAINSWaterTypes +#' @inheritParams TADA_UpdateATTAINSWaterType #' @param org_only Logical. If TRUE, only organization-specific ATTAINS water #' types are used. If FALSE, unmatched types fall back to the TADA default #' crosswalk. @@ -5091,9 +5091,9 @@ build_attains_water_type_crosswalk <- function( #' # example for MT data #' testdat <- Data_MT_MissoulaCounty #' -#' crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +#' crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") #' } -TADA_CrosswalkATTAINSWaterTypes <- function( +TADA_UpdateATTAINSWaterType <- function( .data, org_id = NULL, org_only = FALSE, @@ -5107,7 +5107,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( missing_cols <- setdiff(required_cols, names(.data)) if (length(missing_cols) > 0) { stop( - "TADA_CrosswalkATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) } @@ -5116,13 +5116,13 @@ TADA_CrosswalkATTAINSWaterTypes <- function( (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) ) { stop( - "TADA_CrosswalkATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." + "TADA_UpdateATTAINSWaterType: org_id must be NULL or a single non-NA character string." ) } if (!is.logical(org_only) || length(org_only) != 1 || is.na(org_only)) { stop( - "TADA_CrosswalkATTAINSWaterTypes: org_only must be a single non-NA logical." + "TADA_UpdateATTAINSWaterType: org_only must be a single non-NA logical." ) } @@ -5130,7 +5130,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( !is.logical(replace_all) || length(replace_all) != 1 || is.na(replace_all) ) { stop( - "TADA_CrosswalkATTAINSWaterTypes: replace_all must be a single non-NA logical." + "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." ) } @@ -5195,7 +5195,7 @@ TADA_CrosswalkATTAINSWaterTypes <- function( } -#' Update ATTAINS Water Types +#' Review ATTAINS Water Types #' #' Validates ATTAINS.WaterType against allowable ATTAINS domain values. #' Can either flag invalid values or update them using the crosswalk. @@ -5219,9 +5219,9 @@ TADA_CrosswalkATTAINSWaterTypes <- function( #' ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") #' ) #' -#' review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") +#' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") #' } -TADA_UpdateATTAINSWaterTypes <- function( +TADA_ReviewATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { diff --git a/man/TADA_CreatePointAUs.Rd b/man/TADA_CreatePointAUs.Rd index f2247d990..c29be9928 100644 --- a/man/TADA_CreatePointAUs.Rd +++ b/man/TADA_CreatePointAUs.Rd @@ -70,7 +70,7 @@ the point or multipoint geometry and its corresponding assessment unit identifie } \details{ If \code{ATTAINS.WaterType} is missing or contains any blank values, the function -attempts to populate it by calling \code{TADA_CrosswalkATTAINSWaterTypes()} +attempts to populate it by calling \code{TADA_UpdateATTAINSWaterType()} internally with \code{overwrite_existing = FALSE} and \code{validation = "none"}. \itemize{ \item Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values are replaced @@ -83,5 +83,5 @@ created AUIDs. } } \seealso{ -\code{\link[=TADA_CrosswalkATTAINSWaterTypes]{TADA_CrosswalkATTAINSWaterTypes()}}, \code{\link[=TADA_CreatePointAUGeometry]{TADA_CreatePointAUGeometry()}} +\code{\link[=TADA_UpdateATTAINSWaterType]{TADA_UpdateATTAINSWaterType()}}, \code{\link[=TADA_CreatePointAUGeometry]{TADA_CreatePointAUGeometry()}} } diff --git a/man/TADA_CrosswalkATTAINSWaterTypes.Rd b/man/TADA_UpdateATTAINSWaterType.Rd similarity index 82% rename from man/TADA_CrosswalkATTAINSWaterTypes.Rd rename to man/TADA_UpdateATTAINSWaterType.Rd index fa4be28b1..18678bb59 100644 --- a/man/TADA_CrosswalkATTAINSWaterTypes.Rd +++ b/man/TADA_UpdateATTAINSWaterType.Rd @@ -1,17 +1,17 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ATTAINSCrosswalks.R -\name{TADA_CrosswalkATTAINSWaterTypes} -\alias{TADA_CrosswalkATTAINSWaterTypes} +\name{TADA_UpdateATTAINSWaterType} +\alias{TADA_UpdateATTAINSWaterType} \title{Crosswalk WQP Monitoring Location Type to ATTAINS Water Type} \usage{ -TADA_CrosswalkATTAINSWaterTypes( +TADA_UpdateATTAINSWaterType( .data, org_id = NULL, org_only = FALSE, replace_all = FALSE ) -TADA_CrosswalkATTAINSWaterTypes( +TADA_UpdateATTAINSWaterType( .data, org_id = NULL, org_only = FALSE, @@ -49,7 +49,7 @@ By default, only missing ATTAINS.WaterType values are populated. # example for MT data testdat <- Data_MT_MissoulaCounty -crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") } \dontrun{ @@ -57,6 +57,6 @@ crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") # example for MT data testdat <- Data_MT_MissoulaCounty -crosswalk <- TADA_CrosswalkATTAINSWaterTypes(testat, org_Id = "MTDEQ") +crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") } } diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index 4a65540c4..f8290b060 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -466,16 +466,16 @@ testthat::test_that("Excel file generation works with blank inputs in TADA_MLSum on.exit(if (file.exists(downloads_path)) file.remove(downloads_path)) }) -# test TADA_CrosswalkATTAINSWaterTypes -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors when required columns are missing", { +# test TADA_UpdateATTAINSWaterType +testthat::test_that("TADA_UpdateATTAINSWaterType errors when required columns are missing", { df_missing_id <- data.frame( TADA.MonitoringLocationTypeName = c("Stream", "Lake"), stringsAsFactors = FALSE ) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df_missing_id), - "TADA_CrosswalkATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + TADA_UpdateATTAINSWaterType(df_missing_id), + "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) df_missing_type <- data.frame( @@ -484,12 +484,12 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors when required column ) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df_missing_type), - "TADA_CrosswalkATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + TADA_UpdateATTAINSWaterType(df_missing_type), + "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors when overwrite_existing is not a single logical", { +testthat::test_that("TADA_UpdateATTAINSWaterType errors when overwrite_existing is not a single logical", { df <- data.frame( TADA.MonitoringLocationIdentifier = "A", TADA.MonitoringLocationTypeName = "Stream", @@ -497,58 +497,58 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors when overwrite_exist ) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df, replace_all = "yes"), - "TADA_CrosswalkATTAINSWaterTypes: replace_all must be a single non-NA logical." + TADA_UpdateATTAINSWaterType(df, replace_all = "yes"), + "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." ) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df, replace_all = c(TRUE, FALSE)), - "TADA_CrosswalkATTAINSWaterTypes: replace_all must be a single non-NA logical." + TADA_UpdateATTAINSWaterType(df, replace_all = c(TRUE, FALSE)), + "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." ) }) -# Test TADA_CrosswalkATTAINSWaterTypes -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes fills missing ATTAINS.WaterType", { +# Test TADA_UpdateATTAINSWaterType +testthat::test_that("TADA_UpdateATTAINSWaterType fills missing ATTAINS.WaterType", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c(NA, "") ) - out <- TADA_CrosswalkATTAINSWaterTypes(df) + out <- TADA_UpdateATTAINSWaterType(df) testthat::expect_s3_class(out, "data.frame") testthat::expect_true("ATTAINS.WaterType" %in% names(out)) testthat::expect_false(any(is.na(out$ATTAINS.WaterType))) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes does not overwrite existing values when replace_all = FALSE", { +testthat::test_that("TADA_UpdateATTAINSWaterType does not overwrite existing values when replace_all = FALSE", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("CUSTOM TYPE", NA) ) - out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = FALSE) + out <- TADA_UpdateATTAINSWaterType(df, replace_all = FALSE) testthat::expect_equal(out$ATTAINS.WaterType[1], "CUSTOM TYPE") }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes overwrites all values when replace_all = TRUE", { +testthat::test_that("TADA_UpdateATTAINSWaterType overwrites all values when replace_all = TRUE", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("CUSTOM TYPE", "ANOTHER TYPE") ) - out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = TRUE) + out <- TADA_UpdateATTAINSWaterType(df, replace_all = TRUE) testthat::expect_false(any( out$ATTAINS.WaterType %in% c("CUSTOM TYPE", "ANOTHER TYPE") )) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes creates ATTAINS.WaterType when missing", { +testthat::test_that("TADA_UpdateATTAINSWaterType creates ATTAINS.WaterType when missing", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER", "LAKE") @@ -582,19 +582,19 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors on invalid org_id", # Test TADA_ReviewATTAINSWaterTypes -testthat::test_that("TADA_UpdateATTAINSWaterTypes errors when required columns are missing", { +testthat::test_that("TADA_ReviewATTAINSWaterTypes errors when required columns are missing", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "RIVER" ) testthat::expect_error( - TADA_UpdateATTAINSWaterTypes(df), + TADA_ReviewATTAINSWaterTypes(df), "must contain TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName, and ATTAINS.WaterType" ) }) -testthat::test_that("TADA_UpdateATTAINSWaterTypes creates a flag column for invalid values", { +testthat::test_that("TADA_ReviewATTAINSWaterTypes creates a flag column for invalid values", { skip_if_not_installed("rExpertQuery") df <- tibble::tibble( @@ -603,7 +603,7 @@ testthat::test_that("TADA_UpdateATTAINSWaterTypes creates a flag column for inva ATTAINS.WaterType = "INVALID WATER TYPE" ) - out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "flag") + out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "flag") testthat::expect_true("TADA.ATTAINSWaterType.Flag" %in% names(out)) testthat::expect_true(any(grepl( @@ -612,7 +612,7 @@ testthat::test_that("TADA_UpdateATTAINSWaterTypes creates a flag column for inva ))) }) -testthat::test_that("TADA_UpdateATTAINSWaterTypes leaves valid values flagged as valid", { +testthat::test_that("TADA_ReviewATTAINSWaterTypes leaves valid values flagged as valid", { skip_if_not_installed("rExpertQuery") # Use values that are very likely valid in ATTAINS, but if your environment @@ -623,7 +623,7 @@ testthat::test_that("TADA_UpdateATTAINSWaterTypes leaves valid values flagged as ATTAINS.WaterType = "STREAM" ) - out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "flag") + out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "flag") testthat::expect_true("TADA.ATTAINSWaterType.Flag" %in% names(out)) testthat::expect_true( @@ -632,7 +632,7 @@ testthat::test_that("TADA_UpdateATTAINSWaterTypes leaves valid values flagged as ) }) -testthat::test_that("TADA_UpdateATTAINSWaterTypes updates invalid values when review_action = 'update'", { +testthat::test_that("TADA_ReviewATTAINSWaterTypes updates invalid values when review_action = 'update'", { skip_if_not_installed("rExpertQuery") df <- tibble::tibble( @@ -641,7 +641,7 @@ testthat::test_that("TADA_UpdateATTAINSWaterTypes updates invalid values when re ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") ) - out <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") + out <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") testthat::expect_true(all( out$ATTAINS.WaterType %in% c("STREAM/CREEK/RIVER", "LAKE") From 12d446cfa461ca9a2e66306f1f556b3a4f42aa8a Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 28 Aug 2026 09:18:19 -0400 Subject: [PATCH 40/48] documentation update --- NAMESPACE | 1 - R/ATTAINSCrosswalks.R | 36 ++++++++--------- man/TADA_CreatePointAUs.Rd | 4 +- man/TADA_ReviewATTAINSWaterTypes.Rd | 21 ++++++++++ man/TADA_UpdateATTAINSWaterType.Rd | 62 ----------------------------- man/TADA_UpdateATTAINSWaterTypes.Rd | 56 +++++++++++++++++++------- 6 files changed, 82 insertions(+), 98 deletions(-) delete mode 100644 man/TADA_UpdateATTAINSWaterType.Rd diff --git a/NAMESPACE b/NAMESPACE index 8c7d2fb6b..5ff4366ea 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -108,7 +108,6 @@ export(TADA_TribalOptions) export(TADA_TwoCharacteristicScatterplot) export(TADA_UniqueCharUnitSpeciation) export(TADA_UpdateATTAINSAUMLCrosswalk) -export(TADA_UpdateATTAINSWaterType) export(TADA_UpdateATTAINSWaterTypes) export(TADA_UsesForAnalysis) export(TADA_ViewATTAINS) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index d020aa659..9f4a880b3 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4539,9 +4539,9 @@ TADA_MLSummary <- function( #' # example for MT data #' testdat <- Data_MT_MissoulaCounty #' -#' crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") +#' crosswalk <- TADA_UpdateATTAINSWaterTypes(testat, org_Id = "MTDEQ") #' } -TADA_UpdateATTAINSWaterType <- function( +TADA_UpdateATTAINSWaterTypes <- function( .data, org_id = NULL, org_only = FALSE, @@ -4555,7 +4555,7 @@ TADA_UpdateATTAINSWaterType <- function( missing_cols <- setdiff(required_cols, names(.data)) if (length(missing_cols) > 0) { stop( - "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + "TADA_UpdateATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) } @@ -4565,7 +4565,7 @@ TADA_UpdateATTAINSWaterType <- function( print.org <- paste0(org_id, " is not a valid input.") stop(paste0( - "TADA_UpdateATTAINSWaterType: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier." + "TADA_UpdateATTAINSWaterTypes: org_id must be either NULL or a single non-NA character string matching an ATTAINSOrganizationIdentifier." )) } @@ -4573,7 +4573,7 @@ TADA_UpdateATTAINSWaterType <- function( print.org <- paste0(org_id, " is not a valid input.") stop(paste0( - "TADA_UpdateATTAINSWaterType: org_type must be a single non-NA logical. ", + "TADA_UpdateATTAINSWaterTypes: org_type must be a single non-NA logical. ", print.org )) } @@ -4668,7 +4668,7 @@ TADA_UpdateATTAINSWaterType <- function( } -#' Update ATTAINS Water Types +#' Review ATTAINS Water Types #' #' Validates ATTAINS.WaterType against allowable ATTAINS domain values. #' Can either flag invalid values or update them using the crosswalk. @@ -4692,9 +4692,9 @@ TADA_UpdateATTAINSWaterType <- function( #' ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") #' ) #' -#' review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") +#' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") #' } -TADA_UpdateATTAINSWaterTypes <- function( +TADA_ReviewATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { @@ -4822,7 +4822,7 @@ TADA_UpdateATTAINSWaterTypes <- function( #' the point or multipoint geometry and its corresponding assessment unit identifier. #' #' If `ATTAINS.WaterType` is missing or contains any blank values, the function -#' attempts to populate it by calling `TADA_UpdateATTAINSWaterType()` +#' attempts to populate it by calling `TADA_UpdateATTAINSWaterTypes()` #' internally with `overwrite_existing = FALSE` and `validation = "none"`. #' #' @param .data A data frame containing, at minimum: @@ -4867,7 +4867,7 @@ TADA_UpdateATTAINSWaterTypes <- function( #' `TADA.MonitoringLocationIdentifier`. #' - `ATTAINS.WaterType` is not overwritten unless it is missing or blank. #' -#' @seealso [TADA_UpdateATTAINSWaterType()], [TADA_CreatePointAUGeometry()] +#' @seealso [TADA_UpdateATTAINSWaterTypes()], [TADA_CreatePointAUGeometry()] #' #' @export TADA_CreatePointAUs <- function( @@ -4916,7 +4916,7 @@ TADA_CreatePointAUs <- function( ) } - .data <- TADA_UpdateATTAINSWaterType(.data, replace_all = FALSE) + .data <- TADA_UpdateATTAINSWaterTypes(.data, replace_all = FALSE) } if (nrow(.data) == 0) { @@ -4955,7 +4955,7 @@ TADA_CreatePointAUs <- function( #' Internal helper to construct the crosswalk used to assign ATTAINS.WaterType #' from TADA.MonitoringLocationTypeName. #' -#' @inheritParams TADA_UpdateATTAINSWaterType +#' @inheritParams TADA_UpdateATTAINSWaterTypes #' @param org_only Logical. If TRUE, only organization-specific ATTAINS water #' types are used. If FALSE, unmatched types fall back to the TADA default #' crosswalk. @@ -5091,9 +5091,9 @@ build_attains_water_type_crosswalk <- function( #' # example for MT data #' testdat <- Data_MT_MissoulaCounty #' -#' crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") +#' crosswalk <- TADA_UpdateATTAINSWaterTypes(testat, org_Id = "MTDEQ") #' } -TADA_UpdateATTAINSWaterType <- function( +TADA_UpdateATTAINSWaterTypes <- function( .data, org_id = NULL, org_only = FALSE, @@ -5107,7 +5107,7 @@ TADA_UpdateATTAINSWaterType <- function( missing_cols <- setdiff(required_cols, names(.data)) if (length(missing_cols) > 0) { stop( - "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + "TADA_UpdateATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) } @@ -5116,13 +5116,13 @@ TADA_UpdateATTAINSWaterType <- function( (!is.character(org_id) || length(org_id) != 1 || is.na(org_id)) ) { stop( - "TADA_UpdateATTAINSWaterType: org_id must be NULL or a single non-NA character string." + "TADA_UpdateATTAINSWaterTypes: org_id must be NULL or a single non-NA character string." ) } if (!is.logical(org_only) || length(org_only) != 1 || is.na(org_only)) { stop( - "TADA_UpdateATTAINSWaterType: org_only must be a single non-NA logical." + "TADA_UpdateATTAINSWaterTypes: org_only must be a single non-NA logical." ) } @@ -5130,7 +5130,7 @@ TADA_UpdateATTAINSWaterType <- function( !is.logical(replace_all) || length(replace_all) != 1 || is.na(replace_all) ) { stop( - "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." + "TADA_UpdateATTAINSWaterTypes: replace_all must be a single non-NA logical." ) } diff --git a/man/TADA_CreatePointAUs.Rd b/man/TADA_CreatePointAUs.Rd index c29be9928..a9bfef0a7 100644 --- a/man/TADA_CreatePointAUs.Rd +++ b/man/TADA_CreatePointAUs.Rd @@ -70,7 +70,7 @@ the point or multipoint geometry and its corresponding assessment unit identifie } \details{ If \code{ATTAINS.WaterType} is missing or contains any blank values, the function -attempts to populate it by calling \code{TADA_UpdateATTAINSWaterType()} +attempts to populate it by calling \code{TADA_UpdateATTAINSWaterTypes()} internally with \code{overwrite_existing = FALSE} and \code{validation = "none"}. \itemize{ \item Missing or blank \code{ATTAINS.AssessmentUnitIdentifier} values are replaced @@ -83,5 +83,5 @@ created AUIDs. } } \seealso{ -\code{\link[=TADA_UpdateATTAINSWaterType]{TADA_UpdateATTAINSWaterType()}}, \code{\link[=TADA_CreatePointAUGeometry]{TADA_CreatePointAUGeometry()}} +\code{\link[=TADA_UpdateATTAINSWaterTypes]{TADA_UpdateATTAINSWaterTypes()}}, \code{\link[=TADA_CreatePointAUGeometry]{TADA_CreatePointAUGeometry()}} } diff --git a/man/TADA_ReviewATTAINSWaterTypes.Rd b/man/TADA_ReviewATTAINSWaterTypes.Rd index 4385faa24..95b20a6f5 100644 --- a/man/TADA_ReviewATTAINSWaterTypes.Rd +++ b/man/TADA_ReviewATTAINSWaterTypes.Rd @@ -4,6 +4,8 @@ \alias{TADA_ReviewATTAINSWaterTypes} \title{Review ATTAINS Water Types} \usage{ +TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) + TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) } \arguments{ @@ -12,11 +14,18 @@ TADA_ReviewATTAINSWaterTypes(.data, review_action = c("flag", "update")) \item{review_action}{Character string. One of "flag" or "update".} } \value{ +A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. +If \code{review_action = "update"}, invalid values may also be replaced if an +ATTAINS water type match is available. + A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. If \code{review_action = "update"}, invalid values may also be replaced if an ATTAINS water type match is available. } \description{ +Validates ATTAINS.WaterType against allowable ATTAINS domain values. +Can either flag invalid values or update them using the crosswalk. + Validates ATTAINS.WaterType against allowable ATTAINS domain values. Can either flag invalid values or update them using the crosswalk. } @@ -31,6 +40,18 @@ TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") ) +review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") +} + +\dontrun{ + +# example of updating invalid ATTAINS water types +example.df <- tibble::tibble( +TADA.MonitoringLocationIdentifier = c("id1", "id2"), +TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), +ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") +) + review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") } } diff --git a/man/TADA_UpdateATTAINSWaterType.Rd b/man/TADA_UpdateATTAINSWaterType.Rd deleted file mode 100644 index 18678bb59..000000000 --- a/man/TADA_UpdateATTAINSWaterType.Rd +++ /dev/null @@ -1,62 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ATTAINSCrosswalks.R -\name{TADA_UpdateATTAINSWaterType} -\alias{TADA_UpdateATTAINSWaterType} -\title{Crosswalk WQP Monitoring Location Type to ATTAINS Water Type} -\usage{ -TADA_UpdateATTAINSWaterType( - .data, - org_id = NULL, - org_only = FALSE, - replace_all = FALSE -) - -TADA_UpdateATTAINSWaterType( - .data, - org_id = NULL, - org_only = FALSE, - replace_all = FALSE -) -} -\arguments{ -\item{.data}{A TADA data frame.} - -\item{org_id}{Character string. Optional organization ID used to prioritize -organization-specific ATTAINS values.} - -\item{org_only}{Logical. If TRUE, only org-specific ATTAINS values are used. -If FALSE, unmatched types fall back to the TADA default crosswalk.} - -\item{replace_all}{Logical. If TRUE, replace all ATTAINS.WaterType values. -If FALSE, only fill missing values. Default is FALSE.} -} -\value{ -A TADA data frame with ATTAINS.WaterType populated. - -A TADA data frame with ATTAINS.WaterType populated. -} -\description{ -Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. -By default, only missing ATTAINS.WaterType values are populated. - -Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. -By default, only missing ATTAINS.WaterType values are populated. -} -\examples{ - -\dontrun{ - -# example for MT data -testdat <- Data_MT_MissoulaCounty - -crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") -} - -\dontrun{ - -# example for MT data -testdat <- Data_MT_MissoulaCounty - -crosswalk <- TADA_UpdateATTAINSWaterType(testat, org_Id = "MTDEQ") -} -} diff --git a/man/TADA_UpdateATTAINSWaterTypes.Rd b/man/TADA_UpdateATTAINSWaterTypes.Rd index 69c375c02..63c656802 100644 --- a/man/TADA_UpdateATTAINSWaterTypes.Rd +++ b/man/TADA_UpdateATTAINSWaterTypes.Rd @@ -2,35 +2,61 @@ % Please edit documentation in R/ATTAINSCrosswalks.R \name{TADA_UpdateATTAINSWaterTypes} \alias{TADA_UpdateATTAINSWaterTypes} -\title{Update ATTAINS Water Types} +\title{Crosswalk WQP Monitoring Location Type to ATTAINS Water Type} \usage{ -TADA_UpdateATTAINSWaterTypes(.data, review_action = c("flag", "update")) +TADA_UpdateATTAINSWaterTypes( + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE +) + +TADA_UpdateATTAINSWaterTypes( + .data, + org_id = NULL, + org_only = FALSE, + replace_all = FALSE +) } \arguments{ \item{.data}{A TADA data frame.} -\item{review_action}{Character string. One of "flag" or "update".} +\item{org_id}{Character string. Optional organization ID used to prioritize +organization-specific ATTAINS values.} + +\item{org_only}{Logical. If TRUE, only org-specific ATTAINS values are used. +If FALSE, unmatched types fall back to the TADA default crosswalk.} + +\item{replace_all}{Logical. If TRUE, replace all ATTAINS.WaterType values. +If FALSE, only fill missing values. Default is FALSE.} } \value{ -A TADA data frame with \code{TADA.ATTAINSWaterType.Flag} added. -If \code{review_action = "update"}, invalid values may also be replaced if an -ATTAINS water type match is available. +A TADA data frame with ATTAINS.WaterType populated. + +A TADA data frame with ATTAINS.WaterType populated. } \description{ -Validates ATTAINS.WaterType against allowable ATTAINS domain values. -Can either flag invalid values or update them using the crosswalk. +Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. +By default, only missing ATTAINS.WaterType values are populated. + +Adds or updates ATTAINS.WaterType using TADA.MonitoringLocationTypeName. +By default, only missing ATTAINS.WaterType values are populated. } \examples{ \dontrun{ -# example of updating invalid ATTAINS water types -example.df <- tibble::tibble( -TADA.MonitoringLocationIdentifier = c("id1", "id2"), -TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), -ATTAINS.WaterType = c("INVALID WATER TYPE 1", "INVALID WATER TYPE 2") -) +# example for MT data +testdat <- Data_MT_MissoulaCounty + +crosswalk <- TADA_UpdateATTAINSWaterTypes(testat, org_Id = "MTDEQ") +} + +\dontrun{ + +# example for MT data +testdat <- Data_MT_MissoulaCounty -review.df <- TADA_UpdateATTAINSWaterTypes(df, review_action = "update") +crosswalk <- TADA_UpdateATTAINSWaterTypes(testat, org_Id = "MTDEQ") } } From 37469b8a402854e50f375a79022f0b811e85c288 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Fri, 28 Aug 2026 09:46:03 -0400 Subject: [PATCH 41/48] test updates --- R/ATTAINSCrosswalks.R | 1 - tests/testthat/test-ATTAINSCrosswalks.R | 56 ++++++++++++------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 9f4a880b3..fe25825f8 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4941,7 +4941,6 @@ TADA_CreatePointAUs <- function( .data = .data, target_crs = 4269, download_geo = download_geo, - return_geo = TRUE, auid_prefix = auid_prefix ) diff --git a/tests/testthat/test-ATTAINSCrosswalks.R b/tests/testthat/test-ATTAINSCrosswalks.R index f8290b060..f54437e00 100644 --- a/tests/testthat/test-ATTAINSCrosswalks.R +++ b/tests/testthat/test-ATTAINSCrosswalks.R @@ -467,15 +467,15 @@ testthat::test_that("Excel file generation works with blank inputs in TADA_MLSum }) # test TADA_UpdateATTAINSWaterType -testthat::test_that("TADA_UpdateATTAINSWaterType errors when required columns are missing", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes errors when required columns are missing", { df_missing_id <- data.frame( TADA.MonitoringLocationTypeName = c("Stream", "Lake"), stringsAsFactors = FALSE ) testthat::expect_error( - TADA_UpdateATTAINSWaterType(df_missing_id), - "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + TADA_UpdateATTAINSWaterTypes(df_missing_id), + "TADA_UpdateATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) df_missing_type <- data.frame( @@ -484,12 +484,12 @@ testthat::test_that("TADA_UpdateATTAINSWaterType errors when required columns ar ) testthat::expect_error( - TADA_UpdateATTAINSWaterType(df_missing_type), - "TADA_UpdateATTAINSWaterType: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." + TADA_UpdateATTAINSWaterTypes(df_missing_type), + "TADA_UpdateATTAINSWaterTypes: .data must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName." ) }) -testthat::test_that("TADA_UpdateATTAINSWaterType errors when overwrite_existing is not a single logical", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes errors when overwrite_existing is not a single logical", { df <- data.frame( TADA.MonitoringLocationIdentifier = "A", TADA.MonitoringLocationTypeName = "Stream", @@ -497,85 +497,85 @@ testthat::test_that("TADA_UpdateATTAINSWaterType errors when overwrite_existing ) testthat::expect_error( - TADA_UpdateATTAINSWaterType(df, replace_all = "yes"), - "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." + TADA_UpdateATTAINSWaterTypes(df, replace_all = "yes"), + "TADA_UpdateATTAINSWaterTypes: replace_all must be a single non-NA logical." ) testthat::expect_error( - TADA_UpdateATTAINSWaterType(df, replace_all = c(TRUE, FALSE)), - "TADA_UpdateATTAINSWaterType: replace_all must be a single non-NA logical." + TADA_UpdateATTAINSWaterTypes(df, replace_all = c(TRUE, FALSE)), + "TADA_UpdateATTAINSWaterTypes: replace_all must be a single non-NA logical." ) }) # Test TADA_UpdateATTAINSWaterType -testthat::test_that("TADA_UpdateATTAINSWaterType fills missing ATTAINS.WaterType", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes fills missing ATTAINS.WaterType", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c(NA, "") ) - out <- TADA_UpdateATTAINSWaterType(df) + out <- TADA_UpdateATTAINSWaterTypes(df) testthat::expect_s3_class(out, "data.frame") testthat::expect_true("ATTAINS.WaterType" %in% names(out)) testthat::expect_false(any(is.na(out$ATTAINS.WaterType))) }) -testthat::test_that("TADA_UpdateATTAINSWaterType does not overwrite existing values when replace_all = FALSE", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes does not overwrite existing values when replace_all = FALSE", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("CUSTOM TYPE", NA) ) - out <- TADA_UpdateATTAINSWaterType(df, replace_all = FALSE) + out <- TADA_UpdateATTAINSWaterTypes(df, replace_all = FALSE) testthat::expect_equal(out$ATTAINS.WaterType[1], "CUSTOM TYPE") }) -testthat::test_that("TADA_UpdateATTAINSWaterType overwrites all values when replace_all = TRUE", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes overwrites all values when replace_all = TRUE", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER/STREAM", "LAKE"), ATTAINS.WaterType = c("CUSTOM TYPE", "ANOTHER TYPE") ) - out <- TADA_UpdateATTAINSWaterType(df, replace_all = TRUE) + out <- TADA_UpdateATTAINSWaterTypes(df, replace_all = TRUE) testthat::expect_false(any( out$ATTAINS.WaterType %in% c("CUSTOM TYPE", "ANOTHER TYPE") )) }) -testthat::test_that("TADA_UpdateATTAINSWaterType creates ATTAINS.WaterType when missing", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes creates ATTAINS.WaterType when missing", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = c("id1", "id2"), TADA.MonitoringLocationTypeName = c("RIVER", "LAKE") ) - out <- TADA_CrosswalkATTAINSWaterTypes(df) + out <- TADA_UpdateATTAINSWaterTypes(df) testthat::expect_true("ATTAINS.WaterType" %in% names(out)) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors when required columns are missing", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes errors when required columns are missing", { df <- tibble::tibble(TADA.MonitoringLocationIdentifier = c("id1", "id2")) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df), + TADA_UpdateATTAINSWaterTypes(df), "must contain TADA.MonitoringLocationIdentifier and TADA.MonitoringLocationTypeName" ) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes errors on invalid org_id", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes errors on invalid org_id", { df <- tibble::tibble( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "RIVER" ) testthat::expect_error( - TADA_CrosswalkATTAINSWaterTypes(df, org_id = 1), + TADA_UpdateATTAINSWaterTypes(df, org_id = 1), "org_id must be NULL or a single non-NA character string" ) }) @@ -652,21 +652,21 @@ testthat::test_that("TADA_ReviewATTAINSWaterTypes updates invalid values when re )) }) -testthat::test_that("TADA_CrosswalkATTAINSWaterTypes duplicate monitoring location rows do not break output", { +testthat::test_that("TADA_UpdateWaterTypes: duplicate monitoring location rows do not break output", { df <- data.frame( TADA.MonitoringLocationIdentifier = c("id1", "id1"), TADA.MonitoringLocationTypeName = c("STREAM", "STREAM"), stringsAsFactors = FALSE ) - out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = TRUE) + out <- TADA_UpdateATTAINSWaterTypes(df, replace_all = TRUE) testthat::expect_equal(nrow(out), 2) testthat::expect_true(all(out$ATTAINS.WaterType == "STREAM")) }) -testthat::test_that("existing ATTAINS.OrganizationIdentifier is preserved", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes: existing ATTAINS.OrganizationIdentifier is preserved", { df <- data.frame( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "STREAM", @@ -685,12 +685,12 @@ testthat::test_that("existing ATTAINS.OrganizationIdentifier is preserved", { .package = "utils" ) - out <- TADA_CrosswalkATTAINSWaterTypes(df) + out <- TADA_UpdateATTAINSWaterTypes(df) testthat::expect_equal(out$ATTAINS.OrganizationIdentifier, "ORG123") }) -testthat::test_that("TADA_CrosswalkATTAINSWaterType replace_all = FALSE preserves nonblank existing ATTAINS.WaterType values", { +testthat::test_that("TADA_UpdateATTAINSWaterTypes: replace_all = FALSE preserves nonblank existing ATTAINS.WaterType values", { df <- data.frame( TADA.MonitoringLocationIdentifier = "id1", TADA.MonitoringLocationTypeName = "STREAM", @@ -709,7 +709,7 @@ testthat::test_that("TADA_CrosswalkATTAINSWaterType replace_all = FALSE preserve .package = "utils" ) - out <- TADA_CrosswalkATTAINSWaterTypes(df, replace_all = FALSE) + out <- TADA_UpdateATTAINSWaterTypes(df, replace_all = FALSE) expect_equal(out$ATTAINS.WaterType, "KeepMe") }) From 8a8084398bf244c97df0782e3cf3d72765325d26 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 31 Aug 2026 14:06:27 -0400 Subject: [PATCH 42/48] test updates to reflect removal of return_geo param --- tests/testthat/test-GeospatialFunctions.R | 26 +++++------------------ 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/tests/testthat/test-GeospatialFunctions.R b/tests/testthat/test-GeospatialFunctions.R index 61f6f300c..879d73f0b 100644 --- a/tests/testthat/test-GeospatialFunctions.R +++ b/tests/testthat/test-GeospatialFunctions.R @@ -638,7 +638,7 @@ testthat::test_that("TADA_CreateAUPointGeometry returns sf geometry for valid in stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + result <- TADA_CreatePointAUGeometry(df) testthat::expect_s3_class(result, "sf") testthat::expect_true("geometry" %in% names(result)) @@ -655,27 +655,12 @@ testthat::test_that("TADA_CreatePointAUGeometry creates POINT for one location a stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + result <- TADA_CreatePointAUGeometry(df) geom_types <- sf::st_geometry_type(result) testthat::expect_true(any(geom_types %in% c("POINT", "MULTIPOINT"))) }) -testthat::test_that("TADA_CreatePointAUGeometry returns invisible NULL when return_geo is FALSE", { - df <- data.frame( - ATTAINS.AssessmentUnitIdentifier = "AU1", - TADA.MonitoringLocationIdentifier = "ML1", - TADA.LongitudeMeasure = -90, - TADA.LatitudeMeasure = 40, - HorizontalCoordinateReferenceSystemDatumName = "NAD83", - stringsAsFactors = FALSE - ) - - result <- TADA_CreatePointAUGeometry(df, return_geo = FALSE) - - testthat::expect_null(result) -}) - testthat::test_that("TADA_CreatePointAUGeometry drops rows with missing coordinates", { df <- data.frame( ATTAINS.AssessmentUnitIdentifier = c("AU1", "AU2"), @@ -686,7 +671,7 @@ testthat::test_that("TADA_CreatePointAUGeometry drops rows with missing coordina stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + result <- TADA_CreatePointAUGeometry(df) testthat::expect_equal(nrow(result), 1) }) @@ -702,8 +687,7 @@ testthat::test_that("TADA_CreatePointAUGeometry accepts auid_prefix", { result <- TADA_CreatePointAUGeometry( df, - auid_prefix = "TEST", - return_geo = TRUE + auid_prefix = "TEST" ) testthat::expect_s3_class(result, "sf") @@ -718,7 +702,7 @@ testthat::test_that("TADA_CreatePointAUGeometry works with only TADA.MonitoringL stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry(df, return_geo = TRUE) + result <- TADA_CreatePointAUGeometry(df) testthat::expect_s3_class(result, "sf") }) From 4366e479e938596181e5537bf5330329c70715d4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 18:07:11 +0000 Subject: [PATCH 43/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/testthat/test-GeospatialFunctions.R | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/testthat/test-GeospatialFunctions.R b/tests/testthat/test-GeospatialFunctions.R index 879d73f0b..463c64bb5 100644 --- a/tests/testthat/test-GeospatialFunctions.R +++ b/tests/testthat/test-GeospatialFunctions.R @@ -685,10 +685,7 @@ testthat::test_that("TADA_CreatePointAUGeometry accepts auid_prefix", { stringsAsFactors = FALSE ) - result <- TADA_CreatePointAUGeometry( - df, - auid_prefix = "TEST" - ) + result <- TADA_CreatePointAUGeometry(df, auid_prefix = "TEST") testthat::expect_s3_class(result, "sf") }) From b291e2ce2d1739ffe1b72628ee8acafb1a9691b6 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:00:17 -0400 Subject: [PATCH 44/48] Update ATTAINSCrosswalks.R --- R/ATTAINSCrosswalks.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index fe25825f8..4708fd106 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4698,6 +4698,12 @@ TADA_ReviewATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { + + #set flags + # allowable_value_flag <- + # + # invalid_flag <- + required_cols <- c( "TADA.MonitoringLocationIdentifier", "TADA.MonitoringLocationTypeName", From b90cb24cb64f87537d2c5b085b58d200cc593f75 Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:55:57 -0400 Subject: [PATCH 45/48] Update ATTAINSCrosswalks.R --- R/ATTAINSCrosswalks.R | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 4708fd106..db88a46ed 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4699,10 +4699,9 @@ TADA_ReviewATTAINSWaterTypes <- function( review_action = c("flag", "update") ) { - #set flags - # allowable_value_flag <- - # - # invalid_flag <- + # set flags + allowable_value_flag <- "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." + invalid_flag <- "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." required_cols <- c( "TADA.MonitoringLocationIdentifier", @@ -4739,7 +4738,7 @@ TADA_ReviewATTAINSWaterTypes <- function( if (nrow(invalid_lookup) == 0) { .data <- .data |> dplyr::mutate( - TADA.ATTAINSWaterType.Flag = "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." + TADA.ATTAINSWaterType.Flag = allowable_value_flag ) return(.data |> TADA_OrderCols()) } @@ -4747,7 +4746,7 @@ TADA_ReviewATTAINSWaterTypes <- function( if (review_action == "flag") { flag_lookup <- invalid_lookup |> dplyr::mutate( - TADA.ATTAINSWaterType.Flag = "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." + TADA.ATTAINSWaterType.Flag = invalid_flag ) .data <- .data |> @@ -4762,7 +4761,7 @@ TADA_ReviewATTAINSWaterTypes <- function( dplyr::mutate( TADA.ATTAINSWaterType.Flag = dplyr::if_else( is.na(TADA.ATTAINSWaterType.Flag), - "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value.", + allowable_value_flag, TADA.ATTAINSWaterType.Flag ) ) @@ -4772,6 +4771,12 @@ TADA_ReviewATTAINSWaterTypes <- function( # review_action == "update" if (review_action == "update") { + + # set additional flags for updates + update_to_allowable <- "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName." + + update_set_NA <- "ATTAINS.WaterType was updated to NA as no ATTAINS.WaterType value was found for the TADA.MonitoringLocationTypeName." + cw <- build_attains_water_type_crosswalk() update_lookup <- invalid_lookup |> @@ -4785,8 +4790,7 @@ TADA_ReviewATTAINSWaterTypes <- function( New.ATTAINS.WaterType = TADA.ATTAINS.WaterType, TADA.ATTAINSWaterType.Flag = dplyr::if_else( !is.na(New.ATTAINS.WaterType), - "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName.", - "ATTAINS.WaterType set to NA as no ATTAINS.WaterType value was found for this TADA.MonitoringLocationTypeName." + update_to_allowable, update_set_NA ) ) @@ -4806,7 +4810,7 @@ TADA_ReviewATTAINSWaterTypes <- function( ), TADA.ATTAINSWaterType.Flag = dplyr::if_else( is.na(TADA.ATTAINSWaterType.Flag), - "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value.", + allowable_value_flag, TADA.ATTAINSWaterType.Flag ) ) |> From c8102f4716e53c508369ec3c555499fb23bdc480 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:56:13 +0000 Subject: [PATCH 46/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index db88a46ed..7a2ce052c 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4698,7 +4698,6 @@ TADA_ReviewATTAINSWaterTypes <- function( .data, review_action = c("flag", "update") ) { - # set flags allowable_value_flag <- "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." invalid_flag <- "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." @@ -4737,17 +4736,13 @@ TADA_ReviewATTAINSWaterTypes <- function( if (nrow(invalid_lookup) == 0) { .data <- .data |> - dplyr::mutate( - TADA.ATTAINSWaterType.Flag = allowable_value_flag - ) + dplyr::mutate(TADA.ATTAINSWaterType.Flag = allowable_value_flag) return(.data |> TADA_OrderCols()) } if (review_action == "flag") { flag_lookup <- invalid_lookup |> - dplyr::mutate( - TADA.ATTAINSWaterType.Flag = invalid_flag - ) + dplyr::mutate(TADA.ATTAINSWaterType.Flag = invalid_flag) .data <- .data |> dplyr::left_join( @@ -4771,7 +4766,6 @@ TADA_ReviewATTAINSWaterTypes <- function( # review_action == "update" if (review_action == "update") { - # set additional flags for updates update_to_allowable <- "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName." @@ -4790,7 +4784,8 @@ TADA_ReviewATTAINSWaterTypes <- function( New.ATTAINS.WaterType = TADA.ATTAINS.WaterType, TADA.ATTAINSWaterType.Flag = dplyr::if_else( !is.na(New.ATTAINS.WaterType), - update_to_allowable, update_set_NA + update_to_allowable, + update_set_NA ) ) @@ -4810,7 +4805,7 @@ TADA_ReviewATTAINSWaterTypes <- function( ), TADA.ATTAINSWaterType.Flag = dplyr::if_else( is.na(TADA.ATTAINSWaterType.Flag), - allowable_value_flag, + allowable_value_flag, TADA.ATTAINSWaterType.Flag ) ) |> From 48c6eba7cf659784386c97dbdf30f2959f99e2cc Mon Sep 17 00:00:00 2001 From: hillarymarler <152432687+hillarymarler@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:21:41 -0400 Subject: [PATCH 47/48] Update ATTAINSCrosswalks.R --- R/ATTAINSCrosswalks.R | 158 +++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 94 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index db88a46ed..608c4b2fc 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4694,134 +4694,104 @@ TADA_UpdateATTAINSWaterTypes <- function( #' #' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") #' } -TADA_ReviewATTAINSWaterTypes <- function( - .data, - review_action = c("flag", "update") -) { +TADA_ReviewATTAINSWaterTypes <- function(.data, review_action = c("flag", "update")) { # set flags allowable_value_flag <- "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." invalid_flag <- "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." + # set required cols required_cols <- c( "TADA.MonitoringLocationIdentifier", "TADA.MonitoringLocationTypeName", "ATTAINS.WaterType" ) - # check that all required columns are present in .data + # check columns and review_action param TADA_CheckColumns(.data, required_cols) - review_action <- match.arg(review_action) - # Normalize blanks to NA - .data <- .data |> - dplyr::mutate(ATTAINS.WaterType = dplyr::na_if(ATTAINS.WaterType, "")) - - # Allowed ATTAINS water types + # get ATTAINS water types attains.types <- quiet( rExpertQuery::EQ_DomainValues("water_type", api_key = .setEQKey()) |> - dplyr::select(name) |> - dplyr::distinct() |> - dplyr::pull() + dplyr::pull(name) |> + unique() ) |> append(c("", NA)) - # Identify invalid values + # get rows with invalid ATTAINS water types invalid_lookup <- .data |> dplyr::filter(!ATTAINS.WaterType %in% attains.types) |> - dplyr::distinct( - TADA.MonitoringLocationIdentifier, - TADA.MonitoringLocationTypeName - ) - - if (nrow(invalid_lookup) == 0) { - .data <- .data |> - dplyr::mutate( - TADA.ATTAINSWaterType.Flag = allowable_value_flag - ) - return(.data |> TADA_OrderCols()) - } + dplyr::distinct(TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName) - if (review_action == "flag") { - flag_lookup <- invalid_lookup |> - dplyr::mutate( - TADA.ATTAINSWaterType.Flag = invalid_flag - ) - - .data <- .data |> - dplyr::left_join( - flag_lookup, - by = dplyr::join_by( - TADA.MonitoringLocationIdentifier, - TADA.MonitoringLocationTypeName - ), - relationship = "many-to-many" - ) |> - dplyr::mutate( - TADA.ATTAINSWaterType.Flag = dplyr::if_else( - is.na(TADA.ATTAINSWaterType.Flag), - allowable_value_flag, - TADA.ATTAINSWaterType.Flag - ) + # set water type flags + .data <- .data |> + dplyr::left_join( + invalid_lookup |> + dplyr::mutate(TADA.ATTAINSWaterType.Flag = invalid_flag), + by = dplyr::join_by( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName + ), + relationship = "many-to-many" + ) |> + dplyr::mutate( + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + is.na(TADA.ATTAINSWaterType.Flag), + allowable_value_flag, + TADA.ATTAINSWaterType.Flag ) + ) + # return data if there are no invalid rows or review_action is flag + if (nrow(invalid_lookup) == 0 || review_action == "flag") { return(.data |> TADA_OrderCols()) } - # review_action == "update" - if (review_action == "update") { + # set additional flags for "update" review_action + update_to_allowable <- "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName." + update_set_NA <- "ATTAINS.WaterType was updated to NA as no ATTAINS.WaterType value was found for the TADA.MonitoringLocationTypeName." - # set additional flags for updates - update_to_allowable <- "ATTAINS.WaterType was updated to match an allowable ATTAINS.WaterType value by crosswalking TADA.MonitoringLocationTypeName." + # get water type crosswalk + cw <- build_attains_water_type_crosswalk() - update_set_NA <- "ATTAINS.WaterType was updated to NA as no ATTAINS.WaterType value was found for the TADA.MonitoringLocationTypeName." - - cw <- build_attains_water_type_crosswalk() + # identify replacement ATTAINS.WaterType values for invalid rows via crosswalk + update_lookup <- invalid_lookup |> + dplyr::left_join(cw, by = dplyr::join_by(TADA.MonitoringLocationTypeName)) |> + dplyr::transmute( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName, + New.ATTAINS.WaterType = TADA.ATTAINS.WaterType, + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + !is.na(New.ATTAINS.WaterType), + update_to_allowable, + update_set_NA + ) + ) - update_lookup <- invalid_lookup |> - dplyr::left_join( - cw, - by = dplyr::join_by(TADA.MonitoringLocationTypeName) - ) |> - dplyr::transmute( + # merge update lookup back to the full data, update values where possible, and flag unchanged allowable rows + .data |> + dplyr::left_join( + update_lookup, + by = dplyr::join_by( TADA.MonitoringLocationIdentifier, - TADA.MonitoringLocationTypeName, - New.ATTAINS.WaterType = TADA.ATTAINS.WaterType, - TADA.ATTAINSWaterType.Flag = dplyr::if_else( - !is.na(New.ATTAINS.WaterType), - update_to_allowable, update_set_NA - ) + TADA.MonitoringLocationTypeName + ), + relationship = "many-to-many" + ) |> + dplyr::mutate( + ATTAINS.WaterType = dplyr::coalesce(New.ATTAINS.WaterType, ATTAINS.WaterType), + TADA.ATTAINSWaterType.Flag = dplyr::if_else( + is.na(TADA.ATTAINSWaterType.Flag), + allowable_value_flag, + TADA.ATTAINSWaterType.Flag ) + ) |> + dplyr::select(-New.ATTAINS.WaterType) |> + TADA_OrderCols() - .data <- .data |> - dplyr::left_join( - update_lookup, - by = dplyr::join_by( - TADA.MonitoringLocationIdentifier, - TADA.MonitoringLocationTypeName - ), - relationship = "many-to-many" - ) |> - dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce( - New.ATTAINS.WaterType, - ATTAINS.WaterType - ), - TADA.ATTAINSWaterType.Flag = dplyr::if_else( - is.na(TADA.ATTAINSWaterType.Flag), - allowable_value_flag, - TADA.ATTAINSWaterType.Flag - ) - ) |> - dplyr::select(-New.ATTAINS.WaterType) - - .data |> TADA_OrderCols() - - return(.data) - } + return(.data) } - #' Create an ATTAINS AU–ML Crosswalk from WQP Monitoring Location IDs for New Point AUs #' #' Build a distinct crosswalk between WQP Monitoring Locations and ATTAINS From e45109a5d567b48860cd4edbadc9f943bb741b96 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 20:27:33 +0000 Subject: [PATCH 48/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- R/ATTAINSCrosswalks.R | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/R/ATTAINSCrosswalks.R b/R/ATTAINSCrosswalks.R index 608c4b2fc..9642d16e2 100644 --- a/R/ATTAINSCrosswalks.R +++ b/R/ATTAINSCrosswalks.R @@ -4694,8 +4694,10 @@ TADA_UpdateATTAINSWaterTypes <- function( #' #' review.df <- TADA_ReviewATTAINSWaterTypes(df, review_action = "update") #' } -TADA_ReviewATTAINSWaterTypes <- function(.data, review_action = c("flag", "update")) { - +TADA_ReviewATTAINSWaterTypes <- function( + .data, + review_action = c("flag", "update") +) { # set flags allowable_value_flag <- "ATTAINS.WaterType matches an allowable ATTAINS.WaterType value." invalid_flag <- "ATTAINS.WaterType value does not match any allowable ATTAINS.WaterType." @@ -4722,7 +4724,10 @@ TADA_ReviewATTAINSWaterTypes <- function(.data, review_action = c("flag", "updat # get rows with invalid ATTAINS water types invalid_lookup <- .data |> dplyr::filter(!ATTAINS.WaterType %in% attains.types) |> - dplyr::distinct(TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName) + dplyr::distinct( + TADA.MonitoringLocationIdentifier, + TADA.MonitoringLocationTypeName + ) # set water type flags .data <- .data |> @@ -4757,7 +4762,10 @@ TADA_ReviewATTAINSWaterTypes <- function(.data, review_action = c("flag", "updat # identify replacement ATTAINS.WaterType values for invalid rows via crosswalk update_lookup <- invalid_lookup |> - dplyr::left_join(cw, by = dplyr::join_by(TADA.MonitoringLocationTypeName)) |> + dplyr::left_join( + cw, + by = dplyr::join_by(TADA.MonitoringLocationTypeName) + ) |> dplyr::transmute( TADA.MonitoringLocationIdentifier, TADA.MonitoringLocationTypeName, @@ -4780,7 +4788,10 @@ TADA_ReviewATTAINSWaterTypes <- function(.data, review_action = c("flag", "updat relationship = "many-to-many" ) |> dplyr::mutate( - ATTAINS.WaterType = dplyr::coalesce(New.ATTAINS.WaterType, ATTAINS.WaterType), + ATTAINS.WaterType = dplyr::coalesce( + New.ATTAINS.WaterType, + ATTAINS.WaterType + ), TADA.ATTAINSWaterType.Flag = dplyr::if_else( is.na(TADA.ATTAINSWaterType.Flag), allowable_value_flag,