Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: migraph
Title: Inferential Methods for Multimodal and Other Networks
Version: 1.6.0
Date: 2026-04-04
Version: 1.6.1
Date: 2026-04-14
Description: A set of tools for testing networks.
It includes functions for univariate and multivariate
conditional uniform graph and quadratic assignment procedure testing,
Expand Down
21 changes: 21 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# migraph 1.6.1

2026-04-13

## Package

- Fixed logo sizing and location
- Added tests for `predict()` methods
- Added testing for `{netrics}` tutorials

## Tutorials

- Fixed `run_tute()` and `extract_tute()` to identify and use tutorials in `{netrics}`
- Updated diversity tutorial with new netrics names
- Updated diffusion tutorial with new netrics names
- Updated ergm tutorial with new netrics names

## Testing

- Fixed how `test_fit()` handles diffusion models and non-equal length step results

# migraph 1.6.0

2026-04-04
Expand Down
10 changes: 8 additions & 2 deletions R/model_distrib.R
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,16 @@ test_distribution <- function(diff_model1, diff_model2){
#' @export
test_fit <- function(diff_model, diff_models){ # make into method?
x <- diff_model
if(is_graph(x)) x <- as_diffusion(x)
y <- diff_models
sim <- `0` <- NULL
sims <- y %>% dplyr::select(sim, t, I)
sims <- as.data.frame.matrix(stats::xtabs(I ~ sim + t, sims)) # tidyr::pivot_wider replacement
sims <- y %>% dplyr::select(sim, time, I)
if(max(x$time) < max(sims$time)){
x <- dplyr::bind_rows(x,
dplyr::tibble(time = (max(x$time)+1):max(sims$time),
S = x$S[nrow(x)], I = x$I[nrow(x)]))
}
sims <- as.data.frame.matrix(stats::xtabs(I ~ sim + time, sims)) # tidyr::pivot_wider replacement
sims <- sims[,colSums(stats::cov(sims))!=0]
mah <- stats::mahalanobis(x$I[-1], colMeans(sims), stats::cov(sims))
pval <- pchisq(mah, df=length(x$I[-1]), lower.tail=FALSE)
Expand Down
19 changes: 14 additions & 5 deletions R/tutorial_run.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#' @name tutorials
NULL

stocnet <- c("manynet", "migraph", "autograph")
stocnet <- c("manynet", "migraph", "autograph", "netrics")
Comment thread
jhollway marked this conversation as resolved.

#' @rdname tutorials
#' @export
Expand All @@ -33,12 +33,15 @@ run_tute <- function(tute) {
dplyr::as_tibble(learnr::available_tutorials(package = avail_pkgs[p]),
silent = TRUE) %>% dplyr::select(1:3)
})
dplyr::bind_rows(tutelist) %>% dplyr::arrange(name) %>% print()
dplyr::bind_rows(tutelist) %>%
dplyr::arrange(dplyr::across(dplyr::any_of("name"))) %>%
print()
manynet::snet_info("You can run a tutorial by typing e.g `run_tute('tutorial1')` or `run_tute('Data')` into the console.")
} else {
try(learnr::run_tutorial(tute, "manynet"), silent = TRUE)
try(learnr::run_tutorial(tute, "migraph"), silent = TRUE)
try(learnr::run_tutorial(tute, "autograph"), silent = TRUE)
try(learnr::run_tutorial(tute, "netrics"), silent = TRUE)
try(learnr::run_tutorial(tute, "migraph"), silent = TRUE)
Comment on lines 41 to +44
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

run_tute() now adds an additional package lookup (netrics), but there are no automated tests covering the tutorial resolution / package iteration logic. Consider adding a small test that mocks learnr::run_tutorial (e.g., via testthat::local_mocked_bindings) to assert that run_tute() attempts the expected packages (including netrics) without actually launching a tutorial.

Copilot uses AI. Check for mistakes.
manynet::snet_info("Didn't find a direct match, so looking for close matches...")
tutelist <- lapply(manynet::snet_progress_along(avail_pkgs,
name = "Checking tutorials in stocnet packages"), function(p){
Expand Down Expand Up @@ -71,7 +74,9 @@ extract_tute <- function(tute) {
dplyr::as_tibble(learnr::available_tutorials(package = avail_pkgs[p]),
silent = TRUE) %>% dplyr::select(1:3)
})
dplyr::bind_rows(tutelist) %>% dplyr::arrange(name) %>% print()
dplyr::bind_rows(tutelist) %>%
dplyr::arrange(dplyr::across(dplyr::any_of("name"))) %>%
print()
manynet::snet_info("You can extract the code from one of these tutorials by typing e.g `extract_tute('tutorial1')` into the console.")
} else {
thisRequires("knitr")
Expand All @@ -80,9 +85,13 @@ extract_tute <- function(tute) {
thisRequires("autograph")
pth <- gsub("manynet", "autograph", pth)
}
if(!dir.exists(pth)) {
thisRequires("netrics")
pth <- gsub("autograph", "netrics", pth)
}
if(!dir.exists(pth)) {
thisRequires("migraph")
pth <- gsub("autograph", "migraph", pth)
pth <- gsub("netrics", "migraph", pth)
}
knitr::purl(file.path(pth, list.files(pth, pattern = "*.Rmd")),
documentation = 1)
Expand Down
Binary file added inst/migraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 23 additions & 23 deletions inst/tutorials/tutorial7/diffusion.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -172,18 +172,18 @@ and `graphs()` (at least by default) only graphs the first and last step.
<!-- `grapht()` will show if and when there is complete infection, -->
<!-- but we need to sit through each 'movie'. -->
But there is an easier way.
Play these same diffusions again, this time nesting the call within `net_infection_complete()`.
Play these same diffusions again, this time nesting the call within `net_by_infection_complete()`.

```{r completeinfection, exercise = TRUE, purl = FALSE, fig.width=9}
net_infection_complete(play_diffusion(create_ring(32, width = 2)))
net_infection_complete(play_diffusion(generate_random(32, 0.15)))
net_infection_complete(play_diffusion(generate_scalefree(32, 0.025)))
net_infection_complete(play_diffusion(generate_smallworld(32, 0.025)))
net_by_infection_complete(play_diffusion(create_ring(32, width = 2)))
net_by_infection_complete(play_diffusion(generate_random(32, 0.15)))
net_by_infection_complete(play_diffusion(generate_scalefree(32, 0.025)))
net_by_infection_complete(play_diffusion(generate_smallworld(32, 0.025)))
```

```{r struct-interp, echo = FALSE, purl = FALSE}
question("Does the structure of the network matter for whether and when a diffusion process completes?",
answer("No", message = "Take a closer look at the `net_infection_complete()` results. Are they all the same?"),
answer("No", message = "Take a closer look at the `net_by_infection_complete()` results. Are they all the same?"),
answer("Yes", correct = TRUE, message = "We can see that the different structures have varying outcomes in terms of when the diffusion completes."),
random_answer_order = TRUE,
allow_retry = TRUE
Expand All @@ -203,7 +203,7 @@ You can start the infection in California by specifying `seeds = 5`.
us_diff <- play_diffusion(irps_usgeo, seeds = 5)
plot(us_diff)
graphr(us_diff)
net_infection_complete(us_diff)
net_by_infection_complete(us_diff)
```

What's happening here? Can you interpret this?
Expand Down Expand Up @@ -483,9 +483,9 @@ We could use these on degree centrality, or perhaps some other kind of centralit
sf <- generate_scalefree(32, 0.025)
sf %>%
as_tidygraph() %>%
mutate(degree = ifelse(node_is_max(node_degree(sf)) == TRUE, "max",
ifelse(node_is_min(node_degree(sf)) == TRUE, "min", "others"))) %>%
graphr(node_color = "degree") + guides(color = "legend") + labs(color = "degree")
mutate(degree = ifelse(node_is_max(node_by_degree(sf)) == TRUE, "max",
ifelse(node_is_min(node_by_degree(sf)) == TRUE, "min", "others"))) %>%
graphr(node_color = "degree") + guides(color = "legend")
```

```{r scale, exercise = TRUE, purl = FALSE, exercise.setup="sf", fig.width=9}
Expand All @@ -495,11 +495,11 @@ sf %>%
```{r scale-solution}
plot(play_diffusion(sf, seeds = 10, steps = 10))
plot(play_diffusion(sf, seeds = node_is_random(sf), steps = 10))
plot(play_diffusion(sf, seeds = node_is_max(node_degree(sf)), steps = 10))
plot(play_diffusion(sf, seeds = node_is_min(node_degree(sf)), steps = 10))
plot(play_diffusion(sf, seeds = node_is_max(node_by_degree(sf)), steps = 10))
plot(play_diffusion(sf, seeds = node_is_min(node_by_degree(sf)), steps = 10))

# visualise diffusion in scalefree network
graphs(play_diffusion(sf, seeds = node_is_min(node_degree(sf)), steps = 10))
graphs(play_diffusion(sf, seeds = node_is_min(node_by_degree(sf)), steps = 10))
graphs(play_diffusion(sf, seeds = 16, steps = 10), waves = 1:3)
```

Expand Down Expand Up @@ -713,14 +713,14 @@ It can be interpreted as follows:
- Where $R_0$ = 1, the 'disease' will continue as endemic, if conditions allow.

So how can we establish the $R_0$ here?
We can use `net_reproduction()`.
We can use `net_by_reproduction()`.

```{r r0, exercise = TRUE, exercise.setup = "diffusions", fig.width=9}
rd_diff <- play_diffusion(rando, transmissibility = 0.25, recovery = 0.05)
plot(rd_diff)
# R-nought
net_reproduction(rd_diff)
net_infection_total(rd_diff)
net_by_reproduction(rd_diff)
net_by_infection_total(rd_diff)
```

```{r r0-interp, echo = FALSE, purl = FALSE}
Expand Down Expand Up @@ -762,13 +762,13 @@ the `r gloss("Herd Immunity Threshold", "hit")` or HIT.
HIT indicates the threshold at which the reduction of susceptible members
of the network means that infections will no longer keep increasing,
allowing herd immunity to be achieved.
`net_immunity()` gives us the proportion of the population that would need
`net_by_immunity()` gives us the proportion of the population that would need
to be recovered or vaccinated for the network to have herd immunity.

```{r immunity, exercise = TRUE, exercise.setup = "r0"}
# Herd Immunity Threshold
net_immunity(rd_diff)
net_immunity(rd_diff, normalized = FALSE)
net_by_immunity(rd_diff)
net_by_immunity(rd_diff, normalized = FALSE)
Comment thread
jhollway marked this conversation as resolved.
```

In this model, the HIT score indicates a good proportion of nodes in the network
Expand All @@ -780,7 +780,7 @@ Ok, so let's try this strategy.
rd_diff_vacc <- play_diffusion(rando, transmissibility = 0.25, recovery = 0.05,
immune = 2:9)
plot(rd_diff_vacc)
net_infection_total(rd_diff_vacc)
net_by_infection_total(rd_diff_vacc)
```

We can see that we more rapidly reach a situation in which vaccinated and
Expand Down Expand Up @@ -968,12 +968,12 @@ Which are the highest eigenvector centrality nodes in this network?
```

```{r eigen-hint}
node_eigenvector(ison_networkers)
node_by_eigenvector(ison_networkers)
ison_networkers %>%
mutate(who_to_convince = node_is_max(node_eigenvector(ison_networkers))) %>%
mutate(who_to_convince = node_is_max(node_by_eigenvector(ison_networkers))) %>%
graphr(node_color = who_to_convince)
beliefs2 <- rep(0, net_nodes(ison_networkers))
beliefs2[node_is_max(node_eigenvector(ison_networkers))] <- 1
beliefs2[node_is_max(node_by_eigenvector(ison_networkers))] <- 1
ison_networkers %>% mutate(beliefs = beliefs2) %>% graphr(node_color = "beliefs")
(netlearn2 <- play_learning(ison_networkers, beliefs2))
plot(netlearn2)
Expand Down
Loading
Loading