From bc78a301b5e0d2cf325667e0e052abe977c02e42 Mon Sep 17 00:00:00 2001 From: David Blodgett <dblodgett@usgs.gov> Date: Wed, 8 Sep 2021 16:29:28 -0500 Subject: [PATCH] hyfabric update for networkConnection --- hyfabric/DESCRIPTION | 2 +- hyfabric/R/networkconnection.R | 46 ++++++----- hyfabric/man/NetworkConnection.Rd | 2 +- .../tests/testthat/test_networkconnection.R | 13 ++- workspace/R/NHD_navigate.R | 78 +++++++++--------- workspace/hyfabric_0.3.0.tar.gz | Bin 3874 -> 0 bytes workspace/hyfabric_0.4.0.tar.gz | Bin 0 -> 3973 bytes 7 files changed, 76 insertions(+), 65 deletions(-) delete mode 100644 workspace/hyfabric_0.3.0.tar.gz create mode 100644 workspace/hyfabric_0.4.0.tar.gz diff --git a/hyfabric/DESCRIPTION b/hyfabric/DESCRIPTION index 169d7f8..b3749db 100644 --- a/hyfabric/DESCRIPTION +++ b/hyfabric/DESCRIPTION @@ -1,7 +1,7 @@ Package: hyfabric Type: Package Title: Utility functions for creating the reference geospatial fabric. -Version: 0.3.0 +Version: 0.4.0 Authors@R: c(person(given = "David", family = "Blodgett", role = c("aut", "cre"), diff --git a/hyfabric/R/networkconnection.R b/hyfabric/R/networkconnection.R index 4ba7201..56c360f 100644 --- a/hyfabric/R/networkconnection.R +++ b/hyfabric/R/networkconnection.R @@ -1,61 +1,65 @@ #' Identifies and connects dangles in network generated by Network Nav function -#' @param inCOM list list of input COMIDs +#' @param inCOM list list of input COMIDs #' @param nhdDF sf data.frame (data frame) valid data frame of NHD flowlines #' @import dplyr #' @return (list) list of COMIDs connecting dangle to existing network #' @export -#' @examples +#' @examples #' source(system.file("extdata", "sample_flines.R", package = "nhdplusTools")) -#' +#' #' sample_flines <- nhdplusTools::prepare_nhdplus(sample_flines, 0, 0, 0, FALSE) %>% #' left_join(select(sample_flines, COMID, DnHydroseq, DnLevelPat, Pathlength)) -#' -#' comid <- sample(sample_flines$COMID, 10) -#' +#' +#' comid <- sample(sample_flines$COMID, 10) +#' #' NetworkConnection(comid, sample_flines) NetworkConnection <- function(incom, nhd, status = FALSE){ - + + nhd <- dplyr::group_by(nhd, LevelPathI) %>% + dplyr::mutate(DnLevelPat = min(DnLevelPat)) %>% + dplyr::ungroup() + upnet_DF <- filter(nhd, COMID %in% incom) %>% filter(!DnHydroseq %in% Hydroseq) - + # while the number of dangles is greater than 0 while (length(upnet_DF$COMID) > 0) { - + # create item for number of dangles count <- dim(upnet_DF)[1] - + if(status) message(dim(upnet_DF)) - + # find out which level paths are downstream of dangling huc12 POIs DSLP <- upnet_DF %>% pull(DnLevelPat)#[upnet_DF$COMID %in% incom] - + CLP <- upnet_DF %>% pull(LevelPathI) + # Get the COMID of the hydroseq with level path value # the lowest downstream flowline within the levelpath - inCom2 <- nhd$COMID[nhd$Hydroseq %in% DSLP] - + inCom2 <- nhd$COMID[nhd$Hydroseq %in% c(DSLP, CLP)] + # Run the upstream navigation code - - + upNet <- unique(unlist(lapply(inCom2, function(x, nhd) { nhdplusTools::get_UM(nhd, x, include = TRUE) }, nhd = nhd))) - + # Append result to existing segment list incom <- append(incom, upNet) - + # Get the same variable as above upnet_DF <- filter(nhd, COMID %in% incom, !DnHydroseq %in% Hydroseq) - + # Get the count count2 <- dim(upnet_DF)[1] - + # if the count has remained the same we are done and return the flowline list if (count == count2){ return (incom) } } - + return(incom) } diff --git a/hyfabric/man/NetworkConnection.Rd b/hyfabric/man/NetworkConnection.Rd index f1e4b84..698ebd3 100644 --- a/hyfabric/man/NetworkConnection.Rd +++ b/hyfabric/man/NetworkConnection.Rd @@ -23,7 +23,7 @@ source(system.file("extdata", "sample_flines.R", package = "nhdplusTools")) sample_flines <- nhdplusTools::prepare_nhdplus(sample_flines, 0, 0, 0, FALSE) \%>\% left_join(select(sample_flines, COMID, DnHydroseq, DnLevelPat, Pathlength)) -comid <- sample(sample_flines$COMID, 10) +comid <- sample(sample_flines$COMID, 10) NetworkConnection(comid, sample_flines) } diff --git a/hyfabric/tests/testthat/test_networkconnection.R b/hyfabric/tests/testthat/test_networkconnection.R index cfccc68..5888eda 100644 --- a/hyfabric/tests/testthat/test_networkconnection.R +++ b/hyfabric/tests/testthat/test_networkconnection.R @@ -12,17 +12,22 @@ test_that("networkconnection", { sample_flines <- nhdplusTools::make_standalone(sample_flines) + sample_flines$DnLevelPat[is.na(sample_flines$toCOMID)] <- NA + sample_flines$DnHydroseq[is.na(sample_flines$toCOMID)] <- NA + comid <- c(11689684, 11690056, 11688856, 11687550, 11691374, 11690260) out <- NetworkConnection(comid, sample_flines) - testthat::expect_equal(length(out), 128) + testthat::expect_equal(length(out), 235) + # sub <- sf::st_geometry(filter(sample_flines, COMID %in% out)) + # # plot(sf::st_geometry(sample_flines), col = "blue", lwd = 1) # plot(sf::st_geometry(filter(sample_flines, COMID %in% out)), col = "blue", lwd = 2, add = TRUE) # }) - +# # reprex::reprex({ # # library(nhdplusTools) @@ -38,13 +43,15 @@ test_that("networkconnection", { # # sample_flines <- nhdplusTools::make_standalone(sample_flines) # +# sample_flines$DnLevelPat[is.na(sample_flines$toCOMID)] <- NA +# sample_flines$DnHydroseq[is.na(sample_flines$toCOMID)] <- NA +# # comid <- c(11689684, 11690056, 11688856, 11687550, 11691374, 11690260) # # out <- NetworkConnection(comid, sample_flines) # # testthat::expect_equal(length(out), 128) # -# # # Note there is some disconnected network. # # #We can do this with hyRefactor... diff --git a/workspace/R/NHD_navigate.R b/workspace/R/NHD_navigate.R index 5023832..2382dfe 100644 --- a/workspace/R/NHD_navigate.R +++ b/workspace/R/NHD_navigate.R @@ -15,45 +15,45 @@ NetworkNav <- function(inCom, nhdDF, withTrib){ return(seg) } - -#' Identifies and connects dangles in network generated by Network Nav function -#' @param inCOM (list) list of input COMIDs -#' @param nhdDF (sf data.frame) (data frame) valid data frame of NHD flowlines -#' @param withTrib (logical) flag for if the upstream navigation should include tributaries -# or stick to mainstem level path -# -#' @return (list) list of COMIDs connecting dangle to existing network -NetworkConnection <- function(incom, nhd){ - - upnet_DF <- filter(nhd, COMID %in% incom) %>% - filter(!DnHydroseq %in% Hydroseq) - - # while the number of dangles is greater than 0 - while (length(upnet_DF$COMID) > 0){ - # create item for number of dangles - count <- dim(upnet_DF)[1] - print (dim(upnet_DF)) - # find out which level paths are downstream of dangling huc12 POIs - DSLP <- upnet_DF %>% pull(DnLevelPat)#[upnet_DF$COMID %in% incom] - # Get the COMID of the hydroseq with level path value - # the lowest downstream flowline within the levelpath - inCom2 <- nhd$COMID[nhd$Hydroseq %in% DSLP] - # Run the upstream navigation code - upNet <- unique(unlist(lapply(inCom2, NetworkNav, nhd))) - # Append result to existing segment list - incom <- append(incom, upNet) - # Get the same variable as above - upnet_DF <- filter(nhd, COMID %in% incom, !DnHydroseq %in% Hydroseq) - # Get the count - count2 <- dim(upnet_DF)[1] - # if the count has remained the same we are done and return the flowline list - if (count == count2){ - return (incom) - } - } - # Not sure this other return is needed - return(incom) -} +#' ### DEPRECATED ### +#' #' Identifies and connects dangles in network generated by Network Nav function +#' #' @param inCOM (list) list of input COMIDs +#' #' @param nhdDF (sf data.frame) (data frame) valid data frame of NHD flowlines +#' #' @param withTrib (logical) flag for if the upstream navigation should include tributaries +#' # or stick to mainstem level path +#' # +#' #' @return (list) list of COMIDs connecting dangle to existing network +#' NetworkConnection <- function(incom, nhd){ +#' +#' upnet_DF <- filter(nhd, COMID %in% incom) %>% +#' filter(!DnHydroseq %in% Hydroseq) +#' +#' # while the number of dangles is greater than 0 +#' while (length(upnet_DF$COMID) > 0){ +#' # create item for number of dangles +#' count <- dim(upnet_DF)[1] +#' print (dim(upnet_DF)) +#' # find out which level paths are downstream of dangling huc12 POIs +#' DSLP <- upnet_DF %>% pull(DnLevelPat)#[upnet_DF$COMID %in% incom] +#' # Get the COMID of the hydroseq with level path value +#' # the lowest downstream flowline within the levelpath +#' inCom2 <- nhd$COMID[nhd$Hydroseq %in% DSLP] +#' # Run the upstream navigation code +#' upNet <- unique(unlist(lapply(inCom2, NetworkNav, nhd))) +#' # Append result to existing segment list +#' incom <- append(incom, upNet) +#' # Get the same variable as above +#' upnet_DF <- filter(nhd, COMID %in% incom, !DnHydroseq %in% Hydroseq) +#' # Get the count +#' count2 <- dim(upnet_DF)[1] +#' # if the count has remained the same we are done and return the flowline list +#' if (count == count2){ +#' return (incom) +#' } +#' } +#' # Not sure this other return is needed +#' return(incom) +#' } #' Switches valid POIs from minor to major path divergences diff --git a/workspace/hyfabric_0.3.0.tar.gz b/workspace/hyfabric_0.3.0.tar.gz deleted file mode 100644 index 9bef8e209ee1e2775dae07c2d0842da0bd058ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3874 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 diff --git a/workspace/hyfabric_0.4.0.tar.gz b/workspace/hyfabric_0.4.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..39974852eac028dc8617772324aff7fcc19f0568 GIT binary patch literal 3973 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 literal 0 HcmV?d00001 -- GitLab