Python: networkx: Как сделать автоматическое расширение размера узла в соответствии с меткой
Я использую этот фрагмент кода из примера примера с глубокой символической регрессией, и график отображается нормально, но я хочу, чтобы узлы расширялись в виде закругленных прямоугольников, чтобы они автоматически помещались в текст. (Я не хочу просто указывать размер узла методом проб и ошибок). Как бы я это сделал?
# show tree
import matplotlib.pyplot as plt
import networkx
nodes, edges, labels = gp.graph(bests[0])
graph = networkx.Graph()
graph.add_nodes_from(nodes)
graph.add_edges_from(edges)
pos = networkx.graphviz_layout(graph, prog="dot")
plt.figure(figsize=(7,7))
networkx.draw_networkx_nodes(graph, pos, node_size=900, node_color="w")
networkx.draw_networkx_edges(graph, pos)
networkx.draw_networkx_labels(graph, pos, labels)
plt.axis("off")
plt.show()
4 ответа
Нет простого способа сделать это с помощью matplotlib и networkx (конечно, это возможно при достаточном количестве кода).
Graphviz действительно отлично работает с метками, и легко написать файлы точечного формата из networkx для обработки в Graphviz.
Также взгляните на https://github.com/chebee7i/nxpd который может сделать именно то, что вам нужно.
Аргумент node_size принимает как скалярные, так и векторные значения. В то время как скаляр делает все узлы одинаковыми размерами, вектор помогает вам указать отдельные значения в списке, который будет использоваться для каждого узла. Если идентификаторы вашего узла являются строками, то следующая стратегия работает довольно хорошо.
Просто измените аргумент размера на список в networkx.draw_networkx_nodes, основанный на длине каждого идентификатора узла. Выберите the_base_size соответствующим образом.
networkx.draw_networkx_nodes (graph, pos, node_size = [len (v) * the_base_size для v в graph.nodes()], node_color="w")
Вы можете адаптировать это к случаю, когда вы можете обрабатывать этикетки тоже.
*** Однако я не уверен, будет ли сохранено однозначное соответствие, пока он выбирает размеры узлов из списка на основе размеров меток. Делитесь своими результатами. Я лично использовал его для идентификаторов строк и он работает хорошо.
Я недавно наткнулся на эту проблему. Даже через 5 лет прямого пути к этому нет. Однако после многих проб и ошибок я наконец нашел разумный обходной путь. Вы можете удалить узлы и просто использовать метки с цветом фона.
pos = nx.spring_layout(graph) # Get positions of your nodes
nx.draw_networkx_nodes(graph, pos=pos, label=labels, bbox=dict(fc="r"))
Здесь метки - это словарь с узлом в качестве ключа и именем узла в качестве значения.
Еще один отлаженный способ достижения этого, особенно когда вы хотите настроить свойства каждой метки (например, цвет, форму, фон и т. Д.), Лучший способ добавить метки самостоятельно, используя plt.text()
.
pos = nx.spring_layout(graph) # Get positions of your nodes
for key in pos:
x, y = pos[key]
plt.text(x,y,key,fc="r", ha="center", va="center")
Мне понравилось решение @mathfux, потому что оно правильно позиционирует стрелки в ориентированных графах. Но для решения упомянутой проблемы соответствия требуются некоторые настройки (списки позиций и цветов указаны в порядке компоновки, а не в порядке узлов); также для обработки индексирования списков с нуля. Я также обнаружил, что размеры работают по квадратичному закону, а не линейно. Вот улучшенная версия с цветами, использующая Kamada Kwai, а не Spring, поэтому макет не меняется каждый раз.
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([(0,1), (1, 1), (1, 7), (2, 1), (2, 2), (2, 3),
(2, 6), (3, 5), (4, 3), (5, 4), (5, 8),
(5, 9), (6, 4), (7, 2), (7, 6), (8, 7)])
labelList="zero one twotwotwo three four five six seven eighteighteight nine".split(' ')
positions=nx.kamada_kawai_layout(G)
plt.figure(figsize =(9, 9))
nx.draw_networkx(G,
node_color =['C{}'.format(i) for i in positions],
pos=positions,
labels={idx: val for idx, val in enumerate(labelList)},
node_size=[len(labelList[i])**2 * 60 for i in positions]
)