Creating Visual Dependency Graphs

The fromager graph to-dot command converts your dependency graph into a DOT format file that can be used with Graphviz to create visual representations of your package dependencies.

Prerequisites

To create images from DOT files, you’ll need Graphviz installed:

# On macOS with Homebrew
brew install graphviz

# On Ubuntu/Debian
sudo apt-get install graphviz

# On RHEL/CentOS/Fedora
sudo dnf install graphviz

Basic Usage

Convert a graph file to DOT format:

fromager graph to-dot e2e/build-parallel/graph.json

This outputs the DOT format to stdout. To save it to a file:

fromager graph to-dot e2e/build-parallel/graph.json --output dependency-graph.dot

Creating Visual Images

Once you have a DOT file, create a PNG image:

fromager graph to-dot e2e/build-parallel/graph.json --output graph.dot
dot -Tpng graph.dot -o dependency-graph.png
digraph {

  node1 [label="" style="filled,bold" color=black fillcolor=white fontcolor=black shape=circle]
  node2 [label="cython==3.1.1" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]
  node3 [label="flit-core==3.12.0" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]
  node4 [label="imapautofiler==1.14.0" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node5 [label="imapclient==3.0.1" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node6 [label="jaraco-classes==3.4.0" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node7 [label="jaraco-context==6.0.1" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node8 [label="jaraco-functools==4.1.0" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node9 [label="jinja2==3.1.6" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node10 [label="keyring==25.6.0" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node11 [label="markupsafe==3.0.2" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node12 [label="more-itertools==10.7.0" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node13 [label="packaging==25.0" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]
  node14 [label="pyyaml==6.0.2" style="filled,bold" color=black fillcolor=white fontcolor=black shape=oval]
  node15 [label="setuptools-scm==8.3.1" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]
  node16 [label="setuptools==80.8.0" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]
  node17 [label="wheel==0.46.1" style="filled,dashed" color=black fillcolor=white fontcolor=black shape=oval]

  node1 -> node4 [labeltooltip="imapautofiler==1.14.0" style=dotted]
  node4 -> node16 [labeltooltip="setuptools" style=dotted]
  node4 -> node15 [labeltooltip="setuptools_scm[toml]>=6.2" style=dotted]
  node4 -> node14 [labeltooltip="PyYAML>=3.11"]
  node4 -> node5 [labeltooltip="imapclient>=2.2.0"]
  node4 -> node9 [labeltooltip="jinja2>=2.11.2"]
  node4 -> node10 [labeltooltip="keyring>=10.0.0"]
  node15 -> node16 [labeltooltip="setuptools>=61" style=dotted]
  node15 -> node13 [labeltooltip="packaging>=20" style=dotted]
  node14 -> node2 [labeltooltip="Cython; python_version < '3.13'" style=dotted]
  node14 -> node16 [labeltooltip="setuptools" style=dotted]
  node14 -> node17 [labeltooltip="wheel" style=dotted]
  node5 -> node16 [labeltooltip="setuptools>=40.8.0" style=dotted]
  node9 -> node3 [labeltooltip="flit_core<4" style=dotted]
  node9 -> node11 [labeltooltip="MarkupSafe>=2.0"]
  node10 -> node16 [labeltooltip="setuptools>=61.2" style=dotted]
  node10 -> node15 [labeltooltip="setuptools_scm[toml]>=3.4.1" style=dotted]
  node10 -> node6 [labeltooltip="jaraco.classes"]
  node10 -> node7 [labeltooltip="jaraco.context"]
  node10 -> node8 [labeltooltip="jaraco.functools"]
  node6 -> node16 [labeltooltip="setuptools>=56" style=dotted]
  node6 -> node15 [labeltooltip="setuptools_scm[toml]>=3.4.1" style=dotted]
  node6 -> node12 [labeltooltip="more_itertools"]
  node7 -> node16 [labeltooltip="setuptools>=61.2" style=dotted]
  node7 -> node15 [labeltooltip="setuptools_scm[toml]>=3.4.1" style=dotted]
  node8 -> node16 [labeltooltip="setuptools>=61.2" style=dotted]
  node8 -> node15 [labeltooltip="setuptools_scm[toml]>=3.4.1" style=dotted]
  node8 -> node12 [labeltooltip="more_itertools"]
  node12 -> node3 [labeltooltip="flit_core<4,>=3.2" style=dotted]
  node13 -> node3 [labeltooltip="flit_core>=3.3" style=dotted]
  node11 -> node16 [labeltooltip="setuptools>=70.1" style=dotted]
  node2 -> node16 [labeltooltip="setuptools>=40.8.0" style=dotted]
  node17 -> node3 [labeltooltip="flit_core<4,>=3.8" style=dotted]
  node17 -> node13 [labeltooltip="packaging>=24.0" style=dotted]
}
Example graph

Complete Example

Here’s a complete workflow to create a visual dependency graph:

# Create DOT file from graph
fromager graph to-dot e2e/build-parallel/graph.json --output full-graph.dot

# Create PNG image
dot -Tpng full-graph.dot -o full-dependency-graph.png

# Create a simplified version with only install dependencies
fromager graph to-dot e2e/build-parallel/graph.json --install-only --output install-graph.dot
dot -Tpng install-graph.dot -o install-dependencies.png

Options

Install Dependencies Only

Use --install-only to show only runtime installation dependencies, excluding build-time dependencies:

fromager graph to-dot e2e/build-parallel/graph.json --install-only --output runtime-deps.dot

This creates a cleaner graph focused on what gets installed rather than what’s needed for building.

Understanding the Visual Output

The generated graph uses different visual elements to represent different types of packages:

Node Shapes:

  • Circle: Top-level requirements

  • Oval: Regular dependencies

  • Box: Packages with build settings/overrides

  • Parallelogram: Pre-built packages

  • Note shape: Packages with patches

  • Trapezium: Packages with plugins

  • Triple octagon: Packages with both plugins and patches

Edge Styles:

  • Solid lines: Installation dependencies

  • Dotted lines: Build-system dependencies

  • Bold edges: Installation constraints (when not using –install-only)

  • Dashed edges: Build-only dependencies (when not using –install-only)

Colors:

  • All nodes have black borders with white fill by default

  • Bold edges indicate packages that will be installed in the final environment