TGraphX Insights Creating Interactive Tensor-Shape Diagrams for GNN Articles
← Back to Insights

Creating Interactive Tensor-Shape Diagrams for GNN Articles

Target keyword: tensor shape diagram GNN

Creating Interactive Tensor-Shape Diagrams for GNN Articles

Technical articles about graph neural networks often fail readers at the
visualization step. A prose description of "a tensor of shape [N, C, H, W]
aggregated over neighbors via scatter" is hard to hold in working memory.
A well-designed diagram makes the same information immediately graspable.

This tutorial covers static-site-safe visualization techniques: SVG boxes for
precise diagrams, ASCII art for Markdown compatibility, and HTML details /
summary for lightweight interactivity. No heavy JavaScript frameworks, no
external dependencies.

Why Diagrams Are Hard to Get Right for GNNs

GNN diagrams need to communicate three things simultaneously:
1. Tensor shapes: how many dimensions, what each dimension means
2. Graph structure: which nodes connect to which edges
3. Data flow: how tensors transform through message passing

Most diagram tools optimize for one of these and ignore the others. The
approach here is to design for the reader's mental model rather than for
visual elegance.

Approach 1: ASCII Tensor Diagrams (Markdown-safe)

ASCII diagrams render everywhere: GitHub, static site generators, email,
terminal. They have zero dependencies. The trade-off is limited precision
for complex layouts.

Node feature tensor [N, C, H, W]:

  node_features tensor  shape: [N=6, C=3, H=16, W=16]
          ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
          │ n₀  │ │ n₁  │ │ n₂  │ │ n₃  │ │ n₄  │ │ n₅  │
          │3×16 │ │3×16 │ │3×16 │ │3×16 │ │3×16 │ │3×16 │
          │×16  │ │×16  │ │×16  │ │×16  │ │×16  │ │×16  │
          └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
            ↑       ↑ ───── N nodes, each holding [C,H,W] ─────
        

Edge index tensor [2, E]:

  edge_index  shape: [2, E=8]
          row 0 (src):  [0, 0, 1, 2, 2, 3, 4, 5]
          row 1 (dst):  [1, 2, 3, 3, 4, 5, 5, 0]
                         ↑                    ↑
                       edge 0               edge 7
        

Message passing data flow:

  Aggregation at node n₃:
        
          n₁ ──(e₂)──► n₃ ◄──(e₃)── n₂
                        ↑
                   [message from n₁] + [message from n₂]
                        ↓
                 scatter_reduce (sum/mean)
                        ↓
                   agg_feature[n₃]  shape: [C, H, W]
        

Approach 2: Inline SVG for Precise Diagrams

For HTML-rendered articles (Markdown with HTML support, Jekyll, Hugo, etc.),
inline SVG gives pixel-precise control with no external dependencies:

html
<!-- Tensor shape box diagram -->
        <svg width="500" height="120" xmlns="http://www.w3.org/2000/svg"
             role="img" aria-label="Tensor shape diagram for node_features [N, C, H, W]">
        
          <!-- Background -->
          <rect width="500" height="120" fill="#f8f9fa" rx="8"/>
        
          <!-- Title -->
          <text x="10" y="22" font-family="monospace" font-size="13" fill="#333">
            node_features  shape: [N, C, H, W]
          </text>
        
          <!-- Node boxes -->
          <rect x="10"  y="35" width="60" height="60" fill="#d0e8ff" stroke="#4a90e2" rx="4"/>
          <text x="40"  y="58" text-anchor="middle" font-size="11" fill="#333">n₀</text>
          <text x="40"  y="74" text-anchor="middle" font-size="10" fill="#666">[C,H,W]</text>
        
          <rect x="80"  y="35" width="60" height="60" fill="#d0e8ff" stroke="#4a90e2" rx="4"/>
          <text x="110" y="58" text-anchor="middle" font-size="11" fill="#333">n₁</text>
          <text x="110" y="74" text-anchor="middle" font-size="10" fill="#666">[C,H,W]</text>
        
          <rect x="150" y="35" width="60" height="60" fill="#d0e8ff" stroke="#4a90e2" rx="4"/>
          <text x="180" y="58" text-anchor="middle" font-size="11" fill="#333">n₂</text>
          <text x="180" y="74" text-anchor="middle" font-size="10" fill="#666">[C,H,W]</text>
        
          <!-- Ellipsis -->
          <text x="230" y="68" font-size="20" fill="#999">···</text>
        
          <rect x="270" y="35" width="60" height="60" fill="#d0e8ff" stroke="#4a90e2" rx="4"/>
          <text x="300" y="58" text-anchor="middle" font-size="11" fill="#333">nₙ₋₁</text>
          <text x="300" y="74" text-anchor="middle" font-size="10" fill="#666">[C,H,W]</text>
        
          <!-- Dimension brace label -->
          <line x1="10" y1="108" x2="330" y2="108" stroke="#999" stroke-width="1"/>
          <text x="170" y="118" text-anchor="middle" font-size="11" fill="#666">← N nodes →</text>
        </svg>
        

