---
# === IDENTITY ===
id: consulting/recipes/oia-network-analysis-execution/2026
canonical_question: "How do you execute an ONA using Viva Insights and custom graph analysis?"
aliases:
  - "Organizational network analysis execution guide"
  - "How to run ONA from communication metadata"
  - "Graph analysis for organizational bottleneck detection"
entity_type: execution_recipe
domain: consulting > recipes > OIA Network Analysis Execution
region: global
jurisdiction: global
temporal_scope: 2026-2027

# === VERIFICATION ===
last_verified: 2026-03-29
confidence: 0.85
version: 1.0
first_published: 2026-03-29

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "Initial release — ONA execution protocols v1.0"
  next_review: 2026-09-25
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Minimum 90 days of communication metadata required for stable centrality scores"
  - "Node count must match employee roster — missing nodes invalidate topology"
  - "Edge weights must normalize across communication types (1:1 > group, response > broadcast)"
  - "Anonymized data only — no real names in graph visualization shared with client"
  - "Centrality thresholds: flag nodes > 2 standard deviations from mean"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs data collection, not analysis"
    use_instead: "consulting/recipes/oia-data-collection/2026"
  - condition: "User needs full OIA engagement plan"
    use_instead: "consulting/recipes/oia-engagement-playbook/2026"
  - condition: "User needs autoimmune scan, not network mapping"
    use_instead: "consulting/recipes/oia-autoimmune-scan-execution/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: tool_preference
    question: "Which network analysis tool should be used?"
    type: choice
    options: ["Microsoft Viva Insights", "Python NetworkX", "Gephi", "no preference — auto-select"]
  - key: technical_skill
    question: "What is the analyst's technical skill level?"
    type: choice
    options: ["non-technical (no-code only)", "semi-technical (can run scripts)", "developer (can write code)"]
  - key: org_size
    question: "How many employees are in the network?"
    type: choice
    options: ["50-200", "200-1000", "1000-5000", "5000+"]
  - key: visualization_need
    question: "What level of visualization is needed?"
    type: choice
    options: ["executive dashboard only", "interactive exploration", "publication-quality graphics", "data only — no visualization"]

# === EXECUTION METADATA ===
execution:
  required_inputs:
    - name: "Communication metadata dataset"
      source: "consulting/recipes/oia-data-collection/2026"
      format: "CSV + JSON"
    - name: "Org structure dataset"
      source: "consulting/recipes/oia-data-collection/2026"
      format: "JSON"

  outputs:
    - name: "Network topology report"
      format: "PDF + JSON"
      description: "Directed weighted graph with centrality scores, bottleneck identification, and structural hole analysis"
    - name: "Formal-vs-informal gap analysis"
      format: "PDF + CSV"
      description: "Comparison of formal org chart reporting lines vs actual communication patterns"
    - name: "Network visualization"
      format: "SVG + interactive HTML"
      description: "Annotated network graph for client presentation"

  tools_required:
    - name: "Python NetworkX"
      purpose: "Graph construction and centrality analysis"
      tier: "free"
      cost: "$0"
      alternatives: ["igraph", "graph-tool"]
    - name: "Gephi"
      purpose: "Network visualization"
      tier: "free"
      cost: "$0"
      alternatives: ["D3.js", "Cytoscape.js"]
    - name: "Microsoft Viva Insights"
      purpose: "Automated ONA with built-in dashboards"
      tier: "enterprise"
      cost: "$5K-$10K"
      alternatives: ["NetworkX + Gephi (free)"]

  credentials_needed:
    - service: "Microsoft Viva Insights"
      type: "Admin access"
      where_to_get: "https://learn.microsoft.com/en-us/viva/insights/"
      free_tier_limits: "N/A — enterprise license required"

  estimated_duration: "3-5 days"
  estimated_cost: "$0 (open source) to $5K (Viva Insights license)"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/consulting/recipes/oia-network-analysis-execution/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-29)"

# === RELATED UNITS ===
related_kos:
  depends_on:
    - id: "consulting/recipes/oia-data-collection/2026"
      label: "Data collection recipe that produces input for this analysis"
  feeds_into:
    - id: "consulting/recipes/oia-autoimmune-scan-execution/2026"
      label: "Autoimmune scan that uses network findings"
  related_to:
    - id: "consulting/oia/ona-methodology/2026"
      label: "ONA methodology theory card"

