python - 标记外部节点,与networkx中的其他节点/边缘重叠最小

标签 python label nodes networkx

我正在尝试创建一个在节点外部打印节点标签的图形。我能够生成如下所示的“偏移量”来解决这个目的。但是,有时标签与边缘重叠(这是不可取的,因为节点周围有很多空白区域可以打印相应的标签)。我需要以标签不与任何边缘重叠的方式标记这些节点,或者至少尝试尽可能减少重叠。

import networkx as nx
from networkx.utils import is_list_of_ints, flatten
import matplotlib.pyplot as plt

G=nx.Graph()

G = nx.complete_graph(5)
mapping = {0:'aaaaaaa',1:'bbbbbbb',2:'ccccccc', 3:'dddddddd', 4:'eeeeeeeee'}
G = nx.relabel_nodes(G,mapping)

plt.figure(figsize=(10,10), facecolor="w", frameon=False)
pos = nx.graphviz_layout(G, prog="fdp") #calculate position (x,y) coordinates
nx.draw_networkx_nodes(G,pos,node_size=1200,node_shape='o',node_color='0.75')
nx.draw_networkx_edges(G,pos, width=2,edge_color='b')


#for labeling outside the node
offset =10
pos_labels = {}
keys = pos.keys()
for key in keys:
    x, y = pos[key]
    pos_labels[key] = (x, y+offset)
nx.draw_networkx_labels(G,pos=pos_labels,fontsize=2)
plt.show()

networkx 中是否有任何功能可以处理这种情况。我google了很久没有成功。

最佳答案

我之前曾尝试过类似的事情,主要想法是尽量避开边缘。

假设边是直线,有两种简单相似的方法可以实现:

  1. 基于一个节点的neighbourhood 的边的角度。正在相对于节点本身进行。

  2. 基于centroid社区的节点。

因此,找出从一个节点到其邻域的边缘形成的角度,并尝试将标签定位在远离大多数边缘的位置;或估计节点邻域的质心并将标签沿相反方向定位。

第一个解决方案可能有点问题,主要是因为 atan2函数运行(本质上确定边缘角度),但它确实在定位标签方面提供了一些灵 active 。

第二种方案是最简单的,工作原理如下:

import networkx as nx
import matplotlib.pyplot as plt

#Build the graph
#Please note, the code here is as per the original post
G=nx.Graph()
G = nx.complete_graph(5)
mapping = {0:'aaaaaaa',1:'bbbbbbb',2:'ccccccc', 3:'dddddddd', 4:'eeeeeeeee'}
G = nx.relabel_nodes(G,mapping)

plt.figure(figsize=(10,10), facecolor="w", frameon=False)
#Get a graph layout
pos = nx.graphviz_layout(G, prog="fdp") #calculate position (x,y) coordinates
#Here is an alternative layout, please see below.
#pos = nx.layout.spring_layout(G)
nx.draw_networkx_nodes(G,pos,node_size=1200,node_shape='^',node_color='0.75')
nx.draw_networkx_edges(G,pos, width=2,edge_color='r')
#Show the original position of the labels using a Green colour.
nx.draw_networkx_labels(G,pos,font_color='g')

#Please note, the code below uses the original idea of re-calculating a dictionary of adjusted label positions per node.
label_ratio = 1.0/8.0
pos_labels = {} 
#For each node in the Graph
for aNode in G.nodes():
    #Get the node's position from the layout
    x,y = pos[aNode]
    #Get the node's neighbourhood
    N = G[aNode]
    #Find the centroid of the neighbourhood. The centroid is the average of the Neighbourhood's node's x and y coordinates respectively.
    #Please note: This could be optimised further
    cx = sum(map(lambda x:pos[x][0], N)) / len(pos)
    cy = sum(map(lambda x:pos[x][1], N)) / len(pos)
    #Get the centroid's 'direction' or 'slope'. That is, the direction TOWARDS the centroid FROM aNode.
    slopeY = (y-cy)
    slopeX = (x-cx)
    #Position the label at some distance along this line. Here, the label is positioned at about 1/8th of the distance.
    pos_labels[aNode] = (x+slopeX*label_ratio, y+slopeY*label_ratio)

#Finally, redraw the labels at their new position.
nx.draw_networkx_labels(G,pos=pos_labels,fontsize=2)
#Show the figure
plt.show()

这主要适用于大部分位于图形外围的节点,但对于位于图形中心的节点具有挑战性,因为质心不会提供避开大部分边的可靠方向。

这是 graphviz 的 fdp 的输出布局...

graphviz fdp output

...这里是 networkx 的输出 spring layout .

networkx spring layout

请注意第二个图中绿色和黑色标签的距离。本质上,dddddddd的邻域的质心与节点的实际位置比较接近。

对于更复杂的解决方案,您可能需要检查更复杂的算法,例如 the one that is used by Wordle为了适应标签的初始位置,如果它与边缘相交。

希望这会有所帮助。

关于python - 标记外部节点,与networkx中的其他节点/边缘重叠最小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11946005/

相关文章:

python - Networkx:NetworkXException:节点列表包含随机 block 模型的重复项

java - 如何在java中实现循环双向链表add方法

Python - 如何连接到 for 循环中的字符串?

arrays - 如何在标签中显示数组?

svn - 在 subversion 中创建一个 "label"指示下一个版本中应该包含哪些文件

javascript - 旧版 IE 黑客攻击 : label not focusing input

r - R : collapsing descendant tips of an internal node 中的系统发育学

python - Django 从 1.5 版本迁移到 1.7

python - 如何替换 Pandas 数据框中的非整数值?

python - Scrapy管道到mysql错误1241