问题描述
我想画一个分层的图 如果您可以看下面的图,可以按以下方式订购它
95 85
21 31
42 52 62 22 32
13
14
如果需要,我可以提供提示,提示哪个节点位于哪一层。
过去,我也有类似的需求,但是在这种情况下不起作用: NetworkX: draw graph in layers
我尝试了所有标准布局和所有graph_viz布局:“。dot”,“ twopi”,“ fdp”,“ sfdp”,“ circo”
“分层”是指每组节点都在同一层上(垂直坐标:Y)
就像我已经在上面订购了它们...
这是我的第一个裂缝...现在我必须根据边缘更清楚地进行x轴处理。谢谢mathfux
def layered_layout(nodes,base):
nodes = np.array(nodes)
ncols = np.unique( nodes % base,return_counts=True)[1].max()
nlayers = np.unique(nodes % base).size
ys = np.linspace(0,1,nlayers)
xs = np.linspace(0,ncols)
pos = {}
for j,b in enumerate(np.unique(nodes % base)):
ixs = np.where(nodes % base == b)[0]
for i,x in enumerate(ixs) :
node = nodes[x]
pos[node] = (xs[i],ys[j])
return pos
解决方法
如果找不到任何默认布局,则可以定义自定义布局。分层方式似乎并不复杂。
def layered_layout(layers,stretch=0,alignment='c'):
sizes = np.array([len(n) for n in layers])
lfill = [np.linspace(0,1,n) for n in sizes]
scales = (sizes - 1)/(max(sizes) - 1)
if alignment == 'l':
x_coord_levels = [(x - x[0]) * (s + (1 - s) * stretch) for x,s in zip(lfill,scales)]
elif alignment == 'r':
x_coord_levels = [(x - x[-1]) * (s + (1 - s) * stretch) for x,scales)]
elif alignment == 'c':
x_coord_levels = [(x - (x[0]+x[-1])/2) * (s + (1 - s) * stretch) for x,scales)]
else:
raise AttributeError('invalid alignment attribute')
y_coord_levels = [np.repeat(-y,times) for y,times in zip(np.arange(len(sizes)),sizes)]
pos_levels = [dict(zip(l,zip(*p))) for l,p in zip(layers,zip(x_coord_levels,y_coord_levels))]
pos = {k: v for d in pos_levels for k,v in d.items()}
return pos
创建图形后:
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
G = nx.DiGraph()
G.add_edges_from([(21,42),(52,13),(42,(95,21),(31,52),62),31),(62,(32,95),(13,22),(85,(22,14),(14,32)])
nx.set_edge_attributes(G,{(21,42): 0.20,13): 0.52,13): 0.49,21): 0.15,52): 0.52,62): 0.42,31): 0.47,13): 0.42,95): 0.42,22): 0.71,31): -0.00,14): 0.74,32): 0.74},'w')
layered_layout
应该用于定义pos
参数的值:
layers = [[95,85],[21,31,42],[52,62,22,32],[13],[14]]
pos = layered_layout(layers,stretch=...,alignment=...)
用法示例:
layers = [[95,[14]]
fig = plt.figure(figsize=(20,10))
for i in range(3):
for j in range(3):
ax = fig.add_subplot(3,3,1+3*j+i)
ax.set_title(f'stretch = {[0,0.5,1][j]},alignment={"lcr"[i]}')
pos = layered_layout(layers,stretch = [0,1][j],alignment='lcr'[i])
nx.draw_networkx(G,pos,with_labels=True,font_size=7,node_size=100)
nx.draw_networkx_edge_labels(G,edge_labels = nx.get_edge_attributes(G,'w'),font_size=7)
plt.axis('on'); plt.tick_params(left=True,bottom=True,labelleft=True,labelbottom=True)
plt.show()