在Networkx图形中跟随其边缘的图形标签

时间:2020-03-12 16:09:59

标签: python matplotlib networkx

使用Networkx时,我需要以不同的方式显示多个边缘。 为此,我使用connectionstyle,一些边缘为直线,另一些为Arc3。 问题在于每个边缘都有一个标签,并且标签不遵循这些样式中的边缘。

我借了一个图作为示例:

#!/usr/bin/env python3

import networkx as nx
import matplotlib.pyplot as plt

# Graph data
names = ['A', 'B', 'C', 'D', 'E']
positions = [(0, 0), (0, 1), (1, 0), (0.5, 0.5), (1, 1)]
edges = [('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('D', 'A')]

# Matplotlib figure
plt.figure('My graph problem')

# Create graph
G = nx.MultiDiGraph(format='png', directed=True)

for index, name in enumerate(names):
    G.add_node(name, pos=positions[index])

labels = {}
for edge in edges:
    G.add_edge(edge[0], edge[1])
    labels[(edge[0], edge[1])] = '{} -> {}'.format(edge[0], edge[1])

layout = dict((n, G.node[n]["pos"]) for n in G.nodes())
nx.draw(G, pos=layout, with_labels=True, node_size=300, connectionstyle='Arc3, rad=0.3')

nx.draw_networkx_edge_labels(G, layout, edge_labels=labels, connectionstyle='Arc3, rad=0.3')
# Here is the problem : the labels will not follow the edges

plt.show()

这可能导致出现如下所示的问题 this example image:我们不确定标签的边缘是什么。

有没有办法画沿其边缘的标签?

谢谢

1 个答案:

答案 0 :(得分:1)

是的,可以使用 GraphViz 绘制 networkx 有向图的标记边。使用 Python 包 graphviz、Python 包 networkxGraphViz 程序 dot 的示例:

"""How to draw a NetworkX graph using GraphViz.

Requires:
- The Python package `graphviz`: https://github.com/xflr6/graphviz
  `pip install graphviz`
- The Python package `networkx`: https://github.com/xflr6/graphviz
  `pip install networkx`
- The GraphViz program `dot` in the environment's path
  https://graphviz.org/download/
  https://en.wikipedia.org/wiki/PATH_(variable)
"""
import graphviz as gv
import networkx as nx


def dump_example_directed_graph():
    """Use GraphViz `dot` to layout a directed multigraph.

    Creates a file named 'example_directed_graph' that contains
    the rendered graph.
    """
    g = example_directed_graph()
    h = networkx_to_graphviz(g)
    filename = 'example_directed_graph'
    fileformat = 'pdf'
    h.render(filename, format=fileformat, cleanup=True)
        # The argument `view=True` can be given to
        # the method `graphviz.dot.Digraph.render`
        # to open the rendered file with the
        # default viewer of the operating system


def dump_example_undirected_graph():
    """Use GraphViz `dot` to layout an undirected multigraph.

    Creates a file named `example_undirected_graph` that contains
    the rendered graph.
    """
    g = example_undirected_graph()
    h = networkx_to_graphviz(g)
    filename = 'example_undirected_graph'
    fileformat = 'pdf'
    h.render(filename, format=fileformat, cleanup=True)


def example_directed_graph():
    """Return a sample directed graph as `networkx.MultiDiGraph`."""
    g = nx.MultiDiGraph()
    g.add_node(1, label='A')
    g.add_node(2, label='B')
    g.add_edge(1, 2, label='AB-1')
    g.add_edge(1, 2, label='AB-2')
    g.add_edge(2, 1, label='BA')
    return g


def example_undirected_graph():
    """Return a sample undirected graph as `networkx.MultiGraph`."""
    g = nx.MultiGraph()
    g.add_node(1, label='A')
    g.add_node(2, label='B')
    g.add_edge(1, 2, label='AB-1')
    g.add_edge(1, 2, label='AB-2')
    return g


def networkx_to_graphviz(g):
    """Convert `networkx` graph `g` to `graphviz.Digraph`.

    @type g: `networkx.Graph` or `networkx.DiGraph`
    @rtype: `graphviz.Digraph`
    """
    if g.is_directed():
        h = gv.Digraph()
    else:
        h = gv.Graph()
    for u, d in g.nodes(data=True):
        h.node(str(u), label=d['label'])
    for u, v, d in g.edges(data=True):
        h.edge(str(u), str(v), label=d['label'])
    return h


if __name__ == '__main__':
    dump_example_directed_graph()
    dump_example_undirected_graph()

文档:

以上代码使用 networkx == 2.5.1graphviz == 0.16 和 GraphViz 版本 2.40.1。

使用 matplotlib 的当前可能性

目前看来 networkx 支持:

所以从 networkx <= 2.5.1 开始,标记的曲线边缘不能用 matplotlib 绘制。因此,对于具有连接相同节点的一对标记边(例如,边 1 -> 2 和边 2 -> 1)的有向图,边将绘制在 matplotlib重叠,因此并非所有边缘标签都可见。