Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a6d42cf
Fixed cat() call in net_by_scalefree() and enabled it to test power l…
jhollway Mar 19, 2026
f2b96e5
#patch bump
jhollway Mar 19, 2026
57c4a92
Fixed startup messages
jhollway Mar 20, 2026
c1580f7
Added node_mark roxygen template
jhollway Mar 20, 2026
5181e9b
Added tie_mark roxygen template
jhollway Mar 20, 2026
be82810
Added gap method for cluster k-selection, renamed some arguments to b…
jhollway Mar 20, 2026
53157c6
Separated out centrality scripts and separated out net/node/tie docum…
jhollway Mar 21, 2026
47b599e
Added net/node/tie roxygen templates
jhollway Mar 21, 2026
6852884
Added param templates
jhollway Mar 21, 2026
8d174a8
Added param templating to centrality documentation
jhollway Mar 21, 2026
8ec3b07
Fixed brokerage documentation, added param_memb where required
jhollway Mar 21, 2026
af5fac2
Improved documentation for diversity and assortativity
jhollway Mar 21, 2026
c423ff2
Using motif argument instead of census for consistency
jhollway Mar 21, 2026
a31f399
Rationalising select nodes and ties
jhollway Mar 21, 2026
fe4e8b1
Fixed some documentation
jhollway Mar 21, 2026
39ff13d
Periodwise functions are now motifs not measures
jhollway Mar 21, 2026
fd67ce6
Updated documentation for cohesion, closure, cliques, and components
jhollway Mar 21, 2026
ff399a2
Updated features and hierarchy documentation
jhollway Mar 21, 2026
1a5c722
Separated node_in_community() from hierarchical and non-hierarchical …
jhollway Mar 21, 2026
051c90c
Separated out core documentation into mark, measure, and member
jhollway Mar 21, 2026
8301deb
Renamed node_adoption_time() and node_thresholds() to node_by_adopt_t…
jhollway Mar 21, 2026
cc17982
Updated tests
jhollway Mar 21, 2026
6e19bc1
Updated pkgdown
jhollway Mar 21, 2026
8ff7e4c
Updated namespace
jhollway Mar 21, 2026
bda4105
Updated README
jhollway Mar 21, 2026
980b4b1
#minor bump
jhollway Mar 21, 2026
26ccde2
Initial plan
Copilot Mar 21, 2026
07d49b5
Fill in NEWS.md for v0.2.0
Copilot Mar 21, 2026
8b19e20
Updated NEWS
jhollway Mar 21, 2026
588991e
Fixed documentation issues
jhollway Mar 21, 2026
4c28aa9
Dropped ks test for power law fit
jhollway Mar 21, 2026
56fae79
Initial plan
Copilot Mar 21, 2026
24b367b
Resolve membership to accept string attribute name or categorical vector
Copilot Mar 21, 2026
06c38c6
Fixed .resolve_membership()
jhollway Mar 21, 2026
aa15887
Renamed `node_exposure()` to `node_by_adopt_exposure()`
jhollway Mar 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
^CODE_OF_CONDUCT\.md$
^LICENSE\.md$
man-roxygen
^.*\.Rproj$
^\.Rproj\.user$
^working$
Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: netrics
Title: Many Ways to Measure and Classify Membership for Networks, Nodes, and Ties
Version: 0.1.0
Date: 2026-03-15
Version: 0.2.0
Date: 2026-03-21
Description: Many tools for calculating network, node, or tie
marks, measures, motifs and memberships of many different types of networks.
Marks identify structural positions, measures quantify network properties,
Expand Down
15 changes: 8 additions & 7 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ export(cluster_concor)
export(cluster_cosine)
export(cluster_hierarchical)
export(k_elbow)
export(k_gap)
export(k_silhouette)
export(k_strict)
export(net_by_adhesion)
export(net_by_assortativity)
export(net_by_balance)
export(net_by_betweenness)
export(net_by_change)
export(net_by_closeness)
export(net_by_cohesion)
export(net_by_components)
export(net_by_congruency)
export(net_by_connectedness)
export(net_by_core)
export(net_by_correlation)
export(net_by_degree)
export(net_by_density)
export(net_by_diameter)
Expand Down Expand Up @@ -48,21 +47,26 @@ export(net_by_richness)
export(net_by_scalefree)
export(net_by_smallworld)
export(net_by_spatial)
export(net_by_stability)
export(net_by_strength)
export(net_by_toughness)
export(net_by_transitivity)
export(net_by_transmissibility)
export(net_by_upperbound)
export(net_by_waves)
export(net_x_brokerage)
export(net_x_change)
export(net_x_correlation)
export(net_x_dyad)
export(net_x_hazard)
export(net_x_hierarchy)
export(net_x_mixed)
export(net_x_stability)
export(net_x_tetrad)
export(net_x_triad)
export(node_by_adoption_time)
export(node_by_adopt_exposure)
export(node_by_adopt_recovery)
export(node_by_adopt_threshold)
export(node_by_adopt_time)
export(node_by_alpha)
export(node_by_authority)
export(node_by_betweenness)
Expand All @@ -81,7 +85,6 @@ export(node_by_efficiency)
export(node_by_effsize)
export(node_by_eigenvector)
export(node_by_equivalency)
export(node_by_exposure)
export(node_by_flow)
export(node_by_harmonic)
export(node_by_heterophily)
Expand All @@ -102,12 +105,10 @@ export(node_by_power)
export(node_by_randomwalk)
export(node_by_reach)
export(node_by_reciprocity)
export(node_by_recovery)
export(node_by_redundancy)
export(node_by_richness)
export(node_by_stress)
export(node_by_subgraph)
export(node_by_thresholds)
export(node_by_transitivity)
export(node_by_vitality)
export(node_in_adopter)
Expand Down
42 changes: 42 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
# netrics 0.2.0

