如何在粗线条上获得非圆形箭头?

2022-03-31 00:00:00 python networkx

问题描述

我正在使用networkx在Python语言中绘制有向图。我使用不同宽度的边缘来突出显示权重。不幸的是,箭头是圆形的,看起来很奇怪。我想为看起来像细线箭头的缩放版本的粗线绘制非圆形箭头。

import networkx as nx
import matplotlib.pyplot as plt
import numpy

G=nx.DiGraph()
stake = [
    [0, 1, 1, 3],
    [3, 0, 0, 1],
    [0, 0, 0, 1],
    [1, 0, 3, 0]
    ]
maxS = max(max(stake))
stake1d = numpy.concatenate(stake)
minS = min(stake1d[numpy.nonzero(stake1d)])
minLineWeight = 1
maxLineWeight = 10

for x in range(len(stake)):
    for y in range(x):
        if(stake[x][y] > 0):
            weight = (stake[x][y] - minS) / (maxS - minS) * (maxLineWeight - minLineWeight) + minLineWeight
            G.add_edge(x, y, weight=weight, color='r')

for x in range(len(stake)):
    for y in [i for i in range(len(stake))][-(len(stake)-x):]:
        if(stake[x][y] > 0):
            weight = (stake[x][y] - minS) / (maxS - minS) * (maxLineWeight - minLineWeight) + minLineWeight
            G.add_edge(x, y, weight=weight, color='b')

weights=list(nx.get_edge_attributes(G,'weight').values())
colors=list(nx.get_edge_attributes(G,'color').values())
pos = nx.shell_layout(G)
nx.draw(
    G,
    pos=pos,
    width=weights,
    edge_color=colors,
    with_labels=True,
    arrows=True,
    connectionstyle='arc3',
    arrowstyle='->'
)  
plt.show()

解决方案

我也遇到了同样的问题,我想出了一个解决办法:

  1. 用两个单独的方法调用替换nx.draw调用,这两个方法调用分别绘制节点和边。这很有用,因为networkx边绘制方法draw_networkx_edges返回matplotlib补丁(特别是FancyArrowPatch对象)的列表,然后您可以在渲染之前对其进行操作。

  2. 循环箭头补丁并更改组成每个箭头的线段的FancyArrowPatch mutation_scale和joinstylecapstyle

解决方法

从您的示例代码开始,用以下代码替换对nx.draw的调用。

# First, draw the nodes themselves
nodes = nx.draw_networkx_nodes(
    G,
    pos=pos,
    linewidths=1
)

# Draw node labels
node_label_handles = nx.draw_networkx_labels(
    G, 
    pos=pos
);

# Draw the edges and store the returned FancyArrowPatch list
arrows = nx.draw_networkx_edges(
    G,
    pos=pos,
    arrows=True,
    width=weights,
    edge_color=colors,
    arrowstyle='-|>'  # I personally think this style scales better
)

for a, w in zip(arrows, weights):
    
    # mutation_scale affects only the arrowhead size, not the arrow tail.
    # The constants here are arbitrary; you may want/need to change them
    a.set_mutation_scale(20 + w)
    
    # Sharpen arrowheads by creating a mitered joint between arrowhead 
    # line segments, instead of the default joinstyle='round'
    a.set_joinstyle('miter')
    
    # Prevent each arrow tail from jutting forward and through the arrowhead,
    # which happens with the default capstyle='projecting'
    a.set_capstyle('butt')

我的结果

版本

pandas =1.3.2,Numpy=1.21.2,matplotlib=3.4.3

相关文章