如何在Networkx中画出漂亮的毛毛虫树?
How to draw Caterpillar Trees in Networkx beautifully?
我想用 Networkx 画毛毛虫树。有没有办法画出书脊在一条直线上,叶子清晰可见?
来自维基百科的图片是我想画的东西的一个很好的例子。
我们可以使用random_lobster
网络生成毛毛虫网络
生成函数,参数 p2
保持为零。
import itertools
import networkx as nx
import matplotlib.pyplot as plt
spine_sz = 5
G = nx.random_lobster(spine_sz, 0.65, 0, seed=7)
第二部分,按照画出spine的方式画网络
在一条直线上,叶子清晰可见需要相当多的
计算。
首先,我们必须确定生成的网络的主干是什么。
由于网络是一棵树,这并不困难。我们将使用第一个
与直径一样长的路径。
eccs = nx.eccentricity(G)
diameter = max(eccs.values())
outliers = tuple(node for node in eccs if eccs[node] == diameter)
for combo in itertools.combinations(outliers, 2):
path = nx.shortest_path(G, combo[0], combo[1])
if len(path) == diameter+1:
break
其次,我们必须估计网络所需的 space,假设
我们将在脊柱上方和下方绘制叶子,均匀分布
可能。
def node_space(nleaves):
return 1+int((nleaves-1)/2)
nb_leaves = {}
for node in path:
neighbors = set(G.neighbors(node))
nb_leaves[node] = neighbors - set(path)
max_leaves = max(len(v) for v in nb_leaves.values())
space_needed = 1 + sum(node_space(len(v)) for v in nb_leaves.values())
第三,有了这个间距,我们就可以画出书脊了,每个节点都有
脊柱,在它周围画出叶子,将它们分布在上方和下方
节点,同时还在“脊柱space”中水平分布它们
预订的。我们将使用偶数的节点号来确定它是否会出现
在脊柱上方或下方,为每个后续节点交替使用
树叶;后者通过反转 yhop
变量。
def count_leaves(nleaves, even):
leaf_cnt = int(nleaves/2)
if even:
leaf_cnt += nleaves % 2
return leaf_cnt
def leaf_spacing(nleaves, even):
leaf_cnt = count_leaves(nleaves, even)
if leaf_cnt <= 1:
return 0
return 1 / (leaf_cnt-1)
xhop = 2 / (space_needed+2)
yhop = 0.7
pos = {}
xcurr = -1 + xhop/4
for node in path:
pos[node] = (xcurr, 0)
if len(nb_leaves[node]) > 0:
leaves_cnt = len(nb_leaves[node])
extra_cnt = node_space(leaves_cnt) - 1
extra_space = xhop * extra_cnt / 2
xcurr += extra_space
pos[node] = (xcurr, 0)
l0hop = 2 * extra_space * leaf_spacing(leaves_cnt, True)
l1hop = 2 * extra_space * leaf_spacing(leaves_cnt, False)
l0curr = xcurr - extra_space
l1curr = xcurr - extra_space
if l1hop == 0:
l1curr = xcurr
for j,leaf in enumerate(nb_leaves[node]):
if j % 2 == 0:
pos[leaf] = (l0curr, yhop)
l0curr += l0hop
else:
pos[leaf] = (l1curr, -yhop)
l1curr += l1hop
yhop = -yhop
xcurr += xhop * extra_cnt / 2
prev_leaves = len(nb_leaves[node])
xcurr += xhop
最后一部分是图表的实际绘制,有一些选项
设置颜色和尺寸。
options = {
"font_size": 9,
"node_size": 300,
"node_color": "lime",
"edgecolors": "black",
"linewidths": 1,
"width": 1,
}
nx.draw_networkx(G, pos, **options)
ax = plt.gca()
ax.margins(0.10)
plt.axis("off")
plt.show()
结果图如下所示:
我想用 Networkx 画毛毛虫树。有没有办法画出书脊在一条直线上,叶子清晰可见?
来自维基百科的图片是我想画的东西的一个很好的例子。
我们可以使用random_lobster
网络生成毛毛虫网络
生成函数,参数 p2
保持为零。
import itertools
import networkx as nx
import matplotlib.pyplot as plt
spine_sz = 5
G = nx.random_lobster(spine_sz, 0.65, 0, seed=7)
第二部分,按照画出spine的方式画网络 在一条直线上,叶子清晰可见需要相当多的 计算。
首先,我们必须确定生成的网络的主干是什么。 由于网络是一棵树,这并不困难。我们将使用第一个 与直径一样长的路径。
eccs = nx.eccentricity(G)
diameter = max(eccs.values())
outliers = tuple(node for node in eccs if eccs[node] == diameter)
for combo in itertools.combinations(outliers, 2):
path = nx.shortest_path(G, combo[0], combo[1])
if len(path) == diameter+1:
break
其次,我们必须估计网络所需的 space,假设 我们将在脊柱上方和下方绘制叶子,均匀分布 可能。
def node_space(nleaves):
return 1+int((nleaves-1)/2)
nb_leaves = {}
for node in path:
neighbors = set(G.neighbors(node))
nb_leaves[node] = neighbors - set(path)
max_leaves = max(len(v) for v in nb_leaves.values())
space_needed = 1 + sum(node_space(len(v)) for v in nb_leaves.values())
第三,有了这个间距,我们就可以画出书脊了,每个节点都有
脊柱,在它周围画出叶子,将它们分布在上方和下方
节点,同时还在“脊柱space”中水平分布它们
预订的。我们将使用偶数的节点号来确定它是否会出现
在脊柱上方或下方,为每个后续节点交替使用
树叶;后者通过反转 yhop
变量。
def count_leaves(nleaves, even):
leaf_cnt = int(nleaves/2)
if even:
leaf_cnt += nleaves % 2
return leaf_cnt
def leaf_spacing(nleaves, even):
leaf_cnt = count_leaves(nleaves, even)
if leaf_cnt <= 1:
return 0
return 1 / (leaf_cnt-1)
xhop = 2 / (space_needed+2)
yhop = 0.7
pos = {}
xcurr = -1 + xhop/4
for node in path:
pos[node] = (xcurr, 0)
if len(nb_leaves[node]) > 0:
leaves_cnt = len(nb_leaves[node])
extra_cnt = node_space(leaves_cnt) - 1
extra_space = xhop * extra_cnt / 2
xcurr += extra_space
pos[node] = (xcurr, 0)
l0hop = 2 * extra_space * leaf_spacing(leaves_cnt, True)
l1hop = 2 * extra_space * leaf_spacing(leaves_cnt, False)
l0curr = xcurr - extra_space
l1curr = xcurr - extra_space
if l1hop == 0:
l1curr = xcurr
for j,leaf in enumerate(nb_leaves[node]):
if j % 2 == 0:
pos[leaf] = (l0curr, yhop)
l0curr += l0hop
else:
pos[leaf] = (l1curr, -yhop)
l1curr += l1hop
yhop = -yhop
xcurr += xhop * extra_cnt / 2
prev_leaves = len(nb_leaves[node])
xcurr += xhop
最后一部分是图表的实际绘制,有一些选项 设置颜色和尺寸。
options = {
"font_size": 9,
"node_size": 300,
"node_color": "lime",
"edgecolors": "black",
"linewidths": 1,
"width": 1,
}
nx.draw_networkx(G, pos, **options)
ax = plt.gca()
ax.margins(0.10)
plt.axis("off")
plt.show()
结果图如下所示: