改进 Python NetworkX 图形布局
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21978487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Improving Python NetworkX graph layout
提问by Sayan
I am having some problems in visualizing the graphs created with python-networkx, I want to able to reduce clutter and regulate the distance between the nodes (I have also tried spring_layout, it just lays out the nodes in an elliptical fashion). Please advise.

我在可视化使用 python-networkx 创建的图形时遇到了一些问题,我希望能够减少混乱并调节节点之间的距离(我也尝试过 spring_layout,它只是以椭圆方式布置节点)。请指教。

Parts of code:
部分代码:
nx.draw_networkx_edges(G, pos, edgelist=predges, edge_color='red', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False, style='dashed')
# label fonts
nx.draw_networkx_labels(G,pos,font_size=7,font_family='sans-serif')
nx.draw_networkx_edge_labels(G,pos,q_list,label_pos=0.3)
采纳答案by Hooked
In networkx, it's worth checking out the graph drawing algorithms provided by graphvizvia nx.graphviz_layout.
在 networkx 中,值得查看graphviz通过nx.graphviz_layout.
I've had good success with neatobut the other possible inputs are
我已经取得了很好的成功,neato但其他可能的输入是
dot- "hierarchical" or layered drawings of directed graphs. This is the default tool to use if edges have directionality.neato- "spring model'' layouts. This is the default tool to use if the graph is not too large (about 100 nodes) and you don't know anything else about it. Neato attempts to minimize a global energy function, which is equivalent to statistical multi-dimensional scaling.fdp- "spring model'' layouts similar to those of neato, but does this by reducing forces rather than working with energy.sfdp- multiscale version of fdp for the layout of large graphs.twopi- radial layouts, after Graham Wills 97. Nodes are placed on concentric circles depending their distance from a given root node.circo- circular layout, after Six and Tollis 99, Kauffman and Wiese 02. This is suitable for certain diagrams of multiple cyclic structures, such as certain telecommunications networks.
dot- 有向图的“分层”或分层图。如果边具有方向性,则这是使用的默认工具。neato- “弹簧模型”布局。如果图形不是太大(大约 100 个节点)并且您对它一无所知,这是默认使用的工具。Neato 尝试最小化全局能量函数,这是等效的到统计多维标度。fdp- “弹簧模型”的布局类似于neato的布局,但通过减少力而不是使用能量来实现。sfdp- 用于大图布局的 fdp 多尺度版本。twopi- Graham Wills 97 之后的径向布局。根据节点与给定根节点的距离将节点放置在同心圆上。circo- 圆形布局,在 Six 和 Tollis 99、Kauffman 和 Wiese 02 之后。这适用于多个循环结构的某些图,例如某些电信网络。
In general, graph drawingis a hard problem. If these algorithms are not sufficient, you'll have to write your own or have networkx draw parts individually.
一般来说,图形绘制是一个难题。如果这些算法还不够,您必须自己编写或单独使用 networkx 绘制部件。
回答by phyrox
You have a lot of data in your graph, so it is going to be hard to remove clutter.
您的图表中有大量数据,因此很难消除混乱。
I suggest you to use any standard layout. You said that you used spring_layout. I suggest you to try it again but this time using the weightattribute when adding the edges.
我建议您使用任何标准布局。你说你用过spring_layout。我建议您再试一次,但这次weight在添加边时使用该属性。
For example:
例如:
import networkx as nx
G = nx.Graph();
G.add_node('A')
G.add_node('B')
G.add_node('C')
G.add_node('D')
G.add_edge('A','B',weight=1)
G.add_edge('C','B',weight=1)
G.add_edge('B','D',weight=30)
pos = nx.spring_layout(G,scale=2)
nx.draw(G,pos,font_size=8)
plt.show()
Additionally you can use the parameter scaleto increase the global distance between the nodes.
此外,您可以使用该参数scale来增加节点之间的全局距离。
回答by halloleo
To answer your question how to regulate the distance between nodes, I expand on Hooked's answer:
为了回答您如何调节节点之间的距离的问题,我扩展了Hooked 的答案:
If you draw the graph via the Graphviz backend and when you then use the fdpalgorithm, you can adjust the distance between nodes by the edgeattribute len.
如果通过 Graphviz 后端绘制图形,然后使用该fdp算法,则可以通过边缘属性len调整节点之间的距离。
Here a code example, how to draw a graph Gand save in the Graphviz file gvfilewith wider distance between nodes (default distance for fdpis 0.3):
此处的代码示例,如何绘制的曲线图G,并在Graphviz的文件保存gvfile具有较宽距离的节点之间(默认距离为fdp是0.3):
A = nx.to_agraph(G)
A.edge_attr.update(len=3)
A.write(gv_file_name)
Two comments:
两条评论:
- It is normally advisable to adjust
lenwith the number of nodes in the graph. - The
lenattribute is only recognised by thefdpandneatoalgorithm, but not e.g. by thesfdpalgorithm.
- 通常建议
len根据图中的节点数进行调整。 - 该
len属性仅被fdpandneato算法识别,而不能被sfdp算法识别。
回答by Victoria Stuart
I found this to be useful for quickly visualizing interaction data (here, genes) sourced as a CSV file.
我发现这对于快速可视化作为 CSV 文件来源的交互数据(这里是基因)很有用。
Data file [a.csv]
数据文件 [a.csv]
APC,TP73
BARD1,BRCA1
BARD1,ESR1
BARD1,KRAS2
BARD1,SLC22A18
BARD1,TP53
BRCA1,BRCA2
BRCA1,CHEK2
BRCA1,MLH1
BRCA1,PHB
BRCA2,CHEK2
BRCA2,TP53
CASP8,ESR1
CASP8,KRAS2
CASP8,PIK3CA
CASP8,SLC22A18
CDK2,CDKN1A
CHEK2,CDK2
ESR1,BRCA1
ESR1,KRAS2
ESR1,PPM1D
ESR1,SLC22A18
KRAS2,BRCA1
MLH1,CHEK2
MLH1,PMS2
PIK3CA,BRCA1
PIK3CA,ESR1
PIK3CA,RB1CC1
PIK3CA,SLC22A18
PMS2,TP53
PTEN,BRCA1
PTEN,MLH3
RAD51,BRCA1
RB1CC1,SLC22A18
SLC22A18,BRCA1
TP53,PTEN
Python 3.7 venv
Python 3.7 venv
import networkx as nx
import matplotlib.pyplot as plt
G = nx.read_edgelist("a.csv", delimiter=",")
G.edges()
'''
[('CDKN1A', 'CDK2'), ('MLH3', 'PTEN'), ('TP73', 'APC'), ('CHEK2', 'MLH1'),
('CHEK2', 'BRCA2'), ('CHEK2', 'CDK2'), ('CHEK2', 'BRCA1'), ('BRCA2', 'TP53'),
('BRCA2', 'BRCA1'), ('KRAS2', 'CASP8'), ('KRAS2', 'ESR1'), ('KRAS2', 'BRCA1'),
('KRAS2', 'BARD1'), ('PPM1D', 'ESR1'), ('BRCA1', 'PHB'), ('BRCA1', 'ESR1'),
('BRCA1', 'PIK3CA'), ('BRCA1', 'PTEN'), ('BRCA1', 'MLH1'), ('BRCA1', 'SLC22A18'),
('BRCA1', 'BARD1'), ('BRCA1', 'RAD51'), ('CASP8', 'ESR1'), ('CASP8', 'SLC22A18'),
('CASP8', 'PIK3CA'), ('TP53', 'PMS2'), ('TP53', 'PTEN'), ('TP53', 'BARD1'),
('PMS2', 'MLH1'), ('PIK3CA', 'SLC22A18'), ('PIK3CA', 'ESR1'), ('PIK3CA', 'RB1CC1'),
('SLC22A18', 'ESR1'), ('SLC22A18', 'RB1CC1'), ('SLC22A18', 'BARD1'),
('BARD1', 'ESR1')]
'''
G.number_of_edges()
# 36
G.nodes()
'''
['CDKN1A', 'MLH3', 'TP73', 'CHEK2', 'BRCA2', 'KRAS2', 'CDK2', 'PPM1D', 'BRCA1',
'CASP8', 'TP53', 'PMS2', 'RAD51', 'PIK3CA', 'MLH1', 'SLC22A18', 'BARD1',
'PHB', 'APC', 'ESR1', 'RB1CC1', 'PTEN']
'''
G.number_of_nodes()
# 22
UPDATE
更新
This used to work (2018-03), but now (2019-12) gives a pygraphvizimport error:
这曾经有效(2018-03),但现在(2019-12)出现pygraphviz导入错误:
from networkx.drawing.nx_agraph import graphviz_layout
nx.draw(G, pos = graphviz_layout(G), node_size=1200, node_color='lightblue', \
linewidths=0.25, font_size=10, font_weight='bold', with_labels=True)
Traceback (most recent call last):
...
ImportError: libpython3.7m.so.1.0: cannot open shared object file:
No such file or directory
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
...
ImportError: ('requires pygraphviz ', 'http://pygraphviz.github.io/')
SOLUTION
解决方案
Outside Python (at the venv terminal prompt: $) install pydot.
在 Python 之外(在 venv 终端提示符处:)$安装pydot.
pip install pydot
Back in Python run the following code.
回到 Python 中运行以下代码。
import warnings
warnings.filterwarnings("ignore", category=UserWarning)
import networkx as nx
import matplotlib.pyplot as plt
G = nx.read_edgelist("a.csv", delimiter=",")
# For a DiGraph() [directed edges; not shown]:
# G = nx.read_edgelist("a.csv", delimiter=",", create_using=nx.DiGraph)
nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), node_size=1200, \
node_color='lightblue', linewidths=0.25, font_size=10, \
font_weight='bold', with_labels=True)
plt.show() ## plot1.png attached
The main change was to replace
主要的变化是取代
nx.draw(G, pos = graphviz_layout(G), ...)
with
和
nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), ...)
References
参考
Remove matplotlib depreciation warning from showing
What could cause NetworkX & PyGraphViz to work fine alone but not together?
什么可能导致 NetworkX 和 PyGraphViz 单独工作但不能一起工作?
- Specifically: https://stackoverflow.com/a/40750101/1904943
Improved plot layout
改进的绘图布局
It is difficult to decrease congestion in these static networkx / matplotlib plots; one workaround is to increase the figure size, per this StackOverflow Q/A: High Resolution Image of a Graph using NetworkX and Matplotlib:
在这些静态 networkx / matplotlib 图中很难减少拥塞;一种解决方法是增加图形大小,根据此 StackOverflow Q/A: High Resolution Image of a Graph using NetworkX 和 Matplotlib:
plt.figure(figsize=(20,14))
# <matplotlib.figure.Figure object at 0x7f1b65ea5e80>
nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
node_size=1200, node_color='lightblue', linewidths=0.25, \
font_size=10, font_weight='bold', with_labels=True, dpi=1000)
plt.show() ## plot2.png attached
To reset the output figure size to the system default:
要将输出图形大小重置为系统默认值:
plt.figure()
# <matplotlib.figure.Figure object at 0x7f1b454f1588>
Bonus: shortest path
奖励:最短路径
nx.dijkstra_path(G, 'CDKN1A', 'MLH3')
# ['CDKN1A', 'CDK2', 'CHEK2', 'BRCA1', 'PTEN', 'MLH3']
Although I did not do this here, if you want to add node borders and thicken the node border lines (node edge thickness: linewidths), do the following.
虽然我这里没有这样做,但是如果要添加节点边框并加粗节点边框线(节点边缘粗细:)linewidths,请执行以下操作。
nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
node_size=1200, node_color='lightblue', linewidths=2.0, \
font_size=10, font_weight='bold', with_labels=True)
# Get current axis:
ax = plt.gca()
ax.collections[0].set_edgecolor('r')
# r : red (can also use #FF0000) | b : black (can also use #000000) | ...
plt.show()

