首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Python中的networkx和matplotlib绘制bbox的不同形状和外观的节点?

如何使用Python中的networkx和matplotlib绘制bbox的不同形状和外观的节点?
EN

Stack Overflow用户
提问于 2022-03-17 23:10:23
回答 3查看 958关注 0票数 1

我想用networkx绘制一个简单的图表。每个节点中都有两个带有Python和编程标签的节点。代码和图形如下:

代码语言:javascript
复制
import networkx as nx

G = nx.DiGraph()
G.add_node(0)
G.add_node(1)
G.add_edge(0,1)

nx.draw_networkx(G,
                pos = {0:(0, 0), 1: (1, 0)},
                node_size = [1000, 2000],
                node_color = ["red","green"],
                node_shape = "s",
                )

我可以在两个节点中分别得到两个不同的颜色--红色和绿色,以及在每个节点中设置不同的标签。但是,我也想得到两个不同形状的节点。我希望有第一个节点,因为它是,第二节点的钻石形状,可以获得使用dnode_shape。我尝试以["s","d"]的形式传递列表,并在node_shape中以{0:"s", 1:"d"}的形式传递字典。

但是,两者都返回一个错误。我怎么能在这里得到不同形状的节点?是否可以使用其他库,如graphviz,如何使用?

在另一个步骤中,我希望将标签封装在节点中。因此,我将node_size设置为0,并使用bbox,如下所示。

代码语言:javascript
复制
nx.draw_networkx(G,
                pos = {0:(0, 0), 1: (1, 0)},
                node_size = 0,
                 arrows = True,
                 labels = {0:"Python",1:"Programming"},
                 bbox = dict(facecolor = "skyblue")
                )

我可以将标签封装在bbox中,但是箭头并不隐藏,两个节点中bbox的外观颜色是相同的。在这种情况下,我怎样才能使面部颜色不同呢?解决这个问题的另一种方法是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-04-21 21:12:59

我想出了一个用graphviz包来做这件事的方法。NetworkX包的限制是它不允许节点具有不同的形状,尽管大小或颜色可以以列表的形式不同设置。此外,如果使用边界框(bbox),则其属性在节点之间是一致的。

然而,graphviz在这种情况下提供了更多的灵活性。每个节点的形状、大小和颜色可以单独调整。我是这样做的:

代码语言:javascript
复制
import graphviz

G = graphviz.Digraph()

G.node("Python", style = 'filled', color = "red", shape = "box")
G.node("Programming", style = "filled", color = "green", shape = "ellipse")

G.edge("Python","Programming")

G.view()

因此,我得到了如下情节:

还可以进一步定制图形,如节点位置、边缘颜色等。

票数 1
EN

Stack Overflow用户

发布于 2022-03-18 15:08:56

Networkx不支持一个函数调用中的多个节点形状,因为节点是使用matplotlib的scatter绘制的,后者不支持在同一个函数调用中绘制不同的标记。但是,您可以对nx.draw_networkx_nodes进行多次调用,每个调用都具有不同的节点和形状子集。

将标签封装在节点中是一项棘手的工作。文本框尺寸不能在matplotlib中预先计算,因为它支持多个呈现体。因此,您必须绘制一些虚拟文本对象,确定文本框的大小,然后向后返回到所需的大小。networkx中不包含这种功能。

如果您愿意使用其他库,那么大多数您想要的特性都可以很容易地在netgraph中实现,这是我编写和维护的一个库。支持在一个函数调用中绘制不同的节点形状。箭头应保持可见。更改节点标签背景色是相当容易的。

关于字体大小,在not中,如果没有显式设置节点标签的字体大小,它将计算出最大字体大小,以便所有文本框都适合对应的节点艺术家。正如您在下面的示例中所看到的,该计算存在一个小问题,因为当前的实现呈现一个圆形节点形状,因此第一个节点的文本框并不完全适合正方形节点。我将很快解决这个问题;同时,您必须使用更多的圆形节点形状,或者在一个单独的调用中调整字体大小,如下所示。

代码语言:javascript
复制
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph # pip install netgraph

graph_data = nx.DiGraph([(0, 1)]) # edge lists or igraph Graph objects are also supported

g = Graph(graph_data,
          node_layout = {0: (0, 0), 1: (1, 0)},
          node_size = {0 : 10, 1 : 20},
          node_color = {0 : "red", 1 : "green"},
          node_labels = {0:"Python", 1:"Programming"},
          node_label_fontdict = {'backgroundcolor' : 'lightgray'},
          node_shape = {0 : "s", 1 : "d"},
          arrows=True,
)

# Netgraph currently does not support multiple values for label backgroundcolors.
# However, all artists are exposed in simple to query dictionaries.
# As node label artists are matplotlib text objects,
# we can vary the node label background colors by using matplotlib.text.Text methods:
g.node_label_artists[0].set_backgroundcolor('salmon')
g.node_label_artists[1].set_backgroundcolor('lightgreen')

# Netgraph assumes circular node shapes when computing fontsizes.
# We hence have to manually adjust the node label fontsizes
# by the ratio of the diagonal to the width in a square.
for node, label in g.node_label_artists.items():
    fontsize = label.get_fontsize()
    label.set_fontsize(fontsize * 1./np.sqrt(2))

plt.show()
票数 3
EN

Stack Overflow用户

发布于 2022-04-22 02:05:59

我正在测试Python库,它允许更直观、更友好地绘制图形。我考虑了标记节点的正确连接、不同类型的标签、可以用鼠标拖动的元素以及其他类型的交互。在大多数这些特性中,netgraph看起来很有前途,但不幸的是,它不支持矩形节点和边缘端位置的动态偏移,这对于能够以所需的方式显示有向边缘是必不可少的。事实上,节点和边是matplotlib路径对象,标签在netgraph中是matplotlib文本对象,这意味着矩形文本标签和文本包围的正确连接变得复杂,即使覆盖它的任何一个方法。

另一方面,如果使用networkx连接节点标签,则可以在matplotlib注释中解决这些问题。在本例中,只需要对节点进行注释的networkx.Graph和自定义艺术家:

代码语言:javascript
复制
import matplotlib.pyplot as plt
import networkx as nx

G = nx.DiGraph()
G.add_edges_from([(0, 1)])
G.add_nodes_from([0, 1])
pos = {0:(0.1, 0.9), 1: (0.1, 0.1)}

fig, ax = plt.subplots()

annotations = {0: ax.annotate('Python', xy=pos[0], xycoords='data', size=20,
                ha="center", va="center", bbox=dict(facecolor = "blue")),
            1:ax.annotate('programming', xy=pos[1], xycoords='data',
                ha="center", va="center", bbox=dict(facecolor = "red"))}

for A, B in G.edges:
    ax.annotate("", xy=pos[B], xycoords='data', xytext=pos[A], textcoords='data',
                          arrowprops=dict(arrowstyle="->", color="0.5",  # shrinkA=85, shrinkB=85,
                                          patchA=annotations[A],
                                          patchB=annotations[B],
                                          connectionstyle='arc3'))

plt.axis('off')
plt.show()

另一种灵活性

此外,matplotlib还允许为节点标记提供更多别致的样式:

代码语言:javascript
复制
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnnotationBbox, TextArea, VPacker
import networkx as nx


G = nx.DiGraph()
G.add_edges_from([(0,1), (1,2), (0, 2)])
G.add_nodes_from([0, 1, 2])
pos = {0:(0.1, 0.9), 1: (0.1, 0.1), 2: (0.9, 0.5)}

fig, ax = plt.subplots()

textobjs = [TextArea('IS', textprops=dict(color="blue", size=18, ha='left',va='baseline')),
            TextArea('FUN!', textprops=dict(color="red", size=18, ha='left',va='baseline'))]
ybox = VPacker(children=textobjs, pad=0, sep=0)
anbox = AnnotationBbox(ybox, pos[2], frameon=True, box_alignment=(0,.5),
                       bboxprops=dict(facecolor='yellow', boxstyle='round'))

annotations = {0: ax.annotate('Python', xy=pos[0], xycoords='data',
                ha="center", va="center", bbox=dict(facecolor = "blue")),
            1:ax.annotate('programming', xy=pos[1], xycoords='data',
                ha="center", va="center", bbox=dict(facecolor = "red")),
            2:ax.add_artist(anbox)}

annotations[2].draggable()

for A, B in G.edges:
    ax.annotate("", xy=pos[B], xycoords='data', xytext=pos[A], textcoords='data',
                          arrowprops=dict(arrowstyle="->", color="0.5",  # shrinkA=85, shrinkB=85,
                                          patchA=annotations[A],
                                          patchB=annotations[B],
                                          connectionstyle='arc3'))

plt.axis('off')
plt.show()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71520067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档