Anaphory
Anaphory

Reputation: 6412

How do I copy, but not deepcopy, a networkx Graph?

I want to compare the state of a networkx.Graph object n before a function call d(n) (with side effects) with the state afterwards.

There are mutable object node attributes such as n.node[0]['attribute'], which I want to compare.

Obviously,

before = n
d()
after = n
assert id(before.node[0]['attribute']) == id(after.node[0]['attribute'])

succeeds trivially, because

before == after

but if I set before=n.copy(), a deep copy is made, and therefore id(before.node[0]['attribute']) != id(after.node[0]['attribute']). How do I get a copy of a Graph object without copying all node attribute objects?

Upvotes: 2

Views: 8228

Answers (3)

O.rka
O.rka

Reputation: 30737

Try this:

G = # your graph
G2 = nx.Graph() # or whatever type of graph `G` is
G2.add_edges_from(G.edges())

Upvotes: 1

mengg
mengg

Reputation: 310

Please also note that if your networkx graph contains objects of objects..., even a deepcopy would not work. It would return an error that there are too many levels.

Normally, I would think what exactly is of interest in the graph and just create a new one with that.

Upvotes: -1

Aric
Aric

Reputation: 25299

Calling the copy method gives a deep copy. All attributes of the new graph are copies of the original graph. Calling the constructor (e.g. Graph(G)) gives a shallow copy where the graph structure is copied but the data attributes are references those in the original graph.

From the copy method docs

All copies reproduce the graph structure, but data attributes may be handled in different ways. There are four types of copies of a graph that people might want.

Deepcopy -- The default behavior is a "deepcopy" where the graph structure as well as all data attributes and any objects they might contain are copied. The entire graph object is new so that changes in the copy do not affect the original object.

Data Reference (Shallow) -- For a shallow copy (with_data=False) the graph structure is copied but the edge, node and graph attribute dicts are references to those in the original graph. This saves time and memory but could cause confusion if you change an attribute in one graph and it changes the attribute in the other.

In [1]: import networkx as nx

In [2]: G = nx.Graph()

In [3]: G.add_node(1, color=['red'])

In [4]: G_deep = G.copy()

In [5]: G_deep.node[1]['color'].append('blue')

In [6]: list(G.nodes(data=True))
Out[6]: [(1, {'color': ['red']})]

In [7]: list(G_deep.nodes(data=True))
Out[7]: [(1, {'color': ['red', 'blue']})]

In [8]: G_shallow = nx.Graph(G)

In [9]: G_shallow.node[1]['color'].append('blue')

In [10]: list(G.nodes(data=True))
Out[10]: [(1, {'color': ['red', 'blue']})]

In [11]: list(G_shallow.nodes(data=True))
Out[11]: [(1, {'color': ['red', 'blue']})]

Upvotes: 5

Related Questions