TGraphX Insights Creating a Static Interactive Graph Diagram for Technical Documentation
← Back to Insights

Creating a Static Interactive Graph Diagram for Technical Documentation

Target keyword: interactive graph diagram documentation

Creating a Static Interactive Graph Diagram for Technical Documentation

Technical documentation for graph libraries needs to show graph structure
visually without relying on JavaScript frameworks that may not be available
in static site environments. This tutorial covers building node-edge diagrams
using SVG, CSS, and HTML details/summary, all of which work in GitHub
README files, Hugo/Jekyll static sites, and documentation platforms like
Read the Docs.

Design Goals

A good static graph diagram for documentation:
1. Renders correctly in all major browsers without JS
2. Is accessible (screen reader compatible)
3. Is copy-paste reusable (self-contained SVG or HTML)
4. Shows the information density appropriate for the section

Avoid: D3.js, Cytoscape.js, or any library that requires a JavaScript bundle.
These are appropriate for interactive applications, not documentation.

Approach 1: SVG Node-Edge Diagram

SVG is natively supported in all modern browsers and GitHub Markdown. A simple
5-node graph:

html
<svg width="400" height="280" xmlns="http://www.w3.org/2000/svg"
             role="img"
             aria-label="A 5-node directed graph showing message passing flow">
        
          <title>Message Passing Graph Example</title>
          <desc>Five nodes connected by directed edges illustrating
                neighborhood aggregation in a GNN</desc>
        
          <!-- Edges (draw before nodes so nodes appear on top) -->
          <!-- n0 → n1 -->
          <line x1="80"  y1="80"  x2="190" y2="80"
                stroke="#888" stroke-width="2" marker-end="url(#arrow)"/>
          <!-- n1 → n2 -->
          <line x1="230" y1="80"  x2="310" y2="150"
                stroke="#888" stroke-width="2" marker-end="url(#arrow)"/>
          <!-- n0 → n3 -->
          <line x1="80"  y1="100" x2="80"  y2="180"
                stroke="#888" stroke-width="2" marker-end="url(#arrow)"/>
          <!-- n3 → n2 -->
          <line x1="100" y1="200" x2="310" y2="165"
                stroke="#888" stroke-width="2" marker-end="url(#arrow)"/>
          <!-- n2 → n4 -->
          <line x1="330" y1="170" x2="330" y2="230"
                stroke="#888" stroke-width="2" marker-end="url(#arrow)"/>
        
          <!-- Arrow marker definition -->
          <defs>
            <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5"
                    markerWidth="6" markerHeight="6" orient="auto">
              <path d="M 0 0 L 10 5 L 0 10 z" fill="#888"/>
            </marker>
          </defs>
        
          <!-- Nodes -->
          <circle cx="80"  cy="80"  r="25" fill="#d0e8ff" stroke="#4a90e2" stroke-width="2"/>
          <text x="80"  y="85"  text-anchor="middle" font-size="13" font-family="monospace">n₀</text>
        
          <circle cx="210" cy="80"  r="25" fill="#d0e8ff" stroke="#4a90e2" stroke-width="2"/>
          <text x="210" y="85"  text-anchor="middle" font-size="13" font-family="monospace">n₁</text>
        
          <circle cx="330" cy="160" r="25" fill="#ffe0b2" stroke="#e65100" stroke-width="2"/>
          <text x="330" y="165" text-anchor="middle" font-size="13" font-family="monospace">n₂</text>
        
          <circle cx="80"  cy="200" r="25" fill="#d0e8ff" stroke="#4a90e2" stroke-width="2"/>
          <text x="80"  y="205" text-anchor="middle" font-size="13" font-family="monospace">n₃</text>
        
          <circle cx="330" cy="248" r="25" fill="#c8e6c9" stroke="#2e7d32" stroke-width="2"/>
          <text x="330" y="253" text-anchor="middle" font-size="13" font-family="monospace">n₄</text>
        
          <!-- Legend -->
          <rect x="10" y="250" width="14" height="14" fill="#d0e8ff" stroke="#4a90e2"/>
          <text x="30" y="262" font-size="11" fill="#555">source nodes</text>
        
          <rect x="110" y="250" width="14" height="14" fill="#ffe0b2" stroke="#e65100"/>
          <text x="130" y="262" font-size="11" fill="#555">target node (n₂)</text>
        
          <rect x="240" y="250" width="14" height="14" fill="#c8e6c9" stroke="#2e7d32"/>
          <text x="260" y="262" font-size="11" fill="#555">downstream</text>
        </svg>
        

Approach 2: CSS-Styled Node Grid

For tensor shape diagrams (not graph topology), a CSS grid works well:

