I have a NetworkX MultiDiGraph that contains selfloops. According to the documentation , this is a valid property of a MultiDiGraph.
A MultiDiGraph holds directed edges. Self loops are allowed.
But when I try to remove the selfloops from the MultiDiGraph using MG.remove_edges_from(MG.selfloop_edges())
, the following warning in generated:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-13-ff3391f2296f> in <module>()
1 # remove selfloop edges from the graph
----> 2 MG.remove_edges_from(MG.selfloop_edges())
~/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/networkx/classes/multigraph.py in remove_edges_from(self, ebunch)
603 []
604 """
--> 605 for e in ebunch:
606 try:
607 self.remove_edge(*e[:3])
~/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/networkx/classes/function.py in <genexpr>(.0)
1154 return ((n, n)
1155 for n, nbrs in G.adj.items()
-> 1156 if n in nbrs for d in nbrs[n].values())
1157 else:
1158 return ((n, n) for n, nbrs in G.adj.items() if n in nbrs)
~/Program_Files/miniconda3/envs/py36/lib/python3.6/_collections_abc.py in __iter__(self)
759
760 def __iter__(self):
--> 761 for key in self._mapping:
762 yield self._mapping[key]
763
RuntimeError: dictionary changed size during iteration
Am I missing something in the way you remove a selfloop from a MultliDiGraph or is this a bug with NetworkX?
Reproducible example demonstrating the unexpected error:
import networkx as nx
# create an empty MultiDiGraph
MG = nx.MultiDiGraph()
# add some edges to the graph
MG.add_edges_from([(1, 2), (2, 3), (3, 1), (1, 2), (2, 1), (2, 2)])
# check the edges in the graph
MG.edges()
# remove selfloop edges from the graph
MG.remove_edges_from(MG.selfloop_edges())
This method works as expected with a DiGraph, as seen below:
# create an empty MultiDiGraph
G = nx.DiGraph()
# add some edges to the graph
G.add_edges_from([(1, 2), (2, 3), (3, 1), (1, 2), (2, 1), (2, 2)])
# check the edges in the graph
G.edges
OutEdgeView([(1, 2), (2, 3), (2, 1), (2, 2), (3, 1)])
# remove selfloop edges from the graph
G.remove_edges_from(G.selfloop_edges())
# check the edges in the graph
G.edges()
OutEdgeView([(1, 2), (2, 3), (2, 1), (3, 1)])
The problem is that MG.selfloop_edges()
is an iterator (more precisely generator) over the selfloop edges in the graph, and by removing the edges you are changing the iterator's edges during the iteration.
According to the documentation :
Parameters: ebunch (list or container of edge tuples) - ...
That means that the ebunch
parameter should be a container, while MG.selfloop_edges()
returns a generator. You can read more about the difference between the two here .
The issue can be solved by passing list(MG.selfloop_edges())
to MG.remove_edges_from
(instead of passing MG.selfloop_edges()
directly).
I address this issue in another answer here: https://stackoverflow.com/a/49428652/2966723
Right now you can do MG.remove_edges_from(list(MG.selfloops_edges()))
. However, this is actually a bug and will be fixed in an upcoming release: https://github.com/networkx/networkx/pull/4080 . Then the code you wanted to write will work.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.