Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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.1
Date: 2026-04-14
Version: 1.6.2
Date: 2026-04-17
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
1 change: 0 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export(test_fit)
export(test_gof)
export(test_permutation)
export(test_random)
export(test_tutorials)
export(tidy)
Comment thread
jhollway marked this conversation as resolved.
importFrom(autograph,ag_base)
importFrom(dplyr,"%>%")
Expand Down
17 changes: 16 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# migraph 1.6.2

2026-04-17

## Testing

- Fixed namespace issues

## Tutorials

- Added function testing for migraph tutorials
- Added function testing for manynet tutorials (> v2.0.2)
Comment thread
jhollway marked this conversation as resolved.
- Updated examples in solutions in migraph tutorials where errors could creep in
- Skipped extracting some solutions in migraph where errors could creep in

# migraph 1.6.1

2026-04-13
2026-04-14

## Package

Expand Down
2 changes: 1 addition & 1 deletion R/model_distrib.R
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ 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)
if(manynet::is_graph(x)) x <- manynet::as_diffusion(x)
y <- diff_models
sim <- `0` <- NULL
sims <- y %>% dplyr::select(sim, time, I)
Expand Down
34 changes: 0 additions & 34 deletions R/tutorial_test.R

This file was deleted.

2 changes: 1 addition & 1 deletion cran-comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

0 errors | 0 warnings | 0 notes

- Updates to bring autograph into line with latest version of manynet (> v2.0.0)
- Updates to improve testing length
2 changes: 1 addition & 1 deletion inst/tutorials/tutorial0/tutorial0.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
Remove the hash symbol at the start of this line to run it:

```{r comments, exercise = TRUE}
# 1/5 # this will still be commented...

Check warning on line 108 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=108,col=3,[commented_code_linter] Remove commented code.
```

In an R script you can toggle commenting for one or more lines using Cmd-Shift-C/Ctrl-Shift-C.
Expand All @@ -127,7 +127,7 @@
It is important to note that R is case-sensitive,
i.e. `Print("Hello World")` will not work. Try it!

```{r Print-hello-world, exercise = TRUE}
```{r Print-hello-world, exercise = TRUE, purl=FALSE}
Print("Hello World")
```

Expand All @@ -148,9 +148,9 @@
In R, we can write such logical statements as:

```{r equivalence, exercise = TRUE}
"James"=="james" # Try also "James"!="james"

Check warning on line 151 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=151,col=8,[infix_spaces_linter] Put spaces around all infix operators.
# Other logical statements include: ">", ">=", "<=", "<".
# 1 < 5 # Try also "1 <= 5"

Check warning on line 153 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=153,col=3,[commented_code_linter] Remove commented code.
```

Logical values are always either `TRUE` or `FALSE`,
Expand All @@ -168,10 +168,10 @@

```{r assignment, exercise = TRUE}
surname <- "Hollway"
y.chromosome <- T # or TRUE

Check warning on line 171 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=171,col=18,[T_and_F_symbol_linter] Use TRUE instead of the symbol T.

Check warning on line 171 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=171,col=1,[object_name_linter] Variable and function name style should match snake_case or symbols.
siblings <- 1
age <- NA # This is used for missing information
# Note that these objects then appear in RStudio's environment pane (by default the top right)

Check warning on line 174 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=174,col=81,[line_length_linter] Lines should not be more than 80 characters. This line is 94 characters.
```

You can then recover this information by simply calling these objects:
Expand All @@ -186,7 +186,7 @@
And even operate on them:

```{r mult, exercise = TRUE, exercise.setup = "assignment"}
siblings*3

Check warning on line 189 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=189,col=9,[infix_spaces_linter] Put spaces around all infix operators.
# Try multiplying the other objects by 3
```

Expand All @@ -211,10 +211,10 @@
```{r series, exercise = TRUE}
teenageyrs <- 13:19
teenageqrtrs <- seq(13, 19.99, by = 0.25)
# We can recall every third value from this object using a repeating vector

