CeTZ graph from an adjacency matrix

Hi
I found this to be helpful personally. I am a beginner so any feedback would be great!

#import "@preview/cetz:0.3.3": canvas, draw, tree
// Function to draw a graph from an adjacency matrix
#let draw-graph-from-adj-matrix(
  adj-matrix,
  positions: none,
  node_label_fn: i => text(str(i)),
  node_color_function: i => white,
  node-radius: 0.45,
  stroke: (thickness: 1pt), // Changed to dictionary format
) = {
  canvas({
    import draw: *

    // Number of nodes (assuming the matrix is square)
    let n = adj-matrix.len()
    if n == 0 or adj-matrix.at(0).len() != n {
      panic("Adjacency matrix must be square")
    }

    // Determine node positions
    let node-positions = if positions == none {
      // Default: Circular layout
      let radius = calc.max(2, calc.sqrt(n)) / 2 // Adjust radius based on number of nodes
      let center = (0, 0)
      let positions = ()
      for i in range(n) {
        let angle = 360deg / n * i
        let x = radius * calc.cos(angle)
        let y = radius * calc.sin(angle)
        positions.push((x, y))
      }
      positions
    } else {
      // Use provided positions
      if positions.len() != n {
        panic("Number of positions must match number of nodes")
      }
      positions
    }

    // Draw edges based on the adjacency matrix
    for i in range(n) {
      for j in range(i + 1, n) {
        // Only upper triangle for undirected graph
        if adj-matrix.at(i).at(j) == 1 {
          line(node-positions.at(i), node-positions.at(j), stroke: 1pt)
        }
      }
    }

    // Draw nodes
    for (i, pos) in node-positions.enumerate() {
      circle(pos, radius: node-radius, fill: node_color_function(i), stroke: 1pt)
      content(pos, node_label_fn(i), anchor: "center")
    }
  })
}
// Usage
    #let adj-matrix-raw = (
      (0, 0, 1, 0),
      (0, 0, 1, 0),
      (1, 1, 0, 1),
      (0, 0, 1, 0),
    )
$
      A = mat(delim:"[", ..#adj-matrix-raw) #
$
    #let fig4 = figure(
      supplement: [Figure],
      draw-graph-from-adj-matrix(adj-matrix-raw),
    )

3 Likes

Directing people here, a much better implementation: Function to draw generic (di)graphs · cetz-package/cetz · Discussion #552 · GitHub

2 Likes