364 lines
8.4 KiB
Markdown
364 lines
8.4 KiB
Markdown
# Dagre Ranker Visual Comparison Guide
|
||
|
||
**Purpose**: Explain why "Hierarchical (Top→Bottom)" and "Adaptive (Tight Tree)" layouts look similar
|
||
|
||
---
|
||
|
||
## 🔍 The Core Difference
|
||
|
||
**Both layouts use**:
|
||
- ✅ Same direction: Top→Bottom (TB)
|
||
- ✅ Same layout engine: Dagre
|
||
- ✅ Same spacing rules: nodesep, ranksep
|
||
|
||
**Only difference**:
|
||
- ❌ Ranking algorithm: `network-simplex` vs `tight-tree`
|
||
|
||
---
|
||
|
||
## 📊 Visual Comparison: Simple vs Complex Diagrams
|
||
|
||
### Simple Tree Structure (Like NetworkOrganisation)
|
||
|
||
```
|
||
Root
|
||
/ \
|
||
Child1 Child2
|
||
| |
|
||
Leaf1 Leaf2
|
||
```
|
||
|
||
#### With network-simplex (Hierarchical):
|
||
```
|
||
Root (Rank 0)
|
||
/ \
|
||
Child1 Child2 (Rank 1)
|
||
| |
|
||
Leaf1 Leaf2 (Rank 2)
|
||
```
|
||
|
||
#### With tight-tree (Adaptive):
|
||
```
|
||
Root (Rank 0)
|
||
/ \
|
||
Child1 Child2 (Rank 1)
|
||
| |
|
||
Leaf1 Leaf2 (Rank 2)
|
||
```
|
||
|
||
**Result**: IDENTICAL (both assign same ranks to nodes)
|
||
|
||
---
|
||
|
||
### Complex Graph with Multiple Paths
|
||
|
||
```
|
||
Root
|
||
/ \
|
||
A B
|
||
|\ /|
|
||
| \ / |
|
||
C \/ D
|
||
/\
|
||
E F
|
||
```
|
||
|
||
#### With network-simplex (Hierarchical):
|
||
```
|
||
Root (Rank 0)
|
||
/ \
|
||
A B (Rank 1)
|
||
| |
|
||
C D (Rank 2) ← Balanced ranks
|
||
| |
|
||
E F (Rank 3)
|
||
```
|
||
|
||
#### With tight-tree (Adaptive):
|
||
```
|
||
Root (Rank 0)
|
||
/ \
|
||
A B (Rank 1)
|
||
/ \ / \
|
||
C E D F (Rank 2) ← Compressed into fewer ranks!
|
||
```
|
||
|
||
**Result**: DIFFERENT (tight-tree compresses height)
|
||
|
||
---
|
||
|
||
## 🧮 Algorithm Behavior
|
||
|
||
### network-simplex (Hierarchical)
|
||
|
||
**Goal**: Minimize total edge length
|
||
**Method**: Linear programming solver
|
||
**Behavior**:
|
||
- Distributes nodes evenly across ranks
|
||
- Balances vertical and horizontal space
|
||
- Prioritizes aesthetic appeal
|
||
- May create more ranks (taller graphs)
|
||
|
||
**Best for**:
|
||
- General-purpose diagrams
|
||
- Balanced visual appearance
|
||
- Mixed relationship types
|
||
- Standard UML class diagrams
|
||
|
||
### tight-tree (Adaptive)
|
||
|
||
**Goal**: Minimize graph height
|
||
**Method**: Spanning tree algorithm
|
||
**Behavior**:
|
||
- Compresses nodes into fewer ranks
|
||
- Minimizes vertical space
|
||
- Accepts more horizontal spreading
|
||
- Fewer ranks (shorter graphs)
|
||
|
||
**Best for**:
|
||
- Deep hierarchies (many levels)
|
||
- Space-constrained displays
|
||
- Emphasizing breadth over depth
|
||
- Dense interconnected graphs
|
||
|
||
### longest-path (Adaptive)
|
||
|
||
**Goal**: Emphasize dependency chains
|
||
**Method**: Longest path from roots
|
||
**Behavior**:
|
||
- Maximizes graph height
|
||
- Shows clear dependency levels
|
||
- Creates more ranks
|
||
- Emphasizes sequential relationships
|
||
|
||
**Best for**:
|
||
- Workflow diagrams
|
||
- Build dependency graphs
|
||
- Process flows
|
||
- Showing critical paths
|
||
|
||
---
|
||
|
||
## 📐 Spacing Calculations
|
||
|
||
From UMLVisualization.tsx (Lines 286-298):
|
||
|
||
```typescript
|
||
const isVertical = dagreDirection === 'TB' || dagreDirection === 'BT';
|
||
const nodesep = isVertical ? 80 : 100; // Horizontal spacing
|
||
const ranksep = isVertical ? 120 : 150; // Vertical spacing between ranks
|
||
|
||
g.setGraph({
|
||
rankdir: dagreDirection, // TB, BT, LR, RL
|
||
nodesep: nodesep, // Space between nodes on same rank
|
||
ranksep: ranksep, // Space between ranks
|
||
ranker: dagreRanker, // ← ONLY DIFFERENCE!
|
||
marginx: 50,
|
||
marginy: 50
|
||
});
|
||
```
|
||
|
||
**Same spacing for all rankers!**
|
||
|
||
**Difference**: How many ranks are created (height)
|
||
|
||
---
|
||
|
||
## 🎨 When You'll See Differences
|
||
|
||
### Diagram Complexity Threshold
|
||
|
||
| Diagram Size | Nodes | Links | Ranker Differences? |
|
||
|--------------|-------|-------|---------------------|
|
||
| **Tiny** | <10 | <15 | ❌ No (identical) |
|
||
| **Small** | 10-20 | 15-30 | ⚠️ Subtle |
|
||
| **Medium** | 20-50 | 30-80 | ✅ Noticeable |
|
||
| **Large** | 50-100 | 80-150 | ✅ Significant |
|
||
| **Huge** | 100+ | 150+ | ✅ Very different |
|
||
|
||
### Graph Structure Matters
|
||
|
||
**Simple Trees** (No differences):
|
||
- Single root
|
||
- No cross-hierarchy edges
|
||
- Clear parent-child relationships
|
||
- Example: Simple class inheritance
|
||
|
||
**Complex Graphs** (Clear differences):
|
||
- Multiple roots
|
||
- Cross-hierarchy relationships
|
||
- Dense interconnections
|
||
- Cycles (if present)
|
||
- Example: Full ontology schema
|
||
|
||
---
|
||
|
||
## 🧪 Test Cases to See Differences
|
||
|
||
### Test 1: Simple Tree (NO difference expected)
|
||
**File**: `NetworkOrganisation_20251123_225712.mmd`
|
||
|
||
**Structure**: Linear hierarchy
|
||
```
|
||
UmbrellaOrganisation
|
||
|
|
||
NetworkOrganisation
|
||
|
|
||
Consortium
|
||
```
|
||
|
||
**Result**: All rankers produce identical layout
|
||
|
||
### Test 2: Complex Schema (DIFFERENCES expected)
|
||
**File**: `full_schema_20251123_174151.mmd` (264 lines)
|
||
|
||
**Structure**: Multiple inheritance, cross-references
|
||
```
|
||
Multiple root classes
|
||
Complex relationships
|
||
Many-to-many connections
|
||
Deep hierarchies
|
||
```
|
||
|
||
**Result**:
|
||
- `network-simplex`: Balanced, medium height
|
||
- `tight-tree`: Compressed, shorter height
|
||
- `longest-path`: Stretched, taller height
|
||
|
||
### Test 3: Multi-Aspect Model (SUBTLE differences)
|
||
**File**: `custodian_multi_aspect_20251122_155319.mmd`
|
||
|
||
**Structure**: Hub-and-spoke with cross-links
|
||
```
|
||
Central hub (CustodianObservation)
|
||
Multiple aspects radiating out
|
||
Cross-aspect relationships
|
||
```
|
||
|
||
**Result**:
|
||
- `network-simplex`: Centered hub, even spacing
|
||
- `tight-tree`: Compressed vertical spacing
|
||
- `longest-path`: Emphasized main paths
|
||
|
||
---
|
||
|
||
## 📊 Performance Comparison
|
||
|
||
| Ranker | Time Complexity | Space | Best Use |
|
||
|--------|----------------|-------|----------|
|
||
| **network-simplex** | O(n²) | Balanced | General |
|
||
| **tight-tree** | O(n log n) | Compact | Space-constrained |
|
||
| **longest-path** | O(n) | Spread | Workflows |
|
||
|
||
**For small diagrams (<50 nodes)**: Performance difference negligible
|
||
|
||
---
|
||
|
||
## 💡 Why The Confusion?
|
||
|
||
### User Expectation
|
||
"Adaptive (Tight Tree)" sounds like a completely different layout style
|
||
→ Users expect visually distinct appearance
|
||
|
||
### Technical Reality
|
||
It's the same layout engine with different ranking algorithm
|
||
→ Produces similar results for simple graphs
|
||
|
||
### Solution Options
|
||
|
||
**Option 1**: Update UI descriptions
|
||
```typescript
|
||
// Current
|
||
"Compact arrangement, minimal whitespace"
|
||
|
||
// Better
|
||
"Minimizes height (visible in complex diagrams)"
|
||
```
|
||
|
||
**Option 2**: Add complexity indicator
|
||
```typescript
|
||
if (diagram.nodes.length < 20) {
|
||
showMessage("Tip: Try a complex diagram to see ranker differences");
|
||
}
|
||
```
|
||
|
||
**Option 3**: Side-by-side comparison mode
|
||
- Render with all 3 rankers
|
||
- Show actual differences
|
||
- Educational value
|
||
|
||
---
|
||
|
||
## 🎓 Key Takeaways
|
||
|
||
1. **Rankers are optimization algorithms, not layout styles**
|
||
- They decide which nodes go on which rank (horizontal level)
|
||
- Same spacing rules apply to all rankers
|
||
- Visual differences depend on graph complexity
|
||
|
||
2. **Simple trees → identical layouts**
|
||
- All rankers agree on optimal ranking
|
||
- No alternative solutions exist
|
||
- This is EXPECTED behavior
|
||
|
||
3. **Complex graphs → visible differences**
|
||
- Multiple valid rankings exist
|
||
- Each ranker optimizes for different goals
|
||
- Load `full_schema_20251123_174151.mmd` to see
|
||
|
||
4. **Not a bug, it's algorithm convergence**
|
||
- Mathematically correct behavior
|
||
- UI clarity could be improved
|
||
- User education helps set expectations
|
||
|
||
---
|
||
|
||
## 🔍 How To Verify This
|
||
|
||
### Step 1: Load Simple Diagram
|
||
1. Open `http://localhost:5173/uml-viewer`
|
||
2. Load `NetworkOrganisation_20251123_225712.mmd`
|
||
3. Switch between:
|
||
- Hierarchical (Top→Bottom) [network-simplex]
|
||
- Adaptive (Tight Tree) [tight-tree]
|
||
4. **Observe**: Layouts look identical ✓
|
||
|
||
### Step 2: Load Complex Diagram
|
||
1. Load `full_schema_20251123_174151.mmd`
|
||
2. Switch between same layouts
|
||
3. **Observe**: Layouts now differ! ✓
|
||
- Hierarchical: Balanced spacing
|
||
- Tight Tree: Compressed height
|
||
- Longest Path: Emphasized depth
|
||
|
||
### Step 3: Compare Metrics
|
||
- Count vertical ranks in each layout
|
||
- Measure total graph height
|
||
- Note node clustering differences
|
||
|
||
---
|
||
|
||
## 📚 Further Reading
|
||
|
||
**Dagre Documentation**:
|
||
- Ranker algorithms: https://github.com/dagrejs/dagre/wiki#configuring-the-layout
|
||
- Layout options: https://github.com/dagrejs/dagre/wiki/Configuring-the-Layout
|
||
|
||
**Graph Theory**:
|
||
- Sugiyama framework (hierarchical layout)
|
||
- Network simplex algorithm
|
||
- Longest path in DAGs
|
||
|
||
**UML Best Practices**:
|
||
- When to use different layouts
|
||
- Choosing ranker for diagram type
|
||
- Performance optimization tips
|
||
|
||
---
|
||
|
||
**Created**: November 24, 2025
|
||
**Purpose**: Explain dagre ranker behavior
|
||
**Conclusion**: Layout similarity is expected for simple diagrams
|
||
**Recommendation**: Test with complex diagrams to see differences
|
||
|
||
**Next**: Load `full_schema_20251123_174151.mmd` and compare all 5 layouts!
|