# === SOURCES ===
sources:
  - id: src1
    title: "Driving Results Through Social Networks"
    author: Cross, R. & Thomas, R.
    url: https://www.wiley.com/en-us/Driving+Results+Through+Social+Networks-p-9780470392492
    type: academic_paper
    published: 2009-01-01
    reliability: high
  - id: src2
    title: "The New Science of Building Great Teams"
    author: Pentland, A.
    url: https://hbr.org/2012/04/the-new-science-of-building-great-teams
    type: primary_research
    published: 2012-04-01
    reliability: authoritative
  - id: src3
    title: "Structural Holes and Good Ideas"
    author: Burt, R.
    url: https://www.journals.uchicago.edu/doi/10.1086/421787
    type: academic_paper
    published: 2004-01-01
    reliability: authoritative
  - id: src4
    title: "Microsoft Viva Insights Documentation"
    author: Microsoft
    url: https://learn.microsoft.com/en-us/viva/insights/
    type: official_docs
    published: 2026-01-01
    reliability: authoritative
---

# OIA Network Analysis Execution

## Purpose

This recipe executes an organizational network analysis (ONA) from communication metadata, producing a directed weighted graph with centrality scores, bottleneck identification, structural hole analysis, and a formal-vs-informal gap report. The output reveals who actually drives information flow (vs who the org chart says should) and identifies single points of failure invisible to traditional management. [src1, src2]

## Prerequisites
<!-- Agents: verify ALL prerequisites before executing. Missing prerequisites = failed execution. -->

- [ ] **Communication metadata dataset** from [OIA Data Collection](/consulting/recipes/oia-data-collection/2026) — minimum 90 days
- [ ] **Org structure dataset** (anonymized org chart with reporting lines)
- [ ] **Python 3.10+** with NetworkX, pandas, matplotlib installed (PATH C)
- [ ] **Gephi 0.10+** installed for visualization (PATH C) — or Viva Insights access (PATH A)
- [ ] **Org chart overlay data** — formal reporting lines mapped to anonymized IDs

## Constraints
<!-- Hard rules. Agents: enforce throughout execution. -->

- Node count must match employee roster — missing nodes produce false structural holes. [src3]
- Edge weight normalization required: 1:1 messages weighted 3x, thread replies 2x, channel broadcasts 1x, reactions 0.5x. [src2]
- Centrality threshold: flag nodes > 2 standard deviations above mean as bottlenecks/hubs.
- Anonymized IDs only in all outputs shared with client. Real names only in verbal presentation.
- Minimum sample: 50 nodes for meaningful centrality analysis. Below 50, use qualitative methods.

## Tool Selection Decision

```
Which tool path?
├── Enterprise client with Microsoft 365
│   └── PATH A: Viva Insights — automated ONA, built-in dashboards
├── Technical analyst available AND org size < 1000
│   └── PATH B: Python NetworkX + Gephi — full control, free
├── Technical analyst available AND org size > 1000
│   └── PATH C: Python igraph + D3.js — scalable, interactive
└── Non-technical analyst AND no Viva Insights
    └── PATH D: Gephi desktop — visual-first, limited automation
```

| Path | Tools | Cost | Speed | Output Quality |
|------|-------|------|-------|---------------|
| A: Viva Insights | Microsoft Viva Insights | $5K-$10K | 1-2 days | Excellent — automated, validated |
| B: NetworkX + Gephi | Python, NetworkX, Gephi | $0 | 3-4 days | Excellent — full control |
| C: igraph + D3.js | Python, igraph, D3.js | $0 | 3-5 days | Excellent — scalable |
| D: Gephi desktop | Gephi, spreadsheets | $0 | 4-5 days | Good — visual but manual |

## Execution Flow

### Step 1: Tool Selection

**Duration**: 1-2 hours
**Tool**: Decision based on client environment

Choose between Microsoft Viva Insights (enterprise, no-code, fast), NetworkX + Python (custom, free, full control), igraph (large-scale), or Gephi (visualization-first). Decision factors: client's Microsoft 365 license status, analyst technical skill, org size, and visualization requirements.

For PATH B (most common for OIA engagements):

```bash
pip install networkx pandas matplotlib numpy scipy
# Optional: install Gephi from https://gephi.org/
```

**Verify**: All dependencies installed. Test with `python -c "import networkx; print(networkx.__version__)"`.
**If failed**: If pip fails, use conda. If Gephi unavailable, use matplotlib for basic visualization.

### Step 2: Graph Construction

**Duration**: 4-8 hours
**Tool**: Python NetworkX or igraph

Build directed weighted graph from communication metadata. Nodes = anonymized employee IDs. Edges = communication frequency weighted by interaction type. [src2]

```python
import networkx as nx
import pandas as pd
import numpy as np

# Load combined metadata
df = pd.read_csv("combined_oia_dataset.csv")

# Create directed weighted graph
G = nx.DiGraph()

# Weight by interaction type
WEIGHTS = {
    "direct_message": 3.0,
    "thread_reply": 2.0,
    "channel_message": 1.0,
    "reaction": 0.5,
    "email_direct": 3.0,
    "email_cc": 0.5,
    "pr_review": 2.5,
    "ticket_comment": 1.5,
}

# Aggregate edges
for _, row in df.iterrows():
    sender = row["sender_id"]
    receiver = row["receiver_id"]
    weight = WEIGHTS.get(row["interaction_type"], 1.0)

    if G.has_edge(sender, receiver):
        G[sender][receiver]["weight"] += weight
    else:
        G.add_edge(sender, receiver, weight=weight)

print(f"Nodes: {G.number_of_nodes()}, Edges: {G.number_of_edges()}")
```

**Verify**: Node count matches employee roster (tolerance: +/- 5%). No isolated nodes unless they are genuinely disconnected.
**If failed**: If node count < 90% of roster, check data collection coverage. Missing nodes = missing department data.

### Step 3: Centrality Analysis

**Duration**: 4-8 hours
**Tool**: Python NetworkX

Calculate three centrality measures to identify different types of critical nodes. Flag statistical outliers as organizational risks. [src1, src3]

```python
# Betweenness centrality — bottleneck detection
betweenness = nx.betweenness_centrality(G, weight="weight")

# Degree centrality — hub detection
in_degree = nx.in_degree_centrality(G)
out_degree = nx.out_degree_centrality(G)

# Eigenvector centrality — influence detection
try:
    eigenvector = nx.eigenvector_centrality(G, weight="weight", max_iter=1000)
except nx.PowerIterationFailedConvergence:
    eigenvector = nx.eigenvector_centrality_numpy(G, weight="weight")

# Statistical flagging: > 2 standard deviations
def flag_outliers(centrality_dict, label):
    values = list(centrality_dict.values())
    mean = np.mean(values)
    std = np.std(values)
    threshold = mean + 2 * std
    flagged = {k: v for k, v in centrality_dict.items() if v > threshold}
    print(f"{label}: {len(flagged)} outliers (threshold: {threshold:.4f})")
    return flagged

bottlenecks = flag_outliers(betweenness, "Betweenness (bottlenecks)")
hubs = flag_outliers(in_degree, "In-degree (hubs)")
influencers = flag_outliers(eigenvector, "Eigenvector (influencers)")

# Structural holes (Burt's constraint measure)
constraint = nx.constraint(G, weight="weight")
structural_holes = {k: v for k, v in constraint.items()
                    if v < np.mean(list(constraint.values())) - np.std(list(constraint.values()))}
print(f"Structural hole spanners: {len(structural_holes)}")
```

**Verify**: Top 10 bottlenecks identified. Centrality distributions follow expected power-law shape.
**If failed**: If centrality analysis produces uniform scores, edge weights may be miscalibrated. Re-check weight normalization in Step 2.

### Step 4: Formal vs Informal Gap Analysis

**Duration**: 4-8 hours
**Tool**: Python + org chart data

Overlay formal org chart reporting lines onto actual communication graph. Measure the gap between formal authority and actual information flow. [src1]

