🌐 EN | šŸ‡ÆšŸ‡µ JP | Last sync: 2025-11-16

Chapter 4: Network Visualization Tools

Effective Graph Visualization Using NetworkX, PyVis, igraph, and Gephi

šŸ“š ML-D07 - Introduction to Network Analysis ā±ļø 30 minutes šŸ”§ Implementation Focused

1. NetworkX Visualization

1.1 Integration with Matplotlib

NetworkX is fully integrated with matplotlib, making it suitable for static graph visualization.

import networkx as nx
import matplotlib.pyplot as plt

# Create graph
G = nx.karate_club_graph()

# Basic visualization
plt.figure(figsize=(12, 8))
nx.draw(G, with_labels=True, node_color='lightblue',
        node_size=500, font_size=10, font_weight='bold')
plt.title('Karate Club Network')
plt.axis('off')
plt.tight_layout()
plt.savefig('karate_network.png', dpi=300, bbox_inches='tight')
plt.show()

1.2 Layout Algorithms

Selecting the appropriate layout is essential for understanding network structure.

import numpy as np

# Comparison of various layouts
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
layouts = {
    'Spring': nx.spring_layout(G, k=0.3, iterations=50),
    'Circular': nx.circular_layout(G),
    'Kamada-Kawai': nx.kamada_kawai_layout(G),
    'Spectral': nx.spectral_layout(G)
}

for ax, (name, pos) in zip(axes.flat, layouts.items()):
    nx.draw(G, pos, ax=ax, node_color='lightblue',
            node_size=300, with_labels=True, font_size=8)
    ax.set_title(f'{name} Layout', fontsize=14, fontweight='bold')
    ax.axis('off')

plt.tight_layout()
plt.savefig('layout_comparison.png', dpi=300, bbox_inches='tight')
plt.show()

# Layout algorithm selection criteria
# - Spring: General-purpose, force-directed balance (O(n²))
# - Circular: Visualizes symmetry (O(n))
# - Kamada-Kawai: More accurate distance representation (O(n³))
# - Spectral: Emphasizes community structure (O(n²))

1.3 Node and Edge Customization

Visually representing network attributes deepens data insights.

# Customization based on degree centrality
degree_centrality = nx.degree_centrality(G)
betweenness_centrality = nx.betweenness_centrality(G)

# Node size: degree centrality
node_sizes = [v * 3000 for v in degree_centrality.values()]

# Node color: betweenness centrality
node_colors = list(betweenness_centrality.values())

# Edge width: weight (in this example, product of degrees)
edge_weights = [G.degree(u) * G.degree(v) * 0.1
                for u, v in G.edges()]

plt.figure(figsize=(14, 10))
pos = nx.spring_layout(G, k=0.3, seed=42)

# Draw
nx.draw_networkx_nodes(G, pos, node_size=node_sizes,
                       node_color=node_colors, cmap='YlOrRd',
                       alpha=0.9, edgecolors='black', linewidths=1.5)

nx.draw_networkx_edges(G, pos, width=edge_weights,
                       alpha=0.5, edge_color='gray')

nx.draw_networkx_labels(G, pos, font_size=9, font_weight='bold')

plt.title('Network Visualization Using Centrality Metrics',
          fontsize=16, fontweight='bold')
plt.colorbar(plt.cm.ScalarMappable(cmap='YlOrRd'),
             label='Betweenness Centrality', ax=plt.gca())
plt.axis('off')
plt.tight_layout()
plt.savefig('customized_network.png', dpi=300, bbox_inches='tight')
plt.show()

# Visualization best practices
# 1. Node size: Represents importance (centrality)
# 2. Node color: Represents category or continuous value
# 3. Edge width: Represents relationship strength
# 4. Layout: Choose according to data characteristics

2. Advanced Visualization Libraries

2.1 Interactive Visualization with PyVis

PyVis generates interactive network visualizations in HTML format.

from pyvis.network import Network
import networkx as nx

# Create PyVis network
net = Network(height='750px', width='100%', bgcolor='#222222',
              font_color='white', notebook=True)

# Import from NetworkX graph
G = nx.karate_club_graph()

# Community detection
from networkx.algorithms import community
communities = community.greedy_modularity_communities(G)
community_map = {}
for i, comm in enumerate(communities):
    for node in comm:
        community_map[node] = i

# Set node colors and sizes
for node in G.nodes():
    # Change color by community
    color = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A'][community_map[node]]
    # Change size by degree
    size = G.degree(node) * 3
    net.add_node(node, label=str(node), color=color, size=size,
                 title=f'Node {node}
Degree: {G.degree(node)}') # Add edges for edge in G.edges(): net.add_edge(edge[0], edge[1]) # Physics simulation settings net.set_options(""" var options = { "physics": { "forceAtlas2Based": { "gravitationalConstant": -50, "centralGravity": 0.01, "springLength": 100, "springConstant": 0.08 }, "maxVelocity": 50, "solver": "forceAtlas2Based", "timestep": 0.35, "stabilization": {"iterations": 150} } } """) # HTML output net.save_graph('interactive_network.html') print("Interactive graph saved to interactive_network.html")

2.2 Interactive Graphs with Plotly

Plotly provides highly customizable interactive graphs.

import plotly.graph_objects as go

# Calculate layout
pos = nx.spring_layout(G, k=0.5, seed=42)

# Create edge trace
edge_x = []
edge_y = []
for edge in G.edges():
    x0, y0 = pos[edge[0]]
    x1, y1 = pos[edge[1]]
    edge_x.extend([x0, x1, None])
    edge_y.extend([y0, y1, None])

edge_trace = go.Scatter(
    x=edge_x, y=edge_y,
    line=dict(width=0.5, color='#888'),
    hoverinfo='none',
    mode='lines')

# Create node trace
node_x = []
node_y = []
node_text = []
node_sizes = []
for node in G.nodes():
    x, y = pos[node]
    node_x.append(x)
    node_y.append(y)
    node_text.append(f'Node {node}
Degree: {G.degree(node)}') node_sizes.append(G.degree(node) * 5) node_trace = go.Scatter( x=node_x, y=node_y, mode='markers', hoverinfo='text', text=node_text, marker=dict( showscale=True, colorscale='YlOrRd', size=node_sizes, color=[G.degree(node) for node in G.nodes()], colorbar=dict( thickness=15, title='Node Degree', xanchor='left', titleside='right' ), line=dict(width=2, color='white'))) # Create figure fig = go.Figure(data=[edge_trace, node_trace], layout=go.Layout( title='Plotly Interactive Network', showlegend=False, hovermode='closest', margin=dict(b=0, l=0, r=0, t=40), xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), plot_bgcolor='rgba(240,240,240,0.9)')) fig.write_html('plotly_network.html') fig.show()

2.3 Large-Scale Network Visualization

Large graphs with over 10,000 nodes require special approaches.

# Efficient visualization of large graphs
def visualize_large_network(G, max_nodes=5000, sample_method='degree'):
    """
    Sample and visualize large networks

    Parameters:
    - G: NetworkX graph
    - max_nodes: Maximum number of nodes to display
    - sample_method: 'degree', 'random', 'pagerank'
    """
    if len(G.nodes()) > max_nodes:
        print(f"Sampling nodes from {len(G.nodes())} to {max_nodes}")

        if sample_method == 'degree':
            # Prioritize high-degree nodes
            top_nodes = sorted(G.degree(), key=lambda x: x[1],
                             reverse=True)[:max_nodes]
            nodes_to_keep = [n for n, d in top_nodes]
        elif sample_method == 'pagerank':
            # Select high PageRank nodes
            pr = nx.pagerank(G)
            top_nodes = sorted(pr.items(), key=lambda x: x[1],
                             reverse=True)[:max_nodes]
            nodes_to_keep = [n for n, p in top_nodes]
        else:  # random
            import random
            nodes_to_keep = random.sample(list(G.nodes()), max_nodes)

        G_sample = G.subgraph(nodes_to_keep).copy()
    else:
        G_sample = G

    # Visualize
    plt.figure(figsize=(16, 12))
    pos = nx.spring_layout(G_sample, k=1/np.sqrt(len(G_sample.nodes())),
                          iterations=20)

    degree_centrality = nx.degree_centrality(G_sample)
    node_sizes = [v * 1000 for v in degree_centrality.values()]

    nx.draw_networkx(G_sample, pos,
                     node_size=node_sizes,
                     node_color=list(degree_centrality.values()),
                     cmap='viridis',
                     with_labels=False,
                     alpha=0.7,
                     edge_color='gray',
                     width=0.5)

    plt.title(f'Sampled Network ({len(G_sample.nodes())} nodes)',
              fontsize=16, fontweight='bold')
    plt.axis('off')
    plt.tight_layout()
    plt.savefig('large_network_sampled.png', dpi=300, bbox_inches='tight')
    plt.show()

# Usage example
G_large = nx.barabasi_albert_graph(10000, 3, seed=42)
visualize_large_network(G_large, max_nodes=500, sample_method='pagerank')

3. Fast Analysis with igraph

3.1 igraph vs NetworkX

igraph is implemented in C and excels at high-speed processing of large graphs.

Feature NetworkX igraph
Implementation Language Python C (with Python bindings)
Speed Moderate Fast (10-100x faster)
Memory Efficiency Standard Efficient
Learning Curve Gentle Somewhat steep
Ecosystem Rich (matplotlib, etc.) Custom visualization
Applicability Small to medium scale (~10K nodes) Large scale (100K+ nodes)

3.2 High-Speed Algorithm Implementation

import igraph as ig
import time

# Convert NetworkX graph to igraph
def nx_to_igraph(G_nx):
    """Convert NetworkX graph to igraph"""
    G_ig = ig.Graph()
    G_ig.add_vertices(list(G_nx.nodes()))
    G_ig.add_edges(list(G_nx.edges()))
    return G_ig

# Performance comparison
G_nx = nx.barabasi_albert_graph(5000, 3, seed=42)
G_ig = nx_to_igraph(G_nx)

# NetworkX: PageRank
start = time.time()
pr_nx = nx.pagerank(G_nx)
time_nx = time.time() - start

# igraph: PageRank
start = time.time()
pr_ig = G_ig.pagerank()
time_ig = time.time() - start

print(f"NetworkX PageRank: {time_nx:.4f} seconds")
print(f"igraph PageRank: {time_ig:.4f} seconds")
print(f"Speedup: {time_nx/time_ig:.2f}x")

# Community detection with igraph
start = time.time()
communities = G_ig.community_multilevel()
time_community = time.time() - start

print(f"\nigraph community detection: {time_community:.4f} seconds")
print(f"Communities detected: {len(communities)}")
print(f"Modularity: {communities.modularity:.4f}")

3.3 Large Graph Processing

# Efficient processing of large graphs using igraph
def analyze_large_graph_igraph(n_nodes=100000, m_edges=3):
    """Efficient analysis of large graphs"""
    print(f"Generating graph: {n_nodes} nodes...")
    G = ig.Graph.Barabasi(n_nodes, m_edges)

    print("Calculating centrality metrics...")
    start = time.time()

    # Calculate various centralities
    degree = G.degree()
    betweenness = G.betweenness()
    closeness = G.closeness()
    pagerank = G.pagerank()

    calc_time = time.time() - start
    print(f"Calculation time: {calc_time:.2f} seconds")

    # Community detection
    print("Detecting communities...")
    start = time.time()
    communities = G.community_multilevel()
    comm_time = time.time() - start
    print(f"Detection time: {comm_time:.2f} seconds")
    print(f"Number of communities: {len(communities)}")

    # Visualization (sampling)
    print("Sampling for visualization...")
    # Select top 500 nodes
    top_nodes = sorted(range(len(pagerank)),
                      key=lambda i: pagerank[i], reverse=True)[:500]
    G_sample = G.subgraph(top_nodes)

    # igraph visualization
    visual_style = {
        "vertex_size": [pagerank[i] * 1000 for i in top_nodes],
        "vertex_color": [communities.membership[i] for i in top_nodes],
        "vertex_label": None,
        "edge_width": 0.5,
        "edge_color": "#cccccc",
        "layout": G_sample.layout_fruchterman_reingold()
    }

    ig.plot(G_sample,
            "large_graph_igraph.png",
            bbox=(1200, 1200),
            **visual_style)

    print("Visualization complete: large_graph_igraph.png")

    return {
        'nodes': n_nodes,
        'edges': G.ecount(),
        'calc_time': calc_time,
        'comm_time': comm_time,
        'communities': len(communities),
        'modularity': communities.modularity
    }

# Execute
results = analyze_large_graph_igraph(n_nodes=100000, m_edges=3)
print(f"\nResults summary: {results}")

4. Introduction to Gephi

4.1 Gephi Features

Gephi is a powerful desktop application for interactive visualization and network exploration.

Main Advantages of Gephi:

4.2 Data Export/Import

# Export from NetworkX to Gephi format
import networkx as nx

# Create sample graph and add attributes
G = nx.karate_club_graph()

# Add node attributes
degree_centrality = nx.degree_centrality(G)
betweenness_centrality = nx.betweenness_centrality(G)
communities = nx.community.greedy_modularity_communities(G)

# Add community ID to nodes
community_map = {}
for i, comm in enumerate(communities):
    for node in comm:
        community_map[node] = i

for node in G.nodes():
    G.nodes[node]['degree_centrality'] = degree_centrality[node]
    G.nodes[node]['betweenness_centrality'] = betweenness_centrality[node]
    G.nodes[node]['community'] = community_map[node]
    G.nodes[node]['label'] = f'Node_{node}'

# Add edge attributes
for u, v in G.edges():
    G[u][v]['weight'] = G.degree(u) + G.degree(v)

# Export as GEXF format (Gephi recommended format)
nx.write_gexf(G, 'network_for_gephi.gexf')
print("GEXF file created: network_for_gephi.gexf")

# Can also export as GraphML format
nx.write_graphml(G, 'network_for_gephi.graphml')
print("GraphML file created: network_for_gephi.graphml")

# CSV edge list format (simple method)
import pandas as pd

edges_data = []
for u, v, data in G.edges(data=True):
    edges_data.append({
        'Source': u,
        'Target': v,
        'Weight': data.get('weight', 1)
    })

edges_df = pd.DataFrame(edges_data)
edges_df.to_csv('edges.csv', index=False)

# Node list CSV
nodes_data = []
for node, data in G.nodes(data=True):
    nodes_data.append({
        'Id': node,
        'Label': data.get('label', str(node)),
        'Community': data.get('community', 0),
        'Degree_Centrality': data.get('degree_centrality', 0),
        'Betweenness_Centrality': data.get('betweenness_centrality', 0)
    })

nodes_df = pd.DataFrame(nodes_data)
nodes_df.to_csv('nodes.csv', index=False)

print("CSV files created: edges.csv, nodes.csv")

4.3 Visualization Best Practices

Recommended Gephi Workflow Steps
  1. Data Import: File → Open → Select GEXF/GraphML file
  2. Calculate Statistics: Run the following in Statistics panel
    • Average Degree
    • Network Diameter
    • Modularity (community detection)
    • PageRank
  3. Apply Layout: Select ForceAtlas2 in Layout panel
    • Scaling: 2.0-10.0 (depending on graph size)
    • Gravity: 1.0
    • Prevent Overlap: Check
  4. Visual Adjustments: Configure in Appearance panel
    • Node size: Ranking → Degree/PageRank
    • Node color: Partition → Modularity Class
    • Labels: Size = proportional to node size
  5. Export: Preview → Export → PNG/PDF (300+ DPI recommended)

5. Practice: Large-Scale Network Visualization

5.1 Sampling Techniques

# Implementation of various sampling techniques
class NetworkSampler:
    """Network sampling class for large networks"""

    @staticmethod
    def random_node_sampling(G, sample_size):
        """Random node sampling"""
        import random
        nodes = random.sample(list(G.nodes()),
                            min(sample_size, len(G.nodes())))
        return G.subgraph(nodes).copy()

    @staticmethod
    def random_edge_sampling(G, sample_ratio=0.1):
        """Random edge sampling"""
        import random
        n_edges = int(len(G.edges()) * sample_ratio)
        edges = random.sample(list(G.edges()), n_edges)
        H = nx.Graph()
        H.add_edges_from(edges)
        return H

    @staticmethod
    def induced_subgraph_sampling(G, sample_size):
        """Induced subgraph sampling (prioritizing important nodes)"""
        # Select important nodes using PageRank
        pr = nx.pagerank(G)
        top_nodes = sorted(pr.items(), key=lambda x: x[1],
                          reverse=True)[:sample_size]
        nodes = [n for n, _ in top_nodes]
        return G.subgraph(nodes).copy()

    @staticmethod
    def snowball_sampling(G, seed_nodes, k=2):
        """Snowball sampling (k-hop neighborhood)"""
        sampled_nodes = set(seed_nodes)
        for _ in range(k):
            new_nodes = set()
            for node in sampled_nodes:
                new_nodes.update(G.neighbors(node))
            sampled_nodes.update(new_nodes)
        return G.subgraph(sampled_nodes).copy()

    @staticmethod
    def forest_fire_sampling(G, sample_size, p=0.4):
        """Forest Fire sampling"""
        import random
        sampled_nodes = set()
        queue = [random.choice(list(G.nodes()))]

        while len(sampled_nodes) < sample_size and queue:
            current = queue.pop(0)
            if current not in sampled_nodes:
                sampled_nodes.add(current)
                neighbors = list(G.neighbors(current))
                # Add neighboring nodes with probability p
                n_select = int(len(neighbors) * p)
                queue.extend(random.sample(neighbors,
                                         min(n_select, len(neighbors))))

        return G.subgraph(sampled_nodes).copy()

# Comparison of sampling techniques
G_large = nx.barabasi_albert_graph(10000, 3, seed=42)
sample_size = 500

samplers = {
    'Random Node': NetworkSampler.random_node_sampling(G_large, sample_size),
    'Induced (PageRank)': NetworkSampler.induced_subgraph_sampling(G_large, sample_size),
    'Snowball (k=2)': NetworkSampler.snowball_sampling(
        G_large, [0, 1, 2], k=2),
    'Forest Fire': NetworkSampler.forest_fire_sampling(
        G_large, sample_size, p=0.4)
}

# Compare characteristics of each sampling technique
fig, axes = plt.subplots(2, 2, figsize=(16, 14))

for ax, (name, G_sample) in zip(axes.flat, samplers.items()):
    pos = nx.spring_layout(G_sample, k=0.5, iterations=20)
    degree_centrality = nx.degree_centrality(G_sample)
    node_sizes = [v * 500 for v in degree_centrality.values()]

    nx.draw_networkx(G_sample, pos, ax=ax,
                     node_size=node_sizes,
                     node_color=list(degree_centrality.values()),
                     cmap='viridis',
                     with_labels=False,
                     alpha=0.7,
                     edge_color='gray',
                     width=0.5)

    # Statistical information
    density = nx.density(G_sample)
    avg_degree = sum(dict(G_sample.degree()).values()) / len(G_sample.nodes())

    ax.set_title(f'{name}\nNodes: {len(G_sample.nodes())}, '
                f'Density: {density:.4f}, Avg Degree: {avg_degree:.2f}',
                fontsize=12, fontweight='bold')
    ax.axis('off')

plt.tight_layout()
plt.savefig('sampling_comparison.png', dpi=300, bbox_inches='tight')
plt.show()

5.2 Hierarchical Visualization

# Hierarchical network visualization
def hierarchical_visualization(G, threshold_degree=10):
    """
    Hierarchical visualization: Display important nodes and their surroundings progressively
    """
    # Level 1: High-degree nodes (hubs)
    high_degree_nodes = [n for n, d in G.degree() if d >= threshold_degree]

    # Level 2: Direct neighbors of hubs
    level2_nodes = set()
    for hub in high_degree_nodes:
        level2_nodes.update(G.neighbors(hub))
    level2_nodes = list(level2_nodes - set(high_degree_nodes))

    # Level 3: Other nodes (sampled)
    remaining = set(G.nodes()) - set(high_degree_nodes) - set(level2_nodes)
    import random
    level3_nodes = random.sample(list(remaining),
                                min(100, len(remaining)))

    # Hierarchical layout
    fig = plt.figure(figsize=(18, 6))

    # Level 1 visualization
    ax1 = plt.subplot(131)
    G1 = G.subgraph(high_degree_nodes).copy()
    pos1 = nx.spring_layout(G1, k=1, seed=42)
    nx.draw_networkx(G1, pos1, ax=ax1,
                     node_color='red', node_size=500,
                     with_labels=True, font_size=8)
    ax1.set_title(f'Level 1: Hub Nodes ({len(high_degree_nodes)})',
                  fontsize=14, fontweight='bold')
    ax1.axis('off')

    # Level 2 visualization
    ax2 = plt.subplot(132)
    G2 = G.subgraph(high_degree_nodes + level2_nodes).copy()
    pos2 = nx.spring_layout(G2, k=0.5, seed=42)
    node_colors = ['red' if n in high_degree_nodes else 'lightblue'
                   for n in G2.nodes()]
    node_sizes = [500 if n in high_degree_nodes else 200
                  for n in G2.nodes()]
    nx.draw_networkx(G2, pos2, ax=ax2,
                     node_color=node_colors, node_size=node_sizes,
                     with_labels=False)
    ax2.set_title(f'Level 2: +Direct Neighbors ({len(G2.nodes())})',
                  fontsize=14, fontweight='bold')
    ax2.axis('off')

    # Level 3 visualization
    ax3 = plt.subplot(133)
    all_nodes = high_degree_nodes + level2_nodes + level3_nodes
    G3 = G.subgraph(all_nodes).copy()
    pos3 = nx.spring_layout(G3, k=0.3, seed=42)
    node_colors = ['red' if n in high_degree_nodes
                   else 'lightblue' if n in level2_nodes
                   else 'lightgreen' for n in G3.nodes()]
    node_sizes = [500 if n in high_degree_nodes
                  else 200 if n in level2_nodes
                  else 100 for n in G3.nodes()]
    nx.draw_networkx(G3, pos3, ax=ax3,
                     node_color=node_colors, node_size=node_sizes,
                     with_labels=False, alpha=0.8)
    ax3.set_title(f'Level 3: +Others ({len(G3.nodes())})',
                  fontsize=14, fontweight='bold')
    ax3.axis('off')

    plt.tight_layout()
    plt.savefig('hierarchical_viz.png', dpi=300, bbox_inches='tight')
    plt.show()

# Usage example
G = nx.barabasi_albert_graph(1000, 3, seed=42)
hierarchical_visualization(G, threshold_degree=20)

5.3 Creating Interactive Dashboards

# Interactive dashboard using Plotly Dash
from dash import Dash, dcc, html, Input, Output
import plotly.graph_objects as go
import networkx as nx

# Create graph
G = nx.karate_club_graph()

# Dashboard application
app = Dash(__name__)

# Layout
app.layout = html.Div([
    html.H1("Network Visualization Dashboard",
            style={'textAlign': 'center'}),

    html.Div([
        html.Label("Layout Algorithm:"),
        dcc.Dropdown(
            id='layout-dropdown',
            options=[
                {'label': 'Spring Layout', 'value': 'spring'},
                {'label': 'Circular Layout', 'value': 'circular'},
                {'label': 'Kamada-Kawai', 'value': 'kamada_kawai'},
                {'label': 'Spectral Layout', 'value': 'spectral'}
            ],
            value='spring'
        )
    ], style={'width': '300px', 'margin': '20px'}),

    html.Div([
        html.Label("Node Color Metric:"),
        dcc.Dropdown(
            id='metric-dropdown',
            options=[
                {'label': 'Degree Centrality', 'value': 'degree'},
                {'label': 'Betweenness Centrality', 'value': 'betweenness'},
                {'label': 'Eigenvector Centrality', 'value': 'eigenvector'},
                {'label': 'PageRank', 'value': 'pagerank'}
            ],
            value='degree'
        )
    ], style={'width': '300px', 'margin': '20px'}),

    dcc.Graph(id='network-graph', style={'height': '800px'})
])

# Callback
@app.callback(
    Output('network-graph', 'figure'),
    [Input('layout-dropdown', 'value'),
     Input('metric-dropdown', 'value')]
)
def update_graph(layout_type, metric_type):
    # Calculate layout
    if layout_type == 'spring':
        pos = nx.spring_layout(G, k=0.5, seed=42)
    elif layout_type == 'circular':
        pos = nx.circular_layout(G)
    elif layout_type == 'kamada_kawai':
        pos = nx.kamada_kawai_layout(G)
    else:  # spectral
        pos = nx.spectral_layout(G)

    # Calculate metrics
    if metric_type == 'degree':
        metric = nx.degree_centrality(G)
    elif metric_type == 'betweenness':
        metric = nx.betweenness_centrality(G)
    elif metric_type == 'eigenvector':
        metric = nx.eigenvector_centrality(G)
    else:  # pagerank
        metric = nx.pagerank(G)

    # Edge trace
    edge_x, edge_y = [], []
    for edge in G.edges():
        x0, y0 = pos[edge[0]]
        x1, y1 = pos[edge[1]]
        edge_x.extend([x0, x1, None])
        edge_y.extend([y0, y1, None])

    edge_trace = go.Scatter(
        x=edge_x, y=edge_y,
        line=dict(width=0.5, color='#888'),
        hoverinfo='none',
        mode='lines'
    )

    # Node trace
    node_x = [pos[node][0] for node in G.nodes()]
    node_y = [pos[node][1] for node in G.nodes()]
    node_text = [f'Node {node}
{metric_type}: {metric[node]:.4f}' for node in G.nodes()] node_trace = go.Scatter( x=node_x, y=node_y, mode='markers+text', hoverinfo='text', text=[str(n) for n in G.nodes()], textposition="top center", hovertext=node_text, marker=dict( showscale=True, colorscale='YlOrRd', size=[metric[node] * 50 for node in G.nodes()], color=[metric[node] for node in G.nodes()], colorbar=dict( thickness=15, title=metric_type, xanchor='left', titleside='right' ), line=dict(width=2, color='white') ) ) # Create figure fig = go.Figure( data=[edge_trace, node_trace], layout=go.Layout( title=f'{layout_type.title()} Layout - {metric_type.title()}', showlegend=False, hovermode='closest', margin=dict(b=0, l=0, r=0, t=40), xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), plot_bgcolor='white' ) ) return fig # Run application # if __name__ == '__main__': # app.run_server(debug=True, port=8050) print("Dashboard code ready") print("To execute, uncomment the last 2 lines")
Visualization Tool Selection Guidelines:

Disclaimer