Check warning on line 214 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=214,col=76,[trailing_whitespace_linter] Remove trailing whitespace.
teenageqrtrs
teenageqrtrs[c(FALSE, FALSE, TRUE)]
# teenageqrtrs[c(F, F, T)] # Also works but it is best practice to write out the logic.

Check warning on line 217 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=217,col=81,[line_length_linter] Lines should not be more than 80 characters. This line is 87 characters.

Check warning on line 217 in inst/tutorials/tutorial0/tutorial0.Rmd

View workflow job for this annotation

GitHub Actions / Build for macOS-latest

file=inst/tutorials/tutorial0/tutorial0.Rmd,line=217,col=3,[commented_code_linter] Remove commented code.
```

So R can help us store and recall values and even vectors of values,
Expand Down
22 changes: 11 additions & 11 deletions inst/tutorials/tutorial7/diffusion.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ You can start the infection in California by specifying `seeds = 5`.
```{r usstates-hint}
us_diff <- play_diffusion(irps_usgeo, seeds = 5)
plot(us_diff)
graphr(us_diff)
# graphr(us_diff)
net_by_infection_complete(us_diff)
```

Expand Down Expand Up @@ -577,7 +577,7 @@ to indicate that in only 1/2 cases is contagion successful.
```{r diffusions, exercise = TRUE, fig.width=9}
rando <- generate_random(32, 0.1)
graphr(rando)
plot(play_diffusions(rando, transmissibility = 0.5, times = 5, steps = 10))
plot(play_diffusions(ison_lawfirm, transmissibility = 0.5, times = 5, steps = 10))
```

Note that in this plot the number of new infections is not plotted
Expand Down Expand Up @@ -610,7 +610,7 @@ plot(play_diffusions(____, recovery = ____))
```

```{r sir-solution}
plot(play_diffusions(rando, recovery = 0.2))
plot(play_diffusions(ison_lawfirm, recovery = 0.2))
```

What we see in these kinds of models is typically a spike in infections
Expand All @@ -624,8 +624,8 @@ which should average out these differences and make the results more reliable.

```

```{r sirtimes-solution}
plot(play_diffusions(rando, recovery = 0.2, times = 100))
```{r sirtimes-solution, purl=FALSE}
plot(play_diffusions(ison_lawfirm, recovery = 0.2, times = 100))
```

### SIRS models
Expand All @@ -642,7 +642,7 @@ Play a single diffusion so that you can see what's going on in a particular run.
```

```{r sirs-solution}
plot(play_diffusion(rando, recovery = 0.2, waning = 0.05))
plot(play_diffusion(ison_lawfirm, recovery = 0.2, waning = 0.05))
```

<!-- # visualise diffusion within random graph -->
Expand All @@ -659,7 +659,7 @@ Depending on your particular simulation,
there might be some variation,
so let's run this same diffusion but multiple (100?) times.

```{r sirstimes-solution, exercise.setup = "diffusions", exercise = TRUE, fig.width=9}
```{r sirstimes-solution, exercise.setup = "diffusions", exercise = TRUE, fig.width=9, purl=FALSE}
plot(play_diffusions(rando, recovery = 0.2, waning = 0.05, times = 100))
```

Expand Down Expand Up @@ -689,10 +689,10 @@ Play a single diffusion so that you can see what's going on in a particular run.

```{r seir-solution}
set.seed(123)
plot(play_diffusion(rando, seeds = 10, latency = 0.25, recovery = 0.2))
plot(play_diffusion(ison_lawfirm, seeds = 10, latency = 0.75, recovery = 0.2))

# visualise diffusion with latency and recovery
graphs(play_diffusion(rando, seeds = 10, latency = 0.25, recovery = 0.2), waves = c(1,5,10))
# graphs(play_diffusion(ison_lawfirm, seeds = 10, latency = 0.75, recovery = 0.2), waves = c(1,5,10))
```