```python
import json

# Load org structure
with open("org_structure.json") as f:
    org = json.load(f)

# Build formal hierarchy graph
H = nx.DiGraph()
for emp in org["employees"]:
    if emp.get("manager_id"):
        H.add_edge(emp["manager_id"], emp["employee_id"])

# Gap analysis
formal_edges = set(H.edges())
actual_edges = set(G.edges())

# Communication without formal authority
informal_influence = actual_edges - formal_edges
# Formal authority without communication
silent_authority = formal_edges - actual_edges

# Shadow influencers: high eigenvector centrality but no direct reports
shadow_influencers = []
managers = set(H.nodes()) - set(nx.isolates(H))
for node, score in eigenvector.items():
    if node not in managers and score > np.mean(list(eigenvector.values())) + np.std(list(eigenvector.values())):
        shadow_influencers.append({"id": node, "eigenvector": score})

# Bypassed managers: have direct reports but low communication centrality
bypassed_managers = []
for manager in managers:
    if betweenness.get(manager, 0) < np.mean(list(betweenness.values())):
        bypassed_managers.append({"id": manager, "betweenness": betweenness.get(manager, 0)})

print(f"Shadow influencers: {len(shadow_influencers)}")
print(f"Bypassed managers: {len(bypassed_managers)}")
print(f"Informal influence edges: {len(informal_influence)}")
print(f"Silent authority edges: {len(silent_authority)}")
```

**Verify**: Gap report generated with shadow influencer and bypassed manager lists. Findings reviewed against known organizational dynamics.
**If failed**: If org chart data incomplete, document gaps and note which departments lack formal-vs-informal analysis.

### Step 5: Visualization & Report

**Duration**: 4-8 hours
**Tool**: Gephi, D3.js, or matplotlib

Generate network visualization annotated with bottlenecks, structural holes, and shadow paths. Produce written analysis with findings and recommendations. [src1, src3]

```python
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

# Spring layout for readable visualization
pos = nx.spring_layout(G, k=2, iterations=50, seed=42)

# Color nodes by type
node_colors = []
for node in G.nodes():
    if node in bottlenecks:
        node_colors.append("red")        # Bottleneck
    elif node in [s["id"] for s in shadow_influencers]:
        node_colors.append("orange")     # Shadow influencer
    elif node in [b["id"] for b in bypassed_managers]:
        node_colors.append("yellow")     # Bypassed manager
    else:
        node_colors.append("lightblue")  # Normal

# Size nodes by eigenvector centrality
node_sizes = [eigenvector.get(n, 0.01) * 3000 for n in G.nodes()]

plt.figure(figsize=(20, 16))
nx.draw(G, pos, node_color=node_colors, node_size=node_sizes,
        edge_color="gray", alpha=0.7, arrows=True, arrowsize=8,
        width=[G[u][v]["weight"] * 0.1 for u, v in G.edges()])

legend = [
    mpatches.Patch(color="red", label="Bottleneck"),
    mpatches.Patch(color="orange", label="Shadow Influencer"),
    mpatches.Patch(color="yellow", label="Bypassed Manager"),
    mpatches.Patch(color="lightblue", label="Normal"),
]
plt.legend(handles=legend, loc="upper left", fontsize=12)
plt.title("Organizational Network Topology — OIA Analysis")
plt.savefig("network_topology.svg", format="svg", bbox_inches="tight")
plt.savefig("network_topology.png", dpi=150, bbox_inches="tight")
```

**Output files**:
- `network_topology.svg` — Publication-quality network visualization
- `centrality_report.csv` — All centrality scores per node
- `gap_analysis.csv` — Formal-vs-informal comparison
- `oia_network_findings.pdf` — Written analysis with annotated visualizations

**Verify**: Client validates key findings — top 5 bottlenecks and shadow influencers confirmed against known organizational dynamics.
**If failed**: If client disputes findings, offer to re-run with different edge weight calibration or extended timeframe.

## Output Schema