## Package

- Added roxygen2 parameter templates (`param_attr`, `param_data`,
`param_dir`, `param_memb`, `param_motf`, `param_norm`, `param_select`) and
net/node/tie-level templates (`net_measure`, `net_motif`, `node_mark`,
`node_measure`, `node_member`, `node_motif`, `tie_mark`, `tie_measure`) for
consistent function documentation.
- Fixed startup messages.

## Measuring

- Renamed `node_adoption_time()` to `node_by_adopt_time()`
- Renamed `node_thresholds()` to `node_by_adopt_threshold()`
- Renamed `node_exposure()` to `node_by_adopt_exposure()`
- Renamed `node_recovery()` to `node_by_adopt_recovery()`
- Separated centralisation scripts into different files per measure type
(betweenness, closeness, degree, eigenvector) for easier maintenance,
and into different documentation per level (node, tie) for better organization.
- Updated and separated brokerage, diversity/assortativity, cohesion, closure,
cliques, components, features, and hierarchy documentation by level.

## Members

- Separated `node_in_community()` documentation from the hierarchical
and non-hierarchical community-detection algorithms.
- Core documentation split into separate mark, measure, and member pages.
- Improved various functions that rely on a membership argument to accept
both a membership vector and a string identifier of a network attribute.

## Motifs

- Renamed `net_by_change()` to `net_x_change()` and related functions to
reflect their motif (subgraph-counting) nature.

## Methods

- Added gap method for cluster *k*-selection in `method_k()`.
- Renamed `model_k()` to `method_k()` and related cluster-selection utilities
renamed for clarity.

# netrics 0.1.0

## Release notes
Expand Down
176 changes: 85 additions & 91 deletions R/mark_nodes.R
Original file line number Diff line number Diff line change
@@ -1,76 +1,7 @@
# Degree properties ####

#' Marking nodes based on degree properties
#'
#' @description
#' These functions return logical vectors the length of the
#' nodes in a network identifying which hold certain properties or positions in the network.
#'
#' - `node_is_isolate()` marks nodes that are isolates,
#' with neither incoming nor outgoing ties.
#' - `node_is_pendant()` marks nodes that are pendants,
#' with exactly one incoming or outgoing tie.
#' - `node_is_universal()` identifies whether nodes are adjacent to all other
#' nodes in the network.
#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar.
#' For more information on the standard coercion possible,
#' see [manynet::as_tidygraph()].
#' @family marks
#' @family degree
#' @name mark_degree
NULL

#' @rdname mark_degree
#' @examples
#' node_is_isolate(ison_brandes)
#' @export
node_is_isolate <- function(.data){
.data <- manynet::expect_nodes(.data)
mat <- abs(manynet::as_matrix(.data))
if(manynet::is_twomode(.data)){
out <- c(rowSums(mat)==0, colSums(mat)==0)
} else {
out <- rowSums(mat)==0 & colSums(mat)==0
}
names(out) <- manynet::node_names(.data)
make_node_mark(out, .data)
}

#' @rdname mark_degree
#' @export
node_is_pendant <- function(.data){
.data <- manynet::expect_nodes(.data)
mat <- abs(manynet::as_matrix(.data))
if(manynet::is_twomode(.data)){
out <- c(rowSums(mat)==1, colSums(mat)==1)
} else {
out <- rowSums(mat)==1 & colSums(mat)==1
}
make_node_mark(out, .data)
}

#' @rdname mark_degree
#' @section Universal/dominating node:
#' A universal node is adjacent to all other nodes in the network.
#' It is also sometimes called the dominating vertex because it represents
#' a one-element dominating set.
#' A network with a universal node is called a cone, and its universal node
#' is called the apex of the cone.
#' A classic example of a cone is a star graph,
#' but friendship, wheel, and threshold graphs are also cones.
#' @examples
#' node_is_universal(create_star(11))
#' @export
node_is_universal <- function(.data){
.data <- manynet::expect_nodes(.data)
net <- manynet::to_undirected(manynet::to_unweighted(.data))
make_node_mark(node_by_deg(net)==(manynet::net_nodes(net)-1), .data)
}

# Structural properties ####

