Skip to contents

Draw a node-link diagram on a PlotSpec from vgraph(). mark_edges() draws the edges (straight lines, batched), mark_nodes() the vertices (points), mark_node_text() the vertex labels, and mark_edge_text() labels on the edges. Draw order is fixed regardless of the order you pipe them: edges under edge labels under nodes under node labels. Edges (and edge labels) default to the edge table (vgraph()'s edge_data), nodes and node labels to the node table; the x/y/xend/yend/label/name columns those tables carry are mapped automatically, so bare mark_edges() |> mark_nodes() just works.

Usage

mark_edges(
  plot,
  ...,
  color = NULL,
  linewidth = NULL,
  alpha = NULL,
  linetype = NULL,
  arrow = FALSE,
  routing = c("straight", "elbow"),
  elbow_at = c("mid", "start", "end"),
  elbow_axis = c("auto", "v", "h"),
  gradient = FALSE,
  auto = FALSE,
  blend = NULL,
  effects = list(),
  sketch = NULL,
  data = NULL
)

mark_edge_bundle(
  plot,
  ...,
  type = c("force", "divided", "stub", "path", "hammer", "mingle"),
  color = NULL,
  linewidth = NULL,
  alpha = NULL,
  linetype = NULL,
  params = list(),
  blend = NULL,
  effects = list(),
  sketch = NULL,
  data = NULL
)

mark_flow_map(
  plot,
  ...,
  root,
  type = c("spiral", "steiner"),
  weight = NULL,
  width_range = c(0.3, 3),
  color = NULL,
  alpha = NULL,
  params = list(),
  blend = NULL,
  effects = list(),
  sketch = NULL,
  data = NULL
)

mark_nodes(
  plot,
  ...,
  size = NULL,
  shape = NULL,
  fill = NULL,
  color = NULL,
  alpha = NULL,
  blend = NULL,
  effects = list(),
  sketch = NULL,
  data = NULL
)

mark_node_text(
  plot,
  ...,
  label = NULL,
  color = NULL,
  size = NULL,
  alpha = NULL,
  dist = 0,
  top_n = NULL,
  by = NULL,
  repel = FALSE,
  box_padding = 1,
  point_padding = 1,
  min_segment_length = 2,
  seed = NULL,
  effects = list(),
  blend = NULL,
  data = NULL
)

mark_edge_text(
  plot,
  ...,
  label = NULL,
  color = NULL,
  size = NULL,
  alpha = NULL,
  angle = NULL,
  effects = list(),
  blend = NULL,
  data = NULL
)

mark_node_hull(
  plot,
  ...,
  fill = NULL,
  color = NULL,
  alpha = 0.25,
  expand = 0.08,
  data = NULL
)

mark_node_pie(
  plot,
  cols,
  ...,
  size = 4,
  inner = 0,
  fill = NULL,
  color = "white",
  linewidth = 0.5,
  alpha = NA,
  data = NULL
)

Arguments

plot

A PlotSpec, normally from vgraph().

...

Encodings mapping node/edge attributes to aesthetics. Nodes: size, color/fill, shape, alpha. Edges: color, linewidth, linetype, alpha. The position channels are supplied by vgraph() and need not be mapped.

linewidth

For mark_edges(), the edge width; a constant or (via scale_edge_width()) a mapped expression such as linewidth = weight. For mark_node_pie(), the wedge border width.

linetype

For mark_edges(), the edge line type; a constant or (via scale_edge_linetype()) a mapped expression.

arrow

For mark_edges(), TRUE to draw a closed arrowhead at each edge's target end (the directed convention), FALSE/NULL for none, or a vellum::vl_arrow() spec for full control (ends, type, length, angle) – e.g. arrow = vellum::vl_arrow(ends = "both", type = "open"). Edges are capped exactly at each endpoint's node boundary (per vertex, at any size/resolution), so the head sits on the node edge; self-loops are drawn as teardrop loops sized to the node, with the head on the node boundary.

routing

For mark_edges(), edge routing: "straight" (default) or "elbow" – orthogonal right-angle steps for tree / DAG / dendrogram layouts (still straight segments, no curvature). Elbows keep node-boundary caps and arrowheads.

elbow_at, elbow_axis

For mark_edges(routing = "elbow"), the corner placement and axis. elbow_at is "mid" (default, an S-bend at the midpoint), or "start" / "end" for the corner at the source / target – "start" gives the dendrogram bracket (siblings share a bar at the parent's level). elbow_axis is "auto" (default, the longer side), "v", or "h" to force which axis the corner steps along.

gradient

For mark_edges(), TRUE to fade each (straight) edge from faint at its source to opaque at its target – a direction cue that needs no arrowhead (igraph's edge.gradient). Ignored with routing = "elbow".

auto

For mark_edges(), TRUE to datashade a large graph's edges as a density raster (vellum::datashade_segments()) once the edge count exceeds the datashade threshold, instead of drawing each edge as a vector segment — the fast, overplotting-honest path for hairballs. The device-space refinements of the vector path (parallel-edge offsets, node-boundary caps, arrowheads, teardrop self-loops) do not apply to the rasterised edges.

blend

Optional blend mode (see mark_point()).

effects

A list of layer render effects (glow(), outline(), shadow()) applied to the mark at draw time. On the text marks (mark_node_text() / mark_edge_text()) only shadow() applies.

sketch

A sketch() spec giving the layer a hand-drawn look, NA/FALSE to force it crisp, or NULL (default) to inherit.

data

Optional layer data; overrides the default table.

type

For mark_edge_bundle(), the bundling algorithm: "force" (default, force-directed / FDEB), "divided" (force-directed with direction-split bundles), "stub" (short stubs at each endpoint), "path" (shortest-path bundling), "hammer" (hammer bundling), or "mingle" (multilevel agglomerative edge bundling). Delegated to edgebundle::edge_bundle(). For mark_flow_map(), the flow-tree layout: "spiral" (default, angle-restricted spiral tree; edgebundle only) or "steiner" (approximate Steiner tree; also needs interp).

params

For mark_edge_bundle(), a named list of extra arguments passed to edgebundle::edge_bundle() for the chosen type (e.g. params = list(compatibility_threshold = 0.8)). For mark_flow_map(), extra arguments for the flow-tree builder – edgebundle::flow_tree() when type = "spiral" (e.g. list(alpha = 30)), edgebundle::tnss_tree() when type = "steiner" (e.g. list(gamma = 0.9)). Empty by default.

root

For mark_flow_map(), the source vertex the flow fans out from: a vertex name (matched against the node table) or a vertex index.

weight

For mark_flow_map(), the per-edge flow volume (a mapped edge column, e.g. weight = migrants). Defaults to the graph's weight edge attribute, or 1 if there is none.

width_range

For mark_flow_map(), the drawn branch width range c(min, max) (in linewidth units) that the computed flow is mapped onto. Default c(0.3, 3).

size, shape

For mark_nodes(), the node size (mm) / shape; a constant or a mapped expression. size is also the label font size for mark_node_text()/mark_edge_text().

fill, color, alpha

Convenience aesthetics; a constant or a mapped expression. For nodes, fill (or color) is the marker colour; for mark_edges(), color/alpha map through the edge scales.

label

For mark_node_text(), the label expression (default the vertex name); for mark_edge_text(), the edge label expression (no default – map an edge attribute, e.g. label = weight).

dist

For mark_node_text(), a radial offset (mm) pushing each label outward from the layout centroid, so labels clear the node markers instead of sitting on them. 0 (default) centres the label on the vertex.

top_n, by

For mark_node_text(), label only the top_n vertices with the largest by (an edge/vertex metric column, e.g. by = degree) – the idiomatic "label just the hubs" filter. NULL (default) labels every vertex.

repel

For mark_node_text(), TRUE to move overlapping labels apart with a force-directed layout (ggrepel-style), drawing a thin leader line back to each vertex. box_padding, point_padding, min_segment_length, and seed tune it exactly as in mark_text().

box_padding, point_padding, min_segment_length, seed

Repel tuning for mark_node_text(repel = TRUE); see mark_text().

angle

For mark_edge_text(), the label rotation: a constant in degrees, or "along" to rotate each label along its edge. NULL (default) draws horizontal labels.

expand

For mark_node_hull(), the fraction to grow each hull outward from its centroid so it encloses the node markers (default 0.08).

cols

For mark_node_pie(), the compositional columns (a character vector of node-table column names, at least two) whose values size each node's wedges.

inner

For mark_node_pie(), the inner-radius fraction: 0 (default) draws a pie, > 0 a donut (e.g. 0.5).

Value

The modified PlotSpec.

Details

Edge colour, opacity, and line type train on their own scales (scale_edge_color(), scale_edge_alpha(), scale_edge_linetype(), plus scale_edge_width()), independent of the node colour/alpha/linetype scales – so a plot can map node fill to a discrete community and edge colour to a continuous weight without the two legends colliding.

mark_node_text() has the label-legibility tools a dense graph needs: repel = TRUE nudges overlapping labels apart with leader lines, dist pushes labels radially clear of the node markers, top_n/by label only the hubs, and effects = list(shadow()) drops a shadow behind each label so it stays readable over edges. mark_edge_text() takes the same effects. (Only shadow() applies to text; a glyph outline / glow is not available yet.)

Two more decorations: mark_node_hull() shades communities with a convex hull behind the graph (grouped by a mapped fill, drawn under the edges), and mark_node_pie() replaces node markers with pie / donut glyphs whose wedges come from a set of compositional columns.

mark_edge_bundle() is a drop-in alternative to mark_edges() that routes the edges as bundled curves instead of straight lines, so a hairball collapses into a few legible trunks. It delegates the geometry to the edgebundle package (install it) and draws the returned paths with the edge aesthetics – type picks the algorithm ("force", "divided", "stub", "path", "hammer", "mingle") and params passes tuning through. Bundled edges are faint by default (alpha = 0.3) so overlapping trunks read as density.

mark_flow_map() draws a flow map: a single root fans out to many destinations along smooth, merging branches whose width tracks the flow volume (the Minard / migration-map idiom). It expects a one-to-many (star) graph rooted at root, laid out at fixed coordinates; edge weight drives the flow. type = "spiral" (default, an angle-restricted spiral tree) needs only edgebundle; type = "steiner" (an approximate Steiner tree) additionally needs interp. Branch width is mapped from the computed flow into width_range.

These are thin over the point / segment / text marks; igraph need not be installed to use them (only vgraph() needs it). mark_edge_bundle() and mark_flow_map() also need the edgebundle package.

Examples

if (FALSE) { # \dontrun{
g <- igraph::make_graph("Zachary")
vgraph(g) |>
  mark_edges(alpha = 0.5) |>
  mark_nodes(size = 4, fill = "steelblue")
} # }