Skip to content

v1.0.0 - #18

Merged
jhollway merged 68 commits into
mainfrom
develop
Aug 28, 2026
Merged

v1.0.0#18
jhollway merged 68 commits into
mainfrom
develop

Conversation

@jhollway

@jhollway jhollway commented Aug 9, 2026

Copy link
Copy Markdown
Member

Description

Package

  • Removed the CRAN version check from .onAttach() making library(netrics) faster to attach
    • It now runs once, for the whole stack, in {migraph}, where it is cached and checks GitHub as well as CRAN
  • Updated GitHub Actions workflows to latest major action versions
  • Fixed release workflow referring to actions/actions/checkout, a doubled path segment that would have failed every step using it
  • Added param_cutoff roxygen template, correctly documenting geodesic cutoff for six functions

Measures

  • Added net_by_cyclicality() for detecting generalised exchange
  • Added net_by_compactness() for the average closeness of all pairs of nodes
  • Added node_by_decay() and net_by_decay() for decay centrality, which
    weights alters by distance instead of truncating at a cutoff
  • Added node_by_integration() and net_by_integration() for Valente and
    Foreman's integration and radiality
    • Note these two centralizations normalize over node scores rather
      than reusing net_by_reach()'s denominator, which assumes scores bounded
      by N-1 and would return negative values here
  • Added net_by_inconsistency(), which scores how far a partition's blocks depart
    from ideal types (nul, com, reg, rdo, cdo, dnc), generalising
    net_by_factions() beyond structural equivalence

Memberships

  • Added node_in_labels() for label propagation community detection
  • Fixed node_in_regular() to compute regular equivalence using recursive
    similarity (regularity = "rolesim" (default) or "rege") between nodes
    rather than a triad census
    • Note existing scripts calling node_in_regular() will now return more correct results
    • Moved former behaviour of node_in_regular() to node_in_motif(),
      documented as capturing similarity of local embedding not role equivalence
  • Added node_in_block() for direct blockmodelling, searching partitions
    for the one that minimises net_by_inconsistency()

