cara menggambar grafik terarah menggunakan networkx dengan python?

101

Saya memiliki beberapa node yang berasal dari skrip yang ingin saya petakan menjadi grafik. Di bawah ini, saya ingin menggunakan Panah untuk beralih dari A ke D dan mungkin memiliki tepi yang diwarnai juga (merah atau sesuatu).

Ini pada dasarnya, seperti jalur dari A ke D ketika semua node lain ada. Anda dapat membayangkan setiap node sebagai kota dan perjalanan dari A ke D membutuhkan arah (dengan kepala panah).

Kode di bawah ini membangun grafik

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()

tapi saya ingin sesuatu seperti yang ditunjukkan pada gambar.masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Kepala panah gambar pertama dan tepi berwarna merah ke gambar kedua.

badai otak
sumber

Jawaban:

86

Contoh yang sepenuhnya disempurnakan dengan panah hanya untuk tepi merah:

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()

Tepi merah

Marius
sumber
1
sungguh gila betapa berbedanya dua gambar kami yang diperbarui. 1 untuk mengetahui warna tepi!
mdml
kenapa edge kamu (C, E) tidak merah padahal harus merah sesuai kode kamu di atas?
badai otak
apakah tidak mungkin memiliki kepala panah ini hanya di tepi yang diminati? misalnya (A, C) dan (C, E)
badai otak
@ user1988876: Ah, maaf, (C, E)bukan merah karena saya memilih tepinya red_edgesketika saya masih bekerja dengan grafik tidak terarah Anda, hanya memilih secara acak dari tepi yang dikembalikan oleh G.edges(). Seharusnya begitu red_edges = [('A', 'C'), ('E', 'C')].
Marius
@ user1988876: Memiliki tanda panah hanya pada beberapa edge dimungkinkan dengan panggilan terpisah ke draw_networkx_edges(). Saya telah membersihkan kode dan memperbaiki masalah DiGraph.
Marius
47

Saya hanya memasukkan ini untuk kelengkapan. Saya telah belajar banyak dari marius dan mdml. Berikut adalah bobot tepi. Maaf tentang panahnya. Sepertinya saya bukan satu-satunya yang mengatakan itu tidak bisa membantu. Saya tidak dapat membuat ini dengan notebook ipython. Saya harus langsung dari python yang merupakan masalah dengan mendapatkan bobot tepi saya lebih cepat.

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()

masukkan deskripsi gambar di sini

Back2Basics
sumber
9
Saya menjalankan ini dan tidak mendapatkan label node. Anda harus menambahkan ini: node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels).
MadeOfAir
Dan bagaimana jika Anda sudah memiliki grafik yang tidak berarah dan ingin mereproduksi salinan berarahnya? Apakah ada cara untuk menyetel G.add_edges_from()garis tanpa harus memasukkan titik awal dan akhir secara manual? Mungkin menambahkan tepi dari dict?
FaCoffee
Baris kode pertama di bagian ini (selain baris impor) menentukan jenis grafik dan jenis tepinya yang diterima. Anda dapat beralih dari digraf (lebih banyak informasi) ke grafik (lebih sedikit informasi) tetapi Anda tidak dapat beralih dari grafik (lebih sedikit informasi) ke digraf (lebih banyak informasi) tanpa informasi atau cara untuk membangun informasi yang hilang itu. Saya akan menyarankan untuk mengajukan pertanyaan Anda dengan contoh dalam pertanyaan stack overflow lainnya.
Back2Basics
1
Apakah mungkin untuk mendapatkan panah nyata di tepinya? Saya tidak suka ujung yang lebih tebal.
Wikunia
1
Menggambar panah di matplotlib itu rumit dan saat ini tidak didukung di NetworkX. Permintaan tarik diterima.
Back2Basics
33

Alih-alih nx.draw biasa, Anda mungkin ingin menggunakan:

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

Sebagai contoh:

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

Anda dapat menambahkan opsi dengan menginisialisasi variabel ** seperti ini:

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

Juga beberapa fungsi mendukung directed=True parameter Dalam hal ini status ini adalah yang default:

G = nx.DiGraph(directed=True)

Referensi networkx ditemukan di sini .

Grafik dengan gambar panah

Raz
sumber
21

Anda perlu menggunakan grafik berarah daripada grafik, mis

G = nx.DiGraph()

Kemudian, buat daftar warna tepi yang ingin Anda gunakan dan teruskan ke nx.draw(seperti yang ditunjukkan oleh @Marius).

Menyatukan ini semua, saya mendapatkan gambar di bawah ini. Masih belum cukup dengan gambar lain yang Anda tunjukkan (saya tidak tahu dari mana bobot tepi Anda berasal), tetapi lebih dekat! Jika Anda ingin lebih mengontrol bagaimana grafik output Anda terlihat (misalnya mendapatkan panah yang terlihat seperti panah), saya akan memeriksa NetworkX dengan Graphviz .

masukkan deskripsi gambar di sini

mdml
sumber
Ah cheers, saya tidak tahu mengapa panah tidak berfungsi karena saya bisa melihat argumen untuk mereka di dokumentasi.
Marius
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()

Ini hanyalah cara sederhana menggambar grafik berarah menggunakan python 3.x menggunakan networkx. hanya representasi sederhana dan dapat dimodifikasi dan diwarnai dll. Lihat grafik yang dihasilkan di sini .

Catatan: Ini hanya representasi sederhana. Tepi Tertimbang dapat ditambahkan seperti

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

dan karenanya diplot lagi.

Padmalochan Panda
sumber
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()
Sachin Rawat
sumber