diff --git a/graphblas/io/_networkx.py b/graphblas/io/_networkx.py index 2324a11c2..3c62f27f2 100644 --- a/graphblas/io/_networkx.py +++ b/graphblas/io/_networkx.py @@ -31,7 +31,7 @@ def from_networkx(G, nodelist=None, dtype=None, weight="weight", name=None): # TODO: add parameters to allow different networkx classes and attribute names -def to_networkx(m, edge_attribute="weight"): +def to_networkx(m, edge_attribute="weight", create_isolates=False): """Create a networkx DiGraph from a square adjacency Matrix. Parameters @@ -41,6 +41,11 @@ def to_networkx(m, edge_attribute="weight"): edge_attribute : str, optional Name of edge attribute from values of Matrix. If None, values will be skipped. Default is "weight". + create_isolates : bool, optional + If row $i$ and column $i$ are both empty, then node $i$ is an isolate. By default, + these isolate nodes are ignored. If True, then the graph will also contain the + isolate nodes. Note that for very large adjacency matrices, creating isolates + will increase the memory footprint of the graph. Returns ------- @@ -56,4 +61,6 @@ def to_networkx(m, edge_attribute="weight"): G.add_edges_from(zip(rows, cols)) else: G.add_weighted_edges_from(zip(rows, cols, vals.tolist()), weight=edge_attribute) + if create_isolates: + G.add_nodes_from(range(max(m.shape))) return G diff --git a/graphblas/tests/test_io.py b/graphblas/tests/test_io.py index bf2ca2015..417ce0b50 100644 --- a/graphblas/tests/test_io.py +++ b/graphblas/tests/test_io.py @@ -169,6 +169,17 @@ def test_matrix_to_from_networkx(): assert M.nvals == 0 assert M.shape == (1, 1) + # test creation of isolates + M = gb.Matrix.from_edgelist([(0,1),(3,0)],nrows=5,ncols=5) + G = gb.io.to_networkx(M, create_isolates=True) + G_nx = nx.DiGraph() + G_nx.add_edges_from([(0,1),(3,0)]) + G_nx.add_nodes_from(range(5)) + assert G.number_of_edges() == G_nx.number_of_edges() == 2 + assert G.number_of_nodes() == G_nx.number_of_nodes() == 5 + from networkx.utils import graphs_equal + assert graphs_equal(G, G_nx) + @pytest.mark.skipif("not ss") @pytest.mark.parametrize("engine", ["auto", "scipy", "fmm"])