Closed7
networkx の無向グラフにおいて、ノードの重なりを改善する
このような無向グラフを
↓
こんな感じのノード位置に修正したい、という話
↑によると、やることは以下の2つ
-
matplotlib plots
の画像サイズを手動で設定する -
networkx.draw()
における位置設定の変数pos
に、networkx.nx_pydot.graphviz_layout()
で計算した位置情報を与える
というわけでgraphvizをインストール&パスを通して以下を実行する
(JupyterLab の場合、Lab 自体を再起動しないと Path の設定が反映されないようなので注意)
import matplotlib.pyplot as plt
import networks as nx
# G = nx.Graph() とか
# G.add_nodes_from() をしている前提
plt.figure(figsize=(8,5)) # 適切なサイズで
nx.draw(G, pos=nx.nx_pydot.graphviz_layout(G))
結果
networkx.nx_pydot
は内部でpydot
を使うので、インストールされていないとエラーが出る
pydot
に関するちょっとした問題
-
pydot
は Python3 に対応していないので、現在はpydotplus
が主流(らしい) -
networkx
ではpydotplus
は使えない(らしい 少なくとも雑に検索した限りではそんな感じ)
対応策
ここで説明されているように、nxpydot
をpip install
して対応する
README によると、pydotplus
をpydot
としてnetworkx
に利用させるものらしい
これでnetworkx.nx_pydot
が使えるようになったわけだが、残念ながらnetworkx.nx_pydot.graphviz_layout()
はまだ動かない
具体的には以下のような感じのエラーが出る
Line 51: pos = nx.nx_pydot.graphviz_layout(G)
File C:\Users\PIYO\Anaconda3\lib\site-packages\networkx\drawing\nx_pydot.py, in graphviz_layout:
Line 268: return pydot_layout(G=G, prog=prog, root=root)
File C:\Users\PIYO\Anaconda3\lib\site-packages\networkx\drawing\nx_pydot.py, in pydot_layout:
Line 332: assert len(Q_list) == 1
TypeError: object of type 'Dot' has no len()
エラーの原因の雑なまとめ
-
nxpydot
によって、networkx
はpydotplus
の関数を利用している -
pydotplus
では、pydot
と同じ処理を行っているものの返り値の形式が変更されている - その結果、
networkx
のエラーチェック処理自体が TypeError を出す
具体的には、pydot.graph_from_dot_data()
において返り値が「要素数1のリスト」であったとき
pydot
はそのままリストを返していたが、pydotplus
は中身だけを返すようになっている
→ Q_list
にリストではなく中身(Dot
)が入るので、len(Q_list)
がエラーになる
対応策
いろいろ考えられるが、面倒なのでnetworkx
のpydot_layout()
の中身を書き換えることにした
Anaconda3\Lib\site-packages\networkx\drawing\nx_pydot.py$330あたり
- # List of one or more "pydot.Dot" instances deserialized from this string.
- Q_list = pydot.graph_from_dot_data(D)
- assert len(Q_list) == 1
- # The first and only such instance, as guaranteed by the above assertion.
- Q = Q_list[0]
+ Q = pydot.graph_from_dot_data(D)
リストで返ってくる場合もあるので本当はその対応も必要なのだが、どのみちエラーなので…
というわけでkernel を再起動して再び以下を実行してみると、今度はうまくいくはず
import matplotlib.pyplot as plt
import networks as nx
# G = nx.Graph() とか
# G.add_nodes_from() をしている前提
plt.figure(figsize=(8,5)) # 適切なサイズで
nx.draw(G, pos=nx.nx_pydot.graphviz_layout(G))
このスクラップは2021/04/24にクローズされました