Motifs

  • Added node_x_clique(), returning which maximal cliques each node belongs to,
    and branching on two-mode networks to find bicliques (closes Clique census functions #8, thanks @noortjemay)
    • Note that node_x_clique() considers only positive ties,
      since a clique is a cohesive subgroup
  • Added node_x_ties(), describing the distribution of each node's tie values,
    or its spread across layers in a multiplex network
  • Added node_x_alters() and node_x_similarity(), describing the composition
    of each node's alters and their similarity to it, each branching on whether
    the attribute given is categorical or continuous
    • For two-mode networks, node_x_similarity() compares each node with those
      at distance two, that is, those it shares a node of the other mode with,
      following the tertius effect of {migraph} and {goldfish}
      (Haunss and Hollway 2023)
  • Added net_x_homophily(), returning the table behind the EI index together
    with an expected-EI baseline and Yule's Q
    • Note that on weighted networks this counts ties where
      net_by_heterophily() sums weights, so the two agree only when unweighted

Methods

  • Added regularity_rolesim() and regularity_rege(), recursive role similarity methods
    • Note regularity_rege() degenerate on unweighted connected ones, where it warns

Tutorials

  • Updated position tutorial to use node_in_regular() for regular equivalence rather than the triad census

Checklist:

  • Documentation
    • Longer functions are commented inline or broken down into helper functions to help debugging
  • PR form
    • PR description above and the NEWS.md file are aligned

@jhollway jhollway self-assigned this Aug 9, 2026
Copilot AI lite review requested due to automatic review settings August 9, 2026 14:02
@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.23920% with 92 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.62%. Comparing base (6dfd5a9) to head (f9f5176).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
R/class_metrics.R 74.64% 18 Missing ⚠️
R/member_community.R 93.68% 18 Missing ⚠️
R/measure_features.R 89.61% 16 Missing ⚠️
R/method_k.R 65.38% 9 Missing ⚠️
R/method_coreness.R 94.28% 8 Missing ⚠️
R/motif_composition.R 96.62% 5 Missing ⚠️
R/member_core.R 92.15% 4 Missing ⚠️
R/measure_diffusion.R 91.42% 3 Missing ⚠️
R/member_cliques.R 62.50% 3 Missing ⚠️
R/netrics-utils.R 78.57% 3 Missing ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #18      +/-   ##
==========================================
+ Coverage   82.05%   88.62%   +6.56%     
==========================================
  Files          24       30       +6     
  Lines        2441     3533    +1092     
==========================================
+ Hits         2003     3131    +1128     
+ Misses        438      402      -36     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Releases {netrics} v0.5.0 with substantial new analytic functionality (new measures, motifs, memberships, and regularity methods), plus documentation/tutorial updates and CI/workflow maintenance.

Changes:

  • Added new measures/methods/memberships (cyclicality, compactness, decay/integration centralities, blockmodel inconsistency + direct blockmodelling search, label propagation, clique/biclique participation, ego-composition motifs, RoleSim/REGE regularity).
  • Refactored regular equivalence: node_in_regular() now uses recursive similarity (regularity_*) and the prior census-based behavior is moved to node_in_motif().
  • Updated docs/tutorials/reference index, NEWS/versioning, and modernized GitHub Actions workflow action versions.

Reviewed changes

Copilot reviewed 93 out of 107 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
vignettes/articles/position.Rmd Updates tutorial narrative and examples for net_by_inconsistency()/node_in_block() and the new regularity/motif split.
inst/tutorials/netrics3/position.Rmd Mirrors the position tutorial updates for the bundled tutorial version.
tests/testthat/test-motif_nodes.R Expands motif test exclusions to cover new node motifs requiring attributes.
tests/testthat/test-motif_net.R Adds homophily-specific skips and attribute-only handling in motif-net tests.
tests/testthat/test-motif_composition.R Adds tests for new ego-composition motifs (node_x_ties, node_x_alters, node_x_similarity, net_x_homophily).
tests/testthat/test-motif_cliques.R Adds tests for node_x_clique() on one-mode and two-mode networks and empty networks.
tests/testthat/test-member_equivalence.R Adds coverage for node_in_motif(), regularity methods, updated node_in_regular(), and node_in_block().
tests/testthat/test-member_community.R Adds tests for new node_in_labels() label propagation membership.
tests/testthat/test-measure_fit.R Adds tests for net_by_inconsistency() and relocates fit-related tests from features.
tests/testthat/test-measure_features.R Removes fit-related tests now housed under test-measure_fit.R.
tests/testthat/test-measure_cohesion.R Adds tests for net_by_compactness() and direction-respecting behavior.
tests/testthat/test-measure_closure.R Adds tests for net_by_cyclicality().
tests/testthat/test-measure_centrality.R Adds tests for node_by_decay(), node_by_integration(), and their centralizations.
R/zzz.R Removes CRAN version-check/update prompt from .onAttach() while keeping interactive-only startup behavior.
R/netrics-utils.R Introduces shared local-search perturbation helpers used by membership search algorithms.
R/motif_composition.R Adds ego-composition motifs (node_x_ties, node_x_alters, node_x_similarity) and net_x_homophily().
R/motif_cliques.R Adds node_x_clique() including biclique support for two-mode networks and signed-tie handling.
R/method_regularity.R Adds recursive regularity similarity methods (regularity_rolesim, regularity_rege).
R/member_equivalence.R Updates node_in_regular() to use recursive regularity; adds node_in_motif() and node_in_block().
R/member_community.R Adds node_in_labels() based on igraph label propagation and documents it.
R/member_cliques.R Removes duplicated perturbation helpers now centralized in R/netrics-utils.R.
R/measure_cohesion.R Adds net_by_compactness() and documentation for compactness/global efficiency.
R/measure_closure.R Adds net_by_cyclicality() and documentation contrasting it with transitivity.
R/measure_centrality_closeness.R Adds decay and integration centralities plus decay/integration centralization functions and shared cutoff roxygen.
pkgdown/_pkgdown.yml Reorganizes reference index sections to surface new measure families and pages.
NEWS.md Adds v0.5.0 release notes aligned with the PR description.
NAMESPACE Exports newly added functions across measures, motifs, memberships, and methods.
man/motif_periods.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_path.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_node.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_net.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_homophily.Rd New Rd for net_x_homophily().
man/motif_hierarchy.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_hazard.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_exposure.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_composition.Rd New Rd for ego-composition motifs.
man/motif_clique.Rd New Rd for node_x_clique().
man/motif_brokerage_node.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/motif_brokerage_net.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/method_regularity.Rd New Rd for regularity_rolesim() / regularity_rege().
man/method_kselect.Rd Updates .data parameter docs.
man/method_cluster.Rd Updates .data parameter docs.
man/member_equivalence.Rd Documents new node_in_motif() / node_in_block() and updated node_in_regular() signature/behavior.
man/member_diffusion.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_core.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_components.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_community.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_community_non.Rd Adds node_in_labels() documentation section and references; updates .data parameter docs.
man/member_community_hier.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_cliques.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/member_brokerage.Rd Updates .data parameter docs and adds new motif pages to “See also”.
man/measure_periods.Rd Updates .data parameter docs and links to new measure_fit.
man/measure_hierarchy.Rd Updates .data parameter docs and links to new measure_fit.
man/measure_fragmentation.Rd Updates .data parameter docs and links to new measure_fit.
man/measure_fit.Rd New Rd page separating “fit” measures from intrinsic “features” and documenting net_by_inconsistency().
man/measure_features.Rd Removes core/factions/modularity from “features” page and links to measure_fit.
man/measure_diverse_node.Rd Updates .data parameter docs and links to new motif pages and measure_fit.
man/measure_diverse_net.Rd Updates .data parameter docs and links to new motif pages and measure_fit.
man/measure_diffusion_node.Rd Updates .data parameter docs and links to new motif pages and measure_fit.
man/measure_diffusion_net.Rd Links to new measure_fit.
man/measure_diffusion_infection.Rd Links to new measure_fit.
man/measure_core.Rd Updates .data parameter docs and links to new motif pages and measure_fit.
man/measure_cohesion.Rd Adds net_by_compactness() docs and updates .data parameter docs; links to measure_fit.
man/measure_closure.Rd Adds net_by_cyclicality() docs and updates .data parameter docs; links to measure_fit.
man/measure_closure_node.Rd Updates .data parameter docs; links to measure_fit.
man/measure_centralities_eigen.Rd Updates .data parameter docs; links to measure_fit.
man/measure_centralities_degree.Rd Updates .data parameter docs; links to measure_fit.
man/measure_centralities_close.Rd Updates .data parameter docs; links to measure_fit.
man/measure_centralities_between.Rd Updates .data parameter docs; links to measure_fit.
man/measure_centralisation_eigen.Rd Updates .data parameter docs.
man/measure_centralisation_degree.Rd Updates .data parameter docs.
man/measure_centralisation_close.Rd Adds net_by_decay()/net_by_integration() docs and shared cutoff/decay args; updates .data parameter docs.
man/measure_centralisation_between.Rd Updates .data parameter docs.
man/measure_central_eigen.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_central_degree.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_central_close.Rd Adds node_by_decay()/node_by_integration() docs and shared cutoff/decay args; updates .data parameter docs.
man/measure_central_between.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_brokerage.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_broker_tie.Rd Updates .data parameter docs; links to measure_fit.
man/measure_broker_node.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_breadth.Rd Updates .data parameter docs; links to measure_fit.
man/measure_assort_node.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/measure_assort_net.Rd Updates .data parameter docs; links to new motif pages and measure_fit.
man/mark_triangles.Rd Updates .data parameter docs.
man/mark_ties.Rd Updates .data parameter docs.
man/mark_select_tie.Rd Updates .data parameter docs.
man/mark_select_node.Rd Updates .data parameter docs; links to new motif pages.
man/mark_nodes.Rd Updates .data parameter docs; links to new motif pages.
man/mark_dyads.Rd Updates .data parameter docs.
man/mark_diff.Rd Updates .data parameter docs; links to new motif pages.
man/mark_degree.Rd Updates .data parameter docs; links to new motif pages.
man/mark_core.Rd Updates .data parameter docs; links to new motif pages.
man-roxygen/param_data.R Updates shared .data parameter roxygen template to reference stocnet and as_stocnet().
man-roxygen/param_cutoff.R New shared cutoff parameter template used across multiple docs.
DESCRIPTION Bumps package version to 0.5.0.
.Rbuildignore Ignores Rplots.pdf artifacts in package builds.
.gitignore Adds Rplots.pdf to git ignores.
.github/workflows/pushrelease.yml Updates actions to newer majors and fixes checkout path usage.
.github/workflows/prchecks.yml Updates actions to newer majors.
.github/CONTRIBUTING.md Adds explicit naming conventions for method-helper families and membership naming guidance.
Files not reviewed (7)
  • man/mark_core.Rd: Generated file
  • man/mark_degree.Rd: Generated file
  • man/mark_diff.Rd: Generated file
  • man/mark_dyads.Rd: Generated file
  • man/mark_nodes.Rd: Generated file
  • man/mark_select_node.Rd: Generated file
  • man/mark_select_tie.Rd: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread R/measure_centrality_closeness.R Outdated
Comment on lines +186 to +190
dists <- igraph::distances(manynet::as_igraph(.data),
mode = match.arg(direction))
diag(dists) <- Inf # exclude self from own score
out <- rowSums(decay^(dists-1), na.rm = TRUE) # unreachable contribute 0
if(normalized) out <- out/(manynet::net_nodes(.data)-1)
Comment thread R/member_equivalence.R Outdated
@Kaladani

Copy link
Copy Markdown

I could only briefly check the position tutorial and the nodes_in_motif and nodes_in_regular implementation. They both seem to work as intended, but the question is if nodes_in_motif really is what users could believe it to be: a local approximation of regular equivalence based on the local role ego has in a triad ("role equivalence" after Burt).

And i don't think renaming as nodes_in_local would really change this. The same MAN triad can have multiple roles for ego, e.g.

i -> k -> j

has i as the sender, k as the intermediary and j as the endpoint.

For the flattened networker data set the three approaches result in different partitions:

regular

Regular is relatively coarse here.

motif

Motifs seem to reflect structurally similar communities.

Orbit

Orbits seem to recover local role similarity quite well but is probably too fine grained here.

The last is based on my rcpp version of the orbit counting algorithm I implemented in my local clone of develop. I will make an undirected and tetrad/quad version that also allow taking covariate labels into account for my use. Maybe it would be interesting to add that in a later version of the package, but i don't think it can be fast enough without c++.

Maybe for now it would be a good idea to clarify that nodes_in_motif() just takes triad profiles without taking into account the node's role, which is not the same as in Burt and also different to the orbit-aware tetrard census in Ortman and Brandes.

@Kaladani

Copy link
Copy Markdown

Two things I ran into in R/method_cluster.R while working on #28. The first looks like a
straightforward bug; the second is maybe just clarifying documentation. Neither
is new here but both concern the cluster = argument on the node_in_*() functions, which is.

  1. cluster_cosine() clusters the features, not the nodes

cluster_hierarchical() transposes before correlating; cluster_cosine() doesn't:

cluster_hierarchical <- ... manynet::to_correlation(t(motif))   # n x n  (nodes)
cluster_cosine       <- ... manynet::to_cosine(motif)           # F x F  (features)

So cluster = "cosine" clusters the census columns and returns them as a node membership,
without erroring:

node_in_structural(ison_algebra, cluster = "cosine")
#> 4 groups
#> V1 V2 V3 V4 ...
#> length 96, for a 16-node network

96 is node_x_tie(ison_algebra)'s column count (16 nodes × 2 directions × 3 tie types).
to_cosine(t(motif)) fixes it.

The bug is invisible whenever the census happens to be square.

  1. The @section for cluster_hierarchical() describes a different pipeline

The @section says "a distance matrix is created by subtracting these correlations from 1,
and this is given to stats::hclust()", which describes as.dist(1 - C) —> one profile
comparison. The code inserts stats::dist(), so the clustering runs on distances between the
rows of 1 - C, i.e. a second comparison, on the dissimilarity profiles.

The one-step version is I think more established: sna::sedist() offers correlation, euclidean,
hamming and gamma as alternative ways to make that single comparison: "SE similarity/difference
scores are computed by comparing vertex rows and columns using the measure indicated by
method". And then says "once these similarities/differences are calculated, the results can
be used with a clustering routine (such as equiv.clust)", which duly does
hclust(as.dist(equiv.dist)). On that reading, correlation is a choice of first comparison
rather than something a distance is subsequently taken over.

It might be intentional: clustering the rows of a similarity matrix is not unusual, and
Hoffman's positional-analysis chapter runs kmeans() on exactly such a matrix. But there it
looks like a consequence of kmeans() needing a data matrix rather than a dissimilarity,
and hclust() has no equivalent constraint, since it takes a dist object directly.

It also isn't purely cosmetic: k_silhouette() is the default k and reads hc$distances,
so which pipeline is meant reaches the returned membership, not just the dendrogram.

@jhollway
jhollway merged commit da4503d into main Aug 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clique census functions

3 participants