#' Marking nodes based on structural properties
#'
#' @name mark_nodes
#' @description
#' These functions return logical vectors the length of the
#' nodes in a network identifying which hold certain properties or positions in the network.
Expand All @@ -83,11 +14,8 @@ node_is_universal <- function(.data){
#' triangles that are only connected by that node.
#' - `node_is_mentor()` marks a proportion of high indegree nodes as 'mentors' (see details).
#' - `node_is_neighbor()` marks nodes that are neighbours of a given node.
#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar.
#' For more information on the standard coercion possible,
#' see [manynet::as_tidygraph()].
#' @family marks
#' @name mark_nodes
#' @template param_data
#' @template node_mark
NULL

#' @rdname mark_nodes
Expand Down Expand Up @@ -219,6 +147,72 @@ node_is_neighbor <- function(.data, node){
make_node_mark(out, .data)
}

# Degree properties ####

#' Marking nodes based on degree properties
#' @name mark_degree
#' @description
#' These functions return logical vectors the length of the
#' nodes in a network identifying which hold certain properties or positions in the network.
#'
#' - `node_is_isolate()` marks nodes that are isolates,
#' with neither incoming nor outgoing ties.
#' - `node_is_pendant()` marks nodes that are pendants,
#' with exactly one incoming or outgoing tie.
#' - `node_is_universal()` identifies whether nodes are adjacent to all other
#' nodes in the network.
#' @template param_data
#' @family degree
#' @template node_mark
NULL

#' @rdname mark_degree
#' @examples
#' node_is_isolate(ison_brandes)
#' @export
node_is_isolate <- function(.data){
.data <- manynet::expect_nodes(.data)
mat <- abs(manynet::as_matrix(.data))
if(manynet::is_twomode(.data)){
out <- c(rowSums(mat)==0, colSums(mat)==0)
} else {
out <- rowSums(mat)==0 & colSums(mat)==0
}
names(out) <- manynet::node_names(.data)
make_node_mark(out, .data)
}

#' @rdname mark_degree
#' @export
node_is_pendant <- function(.data){
.data <- manynet::expect_nodes(.data)
mat <- abs(manynet::as_matrix(.data))
if(manynet::is_twomode(.data)){
out <- c(rowSums(mat)==1, colSums(mat)==1)
} else {
out <- rowSums(mat)==1 & colSums(mat)==1
}
make_node_mark(out, .data)
}

#' @rdname mark_degree
#' @section Universal/dominating node:
#' A universal node is adjacent to all other nodes in the network.
#' It is also sometimes called the dominating vertex because it represents
#' a one-element dominating set.
#' A network with a universal node is called a cone, and its universal node
#' is called the apex of the cone.
#' A classic example of a cone is a star graph,
#' but friendship, wheel, and threshold graphs are also cones.
#' @examples
#' node_is_universal(create_star(11))
#' @export
node_is_universal <- function(.data){
.data <- manynet::expect_nodes(.data)
net <- manynet::to_undirected(manynet::to_unweighted(.data))
make_node_mark(node_by_deg(net)==(manynet::net_nodes(net)-1), .data)
}

# Diffusion properties ####

#' Marking nodes based on diffusion properties
Expand All @@ -232,7 +226,7 @@ node_is_neighbor <- function(.data, node){
#' - `node_is_latent()` marks nodes that are latent at a particular time point.
#' - `node_is_recovered()` marks nodes that are recovered at a particular time point.
#' @inheritParams mark_nodes
#' @family marks
#' @template node_mark
#' @family diffusion
#' @name mark_diff
NULL
Expand Down Expand Up @@ -388,7 +382,7 @@ node_is_exposed <- function(.data, mark, time = 0){
if (missing(mark)){
if(manynet::is_changing(.data)){
t <- time
return(make_node_mark(node_by_exposure(.data, time = t)>0, .data))
return(make_node_mark(node_by_adopt_exposure(.data, time = t)>0, .data))
} else if(inherits(.data, "diff_model")){
mark <- summary(.data) %>%
dplyr::filter(t == 0 & event == "I") %>%
Expand All @@ -406,7 +400,7 @@ node_is_exposed <- function(.data, mark, time = 0){
# Selection properties ####

#' Marking nodes based on measures
#'
#' @name mark_select_node
#' @description
#' These functions return logical vectors the length of the
#' nodes in a network identifying which hold certain properties or positions in the network.
Expand All @@ -416,33 +410,33 @@ node_is_exposed <- function(.data, mark, time = 0){
#' for converting the results from some node measure into a mark-class object.
#' They can be particularly useful for highlighting which node or nodes
#' are key because they minimise or, more often, maximise some measure.
#' @inheritParams mark_nodes
#' @family marks
#' @name mark_select
#' @template param_data
#' @family selection
#' @template node_mark
NULL

#' @rdname mark_select
#' @param size The number of nodes to select (as TRUE).
#' @rdname mark_select_node
#' @template param_select
#' @examples
#' node_is_random(ison_brandes, 2)
#' @export
node_is_random <- function(.data, size = 1){
node_is_random <- function(.data, select = 1){
.data <- manynet::expect_nodes(.data)
n <- manynet::net_nodes(.data)
out <- rep(FALSE, n)
out[sample.int(n, size)] <- TRUE
out[sample.int(n, select)] <- TRUE
make_node_mark(out, .data)
}

#' @rdname mark_select
#' @rdname mark_select_node
#' @param node_measure An object created by a `node_` measure.
#' @param ranks The number of ranks of max or min to return.
#' For example, `ranks = 3` will return TRUE for nodes with
#' scores equal to any of the top (or, for `node_is_min()`, bottom)
#' three scores.
#' By default, `ranks = 1`.
#' @examples
#' #node_is_max(node_by_degree(ison_brandes))
#' node_is_max(node_by_degree(ison_brandes))
#' @export
node_is_max <- function(node_measure, ranks = 1){
if(!inherits(node_measure, "node_measure"))
Expand All @@ -466,9 +460,9 @@ node_is_max <- function(node_measure, ranks = 1){
out
}

#' @rdname mark_select
#' @rdname mark_select_node
#' @examples
#' #node_is_min(node_by_degree(ison_brandes))
#' node_is_min(node_by_degree(ison_brandes))
#' @export
node_is_min <- function(node_measure, ranks = 1){
if(!inherits(node_measure, "node_measure"))
Expand All @@ -492,9 +486,9 @@ node_is_min <- function(node_measure, ranks = 1){
out
}

#' @rdname mark_select
#' @rdname mark_select_node
#' @examples
#' #node_is_mean(node_degree(ison_brandes))
#' node_is_mean(node_by_degree(ison_brandes))
#' @export
node_is_mean <- function(node_measure, ranks = 1){
if(!inherits(node_measure, "node_measure"))
Expand Down
Loading
Loading