rigraph icon indicating copy to clipboard operation
rigraph copied to clipboard

union.igraph dispatch doesn't work for lists.

Open zkamvar opened this issue 7 years ago • 7 comments

I'm not exactly sure if this is fixable, but I've discovered that the function union from igraph errors when passed a list of igraph objects. I think what's happening is R does not recognize the list as belonging to igraph, so it dispatches the union.default on the list, resulting in an error. Here's the traceback (since reprex doesn't currently have that capability):

6: as.vector(y)
5: unique(c(as.vector(x), as.vector(y)))
4: base::union(...)
3: union.default(list(net1, net2))
2: igraph::union(list(net1, net2))
1: str(igraph::union(list(net1, net2)))

And here's the reprex

cat("Reproducible example with package reprex version", as.character(packageVersion("reprex")))
#> Reproducible example with package reprex version 0.1.1
library("igraph")
#> 
#> Attaching package: 'igraph'
#> The following objects are masked from 'package:stats':
#> 
#>     decompose, spectrum
#> The following object is masked from 'package:base':
#> 
#>     union
net1 <- graph_from_literal(D - A:B:F:G, A - C - F - A, B - E - G - B, A - B, 
  F - G, H - F:G, H - I - J)
net2 <- graph_from_literal(D - A:F:Y, B - A - X - F - H - Z, F - Y)
# works
str(net1 %u% net2)
#> IGRAPH UN-- 13 21 -- 
#> + attr: name (v/c)
#> + edges (vertex names):
#>  [1] I--J H--Z H--I G--H G--E F--X F--Y F--H F--C F--G B--E B--G A--X A--C
#> [15] A--F A--B D--Y D--G D--F D--B D--A
# Fails when is a list
str(igraph::union(list(net1, net2)))
#> Error in as.vector(y): argument "y" is missing, with no default
traceback()
#> No traceback available
# Works when first argument is an igraph object
str(igraph::union(net1, list(net2)))
#> IGRAPH UN-- 13 21 -- 
#> + attr: name (v/c)
#> + edges (vertex names):
#>  [1] I--J H--Z H--I G--H G--E F--X F--Y F--H F--C F--G B--E B--G A--X A--C
#> [15] A--F A--B D--Y D--G D--F D--B D--A
Session info
devtools::session_info()
#> Session info --------------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.3.3 (2017-03-06)
#>  system   x86_64, darwin13.4.0        
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  tz       America/Chicago             
#>  date     2017-03-31
#> Packages ------------------------------------------------------------------
#>  package   * version    date       source                            
#>  backports   1.0.5      2017-01-18 CRAN (R 3.3.2)                    
#>  devtools    1.12.0     2016-06-24 CRAN (R 3.3.0)                    
#>  digest      0.6.12     2017-01-27 CRAN (R 3.3.2)                    
#>  evaluate    0.10       2016-10-11 cran (@0.10)                      
#>  formatR     1.4        2016-05-09 CRAN (R 3.3.0)                    
#>  htmltools   0.3.5      2016-03-21 CRAN (R 3.2.4)                    
#>  igraph    * 1.0.1      2015-06-26 CRAN (R 3.2.0)                    
#>  knitr       1.15.16    2017-03-29 Github (yihui/knitr@9f6a1c2)      
#>  magrittr    1.5        2014-11-22 CRAN (R 3.2.0)                    
#>  memoise     1.0.0      2016-01-29 CRAN (R 3.2.3)                    
#>  Rcpp        0.12.9     2017-01-14 CRAN (R 3.3.2)                    
#>  rmarkdown   1.4.0.9000 2017-03-29 Github (rstudio/rmarkdown@7ca7fd7)
#>  rprojroot   1.2        2017-01-16 CRAN (R 3.3.2)                    
#>  stringi     1.1.2      2016-10-01 CRAN (R 3.3.0)                    
#>  stringr     1.2.0      2017-02-18 cran (@1.2.0)                     
#>  withr       1.0.2      2016-06-20 cran (@1.0.2)                     
#>  yaml        2.1.14     2016-11-12 cran (@2.1.14)

zkamvar avatar Mar 31 '17 17:03 zkamvar

I have run into this as well. Current workaround is to do do.call(union, list.of.graphs). I don't know how one could ever get this function to work as intended with a list of graphs without making a specific igraphlist class.

mkoohafkan avatar Apr 30 '17 04:04 mkoohafkan

I'm not sure this is a problem with the function, 'union' is only designed to join 2 graphs not deal with lists. mkoohafkan's solution or my alternative both do the job Reduce(union, list.of.graphs )

JonnoB avatar Sep 21 '17 07:09 JonnoB

Thanks, the example do.call(union, list.of.graphs) worked for me! You also may want to specify igraph::union due to potential naming conflicts with dplyr::union.

'union' is only designed to join 2 graphs not deal with lists.

That seems incorrect to me. The documentation ( https://igraph.org/r/doc/union.igraph.html ) specifically states "Graph objects or lists of graph objects", doesn't it?

SimonStolz avatar Jan 23 '19 17:01 SimonStolz

'union' is only designed to join 2 graphs not deal with lists

This is not true, the below example works just fine:

net1 <- graph_from_literal(D - A:B:F:G, A - C - F - A, B - E - G - B, A - B, 
  F - G, H - F:G, H - I - J)
net2 <- graph_from_literal(D - A:F:Y, B - A - X - F - H - Z, F - Y)
net3 <- graph_from_literal(B - Y - X)

do.call(igraph::union, list(net1, net2, net3))

mkoohafkan avatar Jan 23 '19 19:01 mkoohafkan

library("igraph")
#> 
#> Attaching package: 'igraph'
#> The following objects are masked from 'package:stats':
#> 
#>     decompose, spectrum
#> The following object is masked from 'package:base':
#> 
#>     union

net1 <- graph_from_literal(
  D - A:B:F:G, A - C - F - A, B - E - G - B, A - B,
  F - G, H - F:G, H - I - J
)

net2 <- graph_from_literal(D - A:F:Y, B - A - X - F - H - Z, F - Y)

net1 %u% net2
#> IGRAPH e5c9323 UN-- 13 21 -- 
#> + attr: name (v/c)
#> + edges from e5c9323 (vertex names):
#>  [1] I--J H--Z H--I G--H G--E F--X F--Y F--H F--C F--G B--E B--G A--X A--C A--F
#> [16] A--B D--Y D--G D--F D--B D--A
igraph::union(list(net1, net2))
#> Error in as.vector(y): argument "y" is missing, with no default

do.call(igraph::union, list(net1, net2))
#> IGRAPH d978a03 UN-- 13 21 -- 
#> + attr: name (v/c)
#> + edges from d978a03 (vertex names):
#>  [1] I--J H--Z H--I G--H G--E F--X F--Y F--H F--C F--G B--E B--G A--X A--C A--F
#> [16] A--B D--Y D--G D--F D--B D--A

# no dynamic dots thing
igraph::union(!!!list(net1, net2))
#> Error in !list(net1, net2): invalid argument type

Created on 2024-02-26 with reprex v2.1.0

I'm not sure the current behavior of igraph::union(list(net1, net2)) not working is bad, but should we make igraph::union(!!!list(net1, net2)) work, is it at all possible.

maelle avatar Feb 26 '24 12:02 maelle

We can always use rlang::inject() :

options(conflicts.policy = list(warn = FALSE))
library("igraph")

net1 <- graph_from_literal(
  D - A:B:F:G, A - C - F - A, B - E - G - B, A - B,
  F - G, H - F:G, H - I - J
)

net2 <- graph_from_literal(D - A:F:Y, B - A - X - F - H - Z, F - Y)

# no dynamic dots thing
igraph::union(!!!list(net1, net2))
#> Error in !list(net1, net2): invalid argument type

# we always can work around with rlang::inject()
rlang::inject(igraph::union(!!!list(net1, net2)))
#> IGRAPH 18dad17 UN-- 13 21 -- 
#> + attr: name (v/c)
#> + edges from 18dad17 (vertex names):
#>  [1] I--J H--Z H--I G--H G--E F--X F--Y F--H F--C F--G B--E B--G A--X A--C A--F
#> [16] A--B D--Y D--G D--F D--B D--A

Created on 2024-03-12 with reprex v2.1.0

On the other hand:

union(1, 2, 3)
#> Error in union(1, 2, 3): unused argument (3)

options(conflicts.policy = list(warn = FALSE))
library(dplyr)

union(tibble(a = 1), tibble(a = 2), tibble(a = 3))
#> Error in `union()`:
#> ! `...` must be empty.
#> ✖ Problematic argument:
#> • ..1 = tibble(a = 3)
#> ℹ Did you forget to name an argument?

Created on 2024-03-12 with reprex v2.1.0

Propose to drop support for the 3rd, 4th, ... argument, with a lifecycle warning?

krlmlr avatar Mar 12 '24 14:03 krlmlr

Consistency vs. innovation. A hard choice. 🤷

krlmlr avatar Mar 12 '24 14:03 krlmlr