Search code examples
pythonnumpypandasigraph

igraph Graph from numpy or pandas adjacency matrix


I have an adjacency matrix stored as a pandas.DataFrame:

node_names = ['A', 'B', 'C']
a = pd.DataFrame([[1,2,3],[3,1,1],[4,0,2]],
    index=node_names, columns=node_names)
a_numpy = a.as_matrix()

I'd like to create an igraph.Graph from either the pandas or the numpy adjacency matrices. In an ideal world the nodes would be named as expected.

Is this possible? The tutorial seems to be silent on the issue.


Solution

  • In igraph you can use igraph.Graph.Adjacency to create a graph from an adjacency matrix without having to use zip. There are some things to be aware of when a weighted adjacency matrix is used and stored in a np.array or pd.DataFrame.

    • igraph.Graph.Adjacency can't take an np.array as argument, but that is easily solved using tolist.

    • Integers in adjacency-matrix are interpreted as number of edges between nodes rather than weights, solved by using adjacency as boolean.

    An example of how to do it:

    import igraph
    import pandas as pd
    
    node_names = ['A', 'B', 'C']
    a = pd.DataFrame([[1,2,3],[3,1,1],[4,0,2]], index=node_names, columns=node_names)
    
    # Get the values as np.array, it's more convenenient.
    A = a.values
    
    # Create graph, A.astype(bool).tolist() or (A / A).tolist() can also be used.
    g = igraph.Graph.Adjacency((A > 0).tolist())
    
    # Add edge weights and node labels.
    g.es['weight'] = A[A.nonzero()]
    g.vs['label'] = node_names  # or a.index/a.columns
    

    You can reconstruct your adjacency dataframe using get_adjacency by:

    df_from_g = pd.DataFrame(g.get_adjacency(attribute='weight').data,
                             columns=g.vs['label'], index=g.vs['label'])
    (df_from_g == a).all().all()  # --> True