Skip to content

Commit

Permalink
Merge d933566 into a1e7809
Browse files Browse the repository at this point in the history
  • Loading branch information
hagberg committed Apr 20, 2014
2 parents a1e7809 + d933566 commit 0d5b187
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 21 deletions.
70 changes: 56 additions & 14 deletions networkx/convert_matrix.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
"""Functions to convert NetworkX graphs to and from other formats.
"""Functions to convert NetworkX graphs to and from numpy/scipy matrices.
The preferred way of converting data to a NetworkX graph is through the
graph constuctor. The constructor calls the to_networkx_graph() function
which attempts to guess the input type and convert it automatically.
Examples
--------
Create a 10 node random graph from a numpy matrix
>>> import numpy
>>> a=numpy.reshape(numpy.random.random_integers(0,1,size=100),(10,10))
>>> D=nx.DiGraph(a)
>>> a = numpy.reshape(numpy.random.random_integers(0,1,size=100),(10,10))
>>> D = nx.DiGraph(a)
or equivalently
>>> D=nx.to_networkx_graph(a,create_using=nx.DiGraph())
>>> D = nx.to_networkx_graph(a,create_using=nx.DiGraph())
See Also
--------
nx_pygraphviz, nx_pydot
"""
# Copyright (C) 2006-2013 by
# Copyright (C) 2006-2014 by
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
Expand Down Expand Up @@ -80,22 +79,38 @@ def to_numpy_matrix(G, nodelist=None, dtype=None, order=None,
Returns
-------
M : NumPy matrix
Graph adjacency matrix.
Graph adjacency matrix
See Also
--------
to_numpy_recarray, from_numpy_matrix
Notes
-----
The matrix entries are assigned with weight edge attribute. When
an edge does not have the weight attribute, the value of the entry is 1.
For multiple edges, the values of the entries are the sums of the edge
attributes for each edge.
The matrix entries are assigned to the weight edge attribute. When
an edge does not have a weight attribute, the value of the entry is set to
the number 1. For multiple (parallel) edges, the values of the entries
are determined by the 'multigraph_weight' paramter. The default is to
sum the weight attributes for each of the parallel edges.
When `nodelist` does not contain every node in `G`, the matrix is built
from the subgraph of `G` that is induced by the nodes in `nodelist`.
The convention used for self-loop edges in graphs is to assign the
diagonal matrix entry value to the weight attributr of the edge
(or the number 1 if the edge has no weight attribute). If the
alternate convention of doubling the edge weight is desired the
resulting Numpy matrix can be modified as follows:
>>> import numpy as np
>>> G = nx.Graph([(1,1)])
>>> A = nx.to_numpy_matrix(G)
>>> A
matrix([[ 1.]])
>>> A.A[np.diag_indices_from(A)] *= 2
>>> A
matrix([[ 2.]])
Examples
--------
>>> G = nx.MultiDiGraph()
Expand Down Expand Up @@ -394,6 +409,21 @@ def to_scipy_sparse_matrix(G, nodelist=None, dtype=None,
Uses coo_matrix format. To convert to other formats specify the
format= keyword.
The convention used for self-loop edges in graphs is to assign the
diagonal matrix entry value to the weight attribute of the edge
(or the number 1 if the edge has no weight attribute). If the
alternate convention of doubling the edge weight is desired the
resulting Scipy sparse matrix can be modified as follows:
>>> import scipy as sp
>>> G = nx.Graph([(1,1)])
>>> A = nx.to_scipy_sparse_matrix(G)
>>> print(A.todense())
[[1]]
>>> A.setdiag(A.diagonal()*2)
>>> print(A.todense())
[[2]]
Examples
--------
>>> G = nx.MultiDiGraph()
Expand Down Expand Up @@ -435,8 +465,20 @@ def to_scipy_sparse_matrix(G, nodelist=None, dtype=None,
shape=(nlen,nlen), dtype=dtype)
else:
# symmetrize matrix
M = sparse.coo_matrix((data+data, (row+col,col+row)),
shape=(nlen,nlen), dtype=dtype)
d = data + data
r = row + col
c = col + row
# selfloop entries get double counted when symmetrizing
# so we subtract the data on the diagonal
selfloops = G.selfloop_edges(data=True)
if selfloops:
diag_index,diag_data = zip(*((index[u],-d.get(weight,1))
for u,v,d in selfloops
if u in index and v in index))
d += diag_data
r += diag_index
c += diag_index
M = sparse.coo_matrix((d, (r, c)), shape=(nlen,nlen), dtype=dtype)
try:
return M.asformat(format)
except AttributeError:
Expand Down
22 changes: 19 additions & 3 deletions networkx/linalg/graphmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,28 @@ def adjacency_matrix(G, nodelist=None, weight='weight'):
dictionary-of-dictionaries format that can be addressed as a
sparse matrix.
For MultiGraph/MultiDiGraph, the edges weights are summed.
For MultiGraph/MultiDiGraph with parallel edges the weights are summed.
See to_numpy_matrix for other options.
The convention used for self-loop edges in graphs is to assign the
diagonal matrix entry value to the edge weight attribute
(or the number 1 if the edge has no weight attribute). If the
alternate convention of doubling the edge weight is desired the
resulting Scipy sparse matrix can be modified as follows:
>>> import scipy as sp
>>> G = nx.Graph([(1,1)])
>>> A = nx.adjacency_matrix(G)
>>> print(A.todense())
[[1]]
>>> A.setdiag(A.diagonal()*2)
>>> print(A.todense())
[[2]]
See Also
--------
to_numpy_matrix
to_scipy_sparse_matrix
to_dict_of_dicts
"""
return nx.to_scipy_sparse_matrix(G,nodelist=nodelist,weight=weight)
Expand All @@ -147,6 +163,6 @@ def adjacency_matrix(G, nodelist=None, weight='weight'):
def setup_module(module):
from nose import SkipTest
try:
import numpy
import scipy
except:
raise SkipTest("NumPy not available")
raise SkipTest("SciPy not available")
4 changes: 0 additions & 4 deletions networkx/linalg/laplacianmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,6 @@ def normalized_laplacian_matrix(G, nodelist=None, weight='weight'):
nodelist = G.nodes()
A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight,
format='csr')
# the convention for normalized Laplacian is to not count self loops
# twice in the diagonal. So we remove one here.
for n,_ in G.selfloop_edges():
A[n,n] -= 1
n,m = A.shape
diags = A.sum(axis=1).flatten()
D = scipy.sparse.spdiags(diags, [0], m, n, format='csr')
Expand Down
10 changes: 10 additions & 0 deletions networkx/tests/test_convert_scipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,13 @@ def test_ordering(self):
G.add_edge(3,1)
M = nx.to_scipy_sparse_matrix(G,nodelist=[3,2,1])
np_assert_equal(M.todense(), np.matrix([[0,0,1],[1,0,0],[0,1,0]]))

def test_selfloop_graph(self):
G = nx.Graph([(1,1)])
M = nx.to_scipy_sparse_matrix(G)
np_assert_equal(M.todense(), np.matrix([[1]]))

def test_selfloop_digraph(self):
G = nx.DiGraph([(1,1)])
M = nx.to_scipy_sparse_matrix(G)
np_assert_equal(M.todense(), np.matrix([[1]]))

0 comments on commit 0d5b187

Please sign in to comment.