🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3318閲覧

PythonのNetworkxでエッジを描画するとノードの位置ずれが発生する

mi41

総合スコア1

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/02/19 14:15

編集2021/02/21 09:58

前提・実現したいこと

初めて、質問させて頂きます。
現在、PythonのNetworkxを用いて、ネットワークグラフを作成しています。
ノードとエッジの両方を表示させて、同じノード位置で画像を出力したいです。

発生している問題・エラーメッセージ

ノードの表示のみでは、ノード位置は固定されるが、エッジを描画するとノード位置が変わってしまいます。
以下の画像(2枚)は、異なる入力による出力結果になります。この二枚を重ね合わせて比較したいのですが、ノード位置がずれてしまいます。
恐らく、エッジ表示によるノード間距離が変わってしまうのが、原因だと思ってますが、解決策が思いつきません。
プログラム上では、ノードの位置を固定していて、エッジ表示をやめたらノード位置が固定され、重ね合わせて比較できます。
イメージ説明
イメージ説明

該当のソースコード

Python

1import networkx as nx 2from networkx.drawing.nx_pydot import write_dot 3import matplotlib.pyplot as plt 4import numpy as np 5 6node_225 = [] 7for r in range(225): 8 node_225.append(r+1) #ノード用のリスト作成 9 10#グラフの作成 11 12Graph = nx.DiGraph() #空のグラフを作成 13Graph.add_nodes_from(node_225) #ノード格納 14 15 16pos2 = { 17 g+1:(((3840/15)*(g%15)+128),((2160/15)*((int(((225-(g+1))/15)))))+216) #g+1がノード番号 18 for g in range(225) 19 } #ノードの位置固定したい 20 21#描画処理 22plt.figure(dpi = 100,figsize=(38.4,21.6))                   #3840*2160の画像出力したい 23 24Graph.add_weighted_edges_from(omomi_all) #重み付きエッジの登録 25edge_labels = {(i, j): w['weight'] for i, j, w in Graph.edges(data=True)} #'weight'っていう文字を削除とedge_labelsの作成 26#edge_width = [ d['weight']*1 for (u,v,d) in Graph.edges(data=True)] #設定した重みの値に比例して大きさを設定 27 28nx.draw_networkx_edge_labels(Graph,pos2,label_pos=0.3, edge_labels=edge_labels)#エッジの重みを表示する 29 30nx.draw(Graph, with_labels=True,pos=pos2,node_size = node_1_225)#pos2でノード位置固定 31 32plt.show() 33
#上の画像のデータ node_1_225の中身 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 3, 88, 378, 200, 599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 53, 167, 578, 255, 334, 89, 1, 0, 0, 0, 0, 0, 0, 1, 391, 30, 283, 1496, 450, 112, 4, 1, 0, 0, 0, 0, 0, 0, 0, 386, 5, 59, 269, 128, 34, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 375, 43, 4, 4, 23, 2, 0, 0, 0, 0, 0, 0, 0, 0, 61, 64, 3, 1, 24, 30, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 13, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 27, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 14, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0] omomi_allの中身  [エッジの始点ノード,終点ノード,重み] [[202, 187, 0.1], [187, 202, 0.1], [201, 202, 0.1], [188, 187, 0.1], [214, 215, 0.1], [215, 214, 0.1], [114, 130, 3.5], [99, 84, 0.1], [100, 114, 0.25], [115, 114, 0.25], [84, 83, 0.1], [98, 113, 0.25], [85, 100, 0.1], [97, 112, 0.25], [83, 84, 0.1], [113, 128, 0.5], [112, 97, 0.25], [109, 112, 0.1], [116, 114, 0.1], [111, 112, 0.1], [127, 142, 0.1], [156, 142, 0.1], [157, 142, 0.1], [172, 142, 0.1], [142, 127, 0.25], [125, 126, 0.1], [110, 112, 0.1], [67, 188, 0.1], [143, 144, 0.1], [129, 144, 0.25], [130, 115, 0.1], [95, 80, 0.1], [80, 110, 0.1], [96, 111, 0.1], [82, 83, 0.1], [131, 101, 0.1], [101, 116, 0.1], [128, 113, 0.5], [189, 217, 0.1], [217, 203, 0.1], [203, 158, 0.1], [158, 143, 0.1], [159, 144, 0.1], [173, 220, 0.1], [220, 112, 0.1], [218, 158, 0.1], [144, 129, 0.25], [145, 160, 0.1], [146, 145, 0.1], [161, 146, 0.1], [160, 145, 0.1], [147, 162, 0.1], [162, 161, 0.1], [141, 142, 0.1], [126, 127, 0.1], [117, 100, 0.1], [69, 68, 0.1], [68, 83, 0.1], [102, 100, 0.1], [81, 82, 0.1]]
#下の画像のデータ node_1_225の中身 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 31, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 141, 124, 269, 504, 15, 2, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2034, 61, 2013, 464, 126, 2, 1, 0, 0, 0, 0, 0, 0, 0, 143, 2039, 354, 1421, 385, 105, 145, 1, 0, 0, 0, 0, 0, 0, 0, 1, 137, 133, 472, 114, 40, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 22, 394, 2, 6, 21, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 6, 2, 23, 41, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] omomi_allの中身  [エッジの始点ノード,終点ノード,重み] [[97, 96, 0.1], [82, 83, 0.1], [112, 113, 1.5], [113, 128, 0.5], [98, 114, 0.5], [96, 97, 0.1], [111, 112, 0.25], [114, 98, 0.5], [99, 114, 0.5], [84, 114, 0.1], [115, 114, 0.1], [100, 99, 0.1], [130, 115, 0.1], [129, 114, 0.1], [81, 82, 0.1], [95, 112, 0.1], [128, 112, 0.5], [127, 126, 0.5], [94, 111, 0.1], [126, 112, 0.5], [110, 112, 0.1], [125, 112, 0.1], [204, 189, 0.1], [205, 204, 0.1], [189, 204, 0.1], [188, 187, 0.1], [187, 188, 0.1], [116, 101, 0.1], [101, 117, 0.1], [117, 116, 0.1], [102, 116, 0.1], [159, 160, 0.1], [144, 159, 0.1], [143, 144, 0.1], [142, 127, 0.25], [141, 142, 0.1], [156, 141, 0.1], [157, 143, 0.1], [173, 158, 0.1], [158, 143, 0.1], [140, 142, 0.1], [155, 142, 0.1], [145, 144, 0.1], [160, 144, 0.1], [161, 176, 0.1], [146, 161, 0.1], [176, 177, 0.1], [177, 161, 0.1], [175, 159, 0.1], [162, 161, 0.1], [132, 130, 0.1], [131, 130, 0.1], [83, 98, 0.25], [68, 53, 0.1], [69, 83, 0.1], [70, 81, 0.1], [86, 85, 0.1], [85, 84, 0.1], [53, 68, 0.1], [52, 53, 0.1], [67, 66, 0.1], [66, 81, 0.1], [79, 82, 0.1]]

試したこと

該当エラーに関する記事を調べたが、出てこなかった。
ノード間距離の調整を試みたが、出来なかった。

補足情報(FW/ツールのバージョンなど)

環境
Jupiternotebook 6.0.3
Python 3.7.6
Networkx 2.4

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

etherbeg

2021/02/21 08:13 編集

ソースコードの一部が省略されているようですので、すべてを記載してください。 2枚の画像を出力する際に使われたomomi_allの内容もそれぞれ掲載してください。 手元で問題を再現して検証したいのでよろしくお願いします。
mi41

2021/02/21 10:07

etherbeg様、返信ありがとうございます。 初めての質問でしたので、色々と足りない部分がありました。申し訳ありません。 自分の今書いているソースコードを全て記載すると、ものすごい量になってしまう恐れがありましたので、一部抜粋した形で記載しました。 また、コードの追加と修正、必要かと思われるデータを記載しました。 修正部分としては、質問内容と関係ない部分であるカラー表示をやめたこと、エッジの太さも質問内容と関係ないと思いコメントアウトしました。 また、足りない部分がありましたら、教えて頂けると嬉しいです。
etherbeg

2021/02/21 11:00 編集

ありがとうございます。拝見します。
guest

回答1

0

ベストアンサー

私の環境(macOS 11.1, Python 3.9.1, NetworkX 2.5, 仮想環境で実行)でも現象が確認できました。
いくつかの特定のノード間で、エッジ端に矢印を表示している時にこの現象が起こるようです。現象の起こる理由は、NetworkXのソースコードも見てみましたが、結局わかりませんでした。

解決方法1: 矢印を表示しない

python

1nx.draw(Graph, with_labels=True, pos=pos2, node_size=node_1_225, arrows=False)

arrows=Falseで矢印が表示されなくなります。arrowstyleキーワード引数で矢印の形状を、arrowsizeキーワード引数で矢印のサイズを変更することができますが、矢印を表示した状態でこれらを変更しても表示に変わりはありませんでした。
有向グラフなのでこの解決手段は取りたくないかと想像します。

解決方法2: ソースコードに手を加える
こちらは矢印は表示したままでいいです。
Pythonのプログラムを実行している環境でNetworkXのソースコードを探してください。その中からnx_pylab.pyファイルを探してテキストエディタで開いてください。
私の環境では、仮想環境内の

lib/python3.9/site-packages/networkx/drawing/nx_pylab.py

にありました。
draw_networkx_edges関数を定義している箇所を探して、その末尾近くにある

python

1ax.update_datalim(corners) 2ax.autoscale_view()

の2行をコメントアウトしてください。私の環境では780行目と781行目にありました。
なぜこの2行をコメントアウトすると解決するのか、矢印の表示の有無による解決方法とこの箇所はどう関わるのか(関わらないのか)、だいぶソースを見ながら考えてみましたが、結局わかりませんでした。もちろん、この辺が怪しいというのがあればこそ、この2行をコメントアウトするということもやってみたのですが、その原因と結果をちゃんと説明できるまでの理解に至っていません。この部分は矢印の描画の有無に関わらず実行されるし、矢印の描画結果とも関係していないはずなのですが…。

一時凌ぎですので、用が終わったらソースコードは元に戻しておいてください。

以上です。明確な解決策を提示できなくて申し訳ありません。

(補足) NetworkXのドキュメントには次のようにありました。

Proper graph visualization is hard, and we highly recommend that people visualize their graphs with tools dedicated to that task. Notable examples of dedicated and fully-featured graph visualization tools are Cytoscape, Gephi, Graphviz and, for LaTeX typesetting, PGF/TikZ. To use these and other such tools, you should export your NetworkX graph into a format that can be read by those tools. For example, Cytoscape can read the GraphML format, and so, networkx.write_graphml(G, path) might be an appropriate choice.

https://networkx.org/documentation/stable/reference/drawing.html#drawing

投稿2021/02/22 15:33

編集2021/02/22 23:12
etherbeg

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mi41

2021/02/23 02:38

回答して頂き、ありがとうございました。 解決方法:2で試したところ、確かにノードの位置ずれが起きないことを確認しました。 Networkxのソースコード自体をいじらないと駄目だったんですね。。。 補足事項も含めて、大変勉強になりました。 改めて、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問