## Make it stop
Expand All @@ -716,7 +716,7 @@ So how can we establish the $R_0$ here?
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)
rd_diff <- play_diffusion(ison_lawfirm, transmissibility = 0.25, recovery = 0.05)
plot(rd_diff)
# R-nought
net_by_reproduction(rd_diff)
Expand Down Expand Up @@ -777,7 +777,7 @@ The unnormalised version gives the number of nodes that would need to be vaccina
Ok, so let's try this strategy.

```{r vaccinate, exercise = TRUE, exercise.setup = "diffusions", fig.width=9}
rd_diff_vacc <- play_diffusion(rando, transmissibility = 0.25, recovery = 0.05,
rd_diff_vacc <- play_diffusion(ison_lawfirm, transmissibility = 0.25, recovery = 0.05,
immune = 2:9)
plot(rd_diff_vacc)
net_by_infection_total(rd_diff_vacc)
Expand Down
3 changes: 2 additions & 1 deletion inst/tutorials/tutorial8/diversity.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ marvel_friends
```

```{r friends-solution}
marvel_friends <- to_unsigned(ison_marvel_relationships, keep = "positive")
marvel_friends <- to_uniplex(fict_marvel, "relationship")
marvel_friends <- to_unsigned(marvel_friends, keep = "positive")
marvel_friends <- to_giant(marvel_friends)
marvel_friends <- marvel_friends %>% to_subgraph(Appearances >= mean(Appearances))
marvel_friends
Expand Down
2 changes: 1 addition & 1 deletion inst/tutorials/tutorial9/ergm.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ see papers in e.g. *Social Networks* v.29 and *J Stat Software* v. 24.

Now let's try to fit a triangle model like with the Florentine dataset above:

```{r magnmark1, exercise = TRUE}
```{r magnmark1, exercise = TRUE, purl=FALSE}
magn.mark1 <- ergm(magnolia ~ edges + triangle)
```

Expand Down
27 changes: 0 additions & 27 deletions man/test_tutorials.Rd

This file was deleted.

103 changes: 103 additions & 0 deletions tests/testthat/helper-functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,106 @@ bot5 <- function(res, dec = 4){
unname(round(res, dec))[(lr-4):lr]
} else unname(res)[(lr-2):lr]
}

find_pkg_tutorial_paths <- function(pkg) {
tute_folders <- list.dirs(system.file("tutorials", package = pkg),
recursive = F)
tute_files <- unlist(lapply(tute_folders, function(folder) {
list.files(folder, pattern = "*.Rmd", full.names = TRUE)
}))
tute_files
}

check_tute_rendering <- function(path, quiet = TRUE){

stopifnot(all(file.exists(path)))

for(i in path){
if(!quiet) message("Rendering: ", basename(i))
tryCatch({
rmarkdown::render(input = i,
output_dir = tempdir(),
intermediates_dir = tempdir(), quiet = quiet)
Comment thread
jhollway marked this conversation as resolved.
# Note that the Debian setup on CRAN does not allow for writing files to any
# location other than the temporary directory, which is why we must specify
# tempdir() in the two dir arguments.
if(!quiet) message("Successfully rendered: ", basename(i))
}, error = function(e) {
stop("Failed to render ", i, ": ", e$message, call. = FALSE)
})
}
invisible(NULL)
}

