Skip to content

Commit 653c18b

Browse files
committed
added proper support for data.frame attributes
1 parent 00a114b commit 653c18b

File tree

2 files changed

+66
-133
lines changed

2 files changed

+66
-133
lines changed

R/attributes.R

+9
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ graph.attributes <- function(graph) {
349349
"graph.attributes<-" <- function(graph, value) {
350350
ensure_igraph(graph)
351351
assert_named_list(value)
352+
if (inherits(value, "data.frame")) {
353+
value <- as.list(value)
354+
}
352355

353356
.Call(R_igraph_mybracket2_set, graph, igraph_t_idx_attr, igraph_attr_idx_graph, value)
354357
}
@@ -537,6 +540,9 @@ set_value_at <- function(value, idx, length_out) {
537540
ensure_igraph(graph)
538541

539542
assert_named_list(value)
543+
if (inherits(value, "data.frame")) {
544+
value <- as.list(value)
545+
}
540546

541547
if (!all(lengths(value) == length(index))) {
542548
cli::cli_abort("Invalid attribute value length, must match number of vertices.")
@@ -733,6 +739,9 @@ edge.attributes <- function(graph, index = E(graph)) {
733739
ensure_igraph(graph)
734740

735741
assert_named_list(value)
742+
if (inherits(value, "data.frame")) {
743+
value <- as.list(value)
744+
}
736745

737746
if (any(sapply(value, length) != length(index))) {
738747
cli::cli_abort("Invalid attribute value length, must match number of edges")

tests/testthat/test-attributes.R

+57-133
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ test_that("bracketing works with a function (not changing attribute of similar g
3131
g <- set_edge_attr(g, name = "weight", value = 1:ecount(g))
3232
g <- set_graph_attr(g, name = "name", "foo")
3333

34-
run.test <- function(g) {
34+
copy_test <- function(g) {
3535
graph2 <- set_vertex_attr(g, name = "weight", value = rep(1, vcount(g)))
3636
graph2 <- set_edge_attr(g, name = "weight", value = rep(1, ecount(g)))
3737
graph2 <- set_graph_attr(g, name = "name", "foobar")
3838
}
3939

40-
g2 <- run.test(g)
40+
g2 <- copy_test(g)
4141
expect_equal(vertex_attr(g, name = "weight"), 1:4)
4242
expect_equal(edge_attr(g, name = "weight"), 1:3)
4343
expect_equal(graph_attr(g, name = "name"), "foo")
@@ -50,13 +50,13 @@ test_that("bracketing works with shortcuts (not changing attribute of similar gr
5050
g <- set_edge_attr(g, name = "weight", value = 1:ecount(g))
5151
g <- set_graph_attr(g, name = "name", "foo")
5252

53-
run.test <- function(graph) {
53+
copy_test <- function(graph) {
5454
V(graph)$weight <- rep(1, vcount(graph))
5555
E(graph)$weight <- rep(1, ecount(graph))
5656
graph$name <- "foobar"
5757
}
5858

59-
g2 <- run.test(g)
59+
g_copy <- copy_test(g)
6060
expect_equal(vertex_attr(g, name = "weight"), 1:4)
6161
expect_equal(edge_attr(g, name = "weight"), 1:3)
6262
expect_equal(graph_attr(g, name = "name"), "foo")
@@ -188,25 +188,31 @@ test_that("attribute combinations handle errors correctly", {
188188
expect_error(as_undirected(g, edge.attr.comb = list(weight = sum)), "invalid 'type'")
189189
})
190190

191-
test_that("can change type of attributes (#466)", {
191+
test_that("can change type of attributes", {
192+
# https://github.com/igraph/rigraph/issues/466
192193
g <- make_ring(10)
193194

194195
V(g)$foo <- 1
195196
expect_equal(V(g)$foo, rep(1, 10))
197+
196198
V(g)$foo <- "a"
197199
expect_equal(V(g)$foo, rep("a", 10))
200+
198201
V(g)$foo <- 2
199202
expect_equal(V(g)$foo, rep(2, 10))
200203

201204
E(g)$foo <- 1
202205
expect_equal(E(g)$foo, rep(1, 10))
206+
203207
E(g)$foo <- "a"
204208
expect_equal(E(g)$foo, rep("a", 10))
209+
205210
E(g)$foo <- 2
206211
expect_equal(E(g)$foo, rep(2, 10))
207212
})
208213

209-
test_that("setting attributes strips names (#466)", {
214+
test_that("setting attributes strips names", {
215+
# https://github.com/igraph/rigraph/issues/466
210216
g <- make_ring(10)
211217

212218
V(g)$foo <- stats::setNames(1:10, letters[1:10])
@@ -222,7 +228,8 @@ test_that("setting attributes strips names (#466)", {
222228
expect_identical(E(g)$bar, rep(1, 10))
223229
})
224230

225-
test_that("setting NULL attributes works and doesn't change the input (#466)", {
231+
test_that("setting NULL attributes works and doesn't change the input", {
232+
# https://github.com/igraph/rigraph/issues/466
226233
g <- make_ring(10)
227234

228235
expect_identical(set_vertex_attr(g, "foo", value = NULL), g)
@@ -231,96 +238,6 @@ test_that("setting NULL attributes works and doesn't change the input (#466)", {
231238
expect_identical(set_edge_attr(g, "foo", 1:3, value = NULL), g)
232239
})
233240

234-
test_that("GRAPH attributes are destroyed when the graph is destroyed", {
235-
finalized <- FALSE
236-
finalizer <- function(e) {
237-
finalized <<- TRUE
238-
}
239-
240-
env <- new.env(parent = emptyenv())
241-
reg.finalizer(env, finalizer)
242-
243-
g <- make_ring(1)
244-
g$a <- list(env)
245-
rm(env)
246-
gc()
247-
expect_false(finalized)
248-
249-
rm(g)
250-
gc()
251-
expect_true(finalized)
252-
})
253-
254-
test_that("vertex attributes are destroyed when the graph is destroyed", {
255-
finalized <- FALSE
256-
finalizer <- function(e) {
257-
finalized <<- TRUE
258-
}
259-
260-
env <- new.env(parent = emptyenv())
261-
reg.finalizer(env, finalizer)
262-
263-
g <- make_ring(1)
264-
V(g)$a <- list(env)
265-
rm(env)
266-
gc()
267-
expect_false(finalized)
268-
269-
g <- add_vertices(g, 1)
270-
gc()
271-
expect_false(finalized)
272-
273-
g <- delete_vertices(g, 2)
274-
gc()
275-
expect_false(finalized)
276-
277-
# Called for the side effect of clearing the protect list
278-
make_empty_graph()
279-
expect_false(finalized)
280-
281-
rm(g)
282-
283-
gc()
284-
expect_true(finalized)
285-
})
286-
287-
test_that("edge attributes are destroyed when the graph is destroyed", {
288-
finalized <- FALSE
289-
finalizer <- function(e) {
290-
finalized <<- TRUE
291-
}
292-
293-
env <- new.env(parent = emptyenv())
294-
reg.finalizer(env, finalizer)
295-
296-
g <- make_ring(2)
297-
E(g)$a <- list(env)
298-
rm(env)
299-
gc()
300-
expect_false(finalized)
301-
302-
g <- add_vertices(g, 1)
303-
gc()
304-
expect_false(finalized)
305-
306-
g <- add_edges(g, c(2, 3))
307-
gc()
308-
expect_false(finalized)
309-
310-
g <- delete_edges(g, 2)
311-
gc()
312-
expect_false(finalized)
313-
314-
# Called for the side effect of clearing the protect list
315-
make_empty_graph()
316-
expect_false(finalized)
317-
318-
rm(g)
319-
320-
gc()
321-
expect_true(finalized)
322-
})
323-
324241
test_that("assert_named_list() works", {
325242
not_list <- 1:10
326243
expect_error(assert_named_list(not_list), "named list")
@@ -338,81 +255,81 @@ test_that("assert_named_list() works", {
338255
})
339256

340257
test_that("is_bipartite works", {
341-
I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5)
342-
g <- graph_from_biadjacency_matrix(I)
343-
expect_true(bipartite_mapping(g)$res)
258+
biadj_mat1 <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5)
259+
g1 <- graph_from_biadjacency_matrix(biadj_mat1)
260+
expect_true(bipartite_mapping(g1)$res)
344261

345262
withr::local_seed(42)
346-
I <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5)
347-
g <- graph_from_biadjacency_matrix(I)
263+
biadj_mat2 <- matrix(sample(0:1, 35, replace = TRUE, prob = c(3, 1)), ncol = 5)
264+
g2 <- graph_from_biadjacency_matrix(biadj_mat2)
348265
expect_equal(
349-
bipartite_mapping(g),
266+
bipartite_mapping(g2),
350267
list(res = TRUE, type = c(rep(FALSE, 7), rep(TRUE, 5)))
351268
)
352269
})
353270

354271
test_that("without_attr", {
355272
withr::local_seed(42)
356-
g <- sample_gnp(10, 2 / 10) %>%
273+
g_stripped <- sample_gnp(10, 2 / 10) %>%
357274
delete_graph_attr("name") %>%
358275
delete_graph_attr("type") %>%
359276
delete_graph_attr("loops") %>%
360277
delete_graph_attr("p")
361278

362279
withr::local_seed(42)
363-
g2 <- sample_(gnp(10, 2 / 10), without_attr())
280+
g_no_attr <- sample_(gnp(10, 2 / 10), without_attr())
364281

365-
expect_identical_graphs(g, g2)
366-
expect_equal(graph_attr_names(g2), character())
367-
expect_equal(vertex_attr_names(g2), character())
368-
expect_equal(edge_attr_names(g2), character())
282+
expect_identical_graphs(g_stripped, g_no_attr)
283+
expect_equal(graph_attr_names(g_no_attr), character())
284+
expect_equal(vertex_attr_names(g_no_attr), character())
285+
expect_equal(edge_attr_names(g_no_attr), character())
369286
})
370287

371288

372289
test_that("without_loops", {
373-
g <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
290+
g1 <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
374291
simplify(remove.multiple = FALSE)
375292

376293
g2 <- make_(
377294
from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
378295
without_loops()
379296
)
380297

381-
expect_identical_graphs(g, g2)
298+
expect_identical_graphs(g1, g2)
382299
expect_true(all(!which_loop(g2)))
383300
})
384301

385302

386303
test_that("without_multiple", {
387-
g <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
304+
g1 <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
388305
simplify(remove.loops = FALSE)
389306

390307
g2 <- make_(
391308
from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
392309
without_multiples()
393310
)
394311

395-
expect_identical_graphs(g, g2)
312+
expect_identical_graphs(g1, g2)
396313
expect_true(all(!which_multiple(g2)))
397314
})
398315

399316

400317
test_that("simplified", {
401-
g <- make_graph(~ A - A:B:C, B - A:B:C)
318+
g1 <- make_graph(~ A - A:B:C, B - A:B:C)
402319

403320
g2 <- make_(
404321
from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
405322
simplified()
406323
)
407324

408-
expect_identical_graphs(g, g2)
325+
expect_identical_graphs(g1, g2)
409326
expect_true(all(!which_multiple(g2)))
410327
expect_true(all(!which_loop(g2)))
411328
})
412329

413330

414331
test_that("with_vertex_", {
415-
g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
332+
g1 <- make_graph(~ A - A:B:C, B - A:B:C) %>%
416333
set_vertex_attr("color", value = "red") %>%
417334
set_vertex_attr("foo", value = paste0("xx", 1:3))
418335

@@ -424,14 +341,14 @@ test_that("with_vertex_", {
424341
)
425342
)
426343

427-
expect_identical_graphs(g, g2)
344+
expect_identical_graphs(g1, g2)
428345
expect_equal(V(g2)$color, rep("red", gorder(g2)))
429346
expect_equal(V(g2)$foo, paste0("xx", 1:3))
430347
})
431348

432349

433350
test_that("with_edge_", {
434-
g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
351+
g1 <- make_graph(~ A - A:B:C, B - A:B:C) %>%
435352
set_edge_attr("color", value = "red") %>%
436353
set_edge_attr("foo", value = seq_len(3))
437354

@@ -443,14 +360,14 @@ test_that("with_edge_", {
443360
)
444361
)
445362

446-
expect_identical_graphs(g, g2)
447-
expect_equal(E(g)$color, E(g2)$color)
448-
expect_equal(E(g)$foo, E(g2)$foo)
363+
expect_identical_graphs(g1, g2)
364+
expect_equal(E(g1)$color, E(g2)$color)
365+
expect_equal(E(g1)$foo, E(g2)$foo)
449366
})
450367

451368

452369
test_that("with_graph_", {
453-
g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
370+
g1 <- make_graph(~ A - A:B:C, B - A:B:C) %>%
454371
set_graph_attr("color", value = "red") %>%
455372
set_graph_attr("foo", value = 1:5)
456373

@@ -462,24 +379,24 @@ test_that("with_graph_", {
462379
)
463380
)
464381

465-
expect_identical_graphs(g, g2)
466-
expect_equal(g$color, g2$color)
467-
expect_equal(g$foo, g2$foo)
382+
expect_identical_graphs(g1, g2)
383+
expect_equal(g1$color, g2$color)
384+
expect_equal(g1$foo, g2$foo)
468385
})
469386

470387

471388
test_that("adding and removing attributes", {
472-
g <- make_empty_graph()
389+
g1 <- make_empty_graph()
473390
g2 <- make_empty_graph()
474391

475-
g$foo <- "bar"
476-
g <- delete_graph_attr(g, "foo")
477-
E(g)$foo <- "bar"
478-
g <- delete_edge_attr(g, "foo")
479-
V(g)$foo <- "bar"
480-
g <- delete_vertex_attr(g, "foo")
392+
g1$foo <- "bar"
393+
g1 <- delete_graph_attr(g1, "foo")
394+
E(g1)$foo <- "bar"
395+
g1 <- delete_edge_attr(g1, "foo")
396+
V(g1)$foo <- "bar"
397+
g1 <- delete_vertex_attr(g1, "foo")
481398

482-
expect_identical_graphs(g, g2)
399+
expect_identical_graphs(g1, g2)
483400
})
484401

485402
test_that("error messages work", {
@@ -499,3 +416,10 @@ test_that("empty returns work", {
499416
expect_length(vertex_attr_names(g), 0)
500417
expect_length(edge_attr_names(g), 0)
501418
})
419+
420+
test_that("assign data.frame attributes works", {
421+
# https://github.com/igraph/rigraph/issues/1669
422+
g <- make_tree(10, 3)
423+
edge.attributes(g) <- head(mtcars, ecount(g))
424+
expect_no_error(E(g)[c(1, 2)])
425+
})

0 commit comments

Comments
 (0)