```json
{
  "output_type": "ona_analysis_report",
  "format": "PDF + CSV + SVG",
  "files": [
    {"name": "centrality_report.csv", "description": "Betweenness, degree, eigenvector centrality per node"},
    {"name": "gap_analysis.csv", "description": "Formal vs informal edge comparison"},
    {"name": "network_topology.svg", "description": "Annotated network visualization"},
    {"name": "oia_network_findings.pdf", "description": "Written analysis with recommendations"}
  ],
  "key_metrics": [
    {"name": "bottleneck_count", "type": "number", "description": "Nodes > 2 SD above mean betweenness"},
    {"name": "shadow_influencer_count", "type": "number", "description": "High eigenvector, no formal authority"},
    {"name": "bypassed_manager_count", "type": "number", "description": "Formal authority, low communication centrality"},
    {"name": "structural_hole_count", "type": "number", "description": "Nodes spanning disconnected clusters"}
  ]
}
```

## Quality Benchmarks

| Quality Metric | Minimum Acceptable | Good | Excellent |
|---------------|-------------------|------|-----------|
| Node coverage (% of roster) | > 80% | > 90% | > 98% |
| Bottleneck identification (client-validated) | > 50% confirmed | > 70% confirmed | > 85% confirmed |
| Visualization readability | Clusters visible | Annotated clusters | Interactive exploration |
| Gap analysis coverage (departments analyzed) | > 60% | > 80% | > 95% |

**If below minimum**: Extend data collection, add missing platforms, or supplement with interview-based network mapping.

## Error Handling

| Error | Likely Cause | Recovery Action |
|-------|-------------|----------------|
| NetworkX convergence failure (eigenvector) | Graph too sparse or disconnected | Use eigenvector_centrality_numpy instead, or fall back to PageRank |
| Uniform centrality scores | Edge weights not normalized | Re-check weight calibration in Step 2, verify interaction type distribution |
| Too many bottlenecks flagged (> 20%) | Threshold too low or data too noisy | Increase threshold to 2.5 or 3 standard deviations |
| Disconnected graph components | Missing department data | Analyze largest connected component, document gaps |
| Visualization unreadable | Too many nodes overlapping | Use community detection to cluster, then visualize inter-cluster edges |

## Cost Breakdown

| Component | Free (NetworkX) | Mid (Gephi Pro) | Enterprise (Viva) |
|-----------|-----------------|-----------------|-------------------|
| Graph analysis tool | $0 (NetworkX) | $0 (Gephi) | $5K-$10K (Viva license) |
| Visualization | $0 (matplotlib) | $0 (Gephi) | Included in Viva |
| Developer time | 3-5 days | 4-5 days | 1-2 days |
| **Total** | **$0** | **$0** | **$5K-$10K** |

## Anti-Patterns

### Wrong: Treating all communication equally
Giving the same edge weight to a Slack channel broadcast as a 1:1 direct message. Result: channel spammers appear as influential hubs while quiet but critical 1:1 communicators are invisible. [src2]

### Correct: Weight by interaction intimacy
1:1 messages carry 3x the weight of broadcasts. Thread replies 2x. Reactions 0.5x. This reflects actual relationship strength. [src2]

### Wrong: Ignoring structural holes
Focusing only on bottleneck centrality and ignoring Burt's structural holes. Result: missing the people who bridge disconnected groups — often the most strategically valuable individuals. [src3]

### Correct: Measure structural holes explicitly
Calculate Burt's constraint measure. Low-constraint nodes span structural holes. These are the organization's innovation bridges — losing them disconnects entire clusters.

### Wrong: Presenting network visualization without validation
Showing the raw network graph to the client without first validating key findings. Result: false positives (data artifacts) undermine credibility of the entire analysis. [src1]

### Correct: Validate before presenting
Share top 10 findings with 2-3 internal stakeholders before formal presentation. Their context reveals data artifacts vs genuine patterns.

## When This Matters

Use when an agent needs to execute organizational network analysis from communication metadata. This is Step 3 of the OIA engagement lifecycle. Requires the combined communication metadata dataset from the data collection recipe as input. Output feeds into the autoimmune scan and stress test recipes.

## Related Units

- [OIA Data Collection](/consulting/recipes/oia-data-collection/2026)
- [OIA Autoimmune Scan Execution](/consulting/recipes/oia-autoimmune-scan-execution/2026)
- [OIA Engagement Playbook](/consulting/recipes/oia-engagement-playbook/2026)
- [ONA Methodology Theory](/consulting/oia/ona-methodology/2026)