check_tute_functions <- function(path, skip = "ergm\\(", quiet = TRUE){
tmp <- tempfile(fileext = ".R")
knitr::purl(
input = path,
output = tmp,
quiet = TRUE
Comment thread
jhollway marked this conversation as resolved.
Outdated
)
exprs <- parse(tmp) # your purled file
env <- new.env(parent = globalenv())

skip_rest <- FALSE
is_skipped_call <- function(expr) {
any(grepl(skip, deparse(expr)))
}

for (i in seq_along(exprs)) {
if (skip_rest) {
skip(paste("Skipping dependent expressions in", basename(path)))
next
}

if (is_skipped_call(exprs[[i]])) {
skip_rest <- TRUE
skip(paste("Skipping slow functions in", basename(path)))
next
Comment thread
jhollway marked this conversation as resolved.
}

w <- NULL
e <- NULL
m <- NULL

not_out <- withCallingHandlers(
tryCatch(
eval(exprs[[i]], envir = env),
error = function(err) {
e <<- err
NULL
}
),
warning = function(wrn) {
w <<- wrn
invokeRestart("muffleWarning")
},
message = function(msg) {
m <<- c(m, conditionMessage(msg))
invokeRestart("muffleMessage")
}
)
Comment thread
jhollway marked this conversation as resolved.

# If there *was* a warning, check if it's a deprecated/defunct one
if (!is.null(w)) {
msg <- conditionMessage(w)

# Only fail if it's a deprecated/defunct warning
if (!grepl("deprecate|defunct|moved", msg, ignore.case = TRUE)) {
w <- NULL
}
}

# Now test what happened
expect_null(
e,
info = paste0("Error in expression ", i,
" of ", basename(path), ": ", deparse(exprs[[i]]))
)

expect_null(
w,
info = paste("Warning in expression", i, ":", deparse(exprs[[i]]))
)
}
}
2 changes: 1 addition & 1 deletion tests/testthat/test-model_distrib.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ test_that("test_distribution works", {
test_that("test_fit works", {
x <- play_diffusion(generate_random(15), transmissibility = 0.7)
y <- play_diffusions(generate_random(15), transmissibility = 0.1, times = 40)
res <- test_fit(as_diffusion(x), y)
res <- test_fit(x, y)
expect_output(print(res), "statistic")
})
4 changes: 2 additions & 2 deletions tests/testthat/test-model_predict.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
test_that("predict.netlm works", {
networkers <- ison_networkers %>% to_subgraph(Discipline == "Sociology")
model1 <- net_regression(weight ~ ego(Citations) + alter(Citations) + sim(Citations),
networkers, times = 10)
networkers, times = 5)
pred <- predict(model1, matrix(c(1,10,5,2),1,4))
expect_length(pred, 1)
expect_type(pred, "double")
Expand All @@ -11,7 +11,7 @@ test_that("predict.netlogit works", {
networkers <- ison_networkers %>% to_subgraph(Discipline == "Sociology") %>%
to_unweighted()
model1 <- net_regression(. ~ ego(Citations) + alter(Citations) + sim(Citations),
networkers, times = 10)
networkers, times = 5)
pred_link <- predict(model1, matrix(c(1,10,5,2),1,4), type = "link")
pred_response <- predict(model1, matrix(c(1,10,5,2),1,4), type = "response")

Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-tutorials_autograph.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ test_that("autograph tutorials work", {
for(tute.dir in list.dirs(system.file("tutorials", package = "autograph"),
recursive = F)){
tute.file <- list.files(tute.dir, pattern = "*.Rmd", full.names = T)
expect_null(test_tutorials(tute.file))
expect_null(check_tute_rendering(tute.file))
}
})

16 changes: 11 additions & 5 deletions tests/testthat/test-tutorials_manynet.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
test_that("manynet tutorials work", {
for(tute.dir in list.dirs(system.file("tutorials", package = "manynet"),
recursive = F)){
tute.file <- list.files(tute.dir, pattern = "*.Rmd", full.names = T)
expect_null(test_tutorials(tute.file))
for(tute in find_pkg_tutorial_paths("manynet")){
expect_null(check_tute_rendering(tute))
}
})
})

test_that("manynet tutorial code runs without warnings or errors", {
skip_if_not_installed("manynet", minimum_version = "2.0.2")
for(tute in find_pkg_tutorial_paths("manynet")){
expect_null(check_tute_functions(tute),
info = paste("Error in tutorial", basename(tute)))
}
})
Loading
Loading