I have a graph of cities divided into communities with modularity for different years. Each community assignment of nodes lies in a separate dataset according to the year (e.g.community2000 for year 2000 and so on). The graph G contains nodes as follows:
{'Node': {0: 'albany', 1: 'almaty', 2: 'amsterdam'}}
and each ode has a number of edges (below some for albany):
{'Source': {0: 'albany',
1: 'albany',
2: 'albany',
3: 'albany',
4: 'albany',
5: 'albany',
6: 'albany',
7: 'albany',
8: 'albany',
9: 'albany'},
'Target': {0: 'almaty',
1: 'amsterdam',
2: 'ankara',
3: 'athens',
4: 'atlanta',
5: 'auckland',
6: 'austin',
7: 'bangalore',
8: 'bangkok',
9: 'barcelona'}}
To each node is attribute a community in G.nodes[node]['Community'] which has been done via the available community dataframe (community_df) that I had as follows:
for node in G.nodes():
city = node
community = community_df.loc[community_df['city'] == city, 'cluster'+community_filename[-4:]].values[0]
G.nodes[node]['Community'] = community
The code that I am currently using for making the plot of the network is the following:
import matplotlib.pyplot as plt
# Create a dictionary to map community labels to unique integers
community_labels = {}
next_community_label = 0
# Assign a unique integer label to each community
for node in G.nodes():
community = G.nodes[node]['Community']
if community not in community_labels:
community_labels[community] = next_community_label
next_community_label += 1
# Create a dictionary to map cluster labels to unique integers within each community
cluster_labels = {}
# Remove self-loops
G.remove_edges_from(nx.selfloop_edges(G))
# Draw the network graph
pos = nx.spring_layout(G, k=0.3) # Layout algorithm for node positioning
plt.figure(figsize=(12, 8))
for community in community_labels.values():
nodes = [node for node, attr in G.nodes(data=True) if attr['Community'] == community]
# Assign cluster labels within each community
for node in nodes:
cluster = community_df.loc[community_df['city'] == node, 'cluster' + community_filename[-4:]].values[0]
cluster_labels[node] = cluster
node_colors = [cluster_labels[node] for node in nodes]
nx.draw_networkx_nodes(G, pos, nodelist=nodes, node_size=200, node_color=node_colors, cmap='viridis')
nx.draw_networkx_edges(G, pos, edgelist=G.edges, alpha=0.1, width=0.5)
nx.draw_networkx_labels(G, pos, font_size=8, font_color='black', labels={node: node for node in nodes})
plt.axis('off')
plt.title("Network of Cities Divided into Communities and Clusters")
plt.tight_layout()
plt.show()
The result of such a code is unreadable and not divided into communities as I wished:
My desired outcome would be something like this (with city names as labels of nodes):
I'm the author of gravis, a graph visualization package for Python which can be used to plot graph objects from libraries like NetworkX, graph-tool, igraph and more.
Here's an example of creating a graph with NetworkX, detecting communities in it, assigning colors to each node according to community membership and then visualizing it. The same should be possible with your data.
import gravis as gv
import networkx as nx
g = nx.les_miserables_graph()
centrality = nx.algorithms.degree_centrality(g)
nx.set_node_attributes(g, centrality, 'size')
communities = nx.algorithms.community.greedy_modularity_communities(g)
colors = ['red', 'blue', 'green', 'orange', 'pink']
for community, color in zip(communities, colors):
for node in community:
g.nodes[node]['color'] = color
gv.d3(g, use_node_size_normalization=True, node_size_normalization_max=30,
use_edge_size_normalization=True, edge_size_data_source='weight', edge_curvature=0.3)
The output is an interactive visualization in a browser window or notebook cell, which can also be exported as static image in png or other formats: