Ответ 1
Я ранее пытался что-то подобное, основная идея заключалась в том, чтобы в основном не использовать края.
Предполагая, что ребра являются прямыми, существуют два простых и похожих способа достижения этого:
-
На основании углов, что ребра a node neighbourhood делают относительно node.
-
На основе centroid узлов окрестности.
Итак, найдите углы, чтобы края отступали от node к его окрестности и пытались расположить метку AWAY от большинства ребер; ИЛИ оцените центр тяжести окрестности node и поместите метку в противоположном направлении.
Первое решение может быть немного проблематичным, прежде всего из-за того, что работает функция atan2 (которая, по сути, определяет краевые углы), но он обеспечивает некоторую гибкость с точки зрения позиционирования метки.
Второе решение является самым простым и работает следующим образом:
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 position from the layout
x,y = pos[aNode]
#Get the node neighbourhood
N = G[aNode]
#Find the centroid of the neighbourhood. The centroid is the average of the Neighbourhood node 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 '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()
Это работает, главным образом, для узлов, которые в основном находятся на периферии Графа, но сложны для узлов, которые расположены по направлению к центру графика, потому что центроид не обеспечивает надежного направления, которое позволяет избежать большинства ребер.
Вот результат для графика fdp макет...
... и вот вывод для networkx spring layout.
Обратите внимание на близость ярлыков зеленого и черного цветов на втором рисунке. По существу, центр тяжести окрестности ddddddd относительно близок к фактическому положению node.
Для более сложного решения вы можете проверить более сложные алгоритмы, такие как тот, который используется Wordle, чтобы адаптировать исходное положение метки если он пересекает ребро.
Надеюсь, что это поможет.