From c75739cd37bd3957e30def7c3437ebaf9c25027b Mon Sep 17 00:00:00 2001 From: schochastics Date: Wed, 19 Feb 2025 10:55:35 +0100 Subject: [PATCH 1/5] refactor and merge conversion.R tests Part 1 --- tests/testthat/test-conversion.R | 239 +++++++++++++++++++++++++ tests/testthat/test-get.adjacency.R | 25 --- tests/testthat/test-get.adjlist.R | 77 -------- tests/testthat/test-get.edgelist.R | 6 - tests/testthat/test-get.incidence.R | 30 ---- tests/testthat/test-graph.adjlist.R | 13 -- tests/testthat/test-graph.data.frame.R | 16 -- tests/testthat/test-graph.edgelist.R | 26 --- tests/testthat/test-graphNEL.R | 39 ---- 9 files changed, 239 insertions(+), 232 deletions(-) delete mode 100644 tests/testthat/test-get.adjacency.R delete mode 100644 tests/testthat/test-get.adjlist.R delete mode 100644 tests/testthat/test-get.edgelist.R delete mode 100644 tests/testthat/test-get.incidence.R delete mode 100644 tests/testthat/test-graph.adjlist.R delete mode 100644 tests/testthat/test-graph.edgelist.R delete mode 100644 tests/testthat/test-graphNEL.R diff --git a/tests/testthat/test-conversion.R b/tests/testthat/test-conversion.R index 5ea157bb12..4206e0467a 100644 --- a/tests/testthat/test-conversion.R +++ b/tests/testthat/test-conversion.R @@ -297,3 +297,242 @@ test_that("as_biadjacency_matrix() works -- dense + weights", { ) expect_equal(as_unnamed_dense_matrix(A), as_unnamed_dense_matrix(mat)) }) + +test_that("as_adj works", { + g <- sample_gnp(50, 1 / 50) + A <- as_adjacency_matrix(g, sparse = FALSE) + g2 <- graph_from_adjacency_matrix(A, mode = "undirected") + expect_isomorphic(g, g2) + + ### + + A <- as_adjacency_matrix(g, sparse = TRUE) + g2 <- graph_from_adjacency_matrix(A, mode = "undirected") + expect_isomorphic(g, g2) + + ### + + g <- sample_gnp(50, 2 / 50, directed = TRUE) + A <- as_adjacency_matrix(g, sparse = FALSE) + g2 <- graph_from_adjacency_matrix(A) + expect_isomorphic(g, g2) + + ### + + A <- as_adjacency_matrix(g, sparse = TRUE) + g2 <- graph_from_adjacency_matrix(A) + expect_isomorphic(g, g2) +}) + +test_that("as_adj_list works", { + g <- sample_gnp(50, 2 / 50) + al <- as_adj_list(g) + expect_s3_class(al[[1]], "igraph.vs") + g2 <- graph_from_adj_list(al, mode = "all") + expect_isomorphic(g, g2) + expect_true(isomorphic(g, g2, + method = "vf2", + vertex.color1 = 1:vcount(g), + vertex.color2 = 1:vcount(g2) + )) + + #### + + el <- as_adj_edge_list(g) + expect_s3_class(el[[1]], "igraph.es") + for (i in 1:vcount(g)) { + a <- E(g)[.inc(i)] + expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) + expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) + } + + g <- sample_gnp(50, 4 / 50, directed = TRUE) + el1 <- as_adj_edge_list(g, mode = "out") + el2 <- as_adj_edge_list(g, mode = "in") + for (i in 1:vcount(g)) { + a <- E(g)[.from(i)] + expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) + expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) + } + for (i in 1:vcount(g)) { + a <- E(g)[.to(i)] + expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) + expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) + } +}) + + + +test_that("as_adj_list works when return.vs.es is FALSE", { + on.exit(try(igraph_options(old)), add = TRUE) + old <- igraph_options(return.vs.es = FALSE) + + g <- sample_gnp(50, 2 / 50) + al <- as_adj_list(g) + expect_s3_class(al[[1]], NA) + g2 <- graph_from_adj_list(al, mode = "all") + expect_isomorphic(g, g2) + expect_true(isomorphic(g, g2, + method = "vf2", + vertex.color1 = 1:vcount(g), + vertex.color2 = 1:vcount(g2) + )) + + #### + + el <- as_adj_edge_list(g) + for (i in 1:vcount(g)) { + a <- E(g)[.inc(i)] + expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) + expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) + } + + g <- sample_gnp(50, 4 / 50, directed = TRUE) + el1 <- as_adj_edge_list(g, mode = "out") + el2 <- as_adj_edge_list(g, mode = "in") + for (i in 1:vcount(g)) { + a <- E(g)[.from(i)] + expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) + expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) + } + for (i in 1:vcount(g)) { + a <- E(g)[.to(i)] + expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) + expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) + } +}) + +test_that("as_edgelist works", { + g <- sample_gnp(100, 3 / 100) + e <- as_edgelist(g) + g2 <- make_graph(t(e), n = vcount(g), dir = FALSE) + expect_isomorphic(g, g2) +}) + +test_that("as_biadjacency_matrix() works -- dense", { + I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(I) + I2 <- as_biadjacency_matrix(g) + expect_equal(I, I2, ignore_attr = TRUE) + expect_identical(rownames(I2), as.character(1:7)) + expect_identical(colnames(I2), as.character(8:12)) +}) + +test_that("as_biadjacency_matrix() works -- dense named", { + I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(I) + V(g)$name <- letters[1:length(V(g))] + + expect_true(is_named(g)) + + I2 <- as_biadjacency_matrix(g) + expect_equal(I, I2, ignore_attr = TRUE) + expect_identical(rownames(I2), c("a", "b", "c", "d", "e", "f", "g")) + expect_identical(colnames(I2), c("h", "i", "j", "k", "l")) +}) + +test_that("as_biadjacency_matrix() works -- sparse", { + I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(I) + I3 <- as_biadjacency_matrix(g, sparse = TRUE) + expect_equal(as.matrix(I3), I, ignore_attr = TRUE) + expect_identical(rownames(I3), as.character(1:7)) + expect_identical(colnames(I3), as.character(8:12)) +}) + +test_that("graph_from_adj_list works", { + g <- sample_gnp(100, 3 / 100) + al <- as_adj_list(g) + g2 <- graph_from_adj_list(al, mode = "all") + expect_isomorphic(g, g2) + + ## + + g <- sample_gnp(100, 3 / 100, directed = TRUE) + al <- as_adj_list(g, mode = "out") + g2 <- graph_from_adj_list(al, mode = "out") + expect_isomorphic(g, g2) +}) + +test_that("graph_from_edgelist works", { + withr::local_seed(20230115) + + g <- sample_gnp(50, 5 / 50) + el <- as_edgelist(g) + g2 <- graph_from_edgelist(el, directed = FALSE) + expect_isomorphic(g, g2) + + #### + + g <- sample_gnp(50, 5 / 50, directed = TRUE) + el <- as_edgelist(g) + g2 <- graph_from_edgelist(el, directed = TRUE) + expect_isomorphic(g, g2) + + #### + + g <- sample_gnp(26, 5 / 26, directed = TRUE) + el <- as_edgelist(g) + n <- letters[1:26] + names(n) <- 1:26 + mode(el) <- "character" + el[] <- n[el] + g2 <- graph_from_edgelist(el, directed = TRUE) + expect_isomorphic(g, g2) +}) + +test_that("graphNEL conversion works", { + skip_if_not_installed("graph") + + set.seed(20250122) + + g <- sample_gnp(100, 5 / 100) + N <- as_graphnel(g) + g2 <- graph_from_graphnel(N) + gi <- isomorphic(g, g2, method = "vf2") + expect_true(gi) + + ## Attributes + + V(g)$name <- as.character(vcount(g):1) + E(g)$weight <- sample(1:10, ecount(g), replace = TRUE) + g$name <- "Foobar" + + N <- as_graphnel(g) + g2 <- graph_from_graphnel(N) + expect_isomorphic(g, g2) + expect_equal(V(g)$name, V(g2)$name) + + A <- as_adjacency_matrix(g, attr = "weight", sparse = FALSE) + A2 <- as_adjacency_matrix(g2, attr = "weight", sparse = FALSE) + expect_equal(A, A) + expect_equal(g$name, g2$name) +}) + +test_that("graphNEL does not duplicate loop edges", { + skip_if_not_installed("graph") + + mat <- matrix(c(1, 0.5, 0.5, 0), nrow = 2) + dimnames(mat) <- list(c("A", "B"), c("A", "B")) + + igr <- graph_from_adjacency_matrix(mat, mode = "undirected", weighted = T) + + grNEL <- as_graphnel(igr) + expect_equal(graph::edgeL(grNEL)$A$edges, c(1, 2)) +}) + +test_that("as_long_data_frame() works correctly with and without names", { + expect_snapshot({ + ring <- make_ring(3) + as_long_data_frame(ring) + + V(ring)$name <- letters[1:3] + as_long_data_frame(ring) + + V(ring)$score <- LETTERS[1:3] + as_long_data_frame(ring) + + E(ring)$info <- 3:1 + as_long_data_frame(ring) + }) +}) diff --git a/tests/testthat/test-get.adjacency.R b/tests/testthat/test-get.adjacency.R deleted file mode 100644 index 34cf447800..0000000000 --- a/tests/testthat/test-get.adjacency.R +++ /dev/null @@ -1,25 +0,0 @@ -test_that("as_adj works", { - g <- sample_gnp(50, 1 / 50) - A <- as_adjacency_matrix(g, sparse = FALSE) - g2 <- graph_from_adjacency_matrix(A, mode = "undirected") - expect_isomorphic(g, g2) - - ### - - A <- as_adjacency_matrix(g, sparse = TRUE) - g2 <- graph_from_adjacency_matrix(A, mode = "undirected") - expect_isomorphic(g, g2) - - ### - - g <- sample_gnp(50, 2 / 50, directed = TRUE) - A <- as_adjacency_matrix(g, sparse = FALSE) - g2 <- graph_from_adjacency_matrix(A) - expect_isomorphic(g, g2) - - ### - - A <- as_adjacency_matrix(g, sparse = TRUE) - g2 <- graph_from_adjacency_matrix(A) - expect_isomorphic(g, g2) -}) diff --git a/tests/testthat/test-get.adjlist.R b/tests/testthat/test-get.adjlist.R deleted file mode 100644 index 2a80effdaa..0000000000 --- a/tests/testthat/test-get.adjlist.R +++ /dev/null @@ -1,77 +0,0 @@ -test_that("as_adj_list works", { - g <- sample_gnp(50, 2 / 50) - al <- as_adj_list(g) - expect_s3_class(al[[1]], "igraph.vs") - g2 <- graph_from_adj_list(al, mode = "all") - expect_isomorphic(g, g2) - expect_true(isomorphic(g, g2, - method = "vf2", - vertex.color1 = 1:vcount(g), - vertex.color2 = 1:vcount(g2) - )) - - #### - - el <- as_adj_edge_list(g) - expect_s3_class(el[[1]], "igraph.es") - for (i in 1:vcount(g)) { - a <- E(g)[.inc(i)] - expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) - expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) - } - - g <- sample_gnp(50, 4 / 50, directed = TRUE) - el1 <- as_adj_edge_list(g, mode = "out") - el2 <- as_adj_edge_list(g, mode = "in") - for (i in 1:vcount(g)) { - a <- E(g)[.from(i)] - expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) - expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) - } - for (i in 1:vcount(g)) { - a <- E(g)[.to(i)] - expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) - expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) - } -}) - - - -test_that("as_adj_list works when return.vs.es is FALSE", { - on.exit(try(igraph_options(old)), add = TRUE) - old <- igraph_options(return.vs.es = FALSE) - - g <- sample_gnp(50, 2 / 50) - al <- as_adj_list(g) - expect_s3_class(al[[1]], NA) - g2 <- graph_from_adj_list(al, mode = "all") - expect_isomorphic(g, g2) - expect_true(isomorphic(g, g2, - method = "vf2", - vertex.color1 = 1:vcount(g), - vertex.color2 = 1:vcount(g2) - )) - - #### - - el <- as_adj_edge_list(g) - for (i in 1:vcount(g)) { - a <- E(g)[.inc(i)] - expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) - expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) - } - - g <- sample_gnp(50, 4 / 50, directed = TRUE) - el1 <- as_adj_edge_list(g, mode = "out") - el2 <- as_adj_edge_list(g, mode = "in") - for (i in 1:vcount(g)) { - a <- E(g)[.from(i)] - expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) - expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) - } - for (i in 1:vcount(g)) { - a <- E(g)[.to(i)] - expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) - expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) - } -}) diff --git a/tests/testthat/test-get.edgelist.R b/tests/testthat/test-get.edgelist.R deleted file mode 100644 index f3e4bae951..0000000000 --- a/tests/testthat/test-get.edgelist.R +++ /dev/null @@ -1,6 +0,0 @@ -test_that("as_edgelist works", { - g <- sample_gnp(100, 3 / 100) - e <- as_edgelist(g) - g2 <- make_graph(t(e), n = vcount(g), dir = FALSE) - expect_isomorphic(g, g2) -}) diff --git a/tests/testthat/test-get.incidence.R b/tests/testthat/test-get.incidence.R deleted file mode 100644 index a750290c07..0000000000 --- a/tests/testthat/test-get.incidence.R +++ /dev/null @@ -1,30 +0,0 @@ -test_that("as_biadjacency_matrix() works -- dense", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) - I2 <- as_biadjacency_matrix(g) - expect_equal(I, I2, ignore_attr = TRUE) - expect_identical(rownames(I2), as.character(1:7)) - expect_identical(colnames(I2), as.character(8:12)) -}) - -test_that("as_biadjacency_matrix() works -- dense named", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) - V(g)$name <- letters[1:length(V(g))] - - expect_true(is_named(g)) - - I2 <- as_biadjacency_matrix(g) - expect_equal(I, I2, ignore_attr = TRUE) - expect_identical(rownames(I2), c("a", "b", "c", "d", "e", "f", "g")) - expect_identical(colnames(I2), c("h", "i", "j", "k", "l")) -}) - -test_that("as_biadjacency_matrix() works -- sparse", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) - I3 <- as_biadjacency_matrix(g, sparse = TRUE) - expect_equal(as.matrix(I3), I, ignore_attr = TRUE) - expect_identical(rownames(I3), as.character(1:7)) - expect_identical(colnames(I3), as.character(8:12)) -}) diff --git a/tests/testthat/test-graph.adjlist.R b/tests/testthat/test-graph.adjlist.R deleted file mode 100644 index 249030112c..0000000000 --- a/tests/testthat/test-graph.adjlist.R +++ /dev/null @@ -1,13 +0,0 @@ -test_that("graph_from_adj_list works", { - g <- sample_gnp(100, 3 / 100) - al <- as_adj_list(g) - g2 <- graph_from_adj_list(al, mode = "all") - expect_isomorphic(g, g2) - - ## - - g <- sample_gnp(100, 3 / 100, directed = TRUE) - al <- as_adj_list(g, mode = "out") - g2 <- graph_from_adj_list(al, mode = "out") - expect_isomorphic(g, g2) -}) diff --git a/tests/testthat/test-graph.data.frame.R b/tests/testthat/test-graph.data.frame.R index 89f1e05868..27a1a74bdc 100644 --- a/tests/testthat/test-graph.data.frame.R +++ b/tests/testthat/test-graph.data.frame.R @@ -44,19 +44,3 @@ test_that("graph_from_data_frame works on matrices", { el2 <- as_data_frame(g) expect_equal(as.data.frame(el), el2, ignore_attr = TRUE) }) - -test_that("as_long_data_frame() works correctly with and without names", { - expect_snapshot({ - ring <- make_ring(3) - as_long_data_frame(ring) - - V(ring)$name <- letters[1:3] - as_long_data_frame(ring) - - V(ring)$score <- LETTERS[1:3] - as_long_data_frame(ring) - - E(ring)$info <- 3:1 - as_long_data_frame(ring) - }) -}) diff --git a/tests/testthat/test-graph.edgelist.R b/tests/testthat/test-graph.edgelist.R deleted file mode 100644 index 21086e4721..0000000000 --- a/tests/testthat/test-graph.edgelist.R +++ /dev/null @@ -1,26 +0,0 @@ -test_that("graph_from_edgelist works", { - withr::local_seed(20230115) - - g <- sample_gnp(50, 5 / 50) - el <- as_edgelist(g) - g2 <- graph_from_edgelist(el, directed = FALSE) - expect_isomorphic(g, g2) - - #### - - g <- sample_gnp(50, 5 / 50, directed = TRUE) - el <- as_edgelist(g) - g2 <- graph_from_edgelist(el, directed = TRUE) - expect_isomorphic(g, g2) - - #### - - g <- sample_gnp(26, 5 / 26, directed = TRUE) - el <- as_edgelist(g) - n <- letters[1:26] - names(n) <- 1:26 - mode(el) <- "character" - el[] <- n[el] - g2 <- graph_from_edgelist(el, directed = TRUE) - expect_isomorphic(g, g2) -}) diff --git a/tests/testthat/test-graphNEL.R b/tests/testthat/test-graphNEL.R deleted file mode 100644 index f0f4145707..0000000000 --- a/tests/testthat/test-graphNEL.R +++ /dev/null @@ -1,39 +0,0 @@ -test_that("graphNEL conversion works", { - skip_if_not_installed("graph") - - set.seed(20250122) - - g <- sample_gnp(100, 5 / 100) - N <- as_graphnel(g) - g2 <- graph_from_graphnel(N) - gi <- isomorphic(g, g2, method = "vf2") - expect_true(gi) - - ## Attributes - - V(g)$name <- as.character(vcount(g):1) - E(g)$weight <- sample(1:10, ecount(g), replace = TRUE) - g$name <- "Foobar" - - N <- as_graphnel(g) - g2 <- graph_from_graphnel(N) - expect_isomorphic(g, g2) - expect_equal(V(g)$name, V(g2)$name) - - A <- as_adjacency_matrix(g, attr = "weight", sparse = FALSE) - A2 <- as_adjacency_matrix(g2, attr = "weight", sparse = FALSE) - expect_equal(A, A) - expect_equal(g$name, g2$name) -}) - -test_that("graphNEL does not duplicate loop edges", { - skip_if_not_installed("graph") - - mat <- matrix(c(1, 0.5, 0.5, 0), nrow = 2) - dimnames(mat) <- list(c("A", "B"), c("A", "B")) - - igr <- graph_from_adjacency_matrix(mat, mode = "undirected", weighted = T) - - grNEL <- as_graphnel(igr) - expect_equal(graph::edgeL(grNEL)$A$edges, c(1, 2)) -}) From caca75152f669b05ce200ef123898c7ac8c14d24 Mon Sep 17 00:00:00 2001 From: schochastics Date: Wed, 19 Feb 2025 13:45:31 +0100 Subject: [PATCH 2/5] merged data.frame.R into conversion.R --- R/conversion.R | 291 +++++++++++++++++++++++++ R/data_frame.R | 290 ------------------------ tests/testthat/test-conversion.R | 47 ++++ tests/testthat/test-graph.data.frame.R | 46 ---- 4 files changed, 338 insertions(+), 336 deletions(-) delete mode 100644 R/data_frame.R delete mode 100644 tests/testthat/test-graph.data.frame.R diff --git a/R/conversion.R b/R/conversion.R index 808d19ab96..53fb7cbed2 100644 --- a/R/conversion.R +++ b/R/conversion.R @@ -1218,3 +1218,294 @@ as.undirected <- function(graph, lifecycle::deprecate_soft("2.1.0", "as.undirected()", "as_undirected()") as_undirected(graph = graph, mode = mode, edge.attr.comb = edge.attr.comb) } + +#' Create a graph from an edge list matrix +#' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' `graph.edgelist()` was renamed to `graph_from_edgelist()` to create a more +#' consistent API. +#' @inheritParams graph_from_edgelist +#' @keywords internal +#' @export +graph.edgelist <- function(el, directed = TRUE) { # nocov start + lifecycle::deprecate_soft("2.0.0", "graph.edgelist()", "graph_from_edgelist()") + graph_from_edgelist(el = el, directed = directed) +} # nocov end + +#' Creating igraph graphs from data frames or vice-versa +#' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' `graph.data.frame()` was renamed to `graph_from_data_frame()` to create a more +#' consistent API. +#' @inheritParams graph_from_data_frame +#' @keywords internal +#' @export +graph.data.frame <- function(d, directed = TRUE, vertices = NULL) { # nocov start + lifecycle::deprecate_soft("2.0.0", "graph.data.frame()", "graph_from_data_frame()") + graph_from_data_frame(d = d, directed = directed, vertices = vertices) +} # nocov end + +## ---------------------------------------------------------------- +## +## IGraph R package +## Copyright (C) 2005-2014 Gabor Csardi +## 334 Harvard street, Cambridge, MA 02139 USA +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301 USA +## +## ----------------------------------------------------------------- + +#' Creating igraph graphs from data frames or vice-versa +#' +#' This function creates an igraph graph from one or two data frames containing +#' the (symbolic) edge list and edge/vertex attributes. +#' +#' `graph_from_data_frame()` creates igraph graphs from one or two data frames. +#' It has two modes of operation, depending whether the `vertices` +#' argument is `NULL` or not. +#' +#' If `vertices` is `NULL`, then the first two columns of `d` +#' are used as a symbolic edge list and additional columns as edge attributes. +#' The names of the attributes are taken from the names of the columns. +#' +#' If `vertices` is not `NULL`, then it must be a data frame giving +#' vertex metadata. The first column of `vertices` is assumed to contain +#' symbolic vertex names, this will be added to the graphs as the +#' \sQuote{`name`} vertex attribute. Other columns will be added as +#' additional vertex attributes. If `vertices` is not `NULL` then the +#' symbolic edge list given in `d` is checked to contain only vertex names +#' listed in `vertices`. +#' +#' Typically, the data frames are exported from some spreadsheet software like +#' Excel and are imported into R via [read.table()], +#' [read.delim()] or [read.csv()]. +#' +#' All edges in the data frame are included in the graph, which may include +#' multiple parallel edges and loops. +#' +#' `as_data_frame()` converts the igraph graph into one or more data +#' frames, depending on the `what` argument. +#' +#' If the `what` argument is `edges` (the default), then the edges of +#' the graph and also the edge attributes are returned. The edges will be in +#' the first two columns, named `from` and `to`. (This also denotes +#' edge direction for directed graphs.) For named graphs, the vertex names +#' will be included in these columns, for other graphs, the numeric vertex ids. +#' The edge attributes will be in the other columns. It is not a good idea to +#' have an edge attribute named `from` or `to`, because then the +#' column named in the data frame will not be unique. The edges are listed in +#' the order of their numeric ids. +#' +#' If the `what` argument is `vertices`, then vertex attributes are +#' returned. Vertices are listed in the order of their numeric vertex ids. +#' +#' If the `what` argument is `both`, then both vertex and edge data +#' is returned, in a list with named entries `vertices` and `edges`. +#' +#' @param d A data frame containing a symbolic edge list in the first two +#' columns. Additional columns are considered as edge attributes. Since +#' version 0.7 this argument is coerced to a data frame with +#' `as.data.frame`. +#' @param directed Logical scalar, whether or not to create a directed graph. +#' @param vertices A data frame with vertex metadata, or `NULL`. See +#' details below. Since version 0.7 this argument is coerced to a data frame +#' with `as.data.frame`, if not `NULL`. +#' @return An igraph graph object for `graph_from_data_frame()`, and either a +#' data frame or a list of two data frames named `edges` and +#' `vertices` for `as.data.frame`. +#' @note For `graph_from_data_frame()` `NA` elements in the first two +#' columns \sQuote{d} are replaced by the string \dQuote{NA} before creating +#' the graph. This means that all `NA`s will correspond to a single +#' vertex. +#' +#' `NA` elements in the first column of \sQuote{vertices} are also +#' replaced by the string \dQuote{NA}, but the rest of \sQuote{vertices} is not +#' touched. In other words, vertex names (=the first column) cannot be +#' `NA`, but other vertex attributes can. +#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} +#' @seealso [graph_from_literal()] +#' for another way to create graphs, [read.table()] to read in tables +#' from files. +#' @keywords graphs +#' @examples +#' +#' ## A simple example with a couple of actors +#' ## The typical case is that these tables are read in from files.... +#' actors <- data.frame( +#' name = c( +#' "Alice", "Bob", "Cecil", "David", +#' "Esmeralda" +#' ), +#' age = c(48, 33, 45, 34, 21), +#' gender = c("F", "M", "F", "M", "F") +#' ) +#' relations <- data.frame( +#' from = c( +#' "Bob", "Cecil", "Cecil", "David", +#' "David", "Esmeralda" +#' ), +#' to = c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"), +#' same.dept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE), +#' friendship = c(4, 5, 5, 2, 1, 1), advice = c(4, 5, 5, 4, 2, 3) +#' ) +#' g <- graph_from_data_frame(relations, directed = TRUE, vertices = actors) +#' print(g, e = TRUE, v = TRUE) +#' +#' ## The opposite operation +#' as_data_frame(g, what = "vertices") +#' as_data_frame(g, what = "edges") +#' +#' @export +graph_from_data_frame <- function(d, directed = TRUE, vertices = NULL) { + d <- as.data.frame(d) + if (!is.null(vertices)) { + vertices <- as.data.frame(vertices) + } + + if (ncol(d) < 2) { + stop("the data frame should contain at least two columns") + } + + ## Handle if some elements are 'NA' + if (any(is.na(d[, 1:2]))) { + cli::cli_warn("In {.code d}, {.code NA} elements were replaced with string {.str NA}.") + d[, 1:2][is.na(d[, 1:2])] <- "NA" + } + if (!is.null(vertices) && any(is.na(vertices[, 1]))) { + cli::cli_warn("In {.code vertices[,1]}, {.code NA} elements were replaced with string {.str NA}.") + vertices[, 1][is.na(vertices[, 1])] <- "NA" + } + + names <- unique(c(as.character(d[, 1]), as.character(d[, 2]))) + if (!is.null(vertices)) { + names2 <- names + vertices <- as.data.frame(vertices) + if (ncol(vertices) < 1) { + stop("Vertex data frame contains no rows") + } + names <- as.character(vertices[, 1]) + if (any(duplicated(names))) { + stop("Duplicate vertex names") + } + if (any(!names2 %in% names)) { + stop("Some vertex names in edge list are not listed in vertex data frame") + } + } + + # create graph + g <- make_empty_graph(n = 0, directed = directed) + + # vertex attributes + attrs <- list(name = names) + if (!is.null(vertices)) { + if (ncol(vertices) > 1) { + for (i in 2:ncol(vertices)) { + newval <- vertices[, i] + if (inherits(newval, "factor")) { + newval <- as.character(newval) + } + attrs[[names(vertices)[i]]] <- newval + } + } + } + + # add vertices + g <- add_vertices(g, length(names), attr = attrs) + + # create edge list + from <- as.character(d[, 1]) + to <- as.character(d[, 2]) + edges <- rbind(match(from, names), match(to, names)) + + # edge attributes + attrs <- list() + if (ncol(d) > 2) { + for (i in 3:ncol(d)) { + newval <- d[, i] + if (inherits(newval, "factor")) { + newval <- as.character(newval) + } + attrs[[names(d)[i]]] <- newval + } + } + + # add the edges + g <- add_edges(g, edges, attr = attrs) + g +} + +#' @rdname graph_from_data_frame +#' @param ... Passed to `graph_from_data_frame()`. +#' @export +from_data_frame <- function(...) constructor_spec(graph_from_data_frame, ...) + +## ----------------------------------------------------------------- + +#' Create a graph from an edge list matrix +#' +#' `graph_from_edgelist()` creates a graph from an edge list. Its argument +#' is a two-column matrix, each row defines one edge. If it is +#' a numeric matrix then its elements are interpreted as vertex ids. If +#' it is a character matrix then it is interpreted as symbolic vertex +#' names and a vertex id will be assigned to each name, and also a +#' `name` vertex attribute will be added. +#' +#' @concept Edge list +#' @param el The edge list, a two column matrix, character or numeric. +#' @param directed Whether to create a directed graph. +#' @return An igraph graph. +#' +#' @family deterministic constructors +#' @export +#' @examples +#' el <- matrix(c("foo", "bar", "bar", "foobar"), nc = 2, byrow = TRUE) +#' graph_from_edgelist(el) +#' +#' # Create a ring by hand +#' graph_from_edgelist(cbind(1:10, c(2:10, 1))) +graph_from_edgelist <- function(el, directed = TRUE) { + if (!is.matrix(el) || ncol(el) != 2) { + stop("graph_from_edgelist expects a matrix with two columns") + } + + if (nrow(el) == 0) { + res <- make_empty_graph(directed = directed) + } else { + if (is.character(el)) { + ## symbolic edge list + names <- unique(as.character(t(el))) + ids <- seq(names) + names(ids) <- names + res <- make_graph(unname(ids[t(el)]), directed = directed) + rm(ids) + V(res)$name <- names + } else { + ## normal edge list + res <- make_graph(t(el), directed = directed) + } + } + + res +} + +#' @rdname graph_from_edgelist +#' @param ... Passed to `graph_from_edgelist()`. +#' @export +from_edgelist <- function(...) constructor_spec(graph_from_edgelist, ...) diff --git a/R/data_frame.R b/R/data_frame.R deleted file mode 100644 index e54711ecc4..0000000000 --- a/R/data_frame.R +++ /dev/null @@ -1,290 +0,0 @@ -#' Create a graph from an edge list matrix -#' -#' @description -#' `r lifecycle::badge("deprecated")` -#' -#' `graph.edgelist()` was renamed to `graph_from_edgelist()` to create a more -#' consistent API. -#' @inheritParams graph_from_edgelist -#' @keywords internal -#' @export -graph.edgelist <- function(el, directed = TRUE) { # nocov start - lifecycle::deprecate_soft("2.0.0", "graph.edgelist()", "graph_from_edgelist()") - graph_from_edgelist(el = el, directed = directed) -} # nocov end - -#' Creating igraph graphs from data frames or vice-versa -#' -#' @description -#' `r lifecycle::badge("deprecated")` -#' -#' `graph.data.frame()` was renamed to `graph_from_data_frame()` to create a more -#' consistent API. -#' @inheritParams graph_from_data_frame -#' @keywords internal -#' @export -graph.data.frame <- function(d, directed = TRUE, vertices = NULL) { # nocov start - lifecycle::deprecate_soft("2.0.0", "graph.data.frame()", "graph_from_data_frame()") - graph_from_data_frame(d = d, directed = directed, vertices = vertices) -} # nocov end - -## ---------------------------------------------------------------- -## -## IGraph R package -## Copyright (C) 2005-2014 Gabor Csardi -## 334 Harvard street, Cambridge, MA 02139 USA -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -## 02110-1301 USA -## -## ----------------------------------------------------------------- - -#' Creating igraph graphs from data frames or vice-versa -#' -#' This function creates an igraph graph from one or two data frames containing -#' the (symbolic) edge list and edge/vertex attributes. -#' -#' `graph_from_data_frame()` creates igraph graphs from one or two data frames. -#' It has two modes of operation, depending whether the `vertices` -#' argument is `NULL` or not. -#' -#' If `vertices` is `NULL`, then the first two columns of `d` -#' are used as a symbolic edge list and additional columns as edge attributes. -#' The names of the attributes are taken from the names of the columns. -#' -#' If `vertices` is not `NULL`, then it must be a data frame giving -#' vertex metadata. The first column of `vertices` is assumed to contain -#' symbolic vertex names, this will be added to the graphs as the -#' \sQuote{`name`} vertex attribute. Other columns will be added as -#' additional vertex attributes. If `vertices` is not `NULL` then the -#' symbolic edge list given in `d` is checked to contain only vertex names -#' listed in `vertices`. -#' -#' Typically, the data frames are exported from some spreadsheet software like -#' Excel and are imported into R via [read.table()], -#' [read.delim()] or [read.csv()]. -#' -#' All edges in the data frame are included in the graph, which may include -#' multiple parallel edges and loops. -#' -#' `as_data_frame()` converts the igraph graph into one or more data -#' frames, depending on the `what` argument. -#' -#' If the `what` argument is `edges` (the default), then the edges of -#' the graph and also the edge attributes are returned. The edges will be in -#' the first two columns, named `from` and `to`. (This also denotes -#' edge direction for directed graphs.) For named graphs, the vertex names -#' will be included in these columns, for other graphs, the numeric vertex ids. -#' The edge attributes will be in the other columns. It is not a good idea to -#' have an edge attribute named `from` or `to`, because then the -#' column named in the data frame will not be unique. The edges are listed in -#' the order of their numeric ids. -#' -#' If the `what` argument is `vertices`, then vertex attributes are -#' returned. Vertices are listed in the order of their numeric vertex ids. -#' -#' If the `what` argument is `both`, then both vertex and edge data -#' is returned, in a list with named entries `vertices` and `edges`. -#' -#' @param d A data frame containing a symbolic edge list in the first two -#' columns. Additional columns are considered as edge attributes. Since -#' version 0.7 this argument is coerced to a data frame with -#' `as.data.frame`. -#' @param directed Logical scalar, whether or not to create a directed graph. -#' @param vertices A data frame with vertex metadata, or `NULL`. See -#' details below. Since version 0.7 this argument is coerced to a data frame -#' with `as.data.frame`, if not `NULL`. -#' @return An igraph graph object for `graph_from_data_frame()`, and either a -#' data frame or a list of two data frames named `edges` and -#' `vertices` for `as.data.frame`. -#' @note For `graph_from_data_frame()` `NA` elements in the first two -#' columns \sQuote{d} are replaced by the string \dQuote{NA} before creating -#' the graph. This means that all `NA`s will correspond to a single -#' vertex. -#' -#' `NA` elements in the first column of \sQuote{vertices} are also -#' replaced by the string \dQuote{NA}, but the rest of \sQuote{vertices} is not -#' touched. In other words, vertex names (=the first column) cannot be -#' `NA`, but other vertex attributes can. -#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} -#' @seealso [graph_from_literal()] -#' for another way to create graphs, [read.table()] to read in tables -#' from files. -#' @keywords graphs -#' @examples -#' -#' ## A simple example with a couple of actors -#' ## The typical case is that these tables are read in from files.... -#' actors <- data.frame( -#' name = c( -#' "Alice", "Bob", "Cecil", "David", -#' "Esmeralda" -#' ), -#' age = c(48, 33, 45, 34, 21), -#' gender = c("F", "M", "F", "M", "F") -#' ) -#' relations <- data.frame( -#' from = c( -#' "Bob", "Cecil", "Cecil", "David", -#' "David", "Esmeralda" -#' ), -#' to = c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"), -#' same.dept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE), -#' friendship = c(4, 5, 5, 2, 1, 1), advice = c(4, 5, 5, 4, 2, 3) -#' ) -#' g <- graph_from_data_frame(relations, directed = TRUE, vertices = actors) -#' print(g, e = TRUE, v = TRUE) -#' -#' ## The opposite operation -#' as_data_frame(g, what = "vertices") -#' as_data_frame(g, what = "edges") -#' -#' @export -graph_from_data_frame <- function(d, directed = TRUE, vertices = NULL) { - d <- as.data.frame(d) - if (!is.null(vertices)) { - vertices <- as.data.frame(vertices) - } - - if (ncol(d) < 2) { - stop("the data frame should contain at least two columns") - } - - ## Handle if some elements are 'NA' - if (any(is.na(d[, 1:2]))) { - cli::cli_warn("In {.code d}, {.code NA} elements were replaced with string {.str NA}.") - d[, 1:2][is.na(d[, 1:2])] <- "NA" - } - if (!is.null(vertices) && any(is.na(vertices[, 1]))) { - cli::cli_warn("In {.code vertices[,1]}, {.code NA} elements were replaced with string {.str NA}.") - vertices[, 1][is.na(vertices[, 1])] <- "NA" - } - - names <- unique(c(as.character(d[, 1]), as.character(d[, 2]))) - if (!is.null(vertices)) { - names2 <- names - vertices <- as.data.frame(vertices) - if (ncol(vertices) < 1) { - stop("Vertex data frame contains no rows") - } - names <- as.character(vertices[, 1]) - if (any(duplicated(names))) { - stop("Duplicate vertex names") - } - if (any(!names2 %in% names)) { - stop("Some vertex names in edge list are not listed in vertex data frame") - } - } - - # create graph - g <- make_empty_graph(n = 0, directed = directed) - - # vertex attributes - attrs <- list(name = names) - if (!is.null(vertices)) { - if (ncol(vertices) > 1) { - for (i in 2:ncol(vertices)) { - newval <- vertices[, i] - if (inherits(newval, "factor")) { - newval <- as.character(newval) - } - attrs[[names(vertices)[i]]] <- newval - } - } - } - - # add vertices - g <- add_vertices(g, length(names), attr = attrs) - - # create edge list - from <- as.character(d[, 1]) - to <- as.character(d[, 2]) - edges <- rbind(match(from, names), match(to, names)) - - # edge attributes - attrs <- list() - if (ncol(d) > 2) { - for (i in 3:ncol(d)) { - newval <- d[, i] - if (inherits(newval, "factor")) { - newval <- as.character(newval) - } - attrs[[names(d)[i]]] <- newval - } - } - - # add the edges - g <- add_edges(g, edges, attr = attrs) - g -} - -#' @rdname graph_from_data_frame -#' @param ... Passed to `graph_from_data_frame()`. -#' @export -from_data_frame <- function(...) constructor_spec(graph_from_data_frame, ...) - -## ----------------------------------------------------------------- - -#' Create a graph from an edge list matrix -#' -#' `graph_from_edgelist()` creates a graph from an edge list. Its argument -#' is a two-column matrix, each row defines one edge. If it is -#' a numeric matrix then its elements are interpreted as vertex ids. If -#' it is a character matrix then it is interpreted as symbolic vertex -#' names and a vertex id will be assigned to each name, and also a -#' `name` vertex attribute will be added. -#' -#' @concept Edge list -#' @param el The edge list, a two column matrix, character or numeric. -#' @param directed Whether to create a directed graph. -#' @return An igraph graph. -#' -#' @family deterministic constructors -#' @export -#' @examples -#' el <- matrix(c("foo", "bar", "bar", "foobar"), nc = 2, byrow = TRUE) -#' graph_from_edgelist(el) -#' -#' # Create a ring by hand -#' graph_from_edgelist(cbind(1:10, c(2:10, 1))) -graph_from_edgelist <- function(el, directed = TRUE) { - if (!is.matrix(el) || ncol(el) != 2) { - stop("graph_from_edgelist expects a matrix with two columns") - } - - if (nrow(el) == 0) { - res <- make_empty_graph(directed = directed) - } else { - if (is.character(el)) { - ## symbolic edge list - names <- unique(as.character(t(el))) - ids <- seq(names) - names(ids) <- names - res <- make_graph(unname(ids[t(el)]), directed = directed) - rm(ids) - V(res)$name <- names - } else { - ## normal edge list - res <- make_graph(t(el), directed = directed) - } - } - - res -} - -#' @rdname graph_from_edgelist -#' @param ... Passed to `graph_from_edgelist()`. -#' @export -from_edgelist <- function(...) constructor_spec(graph_from_edgelist, ...) diff --git a/tests/testthat/test-conversion.R b/tests/testthat/test-conversion.R index 4206e0467a..cb66b9b8b4 100644 --- a/tests/testthat/test-conversion.R +++ b/tests/testthat/test-conversion.R @@ -536,3 +536,50 @@ test_that("as_long_data_frame() works correctly with and without names", { as_long_data_frame(ring) }) }) + +test_that("graph_from_data_frame works", { + local_igraph_options(print.full = TRUE) + + actors <- data.frame( + name = c( + "Alice", "Bob", "Cecil", "David", + "Esmeralda" + ), + age = c(48, 33, 45, 34, 21), + gender = c("F", "M", "F", "M", "F"), + stringsAsFactors = FALSE + ) + relations <- data.frame( + from = c( + "Bob", "Cecil", "Cecil", "David", + "David", "Esmeralda" + ), + to = c( + "Alice", "Bob", "Alice", "Alice", + "Bob", "Alice" + ), + same.dept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE), + friendship = c(4, 5, 5, 2, 1, 1), advice = c(4, 5, 5, 4, 2, 3), + stringsAsFactors = FALSE + ) + g <- graph_from_data_frame(relations, directed = TRUE, vertices = actors) + + df <- as_data_frame(g, what = "both") + expect_equal(df$vertices, actors, ignore_attr = TRUE) + expect_equal(df$edges, relations) +}) + +test_that("graph_from_data_frame() creates attributes for zero-row data frames (#466)", { + x <- data.frame(from = integer(), to = integer(), foo = integer(), bar = numeric()) + g <- graph_from_data_frame(x) + expect_identical(E(g)$foo, integer()) + expect_identical(E(g)$bar, numeric()) +}) + +test_that("graph_from_data_frame works on matrices", { + el <- cbind(1:5, 5:1, weight = 1:5) + g <- graph_from_data_frame(el) + g <- delete_vertex_attr(g, "name") + el2 <- as_data_frame(g) + expect_equal(as.data.frame(el), el2, ignore_attr = TRUE) +}) diff --git a/tests/testthat/test-graph.data.frame.R b/tests/testthat/test-graph.data.frame.R deleted file mode 100644 index 27a1a74bdc..0000000000 --- a/tests/testthat/test-graph.data.frame.R +++ /dev/null @@ -1,46 +0,0 @@ -test_that("graph_from_data_frame works", { - local_igraph_options(print.full = TRUE) - - actors <- data.frame( - name = c( - "Alice", "Bob", "Cecil", "David", - "Esmeralda" - ), - age = c(48, 33, 45, 34, 21), - gender = c("F", "M", "F", "M", "F"), - stringsAsFactors = FALSE - ) - relations <- data.frame( - from = c( - "Bob", "Cecil", "Cecil", "David", - "David", "Esmeralda" - ), - to = c( - "Alice", "Bob", "Alice", "Alice", - "Bob", "Alice" - ), - same.dept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE), - friendship = c(4, 5, 5, 2, 1, 1), advice = c(4, 5, 5, 4, 2, 3), - stringsAsFactors = FALSE - ) - g <- graph_from_data_frame(relations, directed = TRUE, vertices = actors) - - df <- as_data_frame(g, what = "both") - expect_equal(df$vertices, actors, ignore_attr = TRUE) - expect_equal(df$edges, relations) -}) - -test_that("graph_from_data_frame() creates attributes for zero-row data frames (#466)", { - x <- data.frame(from = integer(), to = integer(), foo = integer(), bar = numeric()) - g <- graph_from_data_frame(x) - expect_identical(E(g)$foo, integer()) - expect_identical(E(g)$bar, numeric()) -}) - -test_that("graph_from_data_frame works on matrices", { - el <- cbind(1:5, 5:1, weight = 1:5) - g <- graph_from_data_frame(el) - g <- delete_vertex_attr(g, "name") - el2 <- as_data_frame(g) - expect_equal(as.data.frame(el), el2, ignore_attr = TRUE) -}) From 3b668c5f3c7cfc8fe9bec77ae24adc6dd595e2ad Mon Sep 17 00:00:00 2001 From: schochastics Date: Wed, 19 Feb 2025 20:32:50 +0100 Subject: [PATCH 3/5] refactored tests --- tests/testthat/test-conversion.R | 274 ++++++++++++++----------------- 1 file changed, 123 insertions(+), 151 deletions(-) diff --git a/tests/testthat/test-conversion.R b/tests/testthat/test-conversion.R index cb66b9b8b4..436463c918 100644 --- a/tests/testthat/test-conversion.R +++ b/tests/testthat/test-conversion.R @@ -1,38 +1,41 @@ test_that("as_directed works", { - g <- sample_gnp(100, 2 / 100) - g2 <- as_directed(g, mode = "mutual") - g3 <- as_directed(g, mode = "arbitrary") - g4 <- as_directed(g, mode = "random") - g5 <- as_directed(g, mode = "acyclic") - - expect_equal(degree(g), degree(g2) / 2) - expect_equal(degree(g), degree(g3)) - expect_equal(degree(g), degree(g4)) - expect_equal(degree(g), degree(g5)) - - expect_isomorphic(g, as_undirected(g2)) - expect_isomorphic(g, as_undirected(g3)) - expect_isomorphic(g, as_undirected(g4)) - expect_isomorphic(g, as_undirected(g5)) + gnp_undirected <- sample_gnp(100, 2 / 100) + gnp_mutual <- as_directed(gnp_undirected, mode = "mutual") + expect_equal(degree(gnp_undirected), degree(gnp_directed) / 2) + expect_isomorphic(gnp_undirected, as_undirected(gnp_mutual)) + + gnp_arbitrary <- as_directed(g, mode = "arbitrary") + expect_equal(degree(gnp_undirected), degree(gnp_arbitrary)) + expect_isomorphic(g, as_undirected(gnp_arbitrary)) + + gnp_random <- as_directed(g, mode = "random") + expect_equal(degree(gnp_undirected), degree(gnp_random)) + expect_isomorphic(gnp_undirected, as_undirected(gnp_random)) + + gnp_acyclic <- as_directed(g, mode = "acyclic") + expect_equal(degree(gnp_undirected), degree(gnp_acyclic)) + expect_isomorphic(gnp_undirected, as_undirected(gnp_acyclic)) }) test_that("as_directed keeps attributes", { g <- graph_from_literal(A - B - C, D - A, E) g$name <- "Small graph" - g2 <- as_directed(g, mode = "mutual") - g3 <- as_directed(g, mode = "arbitrary") - expect_equal(g2$name, g$name) - expect_equal(V(g2)$name, V(g)$name) - expect_equal(g3$name, g$name) - expect_equal(V(g3)$name, V(g)$name) + g_mutual <- as_directed(g, mode = "mutual") + expect_equal(g_mutual$name, g$name) + expect_equal(V(g_mutual)$name, V(g)$name) + + g_arbitrary <- as_directed(g, mode = "arbitrary") + expect_equal(g_arbitrary$name, g$name) + expect_equal(V(g_arbitrary)$name, V(g)$name) E(g)$weight <- seq_len(ecount(g)) - g4 <- as_directed(g, "mutual") - df4 <- as_data_frame(g4) - g5 <- as_directed(g, "arbitrary") - df5 <- as_data_frame(g5) - expect_equal(df4[order(df4[, 1], df4[, 2]), ]$weight, c(1, 2, 1, 3, 3, 2)) - expect_equal(df5[order(df5[, 1], df5[, 2]), ]$weight, 1:3) + g_mutual <- as_directed(g, "mutual") + df_mutual <- as_data_frame(g_mutual) + expect_equal(df_mutual[order(df_mutual[, 1], df_mutual[, 2]), ]$weight, c(1, 2, 1, 3, 3, 2)) + + g_arbitrary <- as_directed(g, "arbitrary") + df_arbitrary <- as_data_frame(g_arbitrary) + expect_equal(df_arbitrary[order(df_arbitrary[, 1], df_arbitrary[, 2]), ]$weight, 1:3) }) test_that("as.directed() deprecation", { @@ -54,20 +57,20 @@ test_that("as_undirected() keeps attributes", { g$name <- "Tiny graph" E(g)$weight <- seq_len(ecount(g)) - g2 <- as_undirected(g, mode = "collapse") - df2 <- as_data_frame(g2) - g3 <- as_undirected(g, mode = "each") - df3 <- as_data_frame(g3) - g4 <- as_undirected(g, mode = "mutual") - df4 <- as_data_frame(g4) + g_tiny <- as_undirected(g, mode = "collapse") + df_tiny <- as_data_frame(g_tiny) + expect_equal(g_tiny$name, g$name) + expect_equal(df_tiny[order(df_tiny[, 1], df_tiny[, 2]), ]$weight, c(4, 2, 9)) - expect_equal(g2$name, g$name) - expect_equal(g3$name, g$name) - expect_equal(g4$name, g$name) + g_each <- as_undirected(g, mode = "each") + df_each <- as_data_frame(g_each) + expect_equal(g_each$name, g$name) + expect_equal(df_each[order(df_each[, 1], df_each[, 2]), ]$weight, c(1, 3, 2, 4, 5)) - expect_equal(df2[order(df2[, 1], df2[, 2]), ]$weight, c(4, 2, 9)) - expect_equal(df3[order(df3[, 1], df3[, 2]), ]$weight, c(1, 3, 2, 4, 5)) - expect_equal(df4[order(df4[, 1], df4[, 2]), ]$weight, c(4, 9)) + g_mutual <- as_undirected(g, mode = "mutual") + df_mutual <- as_data_frame(g_mutual) + expect_equal(g_mutual$name, g$name) + expect_equal(df_mutual[order(df_mutual[, 1], df_mutual[, 2]), ]$weight, c(4, 9)) }) test_that("as_adjacency_matrix() works -- sparse", { @@ -78,17 +81,15 @@ test_that("as_adjacency_matrix() works -- sparse", { c(0, 1, 0, 0, 1, 1, 0, 3, 0, 0, 2, 0, 0, 0, 1, 0), nrow = 4L, ncol = 4L ) - basic_adj_matrix <- as.matrix(basic_adj_matrix) - dimnames(basic_adj_matrix) <- NULL - expect_equal(basic_adj_matrix, expected_matrix) + basic_adj_matrix_dense <- as_unnamed_dense_matrix(basic_adj_matrix) + expect_equal(basic_adj_matrix_dense, expected_matrix) V(g)$name <- letters[1:vcount(g)] letter_adj_matrix <- as_adjacency_matrix(g) expect_s4_class(letter_adj_matrix, "dgCMatrix") expect_setequal(rownames(letter_adj_matrix), letters[1:vcount(g)]) - letter_adj_matrix <- as.matrix(letter_adj_matrix) - dimnames(letter_adj_matrix) <- NULL - expect_equal(basic_adj_matrix, letter_adj_matrix) + letter_adj_matrix_dense <- as_unnamed_dense_matrix(letter_adj_matrix) + expect_equal(basic_adj_matrix, letter_adj_matrix_dense) E(g)$weight <- c(1.2, 3.4, 2.7, 5.6, 6.0, 0.1, 6.1, 3.3, 4.3) weight_adj_matrix <- as_adjacency_matrix(g, attr = "weight") @@ -114,9 +115,8 @@ test_that("as_adjacency_matrix() works -- sparse + not both", { c(0, 2, 0, 0, 0, 1, 0, 3, 0, 0, 2, 1, 0, 0, 0, 0), nrow = 4L, ncol = 4L ) - lower_expected_matrix <- as.matrix(lower_expected_matrix) - dimnames(lower_expected_matrix) <- NULL - expect_equal(lower_expected_matrix, lower_expected_matrix) + lower_expected_matrix_dense <- as_unnamed_dense_matrix(lower_expected_matrix) + expect_equal(lower_expected_matrix, lower_expected_matrix_dense) upper_adj_matrix <- as_adjacency_matrix(g, type = "upper") expect_s4_class(upper_adj_matrix, "dgCMatrix") @@ -124,9 +124,8 @@ test_that("as_adjacency_matrix() works -- sparse + not both", { c(0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 2, 0, 0, 3, 1, 0), nrow = 4L, ncol = 4L ) - upper_adj_matrix <- as.matrix(upper_adj_matrix) - dimnames(upper_adj_matrix) <- NULL - expect_equal(upper_adj_matrix, upper_expected_matrix) + upper_adj_matrix_dense <- as_unnamed_dense_matrix(upper_adj_matrix) + expect_equal(upper_adj_matrix_dense, upper_expected_matrix) }) test_that("as_adjacency_matrix() errors well -- sparse", { @@ -143,10 +142,10 @@ test_that("as_adjacency_matrix() works -- sparse undirected", { adj_matrix <- as_adjacency_matrix(ug) expect_s4_class(adj_matrix, "dgCMatrix") - adj_matrix <- as.matrix(adj_matrix) - dimnames(adj_matrix) <- NULL + adj_matrix_dense <- as_unnamed_dense_matrix(adj_matrix) + expect_equal( - adj_matrix, + adj_matrix_dense, matrix( c(0, 2, 0, 0, 2, 1, 0, 3, 0, 0, 2, 1, 0, 3, 1, 0), nrow = 4L, @@ -177,10 +176,6 @@ test_that("as_adjacency_matrix() works -- dense", { weight_adj_matrix, matrix( c(0, 3.4, 0, 0, 1.2, 2.7, 0, 13.7, 0, 0, 11.6, 0, 0, 0, 0.1, 0), - # below is wrong test result due to a bug (#1551). Weights of ties - # between the same node pair should be aggregated and not only the last - # weight should be considered. The above is consistent with the sparse case - # c(0, 3.4, 0, 0, 1.2, 2.7, 0, 4.3, 0, 0, 6, 0, 0, 0, 0.1, 0), nrow = 4L, ncol = 4L, dimnames = list(c("a", "b", "c", "d"), c("a", "b", "c", "d")) @@ -200,7 +195,6 @@ test_that("as_adjacency_matrix() errors well -- dense", { test_that("as_adjacency_matrix() works -- dense undirected", { dg <- make_graph(c(1, 2, 2, 1, 2, 2, 3, 3, 3, 3, 3, 4, 4, 2, 4, 2, 4, 2), directed = TRUE) ug <- as_undirected(dg, mode = "each") - # no different treatment than undirected if no attribute?! adj_matrix <- as_adjacency_matrix(ug, sparse = FALSE) dimnames(adj_matrix) <- NULL expect_equal( @@ -218,10 +212,6 @@ test_that("as_adjacency_matrix() works -- dense undirected", { weight_adj_matrix, matrix( c(0, 4.6, 0, 0, 4.6, 2.7, 0, 13.7, 0, 0, 11.6, 0.1, 0, 13.7, 0.1, 0), - # below is wrong test result due to a bug (#1551). Weights of ties - # between the same node pair should be aggregated and not only the last - # weight should be considered. The above is consistent with the sparse case - # c(0, 3.4, 0, 0, 3.4, 2.7, 0, 4.3, 0, 0, 6, 0.1, 0, 4.3, 0.1, 0), nrow = 4L, ncol = 4L ) @@ -245,10 +235,6 @@ test_that("as_adjacency_matrix() works -- dense + not both", { lower_adj_matrix, matrix( c(0, 4.6, 0, 0, 0, 2.7, 0, 13.7, 0, 0, 11.6, 0.1, 0, 0, 0, 0), - # below is wrong test result due to a bug (#1551). Weights of ties - # between the same node pair should be aggregated and not only the last - # weight should be considered. The above is consistent with the sparse case - # c(0, 3.4, 0, 0, 0, 2.7, 0, 4.3, 0, 0, 6, 0.1, 0, 0, 0, 0), nrow = 4L, ncol = 4L ) @@ -265,10 +251,6 @@ test_that("as_adjacency_matrix() works -- dense + not both", { upper_adj_matrix, matrix( c(0, 0, 0, 0, 4.6, 2.7, 0, 0, 0, 0, 11.6, 0, 0, 13.7, 0.1, 0), - # below is wrong test result due to a bug (#1551). Weights of ties - # between the same node pair should be aggregated and not only the last - # weight should be considered. The above is consistent with the sparse case - # c(0, 0, 0, 0, 3.4, 2.7, 0, 0, 0, 0, 6, 0, 0, 4.3, 0.1, 0), nrow = 4L, ncol = 4L ) @@ -304,21 +286,15 @@ test_that("as_adj works", { g2 <- graph_from_adjacency_matrix(A, mode = "undirected") expect_isomorphic(g, g2) - ### - A <- as_adjacency_matrix(g, sparse = TRUE) g2 <- graph_from_adjacency_matrix(A, mode = "undirected") expect_isomorphic(g, g2) - ### - g <- sample_gnp(50, 2 / 50, directed = TRUE) A <- as_adjacency_matrix(g, sparse = FALSE) g2 <- graph_from_adjacency_matrix(A) expect_isomorphic(g, g2) - ### - A <- as_adjacency_matrix(g, sparse = TRUE) g2 <- graph_from_adjacency_matrix(A) expect_isomorphic(g, g2) @@ -326,50 +302,47 @@ test_that("as_adj works", { test_that("as_adj_list works", { g <- sample_gnp(50, 2 / 50) - al <- as_adj_list(g) - expect_s3_class(al[[1]], "igraph.vs") - g2 <- graph_from_adj_list(al, mode = "all") - expect_isomorphic(g, g2) - expect_true(isomorphic(g, g2, + adj_list <- as_adj_list(g) + expect_s3_class(adj_list[[1]], "igraph.vs") + g_same <- graph_from_adj_list(adj_list, mode = "all") + expect_isomorphic(g, g_same) + expect_true(isomorphic(g, g_same, method = "vf2", - vertex.color1 = 1:vcount(g), - vertex.color2 = 1:vcount(g2) + vertex.color1 = seq_len(vcount(g)), + vertex.color2 = seq_len(vcount(g_same)) )) - #### - - el <- as_adj_edge_list(g) - expect_s3_class(el[[1]], "igraph.es") - for (i in 1:vcount(g)) { - a <- E(g)[.inc(i)] - expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) - expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) + adj_el_list <- as_adj_edge_list(g) + expect_s3_class(adj_el_list[[1]], "igraph.es") + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.inc(i)] + expect_equal(length(incident_to_i), length(adj_el_list[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list[[i]]), sort(incident_to_i), ignore_attr = TRUE) } g <- sample_gnp(50, 4 / 50, directed = TRUE) - el1 <- as_adj_edge_list(g, mode = "out") - el2 <- as_adj_edge_list(g, mode = "in") - for (i in 1:vcount(g)) { - a <- E(g)[.from(i)] - expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) - expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) + adj_el_list_out <- as_adj_edge_list(g, mode = "out") + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.from(i)] + expect_equal(length(incident_to_i), length(adj_el_list_out[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list_out[[i]]), sort(incident_to_i), ignore_attr = TRUE) } - for (i in 1:vcount(g)) { - a <- E(g)[.to(i)] - expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) - expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) + + adj_el_list_in <- as_adj_edge_list(g, mode = "in") + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.to(i)] + expect_equal(length(incident_to_i), length(adj_el_list_in[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list_in[[i]]), sort(incident_to_i), ignore_attr = TRUE) } }) - - test_that("as_adj_list works when return.vs.es is FALSE", { on.exit(try(igraph_options(old)), add = TRUE) old <- igraph_options(return.vs.es = FALSE) g <- sample_gnp(50, 2 / 50) - al <- as_adj_list(g) - expect_s3_class(al[[1]], NA) + adj_list <- as_adj_list(g) + expect_s3_class(adj_list[[1]], NA) g2 <- graph_from_adj_list(al, mode = "all") expect_isomorphic(g, g2) expect_true(isomorphic(g, g2, @@ -378,79 +351,78 @@ test_that("as_adj_list works when return.vs.es is FALSE", { vertex.color2 = 1:vcount(g2) )) - #### - - el <- as_adj_edge_list(g) - for (i in 1:vcount(g)) { - a <- E(g)[.inc(i)] - expect_equal(length(a), length(el[[i]]), ignore_attr = TRUE) - expect_equal(sort(el[[i]]), sort(a), ignore_attr = TRUE) + adj_el_list <- as_adj_edge_list(g) + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.inc(i)] + expect_equal(length(incident_to_i), length(adj_el_list[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list[[i]]), sort(incident_to_i), ignore_attr = TRUE) } g <- sample_gnp(50, 4 / 50, directed = TRUE) - el1 <- as_adj_edge_list(g, mode = "out") - el2 <- as_adj_edge_list(g, mode = "in") - for (i in 1:vcount(g)) { - a <- E(g)[.from(i)] - expect_equal(length(a), length(el1[[i]]), ignore_attr = TRUE) - expect_equal(sort(el1[[i]]), sort(a), ignore_attr = TRUE) + adj_el_list_out <- as_adj_edge_list(g, mode = "out") + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.from(i)] + expect_equal(length(incident_to_i), length(adj_el_list_out[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list_out[[i]]), sort(incident_to_i), ignore_attr = TRUE) } - for (i in 1:vcount(g)) { - a <- E(g)[.to(i)] - expect_equal(length(a), length(el2[[i]]), ignore_attr = TRUE) - expect_equal(sort(el2[[i]]), sort(a), ignore_attr = TRUE) + + adj_el_list_in <- as_adj_edge_list(g, mode = "in") + for (i in seq_len(vcount(g))) { + incident_to_i <- E(g)[.to(i)] + expect_equal(length(incident_to_i), length(adj_el_list_in[[i]]), ignore_attr = TRUE) + expect_equal(sort(adj_el_list_in[[i]]), sort(incident_to_i), ignore_attr = TRUE) } }) test_that("as_edgelist works", { g <- sample_gnp(100, 3 / 100) - e <- as_edgelist(g) - g2 <- make_graph(t(e), n = vcount(g), dir = FALSE) + el <- as_edgelist(g) + g2 <- make_graph(t(el), n = vcount(g), dir = FALSE) expect_isomorphic(g, g2) }) test_that("as_biadjacency_matrix() works -- dense", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) - I2 <- as_biadjacency_matrix(g) - expect_equal(I, I2, ignore_attr = TRUE) - expect_identical(rownames(I2), as.character(1:7)) - expect_identical(colnames(I2), as.character(8:12)) + biadj_mat <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(biadj_mat) + biadj_mat2 <- as_biadjacency_matrix(g) + expect_equal(biadj_mat, biadj_mat2, ignore_attr = TRUE) + expect_identical(rownames(biadj_mat2), as.character(1:7)) + expect_identical(colnames(biadj_mat2), as.character(8:12)) }) test_that("as_biadjacency_matrix() works -- dense named", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) + biadj_mat <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(biadj_mat) V(g)$name <- letters[1:length(V(g))] expect_true(is_named(g)) - I2 <- as_biadjacency_matrix(g) - expect_equal(I, I2, ignore_attr = TRUE) - expect_identical(rownames(I2), c("a", "b", "c", "d", "e", "f", "g")) - expect_identical(colnames(I2), c("h", "i", "j", "k", "l")) + biadj_mat2 <- as_biadjacency_matrix(g) + expect_equal(biadj_mat, biadj_mat2, ignore_attr = TRUE) + expect_identical(rownames(biadj_mat2), c("a", "b", "c", "d", "e", "f", "g")) + expect_identical(colnames(biadj_mat2), c("h", "i", "j", "k", "l")) }) test_that("as_biadjacency_matrix() works -- sparse", { - I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) - g <- graph_from_biadjacency_matrix(I) - I3 <- as_biadjacency_matrix(g, sparse = TRUE) - expect_equal(as.matrix(I3), I, ignore_attr = TRUE) - expect_identical(rownames(I3), as.character(1:7)) - expect_identical(colnames(I3), as.character(8:12)) + biadj_mat <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5) + g <- graph_from_biadjacency_matrix(biadj_mat) + biadj_mat2 <- as_biadjacency_matrix(g, sparse = TRUE) + expect_equal(as.matrix(biadj_mat2), biadj_mat, ignore_attr = TRUE) + expect_identical(rownames(biadj_mat2), as.character(1:7)) + expect_identical(colnames(biadj_mat2), as.character(8:12)) }) test_that("graph_from_adj_list works", { g <- sample_gnp(100, 3 / 100) - al <- as_adj_list(g) - g2 <- graph_from_adj_list(al, mode = "all") + adj_list <- as_adj_list(g) + g2 <- graph_from_adj_list(adj_list, mode = "all") expect_isomorphic(g, g2) ## g <- sample_gnp(100, 3 / 100, directed = TRUE) - al <- as_adj_list(g, mode = "out") - g2 <- graph_from_adj_list(al, mode = "out") + adj_list_out <- as_adj_list(g, mode = "out") + g2 <- graph_from_adj_list(adj_list_out, mode = "out") expect_isomorphic(g, g2) }) @@ -487,8 +459,8 @@ test_that("graphNEL conversion works", { set.seed(20250122) g <- sample_gnp(100, 5 / 100) - N <- as_graphnel(g) - g2 <- graph_from_graphnel(N) + g_graphnel <- as_graphnel(g) + g2 <- graph_from_graphnel(g_graphnel) gi <- isomorphic(g, g2, method = "vf2") expect_true(gi) @@ -498,8 +470,8 @@ test_that("graphNEL conversion works", { E(g)$weight <- sample(1:10, ecount(g), replace = TRUE) g$name <- "Foobar" - N <- as_graphnel(g) - g2 <- graph_from_graphnel(N) + g_graphnel1 <- as_graphnel(g) + g2 <- graph_from_graphnel(g_graphnel1) expect_isomorphic(g, g2) expect_equal(V(g)$name, V(g2)$name) From 23731f8ed4dd3c79a0df30c53488a3f1ddbf63c6 Mon Sep 17 00:00:00 2001 From: schochastics Date: Wed, 19 Feb 2025 20:50:37 +0100 Subject: [PATCH 4/5] fixed failing tests --- tests/testthat/_snaps/conversion.md | 35 +++++++++++++++++++++++ tests/testthat/_snaps/graph.data.frame.md | 35 ----------------------- tests/testthat/test-conversion.R | 14 ++++----- 3 files changed, 42 insertions(+), 42 deletions(-) delete mode 100644 tests/testthat/_snaps/graph.data.frame.md diff --git a/tests/testthat/_snaps/conversion.md b/tests/testthat/_snaps/conversion.md index 901eeddd70..8da10b7890 100644 --- a/tests/testthat/_snaps/conversion.md +++ b/tests/testthat/_snaps/conversion.md @@ -52,3 +52,38 @@ Error in `as_adjacency_matrix()`: ! Matrices must be either numeric or logical, and the edge attribute is not +# as_long_data_frame() works correctly with and without names + + Code + ring <- make_ring(3) + as_long_data_frame(ring) + Output + from to + 1 1 2 + 2 2 3 + 3 1 3 + Code + V(ring)$name <- letters[1:3] + as_long_data_frame(ring) + Output + from to from_name to_name + 1 1 2 a b + 2 2 3 b c + 3 1 3 a c + Code + V(ring)$score <- LETTERS[1:3] + as_long_data_frame(ring) + Output + from to from_name from_score to_name to_score + 1 1 2 a A b B + 2 2 3 b B c C + 3 1 3 a A c C + Code + E(ring)$info <- 3:1 + as_long_data_frame(ring) + Output + from to info from_name from_score to_name to_score + 1 1 2 3 a A b B + 2 2 3 2 b B c C + 3 1 3 1 a A c C + diff --git a/tests/testthat/_snaps/graph.data.frame.md b/tests/testthat/_snaps/graph.data.frame.md deleted file mode 100644 index 9b11436dd4..0000000000 --- a/tests/testthat/_snaps/graph.data.frame.md +++ /dev/null @@ -1,35 +0,0 @@ -# as_long_data_frame() works correctly with and without names - - Code - ring <- make_ring(3) - as_long_data_frame(ring) - Output - from to - 1 1 2 - 2 2 3 - 3 1 3 - Code - V(ring)$name <- letters[1:3] - as_long_data_frame(ring) - Output - from to from_name to_name - 1 1 2 a b - 2 2 3 b c - 3 1 3 a c - Code - V(ring)$score <- LETTERS[1:3] - as_long_data_frame(ring) - Output - from to from_name from_score to_name to_score - 1 1 2 a A b B - 2 2 3 b B c C - 3 1 3 a A c C - Code - E(ring)$info <- 3:1 - as_long_data_frame(ring) - Output - from to info from_name from_score to_name to_score - 1 1 2 3 a A b B - 2 2 3 2 b B c C - 3 1 3 1 a A c C - diff --git a/tests/testthat/test-conversion.R b/tests/testthat/test-conversion.R index 436463c918..93016bde07 100644 --- a/tests/testthat/test-conversion.R +++ b/tests/testthat/test-conversion.R @@ -1,18 +1,18 @@ test_that("as_directed works", { gnp_undirected <- sample_gnp(100, 2 / 100) gnp_mutual <- as_directed(gnp_undirected, mode = "mutual") - expect_equal(degree(gnp_undirected), degree(gnp_directed) / 2) + expect_equal(degree(gnp_undirected), degree(gnp_mutual) / 2) expect_isomorphic(gnp_undirected, as_undirected(gnp_mutual)) - gnp_arbitrary <- as_directed(g, mode = "arbitrary") + gnp_arbitrary <- as_directed(gnp_undirected, mode = "arbitrary") expect_equal(degree(gnp_undirected), degree(gnp_arbitrary)) - expect_isomorphic(g, as_undirected(gnp_arbitrary)) + expect_isomorphic(gnp_undirected, as_undirected(gnp_arbitrary)) - gnp_random <- as_directed(g, mode = "random") + gnp_random <- as_directed(gnp_undirected, mode = "random") expect_equal(degree(gnp_undirected), degree(gnp_random)) expect_isomorphic(gnp_undirected, as_undirected(gnp_random)) - gnp_acyclic <- as_directed(g, mode = "acyclic") + gnp_acyclic <- as_directed(gnp_undirected, mode = "acyclic") expect_equal(degree(gnp_undirected), degree(gnp_acyclic)) expect_isomorphic(gnp_undirected, as_undirected(gnp_acyclic)) }) @@ -89,7 +89,7 @@ test_that("as_adjacency_matrix() works -- sparse", { expect_s4_class(letter_adj_matrix, "dgCMatrix") expect_setequal(rownames(letter_adj_matrix), letters[1:vcount(g)]) letter_adj_matrix_dense <- as_unnamed_dense_matrix(letter_adj_matrix) - expect_equal(basic_adj_matrix, letter_adj_matrix_dense) + expect_equal(basic_adj_matrix_dense, letter_adj_matrix_dense) E(g)$weight <- c(1.2, 3.4, 2.7, 5.6, 6.0, 0.1, 6.1, 3.3, 4.3) weight_adj_matrix <- as_adjacency_matrix(g, attr = "weight") @@ -343,7 +343,7 @@ test_that("as_adj_list works when return.vs.es is FALSE", { g <- sample_gnp(50, 2 / 50) adj_list <- as_adj_list(g) expect_s3_class(adj_list[[1]], NA) - g2 <- graph_from_adj_list(al, mode = "all") + g2 <- graph_from_adj_list(adj_list, mode = "all") expect_isomorphic(g, g2) expect_true(isomorphic(g, g2, method = "vf2", From 8ea7ba0e10cd76db50232f46c42c82597d517af8 Mon Sep 17 00:00:00 2001 From: schochastics Date: Wed, 19 Feb 2025 21:02:49 +0100 Subject: [PATCH 5/5] convert stop to cli_abort --- R/conversion.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/R/conversion.R b/R/conversion.R index 53fb7cbed2..280ec4308b 100644 --- a/R/conversion.R +++ b/R/conversion.R @@ -649,7 +649,7 @@ as_adj_edge_list <- function(graph, graph_from_graphnel <- function(graphNEL, name = TRUE, weight = TRUE, unlist.attrs = TRUE) { if (!inherits(graphNEL, "graphNEL")) { - stop("Not a graphNEL graph") + cli::cli_abort("{.arg graphNEL} is {.obj_type_friendly {graphNEL}} and not a graphNEL graph") } al <- lapply(graph::edgeL(graphNEL), "[[", "edges") @@ -740,7 +740,7 @@ as_graphnel <- function(graph) { ensure_igraph(graph) if (any_multiple(graph)) { - stop("multiple edges are not supported in graphNEL graphs") + cli::cli_abort("multiple edges are not supported in graphNEL graphs") } if ("name" %in% vertex_attr_names(graph) && @@ -1380,7 +1380,7 @@ graph_from_data_frame <- function(d, directed = TRUE, vertices = NULL) { } if (ncol(d) < 2) { - stop("the data frame should contain at least two columns") + cli::cli_abort("{.arg d} should contain at least two columns") } ## Handle if some elements are 'NA' @@ -1398,14 +1398,14 @@ graph_from_data_frame <- function(d, directed = TRUE, vertices = NULL) { names2 <- names vertices <- as.data.frame(vertices) if (ncol(vertices) < 1) { - stop("Vertex data frame contains no rows") + cli::cli_abort("{.arg vertices} contains no rows") } names <- as.character(vertices[, 1]) if (any(duplicated(names))) { - stop("Duplicate vertex names") + cli::cli_abort("{.arg vertices} contains duplicated vertex names") } if (any(!names2 %in% names)) { - stop("Some vertex names in edge list are not listed in vertex data frame") + cli::cli_abort("Some vertex names in {.arg d} are not listed in {.arg vertices}") } } @@ -1482,7 +1482,7 @@ from_data_frame <- function(...) constructor_spec(graph_from_data_frame, ...) #' graph_from_edgelist(cbind(1:10, c(2:10, 1))) graph_from_edgelist <- function(el, directed = TRUE) { if (!is.matrix(el) || ncol(el) != 2) { - stop("graph_from_edgelist expects a matrix with two columns") + cli::cli_abort("graph_from_edgelist expects a matrix with two columns") } if (nrow(el) == 0) {