jtextor / dagitty

Graphical analysis of structural causal models / graphical causal models.
GNU General Public License v2.0
286 stars 46 forks source link

Feature request: add an as.igraph.dagitty method that captures all dagitty node and edge attributes #84

Open grasshoppermouse opened 10 months ago

grasshoppermouse commented 10 months ago

This would seamlessly export dagitty objects to igraph, tidygraph, and other powerful graph packages. (BTW, thanks for this great package, which I've integrated into my quantitative methods course)

jtextor commented 10 months ago

Can you please help me test this feature? I made it available on a new branch that you can install like this:

remotes::install_github("jtextor/dagitty/r@igraph-export")

grasshoppermouse commented 10 months ago

Thanks for tackling this! I get an error when including a beta edge attribute. It would also be nice to capture the exposure and outcome attributes.

library(dagitty)

g <- dagitty('dag{
  A [pos="0,-2"]
  B [pos="2,-2"]
  D [outcome,pos="2,0"]
  E [exposure,pos="0,0"] 
  Z [pos="1,-1"]
  A -> { E Z }
  B -> { D Z }
  E -> D
  Z -> { D E } }'
)
gi <- convert(g, to = 'igraph')
igraph::edge_attr(gi)
#> $arrow.mode
#> [1] "->" "->" "->" "->" "->" "->" "->"
igraph::vertex_attr(gi) # Doesn't capture exposure or outcome
#> $name
#> [1] "A" "B" "D" "E" "Z"
#> 
#> $x
#> [1] 0 2 2 0 1
#> 
#> $y
#> [1] -2 -2  0  0 -1

# Error when including beta attribute
g <- dagitty('dag{z -> x [beta=-.6] x <- y [beta=-.6] }')
gi <- convert(g, to = 'igraph')
#> Error: object 'ee' not found

Created on 2023-12-07 with reprex v2.0.2

szhorvat commented 10 months ago

Is this conversion meant exclusively for visualization purposes? At the moment, directed, bidirectional and undirected edges are not distinguishable in a way that is useful for computation.

Note that igraph does not support mixed graphs, nor is it likely to do so in the foreseeable future. There are ways around this, but the best way depends on what one might want to do with this graph in igraph (other than just plot it).

What are the goals here?

Probably the most flexible representation for computation is not a single graph, but a pair of graphs, one directed and one undirected. These two can then be combined using union(..., byname=FALSE) after an application-appropriate transformation of the udirected one to directed.

jtextor commented 10 months ago

As far as I am concerned, this is currently for visualization purposes mainly, and will only support a subset of the types of mixed graphs that dagitty supports. Current supported edge types are: "-", "->", "<->", "@--", "@->", "@-@"; but most of the applications only need "-", "->", "<->". In dagitty <-> is not the same thing as two separate directed edges.

Because only undirected, directed, and bi-directed edges cover most use cases, I was thinking of supporting this using the arrow.mode attribute (https://igraph.org/r/doc/plot.common.html currently says "this parameter can be used as a ‘cheap’ solution for drawing “mixed” graphs"). This makes it possible to export a graph and plot it in igraph relatively easily e.g. this currently works:

igraph::plot.igraph(dagitty::convert(dagitty::getExample("Shrier"),"igraph"))

I don't think downstream computations in igraph are currently useful or required, but if someone would do this (e.g. manipulate the graph), it would be quite easy to convert this back to dagitty, provided that the arrow.mode attribute is preserved.

Best regards Johannes