python中图形图上的许多边缘 [英] Lots of edges on a graph plot in python
问题描述
我有以下脚本:
import pandas as pd
from igraph import *
df_p_c = pd.read_csv('data/edges.csv')
...
edges = list_edges
vertices = list(dict_case_to_number.keys())
g = Graph(edges=edges, directed=True)
plot(g, bbox=(6000, 6000))
我有2300条连接很少的边缘.这是我的情节: 以下是其中几个部分的放大图:
I have 2300 edges with rare connection. This is my plot of it: And here are zooms of a few parts of it:
该图不可读,因为边缘之间的距离太小.如何在边缘之间留出更大的距离?只有来自同一家庭"的边缘之间的距离很小.
This plot is not readable because the distance between edges is too small. How can I have a bigger distance between edges? Only edges from the same 'family' have small distance.
还有其他方法可以改善具有很多边缘的图吗? 我正在寻找可视化父子关联的任何方法,它可能是另一个python数据包.
Is there any other way to improve plots with a lot of edges? I'm looking for any way to visualize parent-child correlation, it could be another python packet.
推荐答案
您似乎有很多小的,断开连接的组件.如果您想要一个信息图,我认为您应该按大小对连接的组件进行排序和分组.此外,许多网络布局算法的基本假设是只有一个巨型组件.因此,如果您需要合理的坐标,通常将需要分别计算每个组件的布局,然后相对于彼此布置组件.我将以这种方式重新绘制您的图表:
You seem to have a lot of small, disconnected components. If you want an informative graph, I think you should sort and group the connected components by size. Furthermore, the underlying assumption of many network layout algorithms is that there is a single giant component. Hence if you want sensible coordinates, you will often need to compute the layout for each component separately and then arrange the components with respect to each other. I would re-plot your graph in this way:
我已经使用networkx
编写了该图的代码,因为这是我选择的模块.但是,将networkx
函数替换为igraph
函数将非常容易.您需要替换的两个功能是networkx.connected_component_subgraphs
和要用于component_layout_func
的任何功能.
I have written the code for this graph using networkx
as that is my module of choice. However, it would be very easy to substitute the networkx
functions with igraph
functions. The two functions that you need to replace are networkx.connected_component_subgraphs
and whatever you want to use for the component_layout_func
.
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import networkx
def layout_many_components(graph,
component_layout_func=networkx.layout.spring_layout,
pad_x=1., pad_y=1.):
"""
Arguments:
----------
graph: networkx.Graph object
The graph to plot.
component_layout_func: function (default networkx.layout.spring_layout)
Function used to layout individual components.
You can parameterize the layout function by partially evaluating the
function first. For example:
from functools import partial
my_layout_func = partial(networkx.layout.spring_layout, k=10.)
pos = layout_many_components(graph, my_layout_func)
pad_x, pad_y: float
Padding between subgraphs in the x and y dimension.
Returns:
--------
pos : dict node : (float x, float y)
The layout of the graph.
"""
components = _get_components_sorted_by_size(graph)
component_sizes = [len(component) for component in components]
bboxes = _get_component_bboxes(component_sizes, pad_x, pad_y)
pos = dict()
for component, bbox in zip(components, bboxes):
component_pos = _layout_component(component, bbox, component_layout_func)
pos.update(component_pos)
return pos
def _get_components_sorted_by_size(g):
subgraphs = list(networkx.connected_component_subgraphs(g))
return sorted(subgraphs, key=len)
def _get_component_bboxes(component_sizes, pad_x=1., pad_y=1.):
bboxes = []
x, y = (0, 0)
current_n = 1
for n in component_sizes:
width, height = _get_bbox_dimensions(n, power=0.8)
if not n == current_n: # create a "new line"
x = 0 # reset x
y += height + pad_y # shift y up
current_n = n
bbox = x, y, width, height
bboxes.append(bbox)
x += width + pad_x # shift x down the line
return bboxes
def _get_bbox_dimensions(n, power=0.5):
# return (np.sqrt(n), np.sqrt(n))
return (n**power, n**power)
def _layout_component(component, bbox, component_layout_func):
pos = component_layout_func(component)
rescaled_pos = _rescale_layout(pos, bbox)
return rescaled_pos
def _rescale_layout(pos, bbox):
min_x, min_y = np.min([v for v in pos.values()], axis=0)
max_x, max_y = np.max([v for v in pos.values()], axis=0)
if not min_x == max_x:
delta_x = max_x - min_x
else: # graph probably only has a single node
delta_x = 1.
if not min_y == max_y:
delta_y = max_y - min_y
else: # graph probably only has a single node
delta_y = 1.
new_min_x, new_min_y, new_delta_x, new_delta_y = bbox
new_pos = dict()
for node, (x, y) in pos.items():
new_x = (x - min_x) / delta_x * new_delta_x + new_min_x
new_y = (y - min_y) / delta_y * new_delta_y + new_min_y
new_pos[node] = (new_x, new_y)
return new_pos
def test():
from itertools import combinations
g = networkx.Graph()
# add 100 unconnected nodes
g.add_nodes_from(range(100))
# add 50 2-node components
g.add_edges_from([(ii, ii+1) for ii in range(100, 200, 2)])
# add 33 3-node components
for ii in range(200, 300, 3):
g.add_edges_from([(ii, ii+1), (ii, ii+2), (ii+1, ii+2)])
# add a couple of larger components
n = 300
for ii in np.random.randint(4, 30, size=10):
g.add_edges_from(combinations(range(n, n+ii), 2))
n += ii
pos = layout_many_components(g, component_layout_func=networkx.layout.circular_layout)
networkx.draw(g, pos, node_size=100)
plt.show()
if __name__ == '__main__':
test()
编辑
如果要紧密布置子图,则需要安装矩形包装器(pip install rectangle-packer
),并用以下版本替换_get_component_bboxes
:
EDIT
If you want the subgraphs tightly arranged, you need to install rectangle-packer (pip install rectangle-packer
), and substitute _get_component_bboxes
with this version:
import rpack
def _get_component_bboxes(component_sizes, pad_x=1., pad_y=1.):
dimensions = [_get_bbox_dimensions(n, power=0.8) for n in component_sizes]
# rpack only works on integers; sizes should be in descending order
dimensions = [(int(width + pad_x), int(height + pad_y)) for (width, height) in dimensions[::-1]]
origins = rpack.pack(dimensions)
bboxes = [(x, y, width-pad_x, height-pad_y) for (x,y), (width, height) in zip(origins, dimensions)]
return bboxes[::-1]
这篇关于python中图形图上的许多边缘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!