web-dev-qa-db-ja.com

すべてのエッジを個別に表示する方法でPythonに有向グラフをプロットする

Python=を使用して、有向グラフで行われるプロセスをシミュレートしています。このプロセスのアニメーションを作成したいと思います。

私が遭遇した問題は、ほとんどのPythonグラフ視覚化ライブラリが有向エッジのペアを1つのエッジに結合することです。たとえば、 NetworkX は、2つのエッジのみを描画します。次のグラフを表示しますが、4つのエッジをそれぞれ個別に表示したいと思います。

import networkx as nx
import matplotlib.pyplot as plt 

G = nx.MultiDiGraph()

G.add_edges_from([
    (1, 2),
    (2, 3),
    (3, 2),
    (2, 1),
])

plt.figure(figsize=(8,8))
nx.draw(G)

Output from NetworkX; parallel edges are overlapping, so only two lines are displayed

このようなものを表示したいのですが、それぞれの平行なEdgeが別々に描かれています:

Desired output format; parallel edges are drawn separately

質問 RでのigraphのR相互エッジ は同じ問題を処理するようですが、R igraphライブラリでは、Python oneではなく)解決策があります。

既存のPythonグラフ視覚化ライブラリを使用してこのスタイルのプロットを作成する簡単な方法はありますか?マルチグラフをサポートできればおまけです。

外部プログラムを呼び出して画像を生成するソリューションを利用できます。一連のアニメーションフレーム全体を生成したいので、ソリューションを自動化する必要があります。

24
Josh Rosen

Graphviz ツールは、明確なエッジを表示するように見えます。

たとえば、これを与える:

digraph G {
  A -> B;
  A -> B;
  A -> B;
  B -> C;

  B -> A;
  C -> B;
}

to dotは以下を生成します:

example graph

Graphvizの入力言語はかなり単純なので、自分で生成できますが、「python graphviz」を検索すると、 graphviz module on PyPI を含むいくつかのライブラリが表示されます。

以下はpythonで、graphvizモジュールを使用して上記のグラフを生成します:

from graphviz import Digraph

dot = Digraph()
dot.node('A', 'A')
dot.node('B', 'B')
dot.node('C', 'C')
dot.edges(['AB', 'AB', 'AB', 'BC', 'BA', 'CB'])

print(dot.source)
dot.render(file_name, view=True)
27

NetworkXを使用して、ファイルI/Oを回避し、レイアウトにpydotを介してドットを使用する可能な回避策は次のとおりです。

_import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from io import BytesIO

g = nx.dodecahedral_graph()
d = nx.drawing.nx_pydot.to_pydot(g) # d is a pydot graph object, dot options can be easily set
# attributes get converted from networkx,
# use set methods to control dot attributes after creation

png_str = d.create_png()
sio = BytesIO() # file-like string, appropriate for imread below
sio.write(png_str)
sio.seek(0)

img = mpimg.imread(sio)
imgplot = plt.imshow(img)
_

seek(0)が必要な理由については、 Pythonで文字列から画像を作成する方法をご覧ください

IPython(qt)コンソール内の場合、上記はインラインで出力され、より直接的なアプローチは次のとおりです。

_import networkx as nx
from IPython.display import Image

g = nx.dodecahedral_graph()
d = nx.drawing.nx_pydot.to_pydot(g)

png_str = d.create_png()
Image(data=png_str)
_
12

少し遅れているかもしれませんが、問題の別の解決策を見つけたので、誰かが同じ問題を抱えている場合に役立つように投稿します。これはnx.drawに connectionstyle 引数を追加しています:

import networkx as nx
import matplotlib.pyplot as plt 

G = nx.MultiDiGraph()

G.add_edges_from([
    (1, 2),
    (2, 3),
    (3, 2),
    (2, 1),
])

plt.figure(figsize=(8,8))
nx.draw(G, connectionstyle='arc3, rad = 0.1',)

ここに結果が表示されます:

The result

2
AMangipinto