def from_biadjacency_matrix(A, create_using=None, edge_attribute='weight'): r"""Creates a new bipartite graph from a biadjacency matrix given as a SciPy sparse matrix. Parameters ---------- A: scipy sparse matrix A biadjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Notes ----- The nodes are labeled with the attribute `bipartite` set to an integer 0 or 1 representing membership in part 0 or part 1 of the bipartite graph. If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph` and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. In this case, `edge_attribute` will be ignored. See Also -------- biadjacency_matrix from_numpy_matrix References ---------- [1] http://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph """ G = _prep_create_using(create_using) n, m = A.shape # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n), bipartite=0) G.add_nodes_from(range(n,n+m), bipartite=1) # Create an iterable over (u, v, w) triples and for each triple, add an # edge from u to v with weight w. triples = ((u, n+v, d) for (u, v, d) in _generate_weighted_edges(A)) # If the entries in the adjacency matrix are integers and the graph is a # multigraph, then create parallel edges, each with weight 1, for each # entry in the adjacency matrix. Otherwise, create one edge for each # positive entry in the adjacency matrix and set the weight of that edge to # be the entry in the matrix. if A.dtype.kind in ('i', 'u') and G.is_multigraph(): chain = itertools.chain.from_iterable triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_biadjacency_matrix(A, create_using=None, edge_attribute='weight'): r"""Creates a new bipartite graph from a biadjacency matrix given as a SciPy sparse matrix. Parameters ---------- A: scipy sparse matrix A biadjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Notes ----- The nodes are labeled with the attribute `bipartite` set to an integer 0 or 1 representing membership in part 0 or part 1 of the bipartite graph. If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph` and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. In this case, `edge_attribute` will be ignored. See Also -------- biadjacency_matrix from_numpy_matrix References ---------- [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph """ G = _prep_create_using(create_using) n, m = A.shape # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n), bipartite=0) G.add_nodes_from(range(n, n + m), bipartite=1) # Create an iterable over (u, v, w) triples and for each triple, add an # edge from u to v with weight w. triples = ((u, n + v, d) for (u, v, d) in _generate_weighted_edges(A)) # If the entries in the adjacency matrix are integers and the graph is a # multigraph, then create parallel edges, each with weight 1, for each # entry in the adjacency matrix. Otherwise, create one edge for each # positive entry in the adjacency matrix and set the weight of that edge to # be the entry in the matrix. if A.dtype.kind in ('i', 'u') and G.is_multigraph(): chain = itertools.chain.from_iterable triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_scipy_sparse_matrix(A, create_using=None, edge_attribute='weight'): """Return a graph from scipy sparse matrix adjacency list. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attrbute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Examples -------- >>> import scipy.sparse >>> A = scipy.sparse.eye(2,2,1) >>> G = nx.from_scipy_sparse_matrix(A) """ G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError(\ "Adjacency matrix is not square. nx,ny=%s"%(A.shape,)) G.add_nodes_from(range(n)) # make sure we get isolated nodes if A.format == 'coo': for i, j, d in zip(A.row, A.col, A.data): G.add_edge(i, j, **{edge_attribute: d}) elif A.format == 'dia': # make a copy - could be done more efficiently B = A.tocoo() for i, j, d in zip(B.row, B.col, B.data): G.add_edge(i, j, **{edge_attribute: d}) else: for i, j in zip(*A.nonzero()): G.add_edge(i, j, **{edge_attribute: A[i, j]}) return G
def from_scipy_sparse_matrix(A, create_using=None, edge_attribute='weight'): """Return a graph from scipy sparse matrix adjacency list. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attrbute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Examples -------- >>> import scipy.sparse >>> A = scipy.sparse.eye(2,2,1) >>> G = nx.from_scipy_sparse_matrix(A) """ G = _prep_create_using(create_using) n,m = A.shape if n != m: raise nx.NetworkXError(\ "Adjacency matrix is not square. nx,ny=%s"%(A.shape,)) G.add_nodes_from(range(n)) # make sure we get isolated nodes if A.format == 'coo': for i,j,d in zip(A.row, A.col, A.data): G.add_edge(i,j,**{edge_attribute:d}) elif A.format == 'dia': # make a copy - could be done more efficiently B = A.tocoo() for i,j,d in zip(B.row, B.col, B.data): G.add_edge(i,j,**{edge_attribute:d}) else: for i,j in zip(*A.nonzero()): G.add_edge(i,j,**{edge_attribute:A[i,j]}) return G
def from_scipy_sparse_matrix(A, create_using=None, edge_attribute='weight'): """Return a graph from scipy sparse matrix adjacency list. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Examples -------- >>> import scipy.sparse >>> A = scipy.sparse.eye(2,2,1) >>> G = nx.from_scipy_sparse_matrix(A) """ G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError(\ "Adjacency matrix is not square. nx,ny=%s"%(A.shape,)) G.add_nodes_from(range(n)) # make sure we get isolated nodes if A.format == 'csr': triples = _csr_gen_triples(A) elif A.format == 'csc': triples = _csc_gen_triples(A) elif A.format == 'dok': triples = _dok_gen_triples(A) else: if A.format != 'coo': A = A.tocoo() triples = _coo_gen_triples(A) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_scipy_sparse_matrix(A, create_using=None, edge_attribute='weight'): """Return a graph from scipy sparse matrix adjacency list. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Examples -------- >>> import scipy.sparse >>> A = scipy.sparse.eye(2,2,1) >>> G = nx.from_scipy_sparse_matrix(A) """ G = _prep_create_using(create_using) n,m = A.shape if n != m: raise nx.NetworkXError(\ "Adjacency matrix is not square. nx,ny=%s"%(A.shape,)) G.add_nodes_from(range(n)) # make sure we get isolated nodes if A.format == 'csr': triples = _csr_gen_triples(A) elif A.format == 'csc': triples = _csc_gen_triples(A) elif A.format == 'dok': triples = _dok_gen_triples(A) else: if A.format != 'coo': A = A.tocoo() triples = _coo_gen_triples(A) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_scipy_sparse_matrix(A, parallel_edges=False, create_using=None, edge_attribute='weight'): """Creates a new graph from an adjacency matrix given as a SciPy sparse matrix. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph parallel_edges : Boolean If this is True, `create_using` is a multigraph, and `A` is an integer matrix, then entry *(i, j)* in the matrix is interpreted as the number of parallel edges joining vertices *i* and *j* in the graph. If it is False, then the entries in the adjacency matrix are interpreted as the weight of a single edge joining the vertices. create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Notes ----- If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. In this case, `edge_attribute` will be ignored. If `create_using` is an undirected multigraph, then only the edges indicated by the upper triangle of the matrix `A` will be added to the graph. Examples -------- >>> import scipy.sparse >>> A = scipy.sparse.eye(2,2,1) >>> G = nx.from_scipy_sparse_matrix(A) If `create_using` is a multigraph and the matrix has only integer entries, the entries will be interpreted as weighted edges joining the vertices (without creating parallel edges): >>> import scipy >>> A = scipy.sparse.csr_matrix([[1, 1], [1, 2]]) >>> G = nx.from_scipy_sparse_matrix(A, create_using=nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 2}}) If `create_using` is a multigraph and the matrix has only integer entries but `parallel_edges` is True, then the entries will be interpreted as the number of parallel edges joining those two vertices: >>> import scipy >>> A = scipy.sparse.csr_matrix([[1, 1], [1, 2]]) >>> G = nx.from_scipy_sparse_matrix(A, parallel_edges=True, ... create_using=nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) """ G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError("Adjacency matrix is not square. nx,ny=%s" % (A.shape, )) # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n)) # Create an iterable over (u, v, w) triples and for each triple, add an # edge from u to v with weight w. triples = _generate_weighted_edges(A) # If the entries in the adjacency matrix are integers, the graph is a # multigraph, and parallel_edges is True, then create parallel edges, each # with weight 1, for each entry in the adjacency matrix. Otherwise, create # one edge for each positive entry in the adjacency matrix and set the # weight of that edge to be the entry in the matrix. if A.dtype.kind in ('i', 'u') and G.is_multigraph() and parallel_edges: chain = itertools.chain.from_iterable # The following line is equivalent to: # # for (u, v) in edges: # for d in range(A[u, v]): # G.add_edge(u, v, weight=1) # triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) # If we are creating an undirected multigraph, only add the edges from the # upper triangle of the matrix. Otherwise, add all the edges. This relies # on the fact that the vertices created in the # `_generated_weighted_edges()` function are actually the row/column # indices for the matrix `A`. # # Without this check, we run into a problem where each edge is added twice # when `G.add_weighted_edges_from()` is invoked below. if G.is_multigraph() and not G.is_directed(): triples = ((u, v, d) for u, v, d in triples if u <= v) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_numpy_matrix(A, parallel_edges=False, create_using=None): """Return a graph from numpy matrix. The numpy matrix is interpreted as an adjacency matrix for the graph. Parameters ---------- A : numpy matrix An adjacency matrix representation of a graph parallel_edges : Boolean If this is True, `create_using` is a multigraph, and `A` is an integer matrix, then entry *(i, j)* in the matrix is interpreted as the number of parallel edges joining vertices *i* and *j* in the graph. If it is False, then the entries in the adjacency matrix are interpreted as the weight of a single edge joining the vertices. create_using : NetworkX graph Use specified graph for result. The default is Graph() Notes ----- If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. If `create_using` is an undirected multigraph, then only the edges indicated by the upper triangle of the matrix `A` will be added to the graph. If the numpy matrix has a single data type for each matrix entry it will be converted to an appropriate Python data type. If the numpy matrix has a user-specified compound data type the names of the data fields will be used as attribute keys in the resulting NetworkX graph. See Also -------- to_numpy_matrix, to_numpy_recarray Examples -------- Simple integer weights on edges: >>> import numpy >>> A=numpy.matrix([[1, 1], [2, 1]]) >>> G=nx.from_numpy_matrix(A) If `create_using` is a multigraph and the matrix has only integer entries, the entries will be interpreted as weighted edges joining the vertices (without creating parallel edges): >>> import numpy >>> A = numpy.matrix([[1, 1], [1, 2]]) >>> G = nx.from_numpy_matrix(A, create_using = nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 2}}) If `create_using` is a multigraph and the matrix has only integer entries but `parallel_edges` is True, then the entries will be interpreted as the number of parallel edges joining those two vertices: >>> import numpy >>> A = numpy.matrix([[1, 1], [1, 2]]) >>> temp = nx.MultiGraph() >>> G = nx.from_numpy_matrix(A, parallel_edges = True, create_using = temp) >>> G[1][1] AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) User defined compound data type on edges: >>> import numpy >>> dt = [('weight', float), ('cost', int)] >>> A = numpy.matrix([[(1.0, 2)]], dtype = dt) >>> G = nx.from_numpy_matrix(A) >>> list(G.edges()) [(0, 0)] >>> G[0][0]['cost'] 2 >>> G[0][0]['weight'] 1.0 """ # This should never fail if you have created a numpy matrix with numpy... import numpy as np kind_to_python_type = { 'f': float, 'i': int, 'u': int, 'b': bool, 'c': complex, 'S': str, 'V': 'void' } try: # Python 3.x blurb = chr(1245) # just to trigger the exception kind_to_python_type['U'] = str except ValueError: # Python 2.6+ kind_to_python_type['U'] = unicode G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError("Adjacency matrix is not square.", "nx,ny=%s" % (A.shape, )) dt = A.dtype try: python_type = kind_to_python_type[dt.kind] except: raise TypeError("Unknown numpy data type: %s" % dt) # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n)) # Get a list of all the entries in the matrix with nonzero entries. These # coordinates will become the edges in the graph. edges = zip(*(np.asarray(A).nonzero())) # handle numpy constructed data type if python_type is 'void': # Sort the fields by their offset, then by dtype, then by name. fields = sorted((offset, dtype, name) for name, (dtype, offset) in A.dtype.fields.items()) triples = ((u, v, { name: kind_to_python_type[dtype.kind](val) for (_, dtype, name), val in zip(fields, A[u, v]) }) for u, v in edges) # If the entries in the adjacency matrix are integers, the graph is a # multigraph, and parallel_edges is True, then create parallel edges, each # with weight 1, for each entry in the adjacency matrix. Otherwise, create # one edge for each positive entry in the adjacency matrix and set the # weight of that edge to be the entry in the matrix. elif python_type is int and G.is_multigraph() and parallel_edges: chain = itertools.chain.from_iterable # The following line is equivalent to: # # for (u, v) in edges: # for d in range(A[u, v]): # G.add_edge(u, v, weight=1) # triples = chain(((u, v, dict(weight=1)) for d in range(A[u, v])) for (u, v) in edges) else: # basic data type triples = ((u, v, dict(weight=python_type(A[u, v]))) for u, v in edges) # If we are creating an undirected multigraph, only add the edges from the # upper triangle of the matrix. Otherwise, add all the edges. This relies # on the fact that the vertices created in the # `_generated_weighted_edges()` function are actually the row/column # indices for the matrix `A`. # # Without this check, we run into a problem where each edge is added twice # when `G.add_edges_from()` is invoked below. if G.is_multigraph() and not G.is_directed(): triples = ((u, v, d) for u, v, d in triples if u <= v) G.add_edges_from(triples) return G
def from_pandas_dataframe(df, source='source', target='target', edge_attr=None, create_using=None): """Return a graph from Pandas DataFrame containing an edge list. The Pandas DataFrame should contain at least two columns of node names and zero or more columns of node attributes. Each row will be processed as one edge instance. Note: This function iterates over DataFrame.values, which is not guaranteed to retain the data type across columns in the row. This is only a problem if your row is entirely numeric and a mix of ints and floats. In that case, all values will be returned as floats. See the DataFrame.iterrows documentation for an example. Parameters ---------- df : Pandas DataFrame An edge list representation of a graph source : str or int A valid column name (string or iteger) for the source nodes (for the directed case). target : str or int A valid column name (string or iteger) for the target nodes (for the directed case). edge_attr : str or int, iterable, True A valid column name (str or integer) or list of column names that will be used to retrieve items from the row and add them to the graph as edge attributes. If `True`, all of the remaining columns will be added. create_using : NetworkX graph Use specified graph for result. The default is Graph() See Also -------- to_pandas_dataframe Examples -------- Simple integer weights on edges: >>> import pandas as pd >>> import numpy as np >>> r = np.random.RandomState(seed=5) >>> ints = r.random_integers(1, 10, size=(3,2)) >>> a = ['A', 'B', 'C'] >>> b = ['D', 'A', 'E'] >>> df = pd.DataFrame(ints, columns=['weight', 'cost']) >>> df[0] = a >>> df['b'] = b >>> df weight cost 0 b 0 4 7 A D 1 7 1 B A 2 10 9 C E >>> G=nx.from_pandas_dataframe(df, 0, 'b', ['weight', 'cost']) >>> G['E']['C']['weight'] 10 >>> G['E']['C']['cost'] 9 >>> edges = pd.DataFrame({'source': [0, 1, 2], ... 'target': [2, 2, 3], ... 'weight': [3, 4, 5], ... 'color': ['red', 'blue', 'blue']}) >>> G = nx.from_pandas_dataframe(edges, edge_attr=True) >>> G[0][2]['color'] 'red' """ g = _prep_create_using(create_using) # Index of source and target src_i = df.columns.get_loc(source) tar_i = df.columns.get_loc(target) if edge_attr: # If all additional columns requested, build up a list of tuples # [(name, index),...] if edge_attr is True: # Create a list of all columns indices, ignore nodes edge_i = [] for i, col in enumerate(df.columns): if col is not source and col is not target: edge_i.append((col, i)) # If a list or tuple of name is requested elif isinstance(edge_attr, (list, tuple)): edge_i = [(i, df.columns.get_loc(i)) for i in edge_attr] # If a string or int is passed else: edge_i = [ (edge_attr, df.columns.get_loc(edge_attr)), ] # Iteration on values returns the rows as Numpy arrays for row in df.values: s, t = row[src_i], row[tar_i] if g.is_multigraph(): g.add_edge(s, t) key = max( g[s][t]) # default keys just count, so max is most recent g[s][t][key].update((i, row[j]) for i, j in edge_i) else: g.add_edge(s, t) g[s][t].update((i, row[j]) for i, j in edge_i) # If no column names are given, then just return the edges. else: for row in df.values: g.add_edge(row[src_i], row[tar_i]) return g
def from_scipy_sparse_matrix(A, parallel_edges=False, create_using=None, edge_attribute='weight'): """Creates a new graph from an adjacency matrix given as a SciPy sparse matrix. Parameters ---------- A: scipy sparse matrix An adjacency matrix representation of a graph parallel_edges : Boolean If this is True, `create_using` is a multigraph, and `A` is an integer matrix, then entry *(i, j)* in the matrix is interpreted as the number of parallel edges joining vertices *i* and *j* in the graph. If it is False, then the entries in the adjacency matrix are interpreted as the weight of a single edge joining the vertices. create_using: NetworkX graph Use specified graph for result. The default is Graph() edge_attribute: string Name of edge attribute to store matrix numeric value. The data will have the same type as the matrix entry (int, float, (real,imag)). Notes ----- If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. In this case, `edge_attribute` will be ignored. If `create_using` is an undirected multigraph, then only the edges indicated by the upper triangle of the matrix `A` will be added to the graph. Examples -------- >>> import scipy as sp >>> A = sp.sparse.eye(2, 2, 1) >>> G = nx.from_scipy_sparse_matrix(A) If `create_using` is a multigraph and the matrix has only integer entries, the entries will be interpreted as weighted edges joining the vertices (without creating parallel edges): >>> A = sp.sparse.csr_matrix([[1, 1], [1, 2]]) >>> G = nx.from_scipy_sparse_matrix(A, create_using=nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 2}}) If `create_using` is a multigraph and the matrix has only integer entries but `parallel_edges` is True, then the entries will be interpreted as the number of parallel edges joining those two vertices: >>> A = sp.sparse.csr_matrix([[1, 1], [1, 2]]) >>> G = nx.from_scipy_sparse_matrix(A, parallel_edges=True, ... create_using=nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) """ G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError( "Adjacency matrix is not square. nx,ny=%s" % (A.shape,)) # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n)) # Create an iterable over (u, v, w) triples and for each triple, add an # edge from u to v with weight w. triples = _generate_weighted_edges(A) # If the entries in the adjacency matrix are integers, the graph is a # multigraph, and parallel_edges is True, then create parallel edges, each # with weight 1, for each entry in the adjacency matrix. Otherwise, create # one edge for each positive entry in the adjacency matrix and set the # weight of that edge to be the entry in the matrix. if A.dtype.kind in ('i', 'u') and G.is_multigraph() and parallel_edges: chain = itertools.chain.from_iterable # The following line is equivalent to: # # for (u, v) in edges: # for d in range(A[u, v]): # G.add_edge(u, v, weight=1) # triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) # If we are creating an undirected multigraph, only add the edges from the # upper triangle of the matrix. Otherwise, add all the edges. This relies # on the fact that the vertices created in the # `_generated_weighted_edges()` function are actually the row/column # indices for the matrix `A`. # # Without this check, we run into a problem where each edge is added twice # when `G.add_weighted_edges_from()` is invoked below. if G.is_multigraph() and not G.is_directed(): triples = ((u, v, d) for u, v, d in triples if u <= v) G.add_weighted_edges_from(triples, weight=edge_attribute) return G
def from_numpy_matrix(A, parallel_edges=False, create_using=None): """Return a graph from numpy matrix. The numpy matrix is interpreted as an adjacency matrix for the graph. Parameters ---------- A : numpy matrix An adjacency matrix representation of a graph parallel_edges : Boolean If this is True, `create_using` is a multigraph, and `A` is an integer matrix, then entry *(i, j)* in the matrix is interpreted as the number of parallel edges joining vertices *i* and *j* in the graph. If it is False, then the entries in the adjacency matrix are interpreted as the weight of a single edge joining the vertices. create_using : NetworkX graph Use specified graph for result. The default is Graph() Notes ----- If `create_using` is an instance of :class:`networkx.MultiGraph` or :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the entries of `A` are of type :class:`int`, then this function returns a multigraph (of the same type as `create_using`) with parallel edges. If `create_using` is an undirected multigraph, then only the edges indicated by the upper triangle of the matrix `A` will be added to the graph. If the numpy matrix has a single data type for each matrix entry it will be converted to an appropriate Python data type. If the numpy matrix has a user-specified compound data type the names of the data fields will be used as attribute keys in the resulting NetworkX graph. See Also -------- to_numpy_matrix, to_numpy_recarray Examples -------- Simple integer weights on edges: >>> import numpy as np >>> A = np.matrix([[1, 1], [2, 1]]) >>> G = nx.from_numpy_matrix(A) If `create_using` is a multigraph and the matrix has only integer entries, the entries will be interpreted as weighted edges joining the vertices (without creating parallel edges): >>> A = np.matrix([[1, 1], [1, 2]]) >>> G = nx.from_numpy_matrix(A, create_using=nx.MultiGraph()) >>> G[1][1] AtlasView({0: {'weight': 2}}) If `create_using` is a multigraph and the matrix has only integer entries but `parallel_edges` is True, then the entries will be interpreted as the number of parallel edges joining those two vertices: >>> A = np.matrix([[1, 1], [1, 2]]) >>> temp = nx.MultiGraph() >>> G = nx.from_numpy_matrix(A, parallel_edges=True, create_using=temp) >>> G[1][1] AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) User defined compound data type on edges: >>> dt = [('weight', float), ('cost', int)] >>> A = np.matrix([[(1.0, 2)]], dtype=dt) >>> G = nx.from_numpy_matrix(A) >>> list(G.edges()) [(0, 0)] >>> G[0][0]['cost'] 2 >>> G[0][0]['weight'] 1.0 """ # This should never fail if you have created a numpy matrix with numpy... import numpy as np kind_to_python_type = {'f': float, 'i': int, 'u': int, 'b': bool, 'c': complex, 'S': str, 'V': 'void'} try: # Python 3.x blurb = chr(1245) # just to trigger the exception kind_to_python_type['U'] = str except ValueError: # Python 2.7 kind_to_python_type['U'] = unicode G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError("Adjacency matrix is not square.", "nx,ny=%s" % (A.shape,)) dt = A.dtype try: python_type = kind_to_python_type[dt.kind] except: raise TypeError("Unknown numpy data type: %s" % dt) # Make sure we get even the isolated nodes of the graph. G.add_nodes_from(range(n)) # Get a list of all the entries in the matrix with nonzero entries. These # coordinates will become the edges in the graph. edges = zip(*(np.asarray(A).nonzero())) # handle numpy constructed data type if python_type is 'void': # Sort the fields by their offset, then by dtype, then by name. fields = sorted((offset, dtype, name) for name, (dtype, offset) in A.dtype.fields.items()) triples = ((u, v, {name: kind_to_python_type[dtype.kind](val) for (_, dtype, name), val in zip(fields, A[u, v])}) for u, v in edges) # If the entries in the adjacency matrix are integers, the graph is a # multigraph, and parallel_edges is True, then create parallel edges, each # with weight 1, for each entry in the adjacency matrix. Otherwise, create # one edge for each positive entry in the adjacency matrix and set the # weight of that edge to be the entry in the matrix. elif python_type is int and G.is_multigraph() and parallel_edges: chain = itertools.chain.from_iterable # The following line is equivalent to: # # for (u, v) in edges: # for d in range(A[u, v]): # G.add_edge(u, v, weight=1) # triples = chain(((u, v, dict(weight=1)) for d in range(A[u, v])) for (u, v) in edges) else: # basic data type triples = ((u, v, dict(weight=python_type(A[u, v]))) for u, v in edges) # If we are creating an undirected multigraph, only add the edges from the # upper triangle of the matrix. Otherwise, add all the edges. This relies # on the fact that the vertices created in the # `_generated_weighted_edges()` function are actually the row/column # indices for the matrix `A`. # # Without this check, we run into a problem where each edge is added twice # when `G.add_edges_from()` is invoked below. if G.is_multigraph() and not G.is_directed(): triples = ((u, v, d) for u, v, d in triples if u <= v) G.add_edges_from(triples) return G
def from_pandas_edgelist(df, source='source', target='target', edge_attr=None, create_using=None): """Return a graph from Pandas DataFrame containing an edge list. The Pandas DataFrame should contain at least two columns of node names and zero or more columns of node attributes. Each row will be processed as one edge instance. Note: This function iterates over DataFrame.values, which is not guaranteed to retain the data type across columns in the row. This is only a problem if your row is entirely numeric and a mix of ints and floats. In that case, all values will be returned as floats. See the DataFrame.iterrows documentation for an example. Parameters ---------- df : Pandas DataFrame An edge list representation of a graph source : str or int A valid column name (string or iteger) for the source nodes (for the directed case). target : str or int A valid column name (string or iteger) for the target nodes (for the directed case). edge_attr : str or int, iterable, True A valid column name (str or integer) or list of column names that will be used to retrieve items from the row and add them to the graph as edge attributes. If `True`, all of the remaining columns will be added. create_using : NetworkX graph Use specified graph for result. The default is Graph() See Also -------- to_pandas_edgelist Examples -------- Simple integer weights on edges: >>> import pandas as pd >>> import numpy as np >>> r = np.random.RandomState(seed=5) >>> ints = r.random_integers(1, 10, size=(3,2)) >>> a = ['A', 'B', 'C'] >>> b = ['D', 'A', 'E'] >>> df = pd.DataFrame(ints, columns=['weight', 'cost']) >>> df[0] = a >>> df['b'] = b >>> df weight cost 0 b 0 4 7 A D 1 7 1 B A 2 10 9 C E >>> G = nx.from_pandas_edgelist(df, 0, 'b', ['weight', 'cost']) >>> G['E']['C']['weight'] 10 >>> G['E']['C']['cost'] 9 >>> edges = pd.DataFrame({'source': [0, 1, 2], ... 'target': [2, 2, 3], ... 'weight': [3, 4, 5], ... 'color': ['red', 'blue', 'blue']}) >>> G = nx.from_pandas_edgelist(edges, edge_attr=True) >>> G[0][2]['color'] 'red' """ g = _prep_create_using(create_using) # Index of source and target src_i = df.columns.get_loc(source) tar_i = df.columns.get_loc(target) if edge_attr: # If all additional columns requested, build up a list of tuples # [(name, index),...] if edge_attr is True: # Create a list of all columns indices, ignore nodes edge_i = [] for i, col in enumerate(df.columns): if col is not source and col is not target: edge_i.append((col, i)) # If a list or tuple of name is requested elif isinstance(edge_attr, (list, tuple)): edge_i = [(i, df.columns.get_loc(i)) for i in edge_attr] # If a string or int is passed else: edge_i = [(edge_attr, df.columns.get_loc(edge_attr)), ] # Iteration on values returns the rows as Numpy arrays for row in df.values: s, t = row[src_i], row[tar_i] if g.is_multigraph(): g.add_edge(s, t) key = max(g[s][t]) # default keys just count, so max is most recent g[s][t][key].update((i, row[j]) for i, j in edge_i) else: g.add_edge(s, t) g[s][t].update((i, row[j]) for i, j in edge_i) # If no column names are given, then just return the edges. else: for row in df.values: g.add_edge(row[src_i], row[tar_i]) return g
def from_numpy_matrix(A, create_using=None): """Return a graph from numpy matrix. The numpy matrix is interpreted as an adjacency matrix for the graph. Parameters ---------- A : numpy matrix An adjacency matrix representation of a graph create_using : NetworkX graph Use specified graph for result. The default is Graph() Notes ----- If the numpy matrix has a single data type for each matrix entry it will be converted to an appropriate Python data type. If the numpy matrix has a user-specified compound data type the names of the data fields will be used as attribute keys in the resulting NetworkX graph. See Also -------- to_numpy_matrix, to_numpy_recarray Examples -------- Simple integer weights on edges: >>> import numpy >>> A=numpy.matrix([[1,1],[2,1]]) >>> G=nx.from_numpy_matrix(A) User defined compound data type on edges: >>> import numpy >>> dt=[('weight',float),('cost',int)] >>> A=numpy.matrix([[(1.0,2)]],dtype=dt) >>> G=nx.from_numpy_matrix(A) >>> G.edges() [(0, 0)] >>> G[0][0]['cost'] 2 >>> G[0][0]['weight'] 1.0 """ # This should never fail if you have created a numpy matrix with numpy... import numpy as np kind_to_python_type = { 'f': float, 'i': int, 'u': int, 'b': bool, 'c': complex, 'S': str, 'V': 'void' } try: # Python 3.x blurb = chr(1245) # just to trigger the exception kind_to_python_type['U'] = str except ValueError: # Python 2.6+ kind_to_python_type['U'] = unicode G = _prep_create_using(create_using) n, m = A.shape if n != m: raise nx.NetworkXError("Adjacency matrix is not square.", "nx,ny=%s" % (A.shape, )) dt = A.dtype try: python_type = kind_to_python_type[dt.kind] except: raise TypeError("Unknown numpy data type: %s" % dt) # make sure we get isolated nodes G.add_nodes_from(range(n)) # get a list of edges x, y = np.asarray(A).nonzero() # handle numpy constructed data type if python_type is 'void': fields = sorted([(offset, dtype, name) for name, (dtype, offset) in A.dtype.fields.items()]) for (u, v) in zip(x, y): attr = {} for (offset, dtype, name), val in zip(fields, A[u, v]): attr[name] = kind_to_python_type[dtype.kind](val) G.add_edge(u, v, attr) else: # basic data type G.add_edges_from(((u, v, { 'weight': python_type(A[u, v]) }) for (u, v) in zip(x, y))) return G
def parse_edgelist(lines, comments='#', delimiter=None, create_using=None, nodetype=None, data=True): """Parse lines of an edge list representation of a bipartite graph. Parameters ---------- lines : list or iterator of strings Input data in edgelist format comments : string, optional Marker for comment lines delimiter : string, optional Separator for node labels create_using: NetworkX graph container, optional Use given NetworkX graph for holding nodes or edges. nodetype : Python type, optional Convert nodes to this type. data : bool or list of (label,type) tuples If False generate no edge data or if True use a dictionary representation of edge data or a list tuples specifying dictionary key names and types for edge data. Returns ------- G: NetworkX Graph The bipartite graph corresponding to lines Examples -------- Edgelist with no data: >>> from networkx.algorithms import bipartite >>> lines = ["1 2", ... "2 3", ... "3 4"] >>> G = bipartite.parse_edgelist(lines, nodetype = int) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.nodes(data=True)) [(1, {'bipartite': 0}), (2, {'bipartite': 0}), (3, {'bipartite': 0}), (4, {'bipartite': 1})] >>> sorted(G.edges()) [(1, 2), (2, 3), (3, 4)] Edgelist with data in Python dictionary representation: >>> lines = ["1 2 {'weight':3}", ... "2 3 {'weight':27}", ... "3 4 {'weight':3.0}"] >>> G = bipartite.parse_edgelist(lines, nodetype = int) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.edges(data = True)) [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] Edgelist with data in a list: >>> lines = ["1 2 3", ... "2 3 27", ... "3 4 3.0"] >>> G = bipartite.parse_edgelist(lines, nodetype = int, data=(('weight',float),)) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.edges(data = True)) [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] See Also -------- """ from ast import literal_eval G = _prep_create_using(create_using) for line in lines: p=line.find(comments) if p>=0: line = line[:p] if not len(line): continue # split line, should have 2 or more s=line.strip().split(delimiter) if len(s)<2: continue u=s.pop(0) v=s.pop(0) d=s if nodetype is not None: try: u=nodetype(u) v=nodetype(v) except: raise TypeError("Failed to convert nodes %s,%s to type %s." %(u,v,nodetype)) if len(d)==0 or data is False: # no data or data type specified edgedata={} elif data is True: # no edge types specified try: # try to evaluate as dictionary edgedata=dict(literal_eval(' '.join(d))) except: raise TypeError( "Failed to convert edge data (%s) to dictionary."%(d)) else: # convert edge data to dictionary with specified keys and type if len(d)!=len(data): raise IndexError( "Edge data %s and data_keys %s are not the same length"% (d, data)) edgedata={} for (edge_key,edge_type),edge_value in zip(data,d): try: edge_value=edge_type(edge_value) except: raise TypeError( "Failed to convert %s data %s to type %s." %(edge_key, edge_value, edge_type)) edgedata.update({edge_key:edge_value}) G.add_node(u, bipartite=0) G.add_node(v, bipartite=1) G.add_edge(u, v, attr_dict=edgedata) return G
def parse_edgelist(lines, comments='#', delimiter=None, create_using=None, nodetype=None, data=True): """Parse lines of an edge list representation of a bipartite graph. Parameters ---------- lines : list or iterator of strings Input data in edgelist format comments : string, optional Marker for comment lines delimiter : string, optional Separator for node labels create_using: NetworkX graph container, optional Use given NetworkX graph for holding nodes or edges. nodetype : Python type, optional Convert nodes to this type. data : bool or list of (label,type) tuples If False generate no edge data or if True use a dictionary representation of edge data or a list tuples specifying dictionary key names and types for edge data. Returns ------- G: NetworkX Graph The bipartite graph corresponding to lines Examples -------- Edgelist with no data: >>> from networkx.algorithms import bipartite >>> lines = ["1 2", ... "2 3", ... "3 4"] >>> G = bipartite.parse_edgelist(lines, nodetype = int) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.nodes(data=True)) [(1, {'bipartite': 0}), (2, {'bipartite': 0}), (3, {'bipartite': 0}), (4, {'bipartite': 1})] >>> sorted(G.edges()) [(1, 2), (2, 3), (3, 4)] Edgelist with data in Python dictionary representation: >>> lines = ["1 2 {'weight':3}", ... "2 3 {'weight':27}", ... "3 4 {'weight':3.0}"] >>> G = bipartite.parse_edgelist(lines, nodetype = int) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.edges(data = True)) [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] Edgelist with data in a list: >>> lines = ["1 2 3", ... "2 3 27", ... "3 4 3.0"] >>> G = bipartite.parse_edgelist(lines, nodetype = int, data=(('weight',float),)) >>> sorted(G.nodes()) [1, 2, 3, 4] >>> sorted(G.edges(data = True)) [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] See Also -------- """ from ast import literal_eval G = _prep_create_using(create_using) for line in lines: p = line.find(comments) if p >= 0: line = line[:p] if not len(line): continue # split line, should have 2 or more s = line.strip().split(delimiter) if len(s) < 2: continue u = s.pop(0) v = s.pop(0) d = s if nodetype is not None: try: u = nodetype(u) v = nodetype(v) except: raise TypeError("Failed to convert nodes %s,%s to type %s." % (u, v, nodetype)) if len(d) == 0 or data is False: # no data or data type specified edgedata = {} elif data is True: # no edge types specified try: # try to evaluate as dictionary edgedata = dict(literal_eval(' '.join(d))) except: raise TypeError( "Failed to convert edge data (%s) to dictionary." % (d)) else: # convert edge data to dictionary with specified keys and type if len(d) != len(data): raise IndexError( "Edge data %s and data_keys %s are not the same length" % (d, data)) edgedata = {} for (edge_key, edge_type), edge_value in zip(data, d): try: edge_value = edge_type(edge_value) except: raise TypeError( "Failed to convert %s data %s to type %s." % (edge_key, edge_value, edge_type)) edgedata.update({edge_key: edge_value}) G.add_node(u, bipartite=0) G.add_node(v, bipartite=1) G.add_edge(u, v, attr_dict=edgedata) return G
def from_numpy_matrix(A,create_using=None): """Return a graph from numpy matrix. The numpy matrix is interpreted as an adjacency matrix for the graph. Parameters ---------- A : numpy matrix An adjacency matrix representation of a graph create_using : NetworkX graph Use specified graph for result. The default is Graph() Notes ----- If the numpy matrix has a single data type for each matrix entry it will be converted to an appropriate Python data type. If the numpy matrix has a user-specified compound data type the names of the data fields will be used as attribute keys in the resulting NetworkX graph. See Also -------- to_numpy_matrix, to_numpy_recarray Examples -------- Simple integer weights on edges: >>> import numpy >>> A=numpy.matrix([[1,1],[2,1]]) >>> G=nx.from_numpy_matrix(A) User defined compound data type on edges: >>> import numpy >>> dt=[('weight',float),('cost',int)] >>> A=numpy.matrix([[(1.0,2)]],dtype=dt) >>> G=nx.from_numpy_matrix(A) >>> G.edges() [(0, 0)] >>> G[0][0]['cost'] 2 >>> G[0][0]['weight'] 1.0 """ # This should never fail if you have created a numpy matrix with numpy... import numpy as np kind_to_python_type={'f':float, 'i':int, 'u':int, 'b':bool, 'c':complex, 'S':str, 'V':'void'} try: # Python 3.x blurb = chr(1245) # just to trigger the exception kind_to_python_type['U']=str except ValueError: # Python 2.6+ kind_to_python_type['U']=unicode G=_prep_create_using(create_using) n,m=A.shape if n!=m: raise nx.NetworkXError("Adjacency matrix is not square.", "nx,ny=%s"%(A.shape,)) dt=A.dtype try: python_type=kind_to_python_type[dt.kind] except: raise TypeError("Unknown numpy data type: %s"%dt) # make sure we get isolated nodes G.add_nodes_from(range(n)) # get a list of edges x,y=np.asarray(A).nonzero() # handle numpy constructed data type if python_type is 'void': fields=sorted([(offset,dtype,name) for name,(dtype,offset) in A.dtype.fields.items()]) for (u,v) in zip(x,y): attr={} for (offset,dtype,name),val in zip(fields,A[u,v]): attr[name]=kind_to_python_type[dtype.kind](val) G.add_edge(u,v,attr) else: # basic data type G.add_edges_from( ((u,v,{'weight':python_type(A[u,v])}) for (u,v) in zip(x,y)) ) return G