Customizing style

library(ggtargets)

Every visual detail of the metro style is a style_metro() argument. This article shows most of them, and a few combinations, against the same small graph with a crossing (so bends and bridges are visible). The exceptions are node_size_range and edge_width_range, which only matter when a node’s size or an edge’s width is drawn from a numeric column (node_size and edge_width of ggplot_dag()): see the Collapsing a pipeline article.

dag <- as_dag(data.frame(
  from = c("a", "a", "b", "c"),
  to = c("b", "c", "d", "d")
))

Defaults

ggplot_dag(dag)

The diamond graph in the default metro style.

Node size and fill

node_radius sets the size of every node, the radius of a circle (squares and triangles are drawn to match); to draw each node’s size from a numeric column instead, use node_size of ggplot_dag(). node_fill, unlike node_color, recolors nodes only (edges stay in their own dagviz colors).

ggplot_dag(dag, style = style_metro(node_radius = 10))

The graph with larger nodes.

ggplot_dag(dag, style = style_metro(node_fill = "steelblue"))

The graph with every node the same fill color, edges unaffected.

Node border

ggplot_dag(
  dag,
  style = style_metro(node_stroke = "black", node_stroke_width = 3)
)

The graph with a thick black node border instead of the default thin white one.

Node shapes

A node’s shape shows its type, as in targets::tar_visnetwork(): when the nodes have a type column holding targets’ own vertex types, a regular target (stem) is a circle, a dynamic-branching target (pattern) a square, and an imported function and object an up and a down triangle (targets_node_shapes()). Imports are only in the graph with tar_ggplot(targets_only = FALSE). A legend names the shapes whenever more than one is drawn.

typed <- as_dag(
  data.frame(from = c("a", "a", "b", "c"), to = c("b", "c", "d", "d")),
  nodes = data.frame(
    name = c("a", "b", "c", "d"),
    type = c("stem", "stem", "pattern", "pattern")
  )
)
ggplot_dag(typed)

The graph with circles and squares, and a legend of the two.

node_shape picks another column to shape by, and shapes says which shape each of its values gets ("circle", "square", "diamond", "triangle" or "triangle_down"). With node_color set to the same column, the color and shape legends merge into one. Any value that shapes doesn’t name is a circle (with a warning, when the column is named).

roles <- as_dag(
  data.frame(from = c("a", "a", "b", "c"), to = c("b", "c", "d", "d")),
  nodes = data.frame(
    name = c("a", "b", "c", "d"),
    role = c("input", "step", "step", "output")
  )
)
ggplot_dag(
  roles,
  node_color = "role",
  node_shape = "role",
  shapes = c(input = "diamond", step = "circle", output = "triangle")
)

The graph with a diamond, circles and a triangle, colored by the same column, with one legend.

A single shape name draws every node as that shape, and the shape legend is removed like any ggplot2 legend:

ggplot_dag(typed, node_shape = "square")

The graph with every node a square.

ggplot_dag(typed) + ggplot2::guides(shape = "none")

The graph with circles and squares and no legend.

The plot ends a margin of scale from the nodes’ centers. A triangle or diamond reaches further than a circle of the same node_radius, so with a large node_radius (about 7 or more, at the default scale = 10) one in the first or last row, or the first column, can be cut off: raise scale too.

Edge width

edge_stroke_width sets the width of every edge; to draw each edge’s width from a numeric column instead, use edge_width of ggplot_dag().

ggplot_dag(dag, style = style_metro(edge_stroke_width = 5))

The graph with much thicker edges.

Label font

ggplot_dag(
  dag,
  style = style_metro(label_font_family = "serif", label_font_size = 20)
)

The graph with a larger serif label font.

ggplot_dag(dag, style = style_metro(label_font_color = "darkred"))

The graph with dark red label text.

Label leader line

ggplot_dag(
  dag,
  style = style_metro(
    label_arrow_stroke = "steelblue",
    label_arrow_dash_array = "11"
  )
)

The graph with a finely dotted blue leader line from each node to its label, instead of the default dashed gray one.

Arc radius

arc_radius controls how tight or wide a lane’s bend is.

ggplot_dag(dag, style = style_metro(arc_radius = 6))

The graph with a tight arc radius, sharper bends.

ggplot_dag(dag, style = style_metro(arc_radius = 25))

The graph with a wide arc radius, gentler bends.

Bridge color

The white gap under a crossing line is bridge_color. On a white background it’s invisible against the page; giving it a visible color shows what it’s doing.

ggplot_dag(dag, style = style_metro(bridge_color = "pink"))

The graph with the bridge (the gap drawn under a crossing edge) colored pink instead of white, so it's visible against the page.

Minimum width

By default (minimal_width = NULL) the plot ends just past its longest label, measured from the label text, so a long label widens the plot and a short one doesn’t leave empty space. A number gives dagviz’s rule instead: the plot is at least that many pixels wide, even when the graph itself is narrow. dagviz uses 500, because an SVG can’t measure its own text and so leaves generous room for the labels.

ggplot_dag(dag, style = style_metro(minimal_width = 900))

The same small graph, forced wide by a large minimal_width, leaving blank space to the right of the labels.

A dark background

style_metro() doesn’t have a background argument - the background comes from dag_theme()’s plot.background/panel.background, added after dag_layers(). Match node_stroke, bridge_color and label_font_color to the background for a legible dark-mode variant, the way dagviz’s own dark-style example does:

ggplot_dag(
  dag,
  style = style_metro(
    node_stroke = "#1a1a1a",
    bridge_color = "#1a1a1a",
    label_font_color = "white"
  )
) +
  ggplot2::theme(
    plot.background = ggplot2::element_rect(fill = "#1a1a1a", color = NA),
    panel.background = ggplot2::element_rect(fill = "#1a1a1a", color = NA)
  )

The graph rendered in dark mode: a near-black background, white text, and node borders and bridges matched to the background color.

Compact and large layouts

scale sets the grid spacing - everything else follows it if you scale the other size parameters proportionally.

ggplot_dag(dag, style = style_metro(scale = 5, node_radius = 3, arc_radius = 7))

The graph drawn compactly: small scale, small nodes and arcs.

ggplot_dag(
  dag,
  style = style_metro(
    scale = 20,
    node_radius = 14,
    arc_radius = 28,
    edge_stroke_width = 4
  )
)

The graph drawn large: big scale, big nodes and arcs, thick edges.

Leaving nodes out

To leave targets out of a pipeline plot, use tar_ggplot(exclude = ...) (see vignette("ggtargets")): it drops them and their incident edges, without reconnecting their neighbors. For an edge list, filter the data frame before calling as_dag().