The caugi package provides a flexible plotting system
built on grid graphics for visualizing causal graphs. This vignette
demonstrates how to create plots with different layout algorithms and
customize their appearance.
The simplest way to visualize a caugi graph is with the
plot() function:
# Create a simple DAG
cg <- caugi(
A %-->% B + C,
B %-->% D,
C %-->% D,
class = "DAG"
)
# Plot with default settings
plot(cg)By default, plot() automatically selects the best layout
algorithm based on your graph type. For graphs with only directed edges,
it uses the Sugiyama hierarchical layout. For graphs with other edge
types, it uses the Fruchterman-Reingold force-directed layout.
The caugi package provides three layout algorithms, each
optimized for different use cases.
The Sugiyama layout (Sugiyama, Tagawa, and Toda 1981) is ideal for directed acyclic graphs (DAGs). It arranges nodes in layers to emphasize hierarchical structure and causal flow from top to bottom, minimizing edge crossings.
# Create a more complex DAG
dag <- caugi(
X1 %-->% M1 + M2,
X2 %-->% M2 + M3,
M1 %-->% Y,
M2 %-->% Y,
M3 %-->% Y,
class = "DAG"
)
# Use Sugiyama layout explicitly
plot(dag, layout = "sugiyama")Best for: DAGs, causal models, hierarchical structures
Limitations: Only works with directed edges
The Fruchterman-Reingold layout (Fruchterman and Reingold 1991) uses a physical simulation where edges act as springs and nodes repel each other like charged particles. It produces organic, symmetric layouts with relatively uniform edge lengths.
# Create a graph with bidirected edges (ADMG)
admg <- caugi(
A %-->% C,
B %-->% C,
A %<->% B, # Bidirected edge (latent confounder)
class = "ADMG"
)
# Fruchterman-Reingold handles all edge types
plot(admg, layout = "fruchterman-reingold")Best for: General-purpose visualization, graphs with mixed edge types
Advantages: Fast, works with all edge types, produces balanced layouts
The Kamada-Kawai layout (Kamada and Kawai 1989) minimizes “stress” by making Euclidean distances in the plot proportional to graph-theoretic distances. This produces high-quality layouts that better preserve the global structure compared to Fruchterman-Reingold.
# Create an undirected graph
ug <- caugi(
A %---% B,
B %---% C + D,
C %---% D,
class = "UG"
)
# Kamada-Kawai for publication-quality visualization
plot(ug, layout = "kamada-kawai")Best for: Publication-quality figures, when accurate distance representation matters
Advantages: Better global structure preservation, deterministic results
You can compute and examine layout coordinates directly using
caugi_layout():
# Compute layouts
layout_sug <- caugi_layout(dag, method = "sugiyama")
layout_fr <- caugi_layout(dag, method = "fruchterman-reingold")
layout_kk <- caugi_layout(dag, method = "kamada-kawai")
# Examine coordinates
head(layout_sug)
#> name x y
#> 1 X1 5 0
#> 2 X2 15 0
#> 3 M1 0 10
#> 4 M2 10 10
#> 5 M3 20 10
#> 6 Y 10 20The plot() function provides extensive customization
options for nodes, edges, and labels.
Customize node appearance with the node_style
parameter:
# Customize node colors and sizes
plot(
cg,
node_style = list(
fill = "lightblue", # Fill color
col = "darkblue", # Border color
lwd = 2, # Border width
padding = 4, # Text padding (mm)
size = 1.2 # Size multiplier
)
)Available node style parameters:
gpar()):
fill, col, lwd, lty,
alphapadding (text padding in
mm), size (node size multiplier)Customize edge appearance with the edge_style parameter.
You can set global options or customize each edge type separately:
# Global edge styling
plot(
dag,
edge_style = list(
col = "darkgray", # Edge color
lwd = 1.5, # Edge width
arrow_size = 4 # Arrow size (mm)
)
)# Per-type edge styling for ADMG
plot(
admg,
layout = "fruchterman-reingold",
edge_style = list(
directed = list(col = "blue", lwd = 2),
bidirected = list(col = "red", lwd = 2, lty = "dashed")
)
)Available edge style parameters:
gpar()):
col, lwd, lty,
alpha, fillarrow_size (arrow length in
mm)directed,
undirected, bidirected,
partialCustomize node labels with the label_style
parameter:
# Customize label appearance
plot(
cg,
label_style = list(
col = "white", # Text color
fontsize = 12, # Font size
fontface = "bold", # Font face
fontfamily = "sans" # Font family
),
node_style = list(
fill = "navy" # Dark background for white text
)
)Available label style parameters (passed to gpar()):
col, fontsize, fontface,
fontfamily, cexPut it all together for a fully customized plot:
# Create a publication-ready plot
plot(
dag,
layout = "sugiyama",
node_style = list(
fill = "#E8F4F8",
col = "#2C5F77",
lwd = 1.5,
padding = 3,
size = 1.1
),
edge_style = list(
col = "#555555",
lwd = 1.2,
arrow_size = 3.5
),
label_style = list(
col = "#1A1A1A",
fontsize = 11,
fontface = "bold"
)
)The plotting system works seamlessly with all supported graph types.
# Create a PDAG with both directed and undirected edges
pdag <- caugi(
A %-->% B,
B %---% C, # Undirected edge
C %-->% D,
class = "PDAG"
)
plot(
pdag,
edge_style = list(
directed = list(col = "blue"),
undirected = list(col = "gray", lwd = 2)
)
)# Create an ADMG with confounding
complex_admg <- caugi(
X %-->% M1 + M2,
M1 %-->% Y,
M2 %-->% Y,
M1 %<->% M2, # Latent confounder between mediators
class = "ADMG"
)
plot(
complex_admg,
layout = "kamada-kawai",
node_style = list(fill = "lavender"),
edge_style = list(
directed = list(col = "black", lwd = 1.5),
bidirected = list(col = "red", lwd = 1.5, lty = "dashed", arrow_size = 3)
)
)You can compute layouts separately and reuse them:
# Compute layout once
coords <- caugi_layout(dag, method = "sugiyama")
# The layout can be used for analysis or custom plotting
print(coords)
#> name x y
#> 1 X1 5 0
#> 2 X2 15 0
#> 3 M1 0 10
#> 4 M2 10 10
#> 5 M3 20 10
#> 6 Y 10 20
# Plot uses the computed layout internally
plot(dag, layout = "sugiyama")caugi plots are built on grid graphics, and provide
access to the underlying grid grob object in the
@grob slot of the plot output. This allows for further
customization using grid functions.
# Create a plot
p <- plot(cg)
# The plot is a grid graphics object
class(p)
#> [1] "caugi::caugi_plot" "S7_object"
# You can manipulate it with grid functions
library(grid)
# Draw the plot rotated by 30 degrees
pushViewport(viewport(angle = 30))
grid.draw(p@grob)
popViewport()This also allows you to arrange multiple caugi plots
using packages like gridExtra.