как рисовать ориентированные графы с помощью networkx в Python?

102

У меня есть несколько узлов, поступающих из сценария, которые я хочу отобразить на графике. Ниже я хочу использовать стрелку, чтобы перейти от A к D, и, вероятно, чтобы край тоже был окрашен в красный цвет или что-то в этом роде.

Это в основном похоже на путь от A к D, когда присутствуют все остальные узлы. вы можете представить каждый узел как город, и для путешествия от A к D требуются направления (со стрелками).

Этот код ниже строит график

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

nx.draw(G, cmap = plt.get_cmap('jet'), node_color = values)
plt.show()

но я хочу что-то вроде показанного на изображении.введите описание изображения здесь введите описание изображения здесь

Стрелки первого изображения и края красного цвета на втором изображении.

мозговой штурм
источник

Ответы:

86

Полностью проработанный пример со стрелками только для красных краев:

import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

# Specify the edges you want here
red_edges = [('A', 'C'), ('E', 'C')]
edge_colours = ['black' if not edge in red_edges else 'red'
                for edge in G.edges()]
black_edges = [edge for edge in G.edges() if edge not in red_edges]

# Need to create a layout when doing
# separate calls to draw nodes and edges
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, cmap=plt.get_cmap('jet'), 
                       node_color = values, node_size = 500)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edgelist=red_edges, edge_color='r', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False)
plt.show()

Красные края

Мариус
источник
1
это безумие, насколько разные наши два обновленных изображения. +1 за определение цвета краев!
mdml
почему ваш край (C, E) не красный, хотя он должен быть красным в соответствии с вашим кодом выше?
мозговой штурм
разве нельзя иметь эти стрелки только на интересующих краях? например (A, C) и (C, E)
мозговой штурм
@ user1988876: Ах, извините, (C, E)не красный, потому что я выбирал ребра, red_edgesкогда еще работал с вашим неориентированным графом, просто выбирая случайным образом из ребер, возвращенных G.edges(). Так и должно быть red_edges = [('A', 'C'), ('E', 'C')].
Мариус
@ user1988876: Наличие стрелок только на некоторых краях возможно с помощью отдельных вызовов draw_networkx_edges(). Я очистил код и исправил проблемы с DiGraph.
Мариус
47

Я добавил это только для полноты картины. Я многому научился у мариуса и mdml. Вот веса ребер. Извините за стрелки. Похоже, я не единственный, кто говорит, что ничего не поделаешь. Я не мог отобразить это с помощью ipython notebook. Мне пришлось перейти прямо с python, что было проблемой с получением моих краевых весов раньше.

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import pylab

G = nx.DiGraph()

G.add_edges_from([('A', 'B'),('C','D'),('G','D')], weight=1)
G.add_edges_from([('D','A'),('D','E'),('B','D'),('D','E')], weight=2)
G.add_edges_from([('B','C'),('E','F')], weight=3)
G.add_edges_from([('C','F')], weight=4)


val_map = {'A': 1.0,
                   'D': 0.5714285714285714,
                              'H': 0.0}

values = [val_map.get(node, 0.45) for node in G.nodes()]
edge_labels=dict([((u,v,),d['weight'])
                 for u,v,d in G.edges(data=True)])
red_edges = [('C','D'),('D','A')]
edge_colors = ['black' if not edge in red_edges else 'red' for edge in G.edges()]

pos=nx.spring_layout(G)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw(G,pos, node_color = values, node_size=1500,edge_color=edge_colors,edge_cmap=plt.cm.Reds)
pylab.show()

введите описание изображения здесь

Back2Basics
источник
9
Я запустил это и не получил меток узлов. Вам нужно добавить эти: node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels).
MadeOfAir
А что, если у вас уже есть неориентированный граф и вы хотите воспроизвести его направленную копию? Есть ли способ установить G.add_edges_from()линию без необходимости вручную вводить начальную и конечную точки? Возможно добавление ребер из а dict?
FaCoffee
Первая строка кода в этом разделе (кроме строк импорта) устанавливает, какой это тип графа и какие ребра он принимает. Вы можете перейти от орграфа (больше информации) к графику (меньше информации), но вы не можете перейти от графа (меньше информации) к орграфу (больше информации) без информации или способа построения этой недостающей информации. Я бы предложил поставить ваш вопрос с примером в другом вопросе о переполнении стека.
Back2Basics 03
1
Можно ли получить настоящие стрелки по краям? Мне не нравится только более толстый конец.
Wikunia 05
1
Рисование стрелок в matplotlib сложно и в настоящее время не поддерживается в NetworkX. Запросы на вытягивание принимаются.
Back2Basics 05
33

Вместо обычного nx.draw вы можете использовать:

nx.draw_networkx(G[, pos, arrows, with_labels])

Например:

nx.draw_networkx(G, arrows=True, **options)

Вы можете добавить параметры, инициализировав эту ** переменную следующим образом:

options = {
    'node_color': 'blue',
    'node_size': 100,
    'width': 3,
    'arrowstyle': '-|>',
    'arrowsize': 12,
}

Также некоторые функции поддерживают. directed=True parameter В этом случае это состояние является значением по умолчанию:

G = nx.DiGraph(directed=True)

Ссылка на networkx находится здесь .

График с изображением стрелок

Раз
источник
21

Вам нужно использовать ориентированный граф вместо графа, т.е.

G = nx.DiGraph()

Затем создайте список цветов краев, которые вы хотите использовать, и передайте их в nx.draw (как показано @Marius).

Собирая все это вместе, я получаю изображение ниже. Все еще не совсем то изображение, которое вы показываете (я не знаю, откуда берутся ваши граничные веса), но гораздо ближе! Если вы хотите больше контролировать внешний вид выходного графа (например, получить стрелки, которые выглядят как стрелки), я бы попробовал NetworkX с Graphviz .

введите описание изображения здесь

mdml
источник
Ура, я не мог понять, почему стрелки не работают, поскольку я видел аргументы в их пользу в документации.
Мариус
9
import networkx as nx
import matplotlib.pyplot as plt

g = nx.DiGraph()
g.add_nodes_from([1,2,3,4,5])
g.add_edge(1,2)
g.add_edge(4,2)
g.add_edge(3,5)
g.add_edge(2,3)
g.add_edge(5,4)

nx.draw(g,with_labels=True)
plt.draw()
plt.show()

Это просто, как нарисовать ориентированный граф с использованием python 3.x с помощью networkx. просто простое представление, которое можно изменять и раскрашивать и т. д. См. сгенерированный график здесь .

Примечание: это простое представление. Утяжеленные края могут быть добавлены как

g.add_edges_from([(1,2),(2,5)], weight=2)

и, следовательно, построил снова.

Падмалочан Панда
источник
1
import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_node("A")
G.add_node("B")
G.add_node("C")
G.add_node("D")
G.add_node("E")
G.add_node("F")
G.add_node("G")
G.add_edge("A","B")
G.add_edge("B","C")
G.add_edge("C","E")
G.add_edge("C","F")
G.add_edge("D","E")
G.add_edge("F","G")

print(G.nodes())
print(G.edges())

pos = nx.spring_layout(G)

nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edge_color='r', arrows = True)

plt.show()
Сачин Рават
источник