|
|
import pytest |
|
|
|
|
|
import networkx as nx |
|
|
from networkx.utils import edges_equal, graphs_equal, nodes_equal |
|
|
|
|
|
np = pytest.importorskip("numpy") |
|
|
pd = pytest.importorskip("pandas") |
|
|
|
|
|
|
|
|
class TestConvertPandas: |
|
|
def setup_method(self): |
|
|
self.rng = np.random.RandomState(seed=5) |
|
|
ints = self.rng.randint(1, 11, size=(3, 2)) |
|
|
a = ["A", "B", "C"] |
|
|
b = ["D", "A", "E"] |
|
|
df = pd.DataFrame(ints, columns=["weight", "cost"]) |
|
|
df[0] = a |
|
|
df["b"] = b |
|
|
self.df = df |
|
|
|
|
|
mdf = pd.DataFrame([[4, 16, "A", "D"]], columns=["weight", "cost", 0, "b"]) |
|
|
self.mdf = pd.concat([df, mdf]) |
|
|
|
|
|
def test_exceptions(self): |
|
|
G = pd.DataFrame(["a"]) |
|
|
pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) |
|
|
G = pd.DataFrame(["a", 0.0]) |
|
|
pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) |
|
|
df = pd.DataFrame([[1, 1], [1, 0]], dtype=int, index=[1, 2], columns=["a", "b"]) |
|
|
pytest.raises(nx.NetworkXError, nx.from_pandas_adjacency, df) |
|
|
|
|
|
def test_from_edgelist_all_attr(self): |
|
|
Gtrue = nx.Graph( |
|
|
[ |
|
|
("E", "C", {"cost": 9, "weight": 10}), |
|
|
("B", "A", {"cost": 1, "weight": 7}), |
|
|
("A", "D", {"cost": 7, "weight": 4}), |
|
|
] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", True) |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
MGtrue = nx.MultiGraph(Gtrue) |
|
|
MGtrue.add_edge("A", "D", cost=16, weight=4) |
|
|
MG = nx.from_pandas_edgelist(self.mdf, 0, "b", True, nx.MultiGraph()) |
|
|
assert graphs_equal(MG, MGtrue) |
|
|
|
|
|
def test_from_edgelist_multi_attr(self): |
|
|
Gtrue = nx.Graph( |
|
|
[ |
|
|
("E", "C", {"cost": 9, "weight": 10}), |
|
|
("B", "A", {"cost": 1, "weight": 7}), |
|
|
("A", "D", {"cost": 7, "weight": 4}), |
|
|
] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", ["weight", "cost"]) |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_from_edgelist_multi_attr_incl_target(self): |
|
|
Gtrue = nx.Graph( |
|
|
[ |
|
|
("E", "C", {0: "C", "b": "E", "weight": 10}), |
|
|
("B", "A", {0: "B", "b": "A", "weight": 7}), |
|
|
("A", "D", {0: "A", "b": "D", "weight": 4}), |
|
|
] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", [0, "b", "weight"]) |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_from_edgelist_multidigraph_and_edge_attr(self): |
|
|
|
|
|
edges = [ |
|
|
("X1", "X4", {"Co": "zA", "Mi": 0, "St": "X1"}), |
|
|
("X1", "X4", {"Co": "zB", "Mi": 54, "St": "X2"}), |
|
|
("X1", "X4", {"Co": "zB", "Mi": 49, "St": "X3"}), |
|
|
("X1", "X4", {"Co": "zB", "Mi": 44, "St": "X4"}), |
|
|
("Y1", "Y3", {"Co": "zC", "Mi": 0, "St": "Y1"}), |
|
|
("Y1", "Y3", {"Co": "zC", "Mi": 34, "St": "Y2"}), |
|
|
("Y1", "Y3", {"Co": "zC", "Mi": 29, "St": "X2"}), |
|
|
("Y1", "Y3", {"Co": "zC", "Mi": 24, "St": "Y3"}), |
|
|
("Z1", "Z3", {"Co": "zD", "Mi": 0, "St": "Z1"}), |
|
|
("Z1", "Z3", {"Co": "zD", "Mi": 14, "St": "X3"}), |
|
|
] |
|
|
Gtrue = nx.MultiDiGraph(edges) |
|
|
data = { |
|
|
"O": ["X1", "X1", "X1", "X1", "Y1", "Y1", "Y1", "Y1", "Z1", "Z1"], |
|
|
"D": ["X4", "X4", "X4", "X4", "Y3", "Y3", "Y3", "Y3", "Z3", "Z3"], |
|
|
"St": ["X1", "X2", "X3", "X4", "Y1", "Y2", "X2", "Y3", "Z1", "X3"], |
|
|
"Co": ["zA", "zB", "zB", "zB", "zC", "zC", "zC", "zC", "zD", "zD"], |
|
|
"Mi": [0, 54, 49, 44, 0, 34, 29, 24, 0, 14], |
|
|
} |
|
|
df = pd.DataFrame.from_dict(data) |
|
|
G1 = nx.from_pandas_edgelist( |
|
|
df, source="O", target="D", edge_attr=True, create_using=nx.MultiDiGraph |
|
|
) |
|
|
G2 = nx.from_pandas_edgelist( |
|
|
df, |
|
|
source="O", |
|
|
target="D", |
|
|
edge_attr=["St", "Co", "Mi"], |
|
|
create_using=nx.MultiDiGraph, |
|
|
) |
|
|
assert graphs_equal(G1, Gtrue) |
|
|
assert graphs_equal(G2, Gtrue) |
|
|
|
|
|
def test_from_edgelist_one_attr(self): |
|
|
Gtrue = nx.Graph( |
|
|
[ |
|
|
("E", "C", {"weight": 10}), |
|
|
("B", "A", {"weight": 7}), |
|
|
("A", "D", {"weight": 4}), |
|
|
] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", "weight") |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_from_edgelist_int_attr_name(self): |
|
|
|
|
|
Gtrue = nx.Graph( |
|
|
[("E", "C", {0: "C"}), ("B", "A", {0: "B"}), ("A", "D", {0: "A"})] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", 0) |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_from_edgelist_invalid_attr(self): |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", "misspell" |
|
|
) |
|
|
pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", 1) |
|
|
|
|
|
edgeframe = pd.DataFrame([[0, 1], [1, 2], [2, 0]], columns=["s", "t"]) |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", True |
|
|
) |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", "weight" |
|
|
) |
|
|
pytest.raises( |
|
|
nx.NetworkXError, |
|
|
nx.from_pandas_edgelist, |
|
|
edgeframe, |
|
|
"s", |
|
|
"t", |
|
|
["weight", "size"], |
|
|
) |
|
|
|
|
|
def test_from_edgelist_no_attr(self): |
|
|
Gtrue = nx.Graph([("E", "C", {}), ("B", "A", {}), ("A", "D", {})]) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b") |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_from_edgelist(self): |
|
|
|
|
|
G = nx.cycle_graph(10) |
|
|
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) |
|
|
|
|
|
edgelist = nx.to_edgelist(G) |
|
|
source = [s for s, t, d in edgelist] |
|
|
target = [t for s, t, d in edgelist] |
|
|
weight = [d["weight"] for s, t, d in edgelist] |
|
|
edges = pd.DataFrame({"source": source, "target": target, "weight": weight}) |
|
|
|
|
|
GG = nx.from_pandas_edgelist(edges, edge_attr="weight") |
|
|
assert nodes_equal(G.nodes(), GG.nodes()) |
|
|
assert edges_equal(G.edges(), GG.edges()) |
|
|
GW = nx.to_networkx_graph(edges, create_using=nx.Graph) |
|
|
assert nodes_equal(G.nodes(), GW.nodes()) |
|
|
assert edges_equal(G.edges(), GW.edges()) |
|
|
|
|
|
def test_to_edgelist_default_source_or_target_col_exists(self): |
|
|
G = nx.path_graph(10) |
|
|
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) |
|
|
nx.set_edge_attributes(G, 0, name="source") |
|
|
pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G) |
|
|
|
|
|
|
|
|
for u, v, d in G.edges(data=True): |
|
|
d.pop("source", None) |
|
|
|
|
|
nx.set_edge_attributes(G, 0, name="target") |
|
|
pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G) |
|
|
|
|
|
def test_to_edgelist_custom_source_or_target_col_exists(self): |
|
|
G = nx.path_graph(10) |
|
|
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges)) |
|
|
nx.set_edge_attributes(G, 0, name="source_col_name") |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.to_pandas_edgelist, G, source="source_col_name" |
|
|
) |
|
|
|
|
|
|
|
|
for u, v, d in G.edges(data=True): |
|
|
d.pop("source_col_name", None) |
|
|
|
|
|
nx.set_edge_attributes(G, 0, name="target_col_name") |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.to_pandas_edgelist, G, target="target_col_name" |
|
|
) |
|
|
|
|
|
def test_to_edgelist_edge_key_col_exists(self): |
|
|
G = nx.path_graph(10, create_using=nx.MultiGraph) |
|
|
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges())) |
|
|
nx.set_edge_attributes(G, 0, name="edge_key_name") |
|
|
pytest.raises( |
|
|
nx.NetworkXError, nx.to_pandas_edgelist, G, edge_key="edge_key_name" |
|
|
) |
|
|
|
|
|
def test_from_adjacency(self): |
|
|
nodelist = [1, 2] |
|
|
dftrue = pd.DataFrame( |
|
|
[[1, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist |
|
|
) |
|
|
G = nx.Graph([(1, 1), (1, 2)]) |
|
|
df = nx.to_pandas_adjacency(G, dtype=int) |
|
|
pd.testing.assert_frame_equal(df, dftrue) |
|
|
|
|
|
@pytest.mark.parametrize("graph", [nx.Graph, nx.MultiGraph]) |
|
|
def test_roundtrip(self, graph): |
|
|
|
|
|
Gtrue = graph([(1, 1), (1, 2)]) |
|
|
df = nx.to_pandas_edgelist(Gtrue) |
|
|
G = nx.from_pandas_edgelist(df, create_using=graph) |
|
|
assert graphs_equal(Gtrue, G) |
|
|
|
|
|
adj = {1: {1: {"weight": 1}, 2: {"weight": 1}}, 2: {1: {"weight": 1}}} |
|
|
Gtrue = graph(adj) |
|
|
df = nx.to_pandas_adjacency(Gtrue, dtype=int) |
|
|
G = nx.from_pandas_adjacency(df, create_using=graph) |
|
|
assert graphs_equal(Gtrue, G) |
|
|
|
|
|
def test_from_adjacency_named(self): |
|
|
|
|
|
data = { |
|
|
"A": {"A": 0, "B": 0, "C": 0}, |
|
|
"B": {"A": 1, "B": 0, "C": 0}, |
|
|
"C": {"A": 0, "B": 1, "C": 0}, |
|
|
} |
|
|
dftrue = pd.DataFrame(data, dtype=np.intp) |
|
|
df = dftrue[["A", "C", "B"]] |
|
|
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph()) |
|
|
df = nx.to_pandas_adjacency(G, dtype=np.intp) |
|
|
pd.testing.assert_frame_equal(df, dftrue) |
|
|
|
|
|
def test_edgekey_with_multigraph(self): |
|
|
df = pd.DataFrame( |
|
|
{ |
|
|
"source": {"A": "N1", "B": "N2", "C": "N1", "D": "N1"}, |
|
|
"target": {"A": "N2", "B": "N3", "C": "N1", "D": "N2"}, |
|
|
"attr1": {"A": "F1", "B": "F2", "C": "F3", "D": "F4"}, |
|
|
"attr2": {"A": 1, "B": 0, "C": 0, "D": 0}, |
|
|
"attr3": {"A": 0, "B": 1, "C": 0, "D": 1}, |
|
|
} |
|
|
) |
|
|
Gtrue = nx.MultiGraph( |
|
|
[ |
|
|
("N1", "N2", "F1", {"attr2": 1, "attr3": 0}), |
|
|
("N2", "N3", "F2", {"attr2": 0, "attr3": 1}), |
|
|
("N1", "N1", "F3", {"attr2": 0, "attr3": 0}), |
|
|
("N1", "N2", "F4", {"attr2": 0, "attr3": 1}), |
|
|
] |
|
|
) |
|
|
|
|
|
G = nx.from_pandas_edgelist( |
|
|
df, |
|
|
source="source", |
|
|
target="target", |
|
|
edge_attr=["attr2", "attr3"], |
|
|
edge_key="attr1", |
|
|
create_using=nx.MultiGraph(), |
|
|
) |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
df_roundtrip = nx.to_pandas_edgelist(G, edge_key="attr1") |
|
|
df_roundtrip = df_roundtrip.sort_values("attr1") |
|
|
df_roundtrip.index = ["A", "B", "C", "D"] |
|
|
pd.testing.assert_frame_equal( |
|
|
df, df_roundtrip[["source", "target", "attr1", "attr2", "attr3"]] |
|
|
) |
|
|
|
|
|
def test_edgekey_with_normal_graph_no_action(self): |
|
|
Gtrue = nx.Graph( |
|
|
[ |
|
|
("E", "C", {"cost": 9, "weight": 10}), |
|
|
("B", "A", {"cost": 1, "weight": 7}), |
|
|
("A", "D", {"cost": 7, "weight": 4}), |
|
|
] |
|
|
) |
|
|
G = nx.from_pandas_edgelist(self.df, 0, "b", True, edge_key="weight") |
|
|
assert graphs_equal(G, Gtrue) |
|
|
|
|
|
def test_nonexisting_edgekey_raises(self): |
|
|
with pytest.raises(nx.exception.NetworkXError): |
|
|
nx.from_pandas_edgelist( |
|
|
self.df, |
|
|
source="source", |
|
|
target="target", |
|
|
edge_key="Not_real", |
|
|
edge_attr=True, |
|
|
create_using=nx.MultiGraph(), |
|
|
) |
|
|
|
|
|
|
|
|
def test_to_pandas_adjacency_with_nodelist(): |
|
|
G = nx.complete_graph(5) |
|
|
nodelist = [1, 4] |
|
|
expected = pd.DataFrame( |
|
|
[[0, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist |
|
|
) |
|
|
pd.testing.assert_frame_equal( |
|
|
expected, nx.to_pandas_adjacency(G, nodelist, dtype=int) |
|
|
) |
|
|
|
|
|
|
|
|
def test_to_pandas_edgelist_with_nodelist(): |
|
|
G = nx.Graph() |
|
|
G.add_edges_from([(0, 1), (1, 2), (1, 3)], weight=2.0) |
|
|
G.add_edge(0, 5, weight=100) |
|
|
df = nx.to_pandas_edgelist(G, nodelist=[1, 2]) |
|
|
assert 0 not in df["source"].to_numpy() |
|
|
assert 100 not in df["weight"].to_numpy() |
|
|
|