Skip to contents

Generates LaTeX TikZ code from a Disco, Knowledge, or caugi::caugi object, preserving node positions, labels, and visual styles. Edges are rendered with arrows, line widths, and colors. The output is readable LaTeX code that can be directly compiled or modified.

Usage

make_tikz(
  x,
  ...,
  scale = 10,
  full_doc = TRUE,
  bend_edges = FALSE,
  bend_angle = 25,
  tier_label_pos = c("above", "below", "left", "right")
)

Arguments

x

A Disco, Knowledge, or caugi::caugi object.

...

Additional arguments passed to plot() and caugi::plot().

scale

Numeric scalar. Scaling factor for node coordinates. Default is 10.

full_doc

Logical. If TRUE (default), generates a full standalone LaTeX document. If FALSE, returns only the tikzpicture environment.

bend_edges

Logical. If TRUE, edges are drawn with bent edges. Default is FALSE. Edges connecting the same pair of nodes in both directions (A %-->% B and B %-->% A) are automatically bent left and right to avoid overlap. Bend direction is automatically chosen to reduce overlap.

bend_angle

Numeric scalar. Angle in degrees for bending arrows when bend_edges = TRUE. Default is 25.

tier_label_pos

Character string specifying the position of tier labels relative to the tier rectangles. Must be one of "above", "below", "left", or "right". Default is "above".

Value

A character string containing LaTeX TikZ code. Depending on full_doc, this is either:

  • a complete LaTeX document (full_doc = TRUE), or

  • only the tikzpicture environment (full_doc = FALSE).

Details

The function calls plot() to generate a caugi::caugi_plot object, then traverses the plot object's grob structure to extract nodes and edges. Supported features include:

  • Nodes

    • Fill color and draw color (supports both named colors and custom RGB values)

    • Font size

    • Coordinates are scaled by the scale parameter

  • Edges

    • Line color and width

    • Arrow scale

    • Optional bending to reduce overlapping arrows

The generated TikZ code uses global style settings, and edges are connected to nodes by name (as opposed to hard-coded coordinates), making it easy to modify the output further if needed.

Examples

################# Convert Knowledge to Tikz ################

data(num_data)
kn <- knowledge(
  num_data,
  X1 %-->% X2,
  X2 %!-->% c(X3, Y),
  Y %!-->% Z
)

# Full standalone document
tikz_kn <- make_tikz(kn, scale = 10, full_doc = TRUE)
cat(tikz_kn)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \documentclass[tikz,border=2mm]{standalone}
#> \usetikzlibrary{arrows.meta, positioning, shapes.geometric, fit, backgrounds, calc}
#> 
#> \begin{document}
#> \tikzset{every node/.style={fill=lightgray}, every path/.style={draw=red}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (X1) at (1.667,0) {X1};
#> \node[draw, circle] (X2) at (1.667,3.333) {X2};
#> \node[draw, circle] (X3) at (3.333,6.667) {X3};
#> \node[draw, circle] (Y) at (0,6.667) {Y};
#> \node[draw, circle] (Z) at (0,10) {Z};
#> \path (X1) edge[draw=blue, -Latex] (X2)
#>       (X2) edge[, -Latex] (X3)
#>       (X2) edge[, -Latex] (Y)
#>       (Y) edge[, -Latex] (Z);
#> \end{tikzpicture}
#> \end{document}

# Only the tikzpicture environment
tikz_kn_snippet <- make_tikz(kn, full_doc = FALSE)
cat(tikz_kn_snippet)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill=lightgray}, every path/.style={draw=red}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (X1) at (1.667,0) {X1};
#> \node[draw, circle] (X2) at (1.667,3.333) {X2};
#> \node[draw, circle] (X3) at (3.333,6.667) {X3};
#> \node[draw, circle] (Y) at (0,6.667) {Y};
#> \node[draw, circle] (Z) at (0,10) {Z};
#> \path (X1) edge[draw=blue, -Latex] (X2)
#>       (X2) edge[, -Latex] (X3)
#>       (X2) edge[, -Latex] (Y)
#>       (Y) edge[, -Latex] (Z);
#> \end{tikzpicture}

# With bent edges
tikz_bent <- make_tikz(
  kn,
  full_doc = FALSE,
  bend_edges = TRUE
)
cat(tikz_bent)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill=lightgray}, every path/.style={draw=red}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (X1) at (1.667,0) {X1};
#> \node[draw, circle] (X2) at (1.667,3.333) {X2};
#> \node[draw, circle] (X3) at (3.333,6.667) {X3};
#> \node[draw, circle] (Y) at (0,6.667) {Y};
#> \node[draw, circle] (Z) at (0,10) {Z};
#> \path (X1) edge[draw=blue, bend left=25, -Latex] (X2)
#>       (X2) edge[bend left=25, -Latex] (X3)
#>       (X2) edge[bend right=25, -Latex] (Y)
#>       (Y) edge[bend left=25, -Latex] (Z);
#> \end{tikzpicture}

