在 networkx 中将节点组合在一起 [英] Group nodes together in networkx
问题描述
我有一个涉及图形的可视化问题.我有 N
个节点,它们属于一些 M
网络.节点可以具有网络间边缘(在同一网络内)和网络内边缘(从一个网络中的节点到另一个网络的边缘).
I have a visualization problem involving a graph. I have N
nodes, which belong to say some M
networks. The nodes can have inter-network edges (within the same network) and intra-network edges (edges from a node in one network to another one).
当我在 networkx
中可视化图形时,我正在寻找一种将网络放置/聚集在一起的方法,以便我可以轻松确定网络间/网络内的连接.所以理想情况下,所有蓝色节点都将作为网络聚集在一起(没有特定的顺序).同样对于橙色或绿色的.
When I visualize the graph in networkx
I am looking for a way to place/cluster the networks together so that I can easily make out the inter/intra network connections. So ideally all the blue nodes would be clustered together as network (in no particular order). Similarly for the orange or green ones.
顺便说一下,我不是在寻找集线器/集群,我知道哪些节点在哪些网络中,我只是想找到一种更简洁的可视化方法.有什么简单的方法可以做到这一点吗?类似于高级弹簧布局的东西,我可以指定一些节点应该一起显示,而不管边缘权重/弹簧力如何?
By the way I am not trying to find hubs/clusters, I know which nodes are in which networks, I just am trying to find a way to visualize it neater. Is there some easy way to do this? Something like an advanced spring layout where I can specify some nodes should show up together regardless of the edge weights / spring force?
import string, random
import networkx as nx
import matplotlib.pyplot as plt
from scipy.sparse import random as sparse_random
# Random string generator
def rand_string(size=6, chars=string.ascii_uppercase):
return ''.join(random.choice(chars) for _ in range(size))
# Set up a nodes and networks randomly
nodes = [rand_string() for _ in range(30)]
networks = [rand_string() for _ in range(5)]
networks_list = networks*6
random.shuffle(networks_list)
# Define what nodes belong to what network and what their color should be
node_network_map = dict(zip(nodes, networks_list))
colors = ['green', 'royalblue', 'red', 'orange', 'cyan']
color_map = dict(zip(networks, colors))
graph = nx.Graph()
graph.add_nodes_from(nodes)
nodes_by_color = {val: [node for node in graph if color_map[node_network_map[node]] == val]
for val in colors}
# Take random sparse matrix as adjacency matrix
mat = sparse_random(30, 30, density=0.3).todense()
for row, row_val in enumerate(nodes):
for col, col_val in enumerate(nodes):
if col > row and mat[row, col] != 0.0: # Stick to upper half triangle, mat is not symmetric
graph.add_edge(row_val, col_val, weight=mat[row, col])
# Choose a layout to visualize graph
pos = nx.spring_layout(graph)
edges = graph.edges()
# Get the edge weights and normalize them
weights = [abs(graph[u][v]['weight']) for u, v in edges]
weights_n = [5*float(i)/max(weights) for i in weights] # Change 5 to control thickness
# First draw the nodes
plt.figure()
for color, node_names in nodes_by_color.items():
nx.draw_networkx_nodes(graph, pos=pos, nodelist=node_names, node_color=color)
# Then draw edges with thickness defined by weights_n
nx.draw_networkx_edges(graph, pos=pos, width=weights_n)
nx.draw_networkx_labels(graph, pos=pos)
plt.show()
推荐答案
为了获得更好的节点布局,我从使用圆形布局开始(替换您的弹簧布局).然后我将每组节点沿着一个更大的圆的周长移动到它们的新位置.
To get better nodes layout, I start with using circular layout (replacing your spring-layout). Then I move each group of the nodes to their new locations along perimeter of a bigger circle.
# --- Begin_myhack ---
# All this code should replace original `pos=nx.spring_layout(graph)`
import numpy as np
pos = nx.circular_layout(graph) # replaces your original pos=...
# prep center points (along circle perimeter) for the clusters
angs = np.linspace(0, 2*np.pi, 1+len(colors))
repos = []
rad = 3.5 # radius of circle
for ea in angs:
if ea > 0:
#print(rad*np.cos(ea), rad*np.sin(ea)) # location of each cluster
repos.append(np.array([rad*np.cos(ea), rad*np.sin(ea)]))
for ea in pos.keys():
#color = 'black'
posx = 0
if ea in nodes_by_color['green']:
#color = 'green'
posx = 0
elif ea in nodes_by_color['royalblue']:
#color = 'royalblue'
posx = 1
elif ea in nodes_by_color['red']:
#color = 'red'
posx = 2
elif ea in nodes_by_color['orange']:
#color = 'orange'
posx = 3
elif ea in nodes_by_color['cyan']:
#color = 'cyan'
posx = 4
else:
pass
#print(ea, pos[ea], pos[ea]+repos[posx], color, posx)
pos[ea] += repos[posx]
# --- End_myhack ---
输出图将类似于:
编辑
通常,没有一种特定的布局在所有情况下都是最好的.所以,我提供了第二种解决方案,它使用同心圆来分隔各个节点组.以下是相关代码及其示例输出.
Usually, no particular layout is best in all situations. So, I offer the second solution which uses concentric circles to separate individual groups of the nodes. Here are the relevant code and its sample output.
# --- Begin_my_hack ---
# All this code should replace original `pos=nx.spring_layout(graph)`
import numpy as np
pos = nx.circular_layout(graph)
radii = [7,15,30,45,60] # for concentric circles
for ea in pos.keys():
new_r = 1
if ea in nodes_by_color['green']:
new_r = radii[0]
elif ea in nodes_by_color['royalblue']:
new_r = radii[1]
elif ea in nodes_by_color['red']:
new_r = radii[2]
elif ea in nodes_by_color['orange']:
new_r = radii[3]
elif ea in nodes_by_color['cyan']:
new_r = radii[4]
else:
pass
pos[ea] *= new_r # reposition nodes as concentric circles
# --- End_my_hack ---
这篇关于在 networkx 中将节点组合在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!