I’d like to share CausalStructures.jl, a package for causal graphs that I’ve been working on the last several months, and I just released 1.0.
CausalStructures.jl supports DAGs, of course, but also their equivalence classes (PDAGs/MPDAGs/CPDAGs), graphs with latent variables (ADMGs), Ancestral Graphs (AGs/MAGs), and equivalence classes of MAGs (PAGs). You can then work with the causal graphs, such as:
- Queries: d-/m-separation, ancestors/descendants, Markov blankets, etc.
- Identification: the Generalized Adjustment Criterion, backdoor, frontdoor, instrumental variables, the ID/IDC algorithm, etc.
- Transformations: moralization, latent projection, DAG from/to MPDAG/CPDAG, MAG from/to PAG, etc.
Example
To define a DAG we write the edges as a string
(+ fans a marker out to several nodes at once):
using CausalStructures
dag = DAG("Z --> X + Y, X --> M --> Y")
We can then e.g. find an adjustment set that identifies the effect of X on Y:
adjustment_set(dag, :X, :Y; type = :optimal)
#> 1-element Vector{Symbol}:
#> :Z
Or convert the DAG to its Markov equivalence class:
dag_to_cpdag(dag)
#> CPDAG with 4 nodes and 4 edges:
#> nodes: M, X, Y, Z
#> edges:
#> M --- X, X --- Z, M --> Y, Z --> Y
Of course this barely scratches the surface of what the package can do; see the docs for the rest.
Plotting
Plotting requires loading a Makie backend, and a layout - it then works on any graph class natively. Styling is fully customizable, e.g. node/edge colors, shapes, curvature, and labels:
using CausalStructures, CairoMakie, NetworkLayout
pag = PAG(
"C o-> X, D --> G + Y, X --> D + F, Y --> H, K o-> X, K --> Y"
)
plot(
pag;
layout = :spring,
node_color = Dict(:X => :skyblue, :Y => :gold, :default => :whitesmoke),
node_strokecolor = Dict(:X => :royalblue, :Y => :darkorange, :default => :slategray),
node_shape = Dict(:K => :square, :default => :circle),
node_linestyle = Dict(:K => :dash, :default => nothing),
edge_color = Dict(:partially_directed => :royalblue, :default => :darkslategray),
edge_linestyle = Dict(:partially_directed => :dash),
curvature = Dict((:K, :Y) => 0.3),
edge_labels = Dict((:K, :X) => "cool"),
node_label_color = Dict(:X => :navy, :Y => :saddlebrown, :default => :black),
title = "A cool PAG",
title_fontsize = 18,
title_color = :navy,
)
See the plotting documentation for more details.
Related packages
- dagitty:
Very similar to what this package tries to do. However, it mainly focuses on DAGs only. - CausalInference.jl:
Mainly focuses on causal discovery, and not working with causal graphs. It does implement a few algorithms for DAGs only.
Performance
Performance has also been a priority; see the benchmark docs
for numbers on individual functions, and /benchmark for a direct comparison against CausalInference.jl on the overlapping functionality.
CausalStructures.jl is also --trim=safe compatible for those that care about that :).
Feedback, issues, and contributions are all very welcome:
