Tutorial 4: Visualizing Evolving Communities ============================================ This tutorial demonstrates how to create effective visualizations for understanding and analyzing evolving communities in temporal networks. Prerequisites ------------- .. code-block:: python # Install the package if you haven't already # pip install 'dyn-benchmark[all]' # Import required modules from dyn.benchmark.generator.groundtruth_generator import GroundtruthGenerator from dyn.core.communities import Membership from dyn.drawing.sankey_drawing import plot_sankey 1. Visualizing Community Flow with Sankey Diagrams -------------------------------------------------- First, let's create a benchmark to visualize: .. code-block:: python # Create a generator with parameters to create interesting community evolution generator = GroundtruthGenerator(seed=42) groundtruth = generator.generate() # Extract membership information membership = Membership.from_tcommlist(groundtruth.tcommlist) Sankey diagrams are ideal for visualizing how communities evolve over time: .. code-block:: python # Create a Sankey diagram of community evolution plot_sankey(membership.community_graph) Let's understand the key components of this visualization: .. code-block:: python # Extract and print information about the community flow for t in sorted(community_flow_graph.snapshots): communities_at_t = list(community_flow_graph.snapshot_nodes(t)) print(f"Snapshot {t}: {len(communities_at_t)} communities") for community in communities_at_t: # Get predecessors (sources of incoming members) predecessors = list(community_flow_graph.predecessors(community)) # Get successors (destinations of outgoing members) successors = list(community_flow_graph.successors(community)) # Get size of the community size = community_flow_graph.node_size(community) print(f" Community {community}: Size={size}, Predecessors={len(predecessors)}, Successors={len(successors)}") Complete Example ~~~~~~~~~~~~~~~~ .. code-block:: python # Install the package if you haven't already # pip install 'dyn-benchmark[all]' # Import required modules from dyn.benchmark.generator.groundtruth_generator import GroundtruthGenerator from dyn.core.communities import Membership from dyn.drawing.sankey_drawing import plot_sankey # Create a generator with parameters to create interesting community evolution generator = GroundtruthGenerator(seed=42) groundtruth = generator.generate() # Extract membership information membership = Membership.from_tcommlist(groundtruth.tcommlist) # Create a Sankey diagram of community evolution plot_sankey(membership.community_graph) # Extract and print information about the community flow for t in sorted(community_flow_graph.snapshots): communities_at_t = list(community_flow_graph.snapshot_nodes(t)) print(f"Snapshot {t}: {len(communities_at_t)} communities") for community in communities_at_t: # Get predecessors (sources of incoming members) predecessors = list(community_flow_graph.predecessors(community)) # Get successors (destinations of outgoing members) successors = list(community_flow_graph.successors(community)) # Get size of the community size = community_flow_graph.node_size(community) print(f" Community {community}: Size={size}, Predecessors={len(predecessors)}, Successors={len(successors)}") 2. Visualizing Network Snapshots with Communities ------------------------------------------------- Let's visualize the network structure at each snapshot, with nodes colored by community: .. code-block:: python # Import required modules from dyn.benchmark.generator.groundtruth_generator import GroundtruthGenerator from dyn.core.communities import Membership from dyn.drawing.sankey_drawing import plot_sankey import networkx as nx import matplotlib.pyplot as plt import numpy as np import os def plot_network_with_communities(graph, snapshot, membership, figsize=(10, 8)): """Plot a network with nodes colored by community""" plt.figure(figsize=figsize) # Get community assignments for this snapshot communities = {} for row in membership.tcommlist: if row.snapshot == snapshot: communities[row.node_id] = row.evolving_community_id # Create a color map for communities unique_communities = set(communities.values()) colors = plt.cm.tab20(np.linspace(0, 1, len(unique_communities))) color_map = {com: colors[i % len(colors)] for i, com in enumerate(unique_communities)} # Assign colors to nodes node_colors = [color_map.get(communities.get(node, -1), 'gray') for node in graph.nodes] # Compute layout (with seed for reproducibility) pos = nx.spring_layout(graph, seed=42) # Draw the network nx.draw_networkx( graph, pos=pos, node_color=node_colors, node_size=80, with_labels=False, width=0.5, alpha=0.8 ) # Add a legend for communities handles = [plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=color, markersize=10, label=f'Community {com}') for com, color in color_map.items()] plt.legend(handles=handles, loc='upper right', bbox_to_anchor=(1.15, 1)) plt.title(f"Network Communities at Snapshot {snapshot}", fontsize=14) plt.axis('off') plt.tight_layout() return plt.gcf() # Plot each snapshot snapshots = sorted(groundtruth.graphs.keys()) for snapshot in snapshots: graph = groundtruth.graphs[snapshot] fig = plot_network_with_communities(graph, snapshot, membership) plt.savefig(f"network_snapshot_{snapshot}.png", dpi=300, bbox_inches='tight') plt.show()