# With a color not supported by default TikZ colors; will fall back to RGB
tikz_darkblue <- make_tikz(
  kn,
  node_style = list(fill = "darkblue"),
  full_doc = FALSE
)
cat(tikz_darkblue)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill={rgb:red,0.000;green,0.000;blue,0.545}}, every path/.style={draw=red}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (X1) at (1.667,0) {X1};
#> \node[draw, circle] (X2) at (1.667,3.333) {X2};
#> \node[draw, circle] (X3) at (3.333,6.667) {X3};
#> \node[draw, circle] (Y) at (0,6.667) {Y};
#> \node[draw, circle] (Z) at (0,10) {Z};
#> \path (X1) edge[draw=blue, -Latex] (X2)
#>       (X2) edge[, -Latex] (X3)
#>       (X2) edge[, -Latex] (Y)
#>       (Y) edge[, -Latex] (Z);
#> \end{tikzpicture}

# With tiered knowledge
data(tpc_example)
kn_tiered <- knowledge(
  tpc_example,
  tier(
    child ~ starts_with("child"),
    youth ~ starts_with("youth"),
    old ~ starts_with("old")
  )
)
tikz_tiered_kn <- make_tikz(
  kn_tiered,
  full_doc = FALSE
)
cat(tikz_tiered_kn)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill=lightgray}}
#> \tikzset{arrows={[scale=1]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (child_x1) at (0,0) {child\_x1};
#> \node[draw, circle] (child_x2) at (0,10) {child\_x2};
#> \node[draw, circle] (youth_x3) at (5,0) {youth\_x3};
#> \node[draw, circle] (youth_x4) at (5,10) {youth\_x4};
#> \node[draw, circle] (oldage_x5) at (10,0) {oldage\_x5};
#> \node[draw, circle] (oldage_x6) at (10,10) {oldage\_x6};
#> \begin{scope}[on background layer]
#> \node[draw, rectangle, fill=blue!20, rounded corners, inner sep=0.5cm, fit=(child_x1)(child_x2)] (child) {};
#> \node[draw, rectangle, fill=blue!20, rounded corners, inner sep=0.5cm, fit=(oldage_x5)(oldage_x6)] (old) {};
#> \node[draw, rectangle, fill=blue!20, rounded corners, inner sep=0.5cm, fit=(youth_x3)(youth_x4)] (youth) {};
#> \end{scope}
#> \node[anchor=south, draw=none, fill=none] at ($(child.north)+(0cm,0.2cm)$) {child};
#> \node[anchor=south, draw=none, fill=none] at ($(old.north)+(0cm,0.2cm)$) {old};
#> \node[anchor=south, draw=none, fill=none] at ($(youth.north)+(0cm,0.2cm)$) {youth};
#> \path ;
#> \end{tikzpicture}


################# Convert disco to Tikz ################

data(num_data)
kn <- knowledge(
  num_data,
  X1 %-->% X2,
  X2 %!-->% c(X3, Y),
  Y %!-->% Z
)

pc_bnlearn <- pc(engine = "bnlearn", test = "fisher_z", alpha = 0.05)
disco_kn <- disco(data = num_data, method = pc_bnlearn, knowledge = kn)

tikz_snippet <- make_tikz(disco_kn, scale = 10, full_doc = FALSE)
cat(tikz_snippet)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill=lightgray}, every path/.style={draw=blue}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (X1) at (2.609,3.549) {X1};
#> \node[draw, circle] (X2) at (7.431,3.545) {X2};
#> \node[draw, circle] (X3) at (10,0) {X3};
#> \node[draw, circle] (Z) at (0,0.013) {Z};
#> \node[draw, circle] (Y) at (5.007,0.226) {Y};
#> \path (X1) edge[, -Latex] (X2)
#>       (X1) edge[, -Latex] (Y)
#>       (X1) edge[, -] (Z)
#>       (X3) edge[, -Latex] (X2)
#>       (X3) edge[, -Latex] (Y)
#>       (Y) edge[, -Latex] (X2)
#>       (Z) edge[, -Latex] (Y);
#> \end{tikzpicture}

################# Convert caugi objects to Tikz ################

cg <- caugi::caugi(A %-->% B + C)

tikz_snippet <- make_tikz(
  cg,
  node_style = list(fill = "red"),
  scale = 10,
  full_doc = FALSE
)
cat(tikz_snippet)
#> %%% Generated by causalDisco (version 1.0.1.9000)
#> \tikzset{every node/.style={fill=red}}
#> \tikzset{arrows={[scale=3]}, arrow/.style={-{Stealth}, thick}}
#> \begin{tikzpicture}
#> \node[draw, circle] (A) at (5,0) {A};
#> \node[draw, circle] (B) at (10,10) {B};
#> \node[draw, circle] (C) at (0,10) {C};
#> \path (A) edge[, -Latex] (B)
#>       (A) edge[, -Latex] (C);
#> \end{tikzpicture}