html
<style>
        .tensor-grid {
          display: flex;
          gap: 6px;
          align-items: flex-end;
          font-family: monospace;
          font-size: 12px;
          margin: 12px 0;
        }
        .tensor-node {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 2px;
        }
        .node-box {
          width: 52px;
          height: 52px;
          border: 2px solid #4a90e2;
          border-radius: 6px;
          background: #d0e8ff;
          display: flex;
          align-items: center;
          justify-content: center;
          font-size: 11px;
          color: #333;
        }
        .node-label {
          font-size: 11px;
          color: #555;
        }
        </style>
        
        <div class="tensor-grid" role="img"
             aria-label="node_features tensor: N nodes each holding a C-H-W tensor">
          <div class="tensor-node">
            <div class="node-box">n₀<br>[C,H,W]</div>
            <div class="node-label">node 0</div>
          </div>
          <div class="tensor-node">
            <div class="node-box">n₁<br>[C,H,W]</div>
            <div class="node-label">node 1</div>
          </div>
          <div class="tensor-node">
            <div class="node-box">n₂<br>[C,H,W]</div>
            <div class="node-label">node 2</div>
          </div>
          <span style="font-size:20px;color:#999;padding-bottom:14px">···</span>
          <div class="tensor-node">
            <div class="node-box">nₙ₋₁<br>[C,H,W]</div>
            <div class="node-label">node N-1</div>
          </div>
        </div>
        <p style="font-size:12px;color:#666">
          <code>node_features</code>: shape [N, C, H, W]
        </p>
        

Approach 3: details/summary for Expandable Diagrams

Long diagrams interrupt reading. Wrap complex ones in details/summary:

html
<details>
        <summary>
          <strong>GraphBatch batching diagram</strong>
          — click to expand
        </summary>
        
        <svg width="480" height="200" xmlns="http://www.w3.org/2000/svg"
             aria-label="GraphBatch combines three graphs into one batched graph">
        
          <!-- Graph 1 box -->
          <rect x="10" y="20" width="100" height="80" rx="6"
                fill="#e8f4fd" stroke="#4a90e2" stroke-width="1.5"/>
          <text x="60" y="42" text-anchor="middle" font-size="11">Graph g₁</text>
          <text x="60" y="58" text-anchor="middle" font-size="10" fill="#555">N₁=4 nodes</text>
          <text x="60" y="72" text-anchor="middle" font-size="10" fill="#555">E₁=5 edges</text>
        
          <!-- Graph 2 box -->
          <rect x="120" y="20" width="100" height="80" rx="6"
                fill="#e8f4fd" stroke="#4a90e2" stroke-width="1.5"/>
          <text x="170" y="42" text-anchor="middle" font-size="11">Graph g₂</text>
          <text x="170" y="58" text-anchor="middle" font-size="10" fill="#555">N₂=3 nodes</text>
          <text x="170" y="72" text-anchor="middle" font-size="10" fill="#555">E₂=4 edges</text>
        
          <!-- Graph 3 box -->
          <rect x="230" y="20" width="100" height="80" rx="6"
                fill="#e8f4fd" stroke="#4a90e2" stroke-width="1.5"/>
          <text x="280" y="42" text-anchor="middle" font-size="11">Graph g₃</text>
          <text x="280" y="58" text-anchor="middle" font-size="10" fill="#555">N₃=5 nodes</text>
          <text x="280" y="72" text-anchor="middle" font-size="10" fill="#555">E₃=6 edges</text>
        
          <!-- Arrow -->
          <text x="348" y="65" font-size="20" fill="#888">→</text>
        
          <!-- Batched graph box -->
          <rect x="370" y="10" width="100" height="100" rx="6"
                fill="#fff8e1" stroke="#f57f17" stroke-width="1.5"/>
          <text x="420" y="32" text-anchor="middle" font-size="11">GraphBatch</text>
          <text x="420" y="50" text-anchor="middle" font-size="10" fill="#555">N=12 nodes</text>
          <text x="420" y="65" text-anchor="middle" font-size="10" fill="#555">E=15 edges</text>
          <text x="420" y="80" text-anchor="middle" font-size="10" fill="#555">offsets applied</text>
        
          <!-- Caption -->
          <text x="240" y="175" text-anchor="middle" font-size="11" fill="#555">
            GraphBatch.from_graphs([g1, g2, g3])
          </text>
        </svg>
        
        </details>
        

Accessibility Checklist

Before publishing any diagram:

  • [ ] SVG has role="img" and aria-label attribute
  • [ ] SVG has <title> element inside it
  • [ ] Text in SVG uses <text> elements (not embedded images of text)
  • [ ] Color is not the only way to convey information (use labels too)
  • [ ] details summary text describes content clearly

When to Use Each Approach

Situation Approach
GitHub README (limited HTML) ASCII with fenced code block
GitHub README (SVG allowed) Inline SVG (renders in GitHub)
Static site with HTML support SVG + details/summary
Tensor shape documentation CSS grid or SVG boxes
Complex graph topology SVG with labeled nodes/edges
Print/PDF documentation SVG (PDF renders SVG correctly)
Jupyter notebook SVG or matplotlib (inline)

Static, dependency-free diagrams age well. A diagram built from SVG and HTML
will render correctly in five years without any build step or CDN dependency.
That is worth the extra verbosity compared to a one-line chart library call.