Approach 3: HTML details/summary for Collapsible Diagrams

Long diagrams interrupt reading flow. Use <details> / <summary> to make
them opt-in:

html
<details>
        <summary><strong>Expand: GraphBatch batching diagram</strong></summary>
        
        <pre>
          GraphBatch.from_graphs([g1, g2, g3])
        
          g1: N1=4 nodes, E1=5 edges
          g2: N2=3 nodes, E2=4 edges
          g3: N3=5 nodes, E3=6 edges
        
          Batched graph:
          ┌─────────────────────────────────────────┐
          │ nodes [0..3] = g1  nodes [4..6] = g2   │
          │ nodes [7..11] = g3                      │
          │                                         │
          │ edge_index offsets applied:             │
          │ g2 edges: +4  (N1=4)                   │
          │ g3 edges: +7  (N1+N2=7)               │
          └─────────────────────────────────────────┘
        
          batch vector: [0,0,0,0, 1,1,1, 2,2,2,2,2]
                          g1       g2     g3
        </pre>
        
        </details>
        

This keeps the article readable while letting interested readers expand the
detail.

Approach 4: Shape-Annotated Code Blocks

The simplest diagram is a well-annotated code block. Shape comments in line
with construction code are searchable, copyable, and work in every renderer:

python
import torch
        from tgraphx import Graph
        
        N, E, C, H, W = 32, 80, 3, 16, 16
        
        node_features = torch.randn(N, C, H, W)   # [32, 3, 16, 16]
        edge_index    = torch.randint(0, N, (2, E))  # [2, 80]
        edge_features = torch.randn(E, 64)         # [80, 64]
        node_labels   = torch.randint(0, 5, (N,))  # [32]
        
        g = Graph(
            node_features=node_features,   # [N, C, H, W]
            edge_index=edge_index,         # [2, E]
            edge_features=edge_features,   # [E, d_e]
            node_labels=node_labels,       # [N]
        )
        

Readers copy this code and immediately have correct shapes to work from.

Accessibility Considerations

For SVG diagrams:
- Always include aria-label or <title> inside the SVG
- Use role="img" for decorative diagrams, role="figure" for informational
- Ensure text labels are actual <text> elements, not rasterized

For ASCII diagrams:
- Wrap in <pre> or fenced code blocks for correct monospace rendering
- Consider a short prose summary immediately before the diagram

For details/summary:
- The <summary> text should describe what's inside, not just say "expand"
- Avoid nesting multiple levels of details/summary — it's confusing

When to Use Each Approach

Situation Recommended approach
Markdown-only environment (GitHub) ASCII with code block
HTML static site (Hugo, Jekyll) SVG inline + details/summary
Complex data flow diagram SVG with labeled arrows
Quick shape reference Shape-annotated code block
Long appendix-style diagram details/summary wrapping ASCII or SVG
Print/PDF export needed SVG (renders well in PDF)

A Complete Example: Graph Construction Explainer

Combining approaches, a section explaining TGraphX's Graph might look like:


The Graph class validates shapes and devices at construction time.

python
g = Graph(
            node_features=feats,   # [N, d] — N nodes, d features each
            edge_index=edges,      # [2, E] — source/target pairs
            edge_features=e_feats, # [E, de]
            node_labels=labels,    # [N]
        )
        
What happens if shapes don't match? If `edge_features.shape[0]` does not equal `edge_index.shape[1]`, you get an error at construction — before any forward pass runs. This prevents silent shape mismatches from propagating through training.

This pattern — code block first, expandable detail for edge cases — keeps the
main reading flow clean while providing depth for readers who want it.