我有以下脚本:
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条连接很少的边缘。这是我的情节: 以下是其中几个部分的放大图:
该图不可读,因为边缘之间的距离太小。如何在边缘之间有更大的距离?只有同一“家庭”的边缘之间的距离很小。
还有其他方法可以改善具有很多边缘的图吗? 我正在寻找可视化父子关联的任何方法,它可能是另一个python数据包。
答案 0 :(得分:9)
您似乎有很多小的,断开连接的组件。如果您想要一个信息图,我认为您应该按大小对连接的组件进行排序和分组。此外,许多网络布局算法的基本假设是只有一个巨型组件。因此,如果您需要合理的坐标,通常将需要分别计算每个组件的布局,然后相对于彼此布置组件。我将以这种方式重新绘制您的图表:
我已使用networkx
编写了该图的代码,因为这是我选择的模块。但是,将networkx
函数替换为igraph
函数将非常容易。您需要替换的两个功能是networkx.connected_component_subgraphs
以及您想用于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
:
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]
答案 1 :(得分:0)
您可以签出networkx,这是一个非常不错的图形库。 Networkx有direct plotting support for matplotlib。
它支持各种布局类型,例如spring layout, random layout, and a few more
您应该特别注意spring layout,其中有一些针对您的用例的有趣参数:
k(浮点数(默认值:无))–节点之间的最佳距离。如果没有 distance设置为1 / sqrt(n),其中n是节点数。增加 此值可将节点移得更远。
或将两者与自定义布局结合使用:
pos(dict或None可选(默认= None))–的初始位置 节点作为字典,节点作为键,值作为坐标 列表或元组。如果为None,则使用随机的初始位置。
已修复(列表或“无”可选(默认=“无”))–初始时要固定的节点 位置。
您也可以调整边缘粗细,以获得喜欢的结果:
weight(字符串或无可选(默认值=“ weight”))–边缘 该属性保存用于边缘权重的数值。如果 没有,则所有边缘权重均为1。
我建议将networkx与bokeh结合使用,这是一个新的绘图库,可以创建基于Web的html / js绘图。它直接支持networkx,并具有一些不错的功能,例如易于集成节点悬停工具。如果您的图形不太大,则性能会很好。 (我绘制了约20000个节点和几千条边的图形。
将这两个库组合在一起,您所需要的只是以下示例代码(来自文档),用于尝试构建优化的布局:
import networkx as nx
from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models.graphs import from_networkx
G=nx.karate_club_graph() # Replace with your own graph
plot = figure(title="Networkx Integration Demonstration", x_range=(-1.1,1.1), y_range=(-1.1,1.1),
tools="", toolbar_location=None)
graph = from_networkx(G, nx.spring_layout, scale=2, center=(0,0))
plot.renderers.append(graph)
output_file("networkx_graph.html")
show(plot)
答案 2 :(得分:0)
您知道您要寻找的意思吗?还是在探索?还是这是有关缩放问题的特定问题?
到目前为止,您已经很好地了解了整体结构。您可能会考虑使用一些例程来支持一些新的词汇,以支持它。例如,如果将小聚类设为点和边的集合,则可以绘制直方图,彼此重叠的聚类的可视化效果,比较有无长节点的聚类以及如此。