API Reference
Layout utilities
DAGMakie.time_indexed_layout — Function
time_indexed_layout(n_variables, n_times; dx=2.0, dy=1.5, origin=(0.0, 0.0))Grid layout for time-unrolled causal graphs.
Node order must be outer loop over occasions t = 1:n_times and inner loop over variables v = 1:n_variables (the indexing used by CausalDynamics unroll_temporal_dag). Column t is at x = origin[1] + (t - 1) * dx; variable row v is at y = origin[2] - (v - 1) * dy.
Returns
Vector{Point2f}of lengthn_variables * n_times
DAGMakie.dagplot_time_indexed — Function
dagplot_time_indexed(g, n_variables, n_times; kwargs...)dagplot with time_indexed_layout for graphs unrolled over time.
Pass nlabels with one label per node in the same (t, variable) order as time_indexed_layout. Remaining keywords go to dagplot.
DAGMakie.digraph_skeleton — Function
digraph_skeleton(g::AbstractGraph) -> SimpleGraphUndirected skeleton of a directed graph: keep an undirected edge {i,j} whenever g has i → j, j → i, or both.
Useful for CPDAG-style PC output that encodes an undirected edge as a pair of opposing directed edges. Prefer this over plotting both arrows. See dagplot_skeleton for a ready-made figure with undirected stroke styling.
DAGMakie.dagplot_skeleton — Function
dagplot_skeleton(g; kwargs...)Plot the undirected skeleton of g (digraph_skeleton).
Arrowheads are suppressed and edges use UNDIRECTED_EDGE_COLOR unless overridden. Remaining keywords go to dagplot.
DAGMakie.graph_from_structural_matrix — Function
graph_from_structural_matrix(B; atol=0.0)Build a SimpleDiGraph from a structural parameter matrix B (linear SEM / linear SCM weights), including self-loops for non-zero diagonal entries.
Convention matches structural_edge_labels: B[i, j] is the weight of node j in the assignment for node i, so a non-zero entry yields the directed edge j → i. In particular, B[i, i] ≠ 0 yields a self-loop at i, which GraphMakie draws as a self-pointing arc.
Entries with absolute value at most atol are treated as absent.
Arguments
B: Square structural weight matrixatol: Absolute tolerance for treating entries as zero
Returns
SimpleDiGraphwith one edge per non-zero structural weight
Example
B = [0.0 0.0 0.0; 0.8 0.0 0.0; 0.5 1.2 3.0]
g = graph_from_structural_matrix(B) # edges 1→2, 1→3, 2→3, and self-loop 3→3DAGMakie.ensure_structural_self_loops! — Function
ensure_structural_self_loops!(g, B; atol=0.0)Add missing self-loops i → i whenever |B[i, i]| > atol. Mutates g and returns it. Off-diagonal structure is left unchanged.
Used by structural_edge_labels when ensure_self_loops=true (the default) so a non-zero diagonal is enough to draw self-pointing arcs.
DAGMakie.structural_edge_labels — Function
structural_edge_labels(g, B; latex=true, digits=2, ensure_self_loops=true)Build GraphMakie elabels for g from a structural parameter matrix B (linear SEM / linear SCM weights).
Convention: B[i, j] is the structural weight of node j in the assignment for node i, i.e. the parameter on the directed edge j → i (including self-loops when i == j). Labels are returned in Graphs.edges(g) order (the order GraphMakie expects for elabels).
When ensure_self_loops=true (default), non-zero diagonal entries that are missing from g are added in place via ensure_structural_self_loops! before labels are built. Off-diagonal non-zeros without a matching edge still warn (and are omitted from labels). You can also build the full edge set with graph_from_structural_matrix.
This is deliberately not named “effects”: in the Pearl ladder an effect is usually an interventional or counterfactual estimand, whereas these labels are structural parameters (or other short mechanism annotations) on the graph.
When latex=true (default), each entry is a Makie LaTeXString so parameters render as maths on the edge. Set latex=false for plain String labels.
Examples
g, labels = confounding_graph(["Z", "X", "Y"])
B = [0 0 0; 0.8 0 0; 0.5 1.2 3.0] # diagonal 3.0 → self-loop on Y
fig, ax, p = dagplot(g;
nlabels = labels,
elabels = structural_edge_labels(g, B), # adds Y → Y automatically
elabels_fontsize = 14,
elabels_distance = 12,
elabels_rotation = 0,
)structural_edge_labels(g, labels; latex=false)Pass edge annotations already ordered as Graphs.edges(g). With latex=true, wrap plain strings (or numbers) as LaTeXString via Makie.latexstring so short TeX such as "\\beta_{ZX}" or a fragment of a structural assignment renders on the edge.
DAGMakie.edge_coefficient_labels — Function
edge_coefficient_labels(args...; kwargs...)Deprecated alias for structural_edge_labels.
Main Plotting Functions
DAGMakie.dagplot — Function
dagplot(g; kwargs...)Create a clean DAG visualisation with publication-ready defaults.
This is a convenience wrapper that creates a new figure and axis, then delegates to dagplot!. All keyword arguments are passed through.
Arguments
g::AbstractGraph: A graph from Graphs.jl to plot
Keyword Arguments
figure_size::Tuple{Int, Int} = (600, 400): Figure dimensions- See
dagplot!for all other keyword arguments
Returns
- Tuple
(fig, ax, p)where:fig: The Figure objectax: The Axis objectp: The GraphPlot object (for accessing node positions, etc.)
Examples
using Graphs, DAGMakie, CairoMakie
# Simple chain graph
g = SimpleDiGraph(3)
add_edge!(g, 1, 2)
add_edge!(g, 2, 3)
fig, ax, p = dagplot(g, nlabels=["X", "Y", "Z"])
save("dag.png", fig)
# Access node positions
positions = p[:node_pos][]dagplot(spec::DAGSpec; kwargs...)Plot a DAG from a DAGSpec specification.
Arguments
spec::DAGSpec: A DAG specification with graph, nodes, and edges
Keyword Arguments
- Same as
dagplot(g; kwargs...)
Returns
- Tuple
(fig, ax, p)
dagplot(mg::MixedGraph; kwargs...)Create a DAG visualisation with both directed and bidirected edges.
Bidirected edges (↔) are rendered as curved arcs with double arrowheads, representing unmeasured common causes (latent confounders).
Additional Keyword Arguments
bidirected_color = :gray: Colour for bidirected edgesbidirected_width = 1.0: Line width for bidirected edgesbidirected_style = :dash: Line style for bidirected edgesbidirected_curvature = 0.3: Curvature of bidirected arcsbidirected_arrow_size = 8: Size of arrowheads on bidirected edges
Examples
using DAGMakie, CairoMakie
# Confounded treatment-outcome
mg = mixed_graph(2, [(1, 2)], [(1, 2)]) # X → Y with X ↔ Y
fig, ax, p = dagplot(mg, nlabels=["X", "Y"])
# Instrumental variable with confounding
mg = mixed_graph(3, [(1, 2), (2, 3)], [(2, 3)]) # Z → X → Y, X ↔ Y
fig, ax, p = dagplot(mg, nlabels=["Z", "X", "Y"])DAGMakie.dagplot! — Function
dagplot!(ax, g; kwargs...)Plot a DAG into an existing axis with clean, publication-ready styling.
Automatically hides axis decorations, applies DataAspect, and sets appropriate limits to prevent clipping of nodes and labels.
Arguments
ax: A Makie Axis objectg::AbstractGraph: A graph from Graphs.jl to plot
Layout Keyword Arguments
layout = Spring(): Layout algorithm from NetworkLayout.jlpadding::Float64 = 0.1: Padding around graph as fraction of range
Node Keyword Arguments
node_size = 12: Node marker size in pixelsnode_color = DEFAULT_NODE_COLOR: Node fill colour (single value or vector; steel-blue by default)node_strokewidth = 1.0: Node outline widthnode_strokecolor = :black: Node outline colournode_marker = :circle: Node marker shape
Edge Keyword Arguments
edge_color = :black: Edge colouredge_width = 1.0: Edge line widtharrow_size = 10: Arrowhead sizearrow_shift = :end: Arrow position (:endor Float64 0-1)elabels = nothing: Edge labels inGraphs.edges(g)order. Accepts plainStrings or MakieLaTeXStrings (e.g. fromstructural_edge_labelswithlatex=true) for structural parameters or short mechanism TeX on edgeselabels_fontsize,elabels_distance,elabels_rotation,elabels_side, … : forwarded to GraphMakie (useelabels_rotation = 0to keep maths upright)selfedge_size,selfedge_direction,selfedge_width: GraphMakie self-loop geometry. When the graph has self-loops andselfedge_sizeis omitted, DAGMakie defaults toDEFAULT_SELFEDGE_SIZE(compact beside the node)
Label Keyword Arguments
nlabels = nothing: Node labels (vector of strings /LaTeXStrings, ornothing)nlabels_align = (:center, :center): Makie text-box anchor (or vector of anchors). Named sides are edges of the label, not “label goes this side of the node”:(:left, :center)left-anchors the text so it sits to the right of the node. See the Label Alignment guide.auto_align_labels = false: When true, place labels outside nodes in the largest angular gap (sets a positive distance and dark label colour unless you override them)nlabels_distance = 0: Label distance from node in pixels alongnlabels_align(0 centres labels in nodes; with(:center, :center)the offset is zero regardless of distance—use a non-centred align orauto_align_labels=truefor outside labels)nlabels_fontsize = 16: Label font sizenlabels_color = :white: Label colour (white on dark node fills)
Smart / dagitty colouring
smart = false: Settrue/:ancestorsfor dagitty-style ancestor colours, or:adjustmentto also emphasise a backdoor adjustment set (needs CausalInference oradjustment=)treatment,outcome: Exposure and outcome node indices (required whensmartis on)adjustment: OptionalSet{Int}forsmart=:adjustment
Additional Arguments
- Additional keyword arguments are passed to
GraphMakie.graphplot!
Returns
- The GraphPlot object
Examples
using Graphs, DAGMakie, CairoMakie
g = SimpleDiGraph(3)
add_edge!(g, 1, 2)
add_edge!(g, 1, 3)
add_edge!(g, 2, 3)
# Simple usage
fig = Figure()
ax = Axis(fig[1, 1])
dagplot!(ax, g, nlabels=["Z", "X", "Y"])
# With node colours indicating roles
dagplot!(ax, g,
nlabels=["Confounder", "Treatment", "Outcome"],
node_color=[NODE_COLOR_CONFOUNDER, DEFAULT_NODE_COLOR, DEFAULT_NODE_COLOR]
)
# Multiple DAGs in one figure
fig = Figure(size=(1200, 400))
ax1, ax2, ax3 = Axis(fig[1, 1]), Axis(fig[1, 2]), Axis(fig[1, 3])
dagplot!(ax1, g1, nlabels=["A", "B", "C"])
dagplot!(ax2, g2, nlabels=["X", "Y", "Z"])
dagplot!(ax3, g3, nlabels=["P", "Q", "R"])dagplot!(ax, spec::DAGSpec; kwargs...)Plot a DAG from a DAGSpec specification into an existing axis.
dagplot!(ax, mg::MixedGraph; kwargs...)Plot a MixedGraph (with bidirected edges) into an existing axis.
Convenience Pattern Functions
DAGMakie.dagplot_chain — Function
dagplot_chain(labels; kwargs...)Plot a simple chain DAG: X₁ → X₂ → ... → Xₙ
Arguments
labels::Vector{String}: Labels for each node in the chainkwargs...: Additional arguments passed todagplot
Returns
- Tuple
(fig, ax, p)
DAGMakie.dagplot_fork — Function
dagplot_fork(labels; kwargs...)Plot a fork DAG: X₁ ← X₂ → X₃
Arguments
labels::Vector{String}: Labels [left, fork, right]kwargs...: Additional arguments passed todagplot
DAGMakie.dagplot_collider — Function
dagplot_collider(labels; kwargs...)Plot a collider DAG: X₁ → X₂ ← X₃
Arguments
labels::Vector{String}: Labels [left, collider, right]kwargs...: Additional arguments passed todagplot
DAGMakie.dagplot_confounding — Function
dagplot_confounding(labels; kwargs...)Plot a confounding DAG: Z → X → Y, Z → Y.
Uses a triangle layout by default (confounder on top, treatment and outcome below). Layered left-to-right layout places one node per layer and draws the backdoor edge through the treatment node; pass layout to override.
Arguments
labels::Vector{String}: Labels [confounder, treatment, outcome]kwargs...: Additional arguments passed todagplot
DAGMakie.dagplot_mediation — Function
dagplot_mediation(labels; kwargs...)Plot a mediation DAG: X → M → Y, X → Y.
Uses a triangle layout by default (mediator on top, treatment and outcome below). Layered left-to-right layout places one node per layer and draws the direct effect through the mediator; pass layout to override.
Arguments
labels::Vector{String}: Labels [treatment, mediator, outcome]kwargs...: Additional arguments passed todagplot
DAGMakie.dagplot_confounded — Function
dagplot_confounded(labels; kwargs...)Plot a simple confounded graph: X → Y with X ↔ Y.
Uses a horizontal layout by default so the bidirected arc is visible above the directed edge; pass layout to override.
Arguments
labels::Vector{String}: Labels [treatment, outcome]
DAGMakie.dagplot_frontdoor — Function
dagplot_frontdoor(labels; kwargs...)Plot a frontdoor criterion graph: X → M → Y with X ↔ Y.
Uses a triangle layout by default (mediator on top). Layered layout collinearises the three nodes and obscures the bidirected confounding arc; pass layout to override.
Arguments
labels::Vector{String}: Labels [treatment, mediator, outcome]
DAGMakie.dagplot_iv_confounded — Function
dagplot_iv_confounded(labels; kwargs...)Plot an IV graph with confounding: Z → X → Y, X ↔ Y.
Uses a triangle layout by default (instrument on top). Layered layout collinearises the chain and hides the bidirected confounding arc; pass layout to override.
Arguments
labels::Vector{String}: Labels [instrument, treatment, outcome]
DAGMakie.dagplot_m_bias — Function
dagplot_m_bias(labels; kwargs...)Plot the classic five-node M-bias DAG with explicit latents:
U₁ → X, U₁ → M, U₂ → M, U₂ → YDefault layout forms the letter M (latents on top, $X$–$M$–$Y$ on the base). Pass layout to override.
Arguments
labels::Vector{<:AbstractString}: Labels $[U₁, U₂, X, M, Y]$
Types
Node Types
DAGMakie.NodeType — Type
NodeTypeEnumeration of node types in causal diagrams.
Values
Observed: Measured variable (filled circle)Latent: Unmeasured variable (hollow circle or dashed outline)Treatment: Treatment/exposure variable (thick stroke)Outcome: Outcome variable (emphasised stroke)Instrument: Instrumental variableConfounder: Confounding variableMediator: Mediating variableCollider: Collider variableEffectMeasure: Causal-effect node on an IDAG (not a factual outcome)SwigFixed: Fixed half of a SWIG split node (intervened value)
DAGMakie.NodeSpec — Type
NodeSpecSpecification for a single node in a DAG.
Fields
label::String: Display label for the nodetype::NodeType: Type of node (determines styling)color: Override colour (nothing= use type default)size::Union{Real, Tuple, Nothing}: Override size (nothing = use default; a(width, height)tuple is passed through to Makie for non-square markers)
Edge Types
DAGMakie.EdgeType — Type
EdgeTypeEnumeration of edge types in causal diagrams.
Values
Directed: Standard directed edge (→)Bidirected: Bidirected edge for unmeasured confounding (↔)Undirected: Undirected edge (—)Modifier: Pedagogical annotation that one variable modifies an effect (dash-dot; not an input to d-separation)
DAGMakie.EdgeSpec — Type
EdgeSpecSpecification for a single edge in a DAG.
Fields
src::Int: Source node indexdst::Int: Destination node indextype::EdgeType: Type of edgecolor: Override colourwidth::Union{Real, Nothing}: Override line widthstyle::Union{Symbol, Nothing}: Line style (:solid, :dash, :dot, etc.)label::Union{String, Nothing}: Optional edge label
DAG Specification
DAGMakie.DAGSpec — Type
DAGSpecComplete specification for a causal DAG visualisation.
Fields
graph::AbstractGraph: The underlying graph structurenodes::Vector{NodeSpec}: Node specifications (one per vertex)edges::Vector{EdgeSpec}: Edge specifications (overrides for specific edges)title::Union{String, Nothing}: Optional title for the DAG
Mixed Graphs
DAGMakie.MixedGraph — Type
MixedGraphA graph that supports both directed edges (→) and bidirected edges (↔).
Bidirected edges represent unmeasured common causes (latent confounders) in causal diagrams. Internally, bidirected edges are stored separately from the directed graph structure.
Fields
directed::SimpleDiGraph: The directed edgesbidirected::Set{Tuple{Int, Int}}: Set of bidirected edge pairs (unordered)
Examples
# Create a mixed graph with confounding
mg = MixedGraph(3)
add_directed_edge!(mg, 1, 3) # X → Y
add_directed_edge!(mg, 2, 3) # Z → Y
add_bidirected_edge!(mg, 1, 2) # X ↔ Z (unmeasured confounder)
# Or from existing directed graph
g = SimpleDiGraph(3)
add_edge!(g, 1, 3)
add_edge!(g, 2, 3)
mg = MixedGraph(g, [(1, 2)]) # Add bidirected edgePaths
DAGMakie.CausalPath — Type
CausalPathA path through a DAG, tracking nodes and edge directions (forward or backward along graph edges).
Fields
nodes::Vector{Int}: Sequence of nodesdirections::Vector{Symbol}: Direction of each edge (:forwardor:backward)
DAGMakie.PathSegment — Type
PathSegmentA segment of a path, tracking the direction of traversal.
Fields
node::Int: The node in this segmentdirection::Symbol::forward(→),:backward(←), or:start
DAGMakie.path_edges — Function
path_edges(path::CausalPath)Return the edges in a path as (src, dst) tuples in graph orientation.
DAGMakie.is_directed_path — Function
is_directed_path(path::CausalPath)Return true if every edge in the path is forward (a directed causal path).
Interventions
DAGMakie.Intervention — Type
InterventionSpecification for an intervention (do(·)) on one or more variables.
Fields
nodes::Vector{Int}: Nodes being intervened onvalues::Vector{String}: Display values for the interventions (e.g., "x=1")label::String: Overall intervention label (e.g., "do(X=1)")
DAGMakie.CausalQuery — Type
CausalQueryA query about a causal effect.
Fields
treatment::Int: Treatment variableoutcome::Int: Outcome variableintervention::Union{Intervention, Nothing}: Intervention (if specified)conditioning::Set{Int}: Variables to condition on
Graph Construction
DAGMakie.chain_graph — Function
chain_graph(labels::Vector{String})Create a simple chain DAG: X₁ → X₂ → ... → Xₙ
Arguments
labels: Vector of node labels
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.fork_graph — Function
fork_graph(labels::Vector{String})Create a fork DAG: X₁ ← X₂ → X₃ (with X₂ as the fork point)
Assumes 3 nodes: labels[1] ← labels[2] → labels[3]
Arguments
labels: Vector of 3 node labels
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.collider_graph — Function
collider_graph(labels::Vector{String})Create a collider DAG: X₁ → X₂ ← X₃ (with X₂ as the collider)
Assumes 3 nodes: labels[1] → labels[2] ← labels[3]
Arguments
labels: Vector of 3 node labels
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.confounding_graph — Function
confounding_graph(labels::Vector{String})Create a classic confounding DAG: Z → X → Y, Z → Y
Assumes 3 nodes: Z (confounder), X (treatment), Y (outcome)
Arguments
labels: Vector of 3 node labels [Z, X, Y]
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.mediation_graph — Function
mediation_graph(labels::Vector{String})Create a mediation DAG: X → M → Y, X → Y
Assumes 3 nodes: X (treatment), M (mediator), Y (outcome)
Arguments
labels: Vector of 3 node labels [X, M, Y]
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.instrumental_graph — Function
instrumental_graph(labels::Vector{String})Create an instrumental variable DAG: Z → X → Y, U → X, U → Y
Assumes 4 nodes: Z (instrument), X (treatment), Y (outcome), U (unobserved confounder)
Arguments
labels: Vector of 4 node labels [Z, X, Y, U]
Returns
- Tuple
(g, labels)wheregis the graph
DAGMakie.mixed_graph — Function
mixed_graph(n::Int, directed_edges, bidirected_edges)Create a MixedGraph with specified directed and bidirected edges.
Arguments
n::Int: Number of verticesdirected_edges: Iterable of(src, dst)pairs for directed edgesbidirected_edges: Iterable of(i, j)pairs for bidirected edges
Examples
# Confounded treatment-outcome graph
mg = mixed_graph(2, [(1, 2)], [(1, 2)]) # X → Y with X ↔ Y
# Instrumental variable setup
mg = mixed_graph(4,
[(1, 2), (2, 3)], # Z → X → Y
[(2, 3)] # X ↔ Y (unmeasured confounding)
)DAGMakie.confounded_graph — Function
confounded_graph(labels::Vector{String})Create a simple confounded graph: X → Y with X ↔ Y (unmeasured confounder).
Arguments
labels: Vector of 2 labels [treatment, outcome]
Returns
- Tuple
(mg, labels)wheremgis a MixedGraph
DAGMakie.frontdoor_graph — Function
frontdoor_graph(labels::Vector{String})Create a frontdoor criterion graph: X → M → Y with X ↔ Y.
Arguments
labels: Vector of 3 labels [treatment, mediator, outcome]
Returns
- Tuple
(mg, labels)wheremgis a MixedGraph
DAGMakie.iv_confounded_graph — Function
iv_confounded_graph(labels::Vector{String})Create an instrumental variable graph with confounding: Z → X → Y, X ↔ Y.
Arguments
labels: Vector of 3 labels [instrument, treatment, outcome]
Returns
- Tuple
(mg, labels)wheremgis a MixedGraph
DAGMakie.m_bias_graph — Function
m_bias_graph(labels)Create the classic five-node M-bias DAG with explicit latents:
U₁ → X, U₁ → M, U₂ → M, U₂ → YNo directed edge $X → Y$ (pure M-bias). Conditioning on the collider $M$ opens the non-causal path $X ← U₁ → M ← U₂ → Y$.
Arguments
labels: Vector of 5 labels $[U₁, U₂, X, M, Y]$ (defaults to those symbols)
Returns
- Tuple
(mg, labels)wheremgis aMixedGraphwith no bidirected edges (latents are drawn explicitly rather than as $X ↔ M ↔ Y$)
DAGMakie.m_bias_spec — Function
m_bias_spec(labels)DAGSpec for the five-node M-bias DAG with latent / collider styling.
Same edges as m_bias_graph: $U₁ → X$, $U₁ → M$, $U₂ → M$, $U₂ → Y$.
Highlighting
DAGMakie.HighlightSpec — Type
HighlightSpecSpecification for highlighting elements in a DAG plot.
Fields
nodes::Vector{Int}: Nodes to highlightnode_colors::Vector: Colors for highlighted nodesedges::Vector{Tuple{Int,Int}}: Edges to highlight (as src, dst pairs)edge_colors::Vector: Colors for highlighted edgeslabels::Vector{String}: Optional labels for highlighted nodes
DAGMakie.highlight_from_path — Function
highlight_from_path(path::CausalPath; color=:red)Create a HighlightSpec from a causal path.
DAGMakie.highlight_from_paths — Function
highlight_from_paths(paths::Vector{CausalPath}; colors=nothing)Create a HighlightSpec from multiple paths with different colors.
DAGMakie.highlight_adjustment_set — Function
highlight_adjustment_set(g::AbstractGraph, treatment::Int, outcome::Int,
adjustment::Set{Int}; treatment_color=:green,
outcome_color=:blue, adjustment_color=:orange)Create a HighlightSpec for visualising an adjustment set.
DAGMakie.highlight_backdoor_paths — Function
highlight_backdoor_paths(paths::Vector{CausalPath};
blocked_color=:gray, open_color=:red,
blocked::AbstractVector{Bool}=Bool[])Create a HighlightSpec from precomputed backdoor paths.
Pass blocked of the same length as paths to colour blocked vs open paths. If blocked is empty, all paths use open_color.
Path finding belongs in CausalInference.jl / CausalDynamics.jl — not DAGMakie.
DAGMakie.dagplot_highlighted — Function
dagplot_highlighted(g::AbstractGraph, highlight::HighlightSpec; kwargs...)Create a DAG plot with highlighted elements.
Arguments
g: The graphhighlight: HighlightSpec defining what to highlightkwargs...: Additional arguments passed to dagplot
Examples
g = confounding_graph(["Z", "X", "Y"])[1]
path = CausalPath([1, 2, 3]; directions = [:forward, :forward])
highlight = highlight_from_path(path, color=:red)
fig, ax, p = dagplot_highlighted(g, highlight, nlabels=["Z", "X", "Y"])DAGMakie.dagplot_highlighted! — Function
dagplot_highlighted!(ax, g::AbstractGraph, highlight::HighlightSpec; kwargs...)Plot a highlighted DAG into an existing axis.
DAGMakie.dagplot_backdoor — Function
dagplot_backdoor(g, treatment, outcome; adjustment=Set{Int}(), paths=CausalPath[], kwargs...)Plot a DAG highlighting treatment, outcome, an adjustment set, and optional precomputed backdoor paths.
For automatic adjustment / d-separation from CausalInference.jl, load that package so DAGMakieCausalInferenceExt activates, or pass adjustment / paths explicitly from CausalDynamics.jl.
DAGMakie.dagplot_dsep — Function
dagplot_dsep(g, x, y, z; separated, kwargs...)Plot a DAG with X, Y, and conditioning set Z highlighted.
Pass separated::Bool for the axis title (from CausalInference.jl dsep or CausalDynamics.jl d_separated). With using CausalInference, separated defaults via the package extension when omitted.
DAGMakie.dagplot_causal_paths — Function
dagplot_causal_paths(g, treatment, outcome; paths, kwargs...)Highlight precomputed directed paths from treatment to outcome.
DAGMakie.dagplot_adjustment — Function
dagplot_adjustment(g, treatment, outcome; adjustment=nothing, kwargs...)Plot a DAG with an adjustment set. Pass adjustment::Set{Int} explicitly, or using CausalInference so the extension can compute a minimal backdoor set.
Interventions
DAGMakie.do_surgery — Function
do_surgery(g::AbstractGraph, intervention_nodes::Vector{Int})Perform display-only graph surgery for do(·): remove all incoming edges to intervention nodes. Use this to draw mutilated DAGs in Makie; it is not an identification API.
For CausalDynamics identification and CDM interventions, use DoIntervention / apply_intervention (and related helpers) in CausalDynamics.jl.
Returns a graph where intervened nodes no longer have parents (for plotting).
Arguments
g: Original DAGintervention_nodes: Nodes being intervened on (set to fixed values)
Returns
- New SimpleDiGraph with incoming edges to intervention nodes removed
Examples
# Confounding: Z → X → Y, Z → Y
g = SimpleDiGraph(3)
add_edge!(g, 1, 2) # Z → X
add_edge!(g, 2, 3) # X → Y
add_edge!(g, 1, 3) # Z → Y
# do(X) - intervene on X
g_do = do_surgery(g, [2])
# Result: X → Y, Z → Y (Z → X edge removed)do_surgery(g::AbstractGraph, intervention_node::Int)Single-node intervention convenience method.
DAGMakie.do_surgery! — Function
do_surgery!(g::SimpleDiGraph, intervention_nodes::Vector{Int})In-place display-only graph surgery — modifies the original graph. Same boundary as do_surgery: for plotting mutilated DAGs, not CausalDynamics ID.
DAGMakie.dagplot_intervention — Function
dagplot_intervention(g::AbstractGraph, intervention::Intervention;
show_original::Bool=true, kwargs...)Plot a DAG with intervention applied, showing removed edges.
Arguments
g: Original DAGintervention: Intervention specificationshow_original: If true, show original edges as dashedkwargs...: Additional arguments for dagplot
Examples
g, labels = confounding_graph(["Z", "X", "Y"])
int = Intervention(2) # do(X)
fig, ax, p = dagplot_intervention(g, int, nlabels=labels)DAGMakie.dagplot_intervention! — Function
dagplot_intervention!(ax, g::AbstractGraph, intervention::Intervention; kwargs...)Plot intervention into an existing axis.
DAGMakie.dagplot_do — Function
dagplot_do(g::AbstractGraph, intervention_node::Int; nlabels=nothing, kwargs...)Convenience function for single-node intervention visualisation.
DAGMakie.dagplot_comparison — Function
dagplot_comparison(g::AbstractGraph, intervention::Intervention;
nlabels=nothing, kwargs...)Create a side-by-side comparison of original and post-intervention DAGs.
Returns
- Figure with two panels: original (left) and post-intervention (right)
DAGMakie.dagplot_do_comparison — Function
dagplot_do_comparison(g::AbstractGraph, intervention_node::Int;
nlabels=nothing, kwargs...)Convenience function for side-by-side comparison with single intervention.
DAGMakie.intervention_label — Function
intervention_label(var_name::String; value=nothing)Create a formatted intervention label: do(X) or do(X=x).
DAGMakie.format_intervention_labels — Function
format_intervention_labels(nlabels::Vector{String}, intervention::Intervention)Update node labels to show intervention notation.
DAGMakie.query_to_string — Function
query_to_string(query::CausalQuery, nlabels::Vector{String})Convert a causal query to readable notation for plot titles.
Visual grammar (interactions / DiD)
DAGMakie.modifier_edge — Function
modifier_edge(src, dst; kwargs...)Create a pedagogical modifier EdgeSpec (dash-dot, dark gray).
Modifier edges annotate that one variable modifies an effect; they are not inputs to d-separation. Prefer an IDAG (vaccine_nutrition_idag_spec) when the claim is about effect variation.
DAGMakie.dagplot_side_by_side — Function
dagplot_side_by_side(left, right; titles, figure_size, kwargs...)Plot two DAGSpec (or graph) panels with shared keyword overrides.
Used for outcome-DAG | IDAG and factual-DAG | SWIG companion figures.
DAGMakie.vaccine_nutrition_outcome_spec — Function
vaccine_nutrition_outcome_spec(; labels)Outcome DAG: nutrition $N$ confounds vaccination $V$ and outcome $Y$.
Suitable for identification / adjustment illustrations.
DAGMakie.vaccine_nutrition_idag_spec — Function
vaccine_nutrition_idag_spec(; labels)IDAG companion: replace $Y$ with an additive effect-measure node $δ$.
Arrows into $δ$ show which variables drive effect size (Nilsson et al. style).
DAGMakie.vaccine_nutrition_layout — Function
vaccine_nutrition_layout()Triangle layout with nutrition at the apex (same geometry as confounding demos).
DAGMakie.dagplot_vaccine_nutrition_interaction — Function
dagplot_vaccine_nutrition_interaction(; kwargs...)Side-by-side outcome DAG and IDAG for vaccine × nutrition effect modification.
DAGMakie.did_2x2_factual_spec — Function
did_2x2_factual_spec(; labels)Time-expanded factual DAG for a two-group, two-period DiD design.
Nodes (default order): $G$, $U$, $Y₀$, $Y₁$, $A₁$.
DAGMakie.did_2x2_swig_spec — Function
did_2x2_swig_spec(; labels)SWIG under $do(A₁ = 0)$ for the untreated world used by parallel trends.
Nodes (default order): $G$, $U$, $Y₀$, $Y₁(0)$, $A₁$, $a=0$. Incoming edges stay on the random half $A₁$; outflows leave from the fixed half $a=0$.
DAGMakie.did_2x2_factual_layout — Function
did_2x2_factual_layout()Manual positions for the factual 2×2 DiD DAG (time left→right).
DAGMakie.did_2x2_swig_layout — Function
did_2x2_swig_layout()Manual positions for the DiD SWIG with a split treatment node.
DAGMakie.dagplot_did_swig — Function
dagplot_did_swig(; kwargs...)Side-by-side factual 2×2 DiD DAG and untreated-world SWIG.
Smart / dagitty colouring
DAGMakie.SmartNodeRole — Type
SmartNodeRoleStructural role of a node relative to a chosen exposure and outcome (dagitty- style ancestor highlighting).
DAGMakie.classify_smart_roles — Function
classify_smart_roles(g, treatment, outcome; anc_treatment=nothing, anc_outcome=nothing)Classify each vertex into a SmartNodeRole given exposure treatment and outcome (1-based indices).
DAGMakie.smart_style_for_graph — Function
smart_style_for_graph(g, treatment, outcome; mode=:ancestors, adjustment=nothing)Return a named tuple of per-node styling for dagitty-like smart colouring.
Modes
:ancestors— exposure / outcome / ancestor-of-X / ancestor-of-Y / both / gray:adjustment— same, plus thicker stroke on a backdoor adjustment set (requires CausalInference, or passadjustment::Set{Int})
DAGMakie.dagplot_smart — Function
dagplot_smart(g, treatment, outcome; smart=:ancestors, kwargs...)Convenience wrapper: dagplot with dagitty-style smart node colours.
DAGMakie.ancestor_sets — Function
ancestor_sets(g, treatment, outcome) -> (anc_treatment, anc_outcome)Return ancestor sets of treatment and outcome. Uses CausalInference.jl when the extension is loaded; otherwise Graphs reverse-BFS.
DAGMakie.ancestors_via_graphs — Function
ancestors_via_graphs(g, seeds) -> Set{Int}Ancestors of seeds including the seeds themselves, via reverse BFS on inneighbors (Graphs only; no CausalInference).
DAGMakie.smart_node_color — Function
smart_node_color(role::SmartNodeRole)Return the default fill colour for a smart node role.
DAGMakie.smart_label_color — Function
smart_label_color(role::SmartNodeRole)Return in-node label colour for a smart role (black on light gray).
DAGMakie.SMART_COLOR_EXPOSURE — Constant
Fill for the exposure / treatment node under smart colouring.
DAGMakie.SMART_COLOR_OUTCOME — Constant
Fill for the outcome node under smart colouring.
DAGMakie.SMART_COLOR_ANC_EXPOSURE — Constant
Dagitty-like fill for ancestors of the exposure only.
DAGMakie.SMART_COLOR_ANC_OUTCOME — Constant
Dagitty-like fill for ancestors of the outcome only.
DAGMakie.SMART_COLOR_ANC_BOTH — Constant
Dagitty-like fill for ancestors of both (often backdoor-relevant).
DAGMakie.SMART_COLOR_IRRELEVANT — Constant
Fill for nodes outside the ancestral closure of exposure ∪ outcome.
Label Alignment
DAGMakie.compute_auto_label_aligns — Function
compute_auto_label_aligns(g::AbstractGraph, node_positions::AbstractVector)Compute optimal label alignment for each node to avoid edge overlaps.
For each node, finds the largest angular gap between incident edges and places the label in the middle of that gap. This ensures labels do not overlap with edges, improving readability of causal diagrams.
Arguments
g::AbstractGraph: A graph from Graphs.jl (directed or undirected)node_positions::AbstractVector: Vector of node positions (Point2f or similar)
Returns
Vector{Tuple{Symbol, Symbol}}: Alignment tuples(:horizontal, :vertical)for each node, suitable for use withnlabels_alignin GraphMakie.
Algorithm
- For each node, collect angles of all incident edges (both incoming and outgoing)
- Normalise angles to [0, 2π] and sort
- Find the largest angular gap between adjacent edges (including wrap-around)
- Place label in the middle of the largest gap
- Map the gap midpoint angle to one of 8 alignment directions
Edge Cases
- Isolated nodes (no incident edges): Returns
(:right, :bottom)as default - Single edge: Places label opposite the edge direction
- All edges in one direction: Places label in the opposite hemisphere
Examples
using Graphs, DAGMakie
g = SimpleDiGraph(3)
add_edge!(g, 1, 2)
add_edge!(g, 2, 3)
# Compute positions (e.g., from a layout algorithm)
positions = [Point2f(0, 0), Point2f(1, 0), Point2f(2, 0)]
# Get optimal alignments
aligns = compute_auto_label_aligns(g, positions)
# aligns[1] might be (:center, :top) since edge goes right
# aligns[2] might be (:center, :top) since edges go left and right
# aligns[3] might be (:center, :top) since edge goes leftNotes
- Works with any layout algorithm (uses computed node positions)
- Handles both directed and undirected graphs
- Time complexity: O(V × E) where V is vertices and E is edges
- Intended for outside-node labels: pair with a positive
nlabels_distance(seeresolve_auto_align_label_settings). With distance 0 the non-centred alignments only shift text inside the marker and look broken.
DAGMakie.align_to_direction — Function
align_to_direction(align::Tuple{Symbol, Symbol})Convert a Makie text-box align to the offset direction GraphMakie uses with nlabels_distance.
Makie align names the edge of the label that sits on the anchor. Combined with a positive distance, that places the label on the opposite side of the node (e.g. (:left, :center) → offset east → label to the right of the node).
Arguments
align: Tuple of(:horizontal, :vertical)Makie text-align symbols
Returns
- Direction from node toward the label (for use as
distance .* dir)
Examples
align_to_direction((:left, :center)) # (1, 0) — label ends up east of node
align_to_direction((:right, :center)) # (-1, 0) — label ends up west of node
align_to_direction((:center, :bottom)) # (0, 1) — label ends up north of nodeDAGMakie.resolve_auto_align_label_settings — Function
resolve_auto_align_label_settings(g, positions; align, distance, color,
distance_explicit, color_explicit)Resolve label align / distance / colour when auto_align_labels=true.
Auto-align places labels in the largest angular gap outside the node. If the caller left the in-node defaults (distance == 0, white text), switch to AUTO_ALIGN_LABEL_DISTANCE and AUTO_ALIGN_LABEL_COLOR. Explicit nlabels_distance / nlabels_color from the caller are preserved.
Layout Utilities
DAGMakie.estimate_label_extent — Function
estimate_label_extent(label, align, fontsize, distance)Estimate the extent of a label in pixel coordinates.
Returns a named tuple (dx_min, dx_max, dy_min, dy_max) representing the approximate bounding box offset from the node position.
Arguments
label::AbstractString: The label textalign::Tuple{Symbol, Symbol}: Alignment tuple(:horizontal, :vertical)fontsize::Real: Font size in pixelsdistance::Real: Label distance from node in pixels
Returns
- Named tuple with
dx_min,dx_max,dy_min,dy_maxin pixels
Notes
- Uses approximate character width of 0.6 × fontsize for typical fonts
- Returns pixel-space estimates (caller must convert to data coordinates)
DAGMakie.compute_label_bounds — Function
compute_label_bounds(node_positions, nlabels, nlabels_align, nlabels_distance, nlabels_fontsize)Compute the bounding box that encompasses all nodes and their labels.
Arguments
node_positions::AbstractVector: Vector of node positions (Point2f or similar)nlabels::AbstractVector{<:AbstractString}: Vector of label stringsnlabels_align: Vector of alignment tuples or single tuple for allnlabels_distance::Real: Label distance from node in pixelsnlabels_fontsize::Real: Font size for labels
Returns
- Tuple
(x_min, x_max, y_min, y_max)in data coordinates
Notes
- Estimates pixel-to-data conversion based on current data range
- Assumes typical figure width of ~500 pixels for the data range
DAGMakie.compute_padded_limits — Function
compute_padded_limits(node_positions, nlabels, nlabels_align, nlabels_distance, nlabels_fontsize; padding=0.1, node_sizes=nothing)Compute axis limits with padding that includes all nodes, labels, and marker extents.
Arguments
node_positions: Vector of node positionsnlabels: Vector of label strings (ornothingfor no labels)nlabels_align: Alignment specificationnlabels_distance: Label distance in pixelsnlabels_fontsize: Font sizepadding::Float64 = 0.1: Padding as fraction of range (0.1 = 10%)node_sizes: Optional node marker size(s) in pixels; used so flat chains/columns are not cropped underDataAspect
Returns
- Tuple of tuples
((x_min, x_max), (y_min, y_max))for axis limits
DAGMakie.get_node_positions — Function
get_node_positions(p)Extract node positions from a GraphPlot object.
Arguments
p: A GraphMakie GraphPlot object
Returns
- Vector of node positions (Point2f or Point3f)
DAGMakie.graph_extent — Function
graph_extent(node_positions)Compute the spatial extent of a graph from node positions.
Arguments
node_positions: Vector of node positions
Returns
- Named tuple
(x_min, x_max, y_min, y_max, x_range, y_range)
DAGMakie.compute_graph_layout — Function
compute_graph_layout(g; kwargs...)Resolve deterministic positions and feedback-edge routing metadata for a graph.
If layout is provided, those positions are respected, but the graph is still classified so cyclic feedback routing can be applied consistently.
When layout is omitted and the graph is a 3-node transitive triangle (unique source with edges to both other nodes plus an edge between them), an apex-top pedagogical layout is used so the shortcut edge remains visible.
DAGMakie.DAGLayoutResult — Type
DAGLayoutResultResolved node positions and routing metadata for a graph visualisation.
Fields
positions::Vector{Point2f}: Node positions in data coordinateskind::Symbol: One of:acyclic,:cyclic,:mixed_acyclic, or:mixed_cyclicnode_layers::Vector{Int}: Layer index for each nodecomponent_index::Vector{Int}: Strongly connected component index for each nodecomponents::Vector{Vector{Int}}: Node membership for each componentcomponent_layers::Vector{Int}: Layer index for each componentfeedback_edges::Vector{Tuple{Int, Int}}: Directed edges routed as feedback edgesedge_waypoints::Dict{Tuple{Int, Int}, Vector{Point2f}}: Extra waypoints for curved edges
DAGMakie.classify_graph_kind — Function
classify_graph_kind(g)Classify a graph by directed cyclicity and mixed-edge support.
Self-loops are ignored for this classification: they are drawn by GraphMakie as local self-arcs and should not force the multi-node cyclic / feedback layout.
DAGMakie.feedback_edge_mask — Function
feedback_edge_mask(g, layout_result)Return a Boolean mask, aligned with edges(g), indicating which directed edges should be rendered as curved feedback overlays.
DAGMakie.edge_waypoint_vector — Function
edge_waypoint_vector(g, layout_result)Materialise a per-edge waypoint vector aligned with edges(g) for GraphMakie.graphplot!.
DAGMakie.node — Function
node(label; kwargs...)Shorthand for creating a NodeSpec.
DAGMakie.edge — Function
edge(src, dst; kwargs...)Shorthand for creating an EdgeSpec.
Themes and Styling
DAGMakie.dag_theme — Function
dag_theme()Return a clean theme for DAG visualisation.
This theme removes axes, grids, and frames to create publication-ready causal diagrams with focus on the graph structure.
Returns
Theme: A Makie theme with clean DAG styling
Usage
using CairoMakie, DAGMakie
# Apply theme globally
set_theme!(dag_theme())
# Or use with_theme for a single plot
with_theme(dag_theme()) do
dagplot(g, nlabels=["X", "Y", "Z"])
endDAGMakie.apply_dag_theme! — Function
apply_dag_theme!(ax)Apply clean DAG theme to an existing axis.
Hides all axis decorations (spines, ticks, labels, grid) and sets DataAspect for proper graph proportions.
Arguments
ax: A Makie Axis object
Example
fig = Figure()
ax = Axis(fig[1, 1])
apply_dag_theme!(ax)
graphplot!(ax, g)DAGMakie.DAGStyle — Type
DAGStylePreset styling configuration for DAG visualisation.
Fields
node_size::Real: Node size in pixelsnode_color::Symbol: Default node colournode_strokewidth::Real: Node outline widthnode_strokecolor::Symbol: Node outline colouredge_color::Symbol: Edge colouredge_width::Real: Edge line widtharrow_size::Real: Arrowhead sizearrow_shift: Arrow position (:endor Float64)label_fontsize::Real: Label font sizelabel_color::Symbol: Label colourlabel_distance::Real: Label distance from nodepadding::Float64: Padding fraction
DAGMakie.default_style — Function
default_style()Return the default DAG styling configuration.
DAGMakie.minimal_style — Function
minimal_style()Return a minimal DAG style with smaller nodes and thinner edges.
DAGMakie.bold_style — Function
bold_style()Return a bold DAG style with larger nodes and thicker edges.
DAGMakie.presentation_style — Function
presentation_style()Return a style optimised for presentations (large, high contrast, in-node labels).
DAGMakie.UNDIRECTED_EDGE_COLOR — Constant
Default colour for undirected (CPDAG skeleton) edges.
DAGMakie.AUTO_ALIGN_LABEL_DISTANCE — Constant
Pixel offset used when auto_align_labels=true places labels outside nodes.
DAGMakie.AUTO_ALIGN_LABEL_COLOR — Constant
Label colour for outside-node auto-aligned labels.
DAGMakie.DEFAULT_NODE_COLOR — Constant
Default node colour (steel-blue; white labels read clearly).
DAGMakie.DEFAULT_NODE_SIZE — Constant
Default node size in pixels (large enough for in-node labels).
DAGMakie.DEFAULT_EDGE_COLOR — Constant
Default edge colour.
DAGMakie.DEFAULT_LABEL_FONTSIZE — Constant
Default label font size.
DAGMakie.DEFAULT_LABEL_DISTANCE — Constant
Default label distance from node (pixels); 0 centres labels in nodes.
DAGMakie.DEFAULT_SELFEDGE_SIZE — Constant
Default GraphMakie selfedge_size (data units) for self-loops.
GraphMakie's automatic size is half the nearest-neighbour distance, which is oversized on typical DAG layouts; keep loops compact beside the marker.
DAGMakie.MODIFIER_EDGE_COLOR — Constant
Colour for pedagogical modifier annotations.
DAGMakie.MODIFIER_EDGE_STYLE — Constant
Line style for pedagogical modifier annotations.
DAGMakie.MODIFIER_EDGE_WIDTH — Constant
Line width for pedagogical modifier annotations.
DAGMakie.NODE_COLOR_CONFOUNDER — Constant
Highlight colour for confounders / exogenous noise / instruments.
DAGMakie.NODE_COLOR_MEDIATOR — Constant
Highlight colour for mediators or other focal nodes.
DAGMakie.NODE_COLOR_EFFECT — Constant
Fill for IDAG effect-measure nodes (same family as mediators).
DAGMakie.NODE_COLOR_SWIG_FIXED — Constant
Fill for the fixed half of a SWIG split node.
DAGMakie.TREATMENT_STROKEWIDTH — Constant
Stroke width for treatment / exposure nodes.
DAGMakie.OUTCOME_STROKEWIDTH — Constant
Stroke width for outcome nodes (emphasised outline).
Node Type Styling
DAGMakie.default_node_color — Function
default_node_color(type::NodeType)Return the default colour for a given node type.
DAGMakie.default_node_marker — Function
default_node_marker(type::NodeType)Return the default marker for a given node type.
DAGMakie.default_node_strokewidth — Function
default_node_strokewidth(type::NodeType)Return the default stroke width for a given node type.
DAGMakie.default_node_strokecolor — Function
default_node_strokecolor(type::NodeType)Return the default outline colour for a given node type.
DAGMakie.default_node_label_color — Function
default_node_label_color(type::NodeType)Return the default in-node label colour for a given node type.
DAGMakie.node_type_marker — Function
node_type_marker(type::NodeType)Return the marker shape for a given node type (delegates to default_node_marker).
DAGMakie.node_type_color — Function
node_type_color(type::NodeType)Return the default fill colour for a given node type.
DAGMakie.node_type_strokewidth — Function
node_type_strokewidth(type::NodeType)Return the stroke width for a given node type.
DAGMakie.node_type_strokecolor — Function
node_type_strokecolor(type::NodeType)Return the stroke colour for a given node type.
DAGMakie.node_type_label_color — Function
node_type_label_color(type::NodeType)Return the in-node label colour for a given node type.
DAGMakie.apply_node_type_styling — Function
apply_node_type_styling(node_types::Vector{NodeType})Generate styling arrays for a list of node types.
Arguments
node_types: Vector of NodeType for each node
Returns
- Named tuple with:
colors: Vector of fill coloursmarkers: Vector of marker shapesstrokewidths: Vector of stroke widthsstrokecolors: Vector of stroke colours
label_colors: Vector of in-node label colours
apply_node_type_styling(spec::DAGSpec)Generate styling arrays from a DAGSpec.
DAGMakie.typed_confounding_graph — Function
typed_confounding_graph()Create a confounding graph with proper node types.
Returns DAGSpec with: Confounder → Treatment → Outcome, Confounder → Outcome
DAGMakie.typed_mediation_graph — Function
typed_mediation_graph()Create a mediation graph with proper node types.
Returns DAGSpec with: Treatment → Mediator → Outcome, Treatment → Outcome
DAGMakie.typed_instrumental_graph — Function
typed_instrumental_graph()Create an instrumental variable graph with proper node types.
Returns DAGSpec with: Instrument → Treatment → Outcome, Confounder → Treatment, Confounder → Outcome
DAGMakie.typed_collider_graph — Function
typed_collider_graph()Create a collider graph with proper node types.
Returns DAGSpec with: Cause₁ → Collider ← Cause₂
Mixed Graph Operations
DAGMakie.add_directed_edge! — Function
add_directed_edge!(mg::MixedGraph, i::Int, j::Int)Add a directed edge i → j to the mixed graph.
DAGMakie.add_bidirected_edge! — Function
add_bidirected_edge!(mg::MixedGraph, i::Int, j::Int)Add a bidirected edge i ↔ j to the mixed graph.
DAGMakie.has_bidirected_edge — Function
has_bidirected_edge(mg::MixedGraph, i::Int, j::Int)Check if there is a bidirected edge between nodes i and j.
DAGMakie.bidirected_edges — Function
bidirected_edges(mg::MixedGraph)Return an iterator over all bidirected edge pairs.
DAGMakie.num_bidirected_edges — Function
num_bidirected_edges(mg::MixedGraph)Return the number of bidirected edges.
DAGMakie.compute_bidirected_path — Function
compute_bidirected_path(p1::Point2f, p2::Point2f; curvature=0.3)Compute a curved path for a bidirected edge between two points.
Returns a vector of points representing a quadratic Bézier curve that arcs above the straight line connecting the two points.
Arguments
p1: Start pointp2: End pointcurvature::Float64 = 0.3: How much the arc curves (fraction of distance)
Returns
- Vector of Point2f representing the curved path
DAGMakie.compute_all_bidirected_paths — Function
compute_all_bidirected_paths(mg::MixedGraph, positions::AbstractVector; curvature=0.3)Compute curved paths for all bidirected edges in a mixed graph.
Arguments
mg: The mixed graphpositions: Vector of node positionscurvature: Arc curvature parameter
Returns
- Vector of path vectors, one per bidirected edge
DAGMakie.bidirected_arrow_positions — Function
bidirected_arrow_positions(mg::MixedGraph, positions::AbstractVector; curvature=0.3, arrow_offset=0.1)Compute positions and rotations for arrowheads on bidirected edges.
Returns positions and rotation angles for arrows at both ends of each bidirected edge.
Arguments
mg: The mixed graphpositions: Vector of node positionscurvature: Arc curvature parameterarrow_offset: How far from the node centre to place arrows (0-0.5)
Returns
- Named tuple with:
positions: Vector of Point2f for arrow positionsrotations: Vector of Float64 rotation anglesedge_indices: Which bidirected edge each arrow belongs to
Utilities
DAGMakie.is_dag — Function
is_dag(g::AbstractGraph)Check if a directed graph is acyclic (a valid DAG).
Arguments
g: A directed graph
Returns
trueif the graph has no cycles,falseotherwise
DAGMakie.edge_list — Function
edge_list(g::AbstractGraph)Return a vector of (src, dst) tuples for all edges in the graph.
DAGMakie.adjacency_to_graph — Function
adjacency_to_graph(adj::AbstractMatrix)Create a DiGraph from an adjacency matrix.
Arguments
adj: Square adjacency matrix whereadj[i,j] != 0indicates edge i → j
Returns
SimpleDiGraphwith edges from the adjacency matrix
DAGMakie.graph_from_edges — Function
graph_from_edges(n::Int, edge_pairs::Vector{Tuple{Int, Int}})Create a DiGraph from a list of edge pairs.
Arguments
n: Number of verticesedge_pairs: Vector of (src, dst) tuples
Returns
SimpleDiGraphwith the specified edges
Example
g = graph_from_edges(3, [(1, 2), (2, 3), (1, 3)])