# \[ANN\] CausalStructures.jl: a Julia package for causal graphs

**URL:** <https://discourse.julialang.org/t/ann-causalstructures-jl-a-julia-package-for-causal-graphs/139717>\
**Category:** Package Announcements\
**Tags:** package, announcement, plotting, statistics, causal-inference\
**Created:** [September 28, 2026, 12:17pm UTC](https://discourse.julialang.org/t/ann-causalstructures-jl-a-julia-package-for-causal-graphs/139717 "2026-09-28T12:17:03Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![BjarkeHautop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarkehautop/32/219291_2.png) [@BjarkeHautop](https://discourse.julialang.org/u/BjarkeHautop)\
**Post date:** [September 28, 2026, 12:17pm UTC](https://discourse.julialang.org/t/ann-causalstructures-jl-a-julia-package-for-causal-graphs/139717/1 "2026-09-28T12:17:03Z")

</div>

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):

```julia
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`:

```julia
adjustment_set(dag, :X, :Y; type = :optimal)
#> 1-element Vector{Symbol}:
#> :Z

```

Or convert the DAG to its Markov equivalence class:

```julia
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](https://bjarkehautop.github.io/CausalStructures.jl/stable) 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:

```julia
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,
)

```

 ![plot-1](https://global.discourse-cdn.com/julialang/original/3X/c/1/c1bac1d86167b51ee00167d6e75679ae13351e08.png)

See the [plotting documentation](https://bjarkehautop.github.io/CausalStructures.jl/dev/40-plotting/) for more details.

# Related packages

- [dagitty](https://dagitty.net/):  
Very similar to what this package tries to do. However, it mainly focuses on DAGs only.
- [CausalInference.jl](https://github.com/mschauer/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](https://bjarkehautop.github.io/CausalStructures.jl/dev/70-benchmarks/)  
for numbers on individual functions, and [/benchmark](https://github.com/BjarkeHautop/CausalStructures.jl/tree/main/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:

- [GitHub](https://github.com/BjarkeHautop/CausalStructures.jl)
- [Docs](https://bjarkehautop.github.io/CausalStructures.jl/stable)
