From 39b1d3420339b73feaa2d0a43c14c878f1d19ced Mon Sep 17 00:00:00 2001 From: James Hollway Date: Tue, 23 Jun 2026 17:38:29 +0200 Subject: [PATCH 1/5] Fixed stocnet validation test issue --- .github/pull_request_template.md | 1 - DESCRIPTION | 2 +- NEWS.md | 6 ++++++ cran-comments.md | 3 +-- tests/testthat/test-class_stocnet.R | 6 +++--- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4e13534ef..d94118716 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,7 +4,6 @@ - Documentation - [ ] DESCRIPTION file version is bumped by the appropriate increment (major, minor, patch) - - [ ] Date in DESCRIPTION is correct - [ ] Longer functions are commented inline or broken down into helper functions to help debugging - PR form - [ ] Title indicates expected version number diff --git a/DESCRIPTION b/DESCRIPTION index 886afecaa..75c4c9661 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: manynet Title: Many Ways to Make, Manipulate, and Modify Myriad Networks -Version: 2.1.2 +Version: 2.1.3 Description: Many tools for making, manipulating, and modifying many different types of networks. All functions operate with matrices, edge lists, and 'igraph', 'network', and 'tidygraph' objects, on directed, multiplex, multimodal, signed, and other networks. diff --git a/NEWS.md b/NEWS.md index 63d6f4fce..d34489703 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# manynet 2.1.3 + +## Package + +- Fixed stocnet validation test issue + # manynet 2.1.2 ## Package diff --git a/cran-comments.md b/cran-comments.md index 062b48694..e521feb67 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -9,5 +9,4 @@ 0 errors | 0 warnings | 0 notes -- Fixed README link issue -- Together with parallel submissions of 'netrics' and 'migraph', should pass all reverse dependency checks now too \ No newline at end of file +- Fixed intermittent validation test error \ No newline at end of file diff --git a/tests/testthat/test-class_stocnet.R b/tests/testthat/test-class_stocnet.R index a3a7906a4..c21469207 100644 --- a/tests/testthat/test-class_stocnet.R +++ b/tests/testthat/test-class_stocnet.R @@ -7,7 +7,7 @@ test_that("stocnet validation", { reserved_cols( .data = list(nodes = tibble::tibble(id = 1)), component = "nodes", - reserved_cols = "label", + column = "label", class = "character", aka = c("name", "id") ), @@ -17,7 +17,7 @@ test_that("stocnet validation", { reserved_cols( .data = list(nodes = tibble::tibble(mode = 1)), component = "nodes", - reserved_cols = "mode", + column = "mode", class = "character" ), "'mode' must be of class 'character'." @@ -26,7 +26,7 @@ test_that("stocnet validation", { required_cols( .data = list(nodes = tibble::tibble(nabel = 1)), component = "nodes", - required_cols = "label" + column = "label" ), "The 'nodes' component of a stocnet object must have the following columns: label." ) From 508ba42a00565e52ca50b7418b06100a140e7c7f Mon Sep 17 00:00:00 2001 From: James Hollway Date: Tue, 23 Jun 2026 17:38:48 +0200 Subject: [PATCH 2/5] Fixed `mode_names.stocnet()` and `layer_names.stocnet()` to look up correct info names --- NEWS.md | 7 ++++++- R/measure_properties.R | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index d34489703..c79c88ce0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,14 @@ # manynet 2.1.3 -## Package +## Class - Fixed stocnet validation test issue +## Describing + +- Fixed `mode_names.stocnet()` and `layer_names.stocnet()` to look up correct info names + + # manynet 2.1.2 ## Package diff --git a/R/measure_properties.R b/R/measure_properties.R index 10b1d1a1b..971d38553 100644 --- a/R/measure_properties.R +++ b/R/measure_properties.R @@ -284,7 +284,7 @@ mode_names.igraph <- function(.data){ #' @export mode_names.stocnet <- function(.data){ - .data$info$nodes + .data$info$modes } #' @rdname member_names @@ -335,7 +335,7 @@ layer_names.igraph <- function(.data){ #' @export layer_names.stocnet <- function(.data){ - .data$info$ties + .data$info$layers %||% unique(.data$ties$layer) } #' @rdname member_names From 6bfc197c265f2430f3964e5b55f6a363512b003f Mon Sep 17 00:00:00 2001 From: James Hollway Date: Tue, 23 Jun 2026 17:55:21 +0200 Subject: [PATCH 3/5] `add_info(.data)` (so no further arguments) now checks to see whether metadata may be added and prompts the user to add it if so --- NEWS.md | 4 ++++ R/manip_info.R | 10 +++++++++- man/manip_info.Rd | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c79c88ce0..8f83768df 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,10 @@ - Fixed `mode_names.stocnet()` and `layer_names.stocnet()` to look up correct info names +## Manipulating + +- Improved `add_info()` + - `add_info(.data)` (so no further arguments) now checks to see whether metadata may be added and prompts the user to add it if so # manynet 2.1.2 diff --git a/R/manip_info.R b/R/manip_info.R index 1619090a2..bf222a6bd 100644 --- a/R/manip_info.R +++ b/R/manip_info.R @@ -42,7 +42,9 @@ add_info.igraph <- function(.data, ...){ } info <- list(...) - if(length(info)==0) return(.check_info(.data)) + optional <- info$optional %||% FALSE + info$optional <- NULL + if(length(info)==0) return(.check_info(.data, optional = optional)) unrecog <- setdiff(names(info), c("name", "nodes", "ties", "doi", "source", "method", "location", "date", "system", @@ -85,6 +87,12 @@ add_info.igraph <- function(.data, ...){ #' @export add_info.stocnet <- function(.data, ...){ dots <- list(...) + # if dots contains optional = FALSE/TRUE + optional <- dots$optional %||% FALSE + dots$optional <- NULL + if(length(dots) == 0){ + return(.check_info(.data, optional = optional)) + } for(item in names(dots)){ .data$info[[item]] <- dots[[item]] } diff --git a/man/manip_info.Rd b/man/manip_info.Rd index 0ef955e4d..cb9944b47 100644 --- a/man/manip_info.Rd +++ b/man/manip_info.Rd @@ -30,6 +30,10 @@ net_attributes(.data) ("survey", "interview","sensor","observation","archival", or "simulation"), "nodes" (a vector of the names of the nodes) or "vertex1"/"vertex2", "ties" or "edge.pos"/"edge.neg" for defining the ties.} + +If no arguments are used, +the function will check for missing information and prompt the user to add it. +If \code{optional = TRUE} is specified, the function will also prompt for optional information.} } \value{ A data object of the same class as the function was given. From 41d2190430f2fb035c758f190cc5f6353bc437d0 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Tue, 23 Jun 2026 17:56:12 +0200 Subject: [PATCH 4/5] `add_info(.data, optional = TRUE)` extends this to further, optional metadata --- NEWS.md | 2 + R/manip_info.R | 137 +++++++++++++++++++++++++++++++++++----------- man/manip_info.Rd | 28 +++++++--- 3 files changed, 127 insertions(+), 40 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8f83768df..03b122f53 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,8 @@ - Improved `add_info()` - `add_info(.data)` (so no further arguments) now checks to see whether metadata may be added and prompts the user to add it if so + - `add_info(.data, optional = TRUE)` extends this to further, optional metadata + - This includes prompting the user by layer for multiplex networks # manynet 2.1.2 diff --git a/R/manip_info.R b/R/manip_info.R index bf222a6bd..6663c94e2 100644 --- a/R/manip_info.R +++ b/R/manip_info.R @@ -5,8 +5,6 @@ #' @description #' These functions allow users to add and edit information about the network #' itself. -#' This includes the name, year, and mode of collection of the network, -#' as well as definitions of the nodes and ties in the network. #' Where available, this information is printed for tidygraph-class objects, #' and can be used for printing a grand table in the `{grand}` package. #' @@ -18,11 +16,28 @@ #' @eval detail_avail(".*_info") #' @template fam_manip #' @param ... Named attributes. The following are currently recognised: -#' "name", "year", and "doi" of the network, -#' "collection" or "mode" of the network -#' ("survey", "interview","sensor","observation","archival", or "simulation"), -#' "nodes" (a vector of the names of the nodes) or "vertex1"/"vertex2", -#' "ties" or "edge.pos"/"edge.neg" for defining the ties. +#' - "name" is the name of the network +#' - "modes" is the name(s) of the nodeset(s) +#' - "layers" is the name(s) of the tie type(s) +#' - "directed" is a logical vector indicating whether each layer is directed +#' - "source" is the source of the network ("empirical" or "synthetic") +#' - "method" is the method of data collection or model used +#' (e.g. "survey", "interview","sensor","observation","archival", or "simulation") +#' - "location" is the geographic, institutional, or digital location of the network +#' - "date" is the date of data collection or model run +#' - "boundary" is the boundary specification of the network ("ego", "roster", or "snowball") +#' - "observation" is the observation type of the network ("cross-sectional", +#' "panel", or "event") +#' - "update" is the update type of the network ("increment" or "replacement") +#' - "max_degree" is the maximum degree of the network +#' - "min_degree" is the minimum degree of the network +#' - "doi" is the DOI or URL of the network +#' +#' If no arguments are used, +#' the function will check for missing information and prompt the user to add it. +#' If `optional = TRUE` is specified, the function will also prompt for optional information. +#' @seealso \href{https://grand-statement.org}{GRAND statement} for more +#' information on the Guidelines for Reporting About Network Data (GRAND). #' @examples #' add_info(ison_algebra, name = "Algebra") #' @export @@ -138,48 +153,104 @@ net_attributes <- function(.data){ .check_info <- function(.data, optional = FALSE){ out <- .data + read_optional <- function(prompt) { + x <- readline(prompt) + if (x == "") NULL else x + } # Names - if(is.null(net_name(.data)) || net_name(.data) == ""){ + if(is.null(net_name(out)) || net_name(out) == ""){ snet_prompt("This network does not have a name. Please add one.") - out <- add_info(out, name = readline(prompt = "Network name: ")) - } else snet_success("Network name: {net_name(out)}") + out <- add_info(out, name = read_optional(prompt = "Network name: ")) + } + if(!is.null(net_name(out))) snet_success("Network name: {net_name(out)}") - # Nodes - if(is_twomode(.data) && is.null(mode_names(.data))){ + # Nodes #### + if(is.null(mode_names(out))){ + if(is_twomode(out)){ snet_prompt("This two-mode network does not have names for the nodesets. Please add one.") - out$nodes <- c(readline(prompt = "Nodeset 1 name: "), - readline(prompt = "Nodeset 2 name: ")) - } else if(is_twomode(.data)){ - snet_success("Nodesets: {mode_names(out)}") - } else if(!is_twomode(.data) && is.null(mode_names(.data))){ - snet_prompt("This network does not have a name for the nodes. Please add one.") - out <- add_info(out, nodes = readline(prompt = "Nodeset name: ")) - } else snet_success("Nodeset: {mode_names(out)}") + out$modes <- c(read_optional(prompt = "Nodeset 1 name: "), + read_optional(prompt = "Nodeset 2 name: ")) + } else { + snet_prompt("This network does not have a name for the nodeset. Please add one.") + out <- add_info(out, modes = read_optional(prompt = "Nodeset name: ")) + }} + if(!is.null(mode_names(out))) snet_success("Modes: {mode_names(out)}") + + # Ties #### + if(is.null(layer_names(out))){ + snet_prompt("This network does not have a name for the layer/type of tie. Please add one.") + out <- add_info(out, layers = read_optional(prompt = "Layer name: ")) + } + if(!is.null(layer_names(out))) snet_success("Layers: {layer_names(out)}") + if(!"directed" %in% net_attributes(out)){ + if(net_layers(out) > 1){ + snet_prompt("This network has multiple layers. Please specify whether they are directed or undirected.") + for (layer in layer_names(out)) { + directed <- utils::menu(choices = c("Directed", "Undirected"), + title = paste0("Is the layer '", layer, "' directed or undirected?")) + out$info$directed[match(layer, layer_names(out))] <- stats::setNames(directed == 1, layer) + } + } else out <- add_info(out, directed = is_directed(.data)) + } + if("directed" %in% net_attributes(out)) snet_success("Directed: {as_infolist(out)$directed}") - # Source & method + # Optionals #### if(optional){ - if(!"source" %in% net_attributes(.data)){ + if(!"source" %in% net_attributes(out)){ snet_prompt("This network does not have a source. You may add one.") - source_options <- c("Observed", "Synthetic") - source <- utils::menu(choices = source_options, title = "Is this network observed or synthetic?") + source_options <- c("Empirical", "Synthetic") + source <- utils::menu(choices = source_options, title = "Is this network empirical or synthetic?") if(source == 1){ method_options <- c("Survey", "Interview", "Sensor", "Archival", "Trace", "Ethnography") out <- add_info(out, source = source_options[source], - method = utils::menu(choices = source_options, title = "Method: ")) + method = utils::menu(choices = method_options, title = "Method: ")) + out <- add_info(out, location = read_optional(prompt = "Location: ")) + out <- add_info(out, date = read_optional(prompt = "Date: ")) + bound_options <- c("Ego", "Roster", "Snowball") + out <- add_info(out, boundary = utils::menu(choices = bound_options, title = "Boundary: ")) } else if(source == 2){ out <- add_info(out, source = source_options[source], - method = readline(prompt = "Model: ")) + method = read_optional(prompt = "Model: ")) } - } else snet_success("Source: {net_info(out)$source}") + if(!"doi" %in% net_attributes(out)){ + out <- add_info(out, doi = read_optional(prompt = "DOI/URL: ")) + } + if(!"max_degree" %in% net_attributes(out)){ + out <- add_info(out, max_degree = read_optional(prompt = "Maximum degree: ")) + } + if(!"min_degree" %in% net_attributes(out)){ + out <- add_info(out, min_degree = read_optional(prompt = "Minimum degree: ")) + } + if(!"observation" %in% net_attributes(out)){ + obs_options <- c("Cross-sectional", "Panel", "Event") + for (layer in layer_names(out)) { + observation <- utils::menu(choices = obs_options, + title = paste0("The layer '", layer, "' is observed as: ")) + out$info$observation[match(layer, layer_names(out))] <- stats::setNames(obs_options[observation], layer) + } + } + if(is_weighted(out) && !"update" %in% net_attributes(out)){ + upd_options <- c("Increment", "Replacement") + for (layer in layer_names(out)) { + update <- utils::menu(choices = upd_options, + title = paste0("The layer '", layer, "' is updated by: ")) + out$info$update[match(layer, layer_names(out))] <- stats::setNames(upd_options[update], layer) + } + } + } + if("source" %in% net_attributes(out)) snet_success("Source: {as_infolist(out)$source}") + if("method" %in% net_attributes(out)) snet_success("Method/Model: {as_infolist(out)$method}") + if("boundary" %in% net_attributes(out)) snet_success("Boundary: {as_infolist(out)$boundary}") + if("location" %in% net_attributes(out)) snet_success("Location: {as_infolist(out)$location}") + if("observation" %in% net_attributes(out)) snet_success("Observation: {as_infolist(out)$observation}") + if("update" %in% net_attributes(out)) snet_success("Update: {as_infolist(out)$update}") + if("max_degree" %in% net_attributes(out)) snet_success("Max degree: {as_infolist(out)$max_degree}") + if("min_degree" %in% net_attributes(out)) snet_success("Min degree: {as_infolist(out)$min_degree}") + if("date" %in% net_attributes(out)) snet_success("Date: {as_infolist(out)$date}") + if("doi" %in% net_attributes(out)) snet_success("DOI/URL: {as_infolist(out)$doi}") } - # Ties - if(is.null(layer_names(.data))){ - snet_prompt("This network does not have a name for the ties. Please add one.") - out <- add_info(out, ties = readline(prompt = "Ties name: ")) - } else snet_success("Ties: {layer_names(out)}") - out } diff --git a/man/manip_info.Rd b/man/manip_info.Rd index cb9944b47..716d62ea8 100644 --- a/man/manip_info.Rd +++ b/man/manip_info.Rd @@ -25,11 +25,24 @@ net_attributes(.data) }} \item{...}{Named attributes. The following are currently recognised: -"name", "year", and "doi" of the network, -"collection" or "mode" of the network -("survey", "interview","sensor","observation","archival", or "simulation"), -"nodes" (a vector of the names of the nodes) or "vertex1"/"vertex2", -"ties" or "edge.pos"/"edge.neg" for defining the ties.} +\itemize{ +\item "name" is the name of the network +\item "modes" is the name(s) of the nodeset(s) +\item "layers" is the name(s) of the tie type(s) +\item "directed" is a logical vector indicating whether each layer is directed +\item "source" is the source of the network ("empirical" or "synthetic") +\item "method" is the method of data collection or model used +(e.g. "survey", "interview","sensor","observation","archival", or "simulation") +\item "location" is the geographic, institutional, or digital location of the network +\item "date" is the date of data collection or model run +\item "boundary" is the boundary specification of the network ("ego", "roster", or "snowball") +\item "observation" is the observation type of the network ("cross-sectional", +"panel", or "event") +\item "update" is the update type of the network ("increment" or "replacement") +\item "max_degree" is the maximum degree of the network +\item "min_degree" is the minimum degree of the network +\item "doi" is the DOI or URL of the network +} If no arguments are used, the function will check for missing information and prompt the user to add it. @@ -41,8 +54,6 @@ A data object of the same class as the function was given. \description{ These functions allow users to add and edit information about the network itself. -This includes the name, year, and mode of collection of the network, -as well as definitions of the nodes and ties in the network. Where available, this information is printed for tidygraph-class objects, and can be used for printing a grand table in the \code{{grand}} package. \itemize{ @@ -70,6 +81,9 @@ If no method is available for any class, an error will be thrown. add_info(ison_algebra, name = "Algebra") } \seealso{ +\href{https://grand-statement.org}{GRAND statement} for more +information on the Guidelines for Reporting About Network Data (GRAND). + Other manipulations: \code{\link{manip_changes}}, \code{\link{manip_global}}, From d75d6be9244839a7c65b0c436cd26f85ee428613 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Tue, 23 Jun 2026 19:14:59 +0200 Subject: [PATCH 5/5] Recog release less than 10 days --- cran-comments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cran-comments.md b/cran-comments.md index e521feb67..368e61c23 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -9,4 +9,4 @@ 0 errors | 0 warnings | 0 notes -- Fixed intermittent validation test error \ No newline at end of file +- Though less than 10 days, this version fixes intermittent validation test error on CRAN \ No newline at end of file