python中图形图上的许多边缘 [英] Lots of edges on a graph plot in python

查看:68
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