Parallel Edges in DiGraph

954 views
Skip to first unread message

Denzil Correa

unread,
Sep 19, 2011, 11:08:52 AM9/19/11
to networkx...@googlegroups.com
Hi,

The documentation reads that multiple(parallel) edges aren't allowed for DiGraph. Moreover, adding an edge which already exists should update the edge. However, I seem to have them in my DiGraph object. I am writing the object into the GraphML format. PFA the file for reference.

Any idea on why this should happen?


--
Regards,

Denzil Correa
IIIT-Delhi
--------------------------------------------
Q: Why is this email five sentences or less?



2NW.graphml

Dan Schult

unread,
Sep 19, 2011, 11:19:01 AM9/19/11
to networkx...@googlegroups.com
It is possible that you have a MultiDiGraph instead of a DiGraph object.
How are you creating your NetworkX graph?
Dan

> --
> You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
> To post to this group, send email to networkx...@googlegroups.com.
> To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.
> <2NW.graphml>

Aric Hagberg

unread,
Sep 19, 2011, 11:18:46 AM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 9:08 AM, Denzil Correa <den...@iiitd.ac.in> wrote:
> Hi,
>
> The documentation reads that multiple(parallel) edges aren't allowed for
> DiGraph. Moreover, adding an edge which already exists should update the
> edge. However, I seem to have them in my DiGraph object. I am writing the
> object into the GraphML format. PFA the file for reference.
>
> Any idea on why this should happen?

Can you post a small (nonworking) example. This is working for me:


In [1]: import networkx as nx

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

In [3]: G.add_edge(1,2,weight=7)

In [4]: G.add_edge(1,2,weight=22) # update edge with new weight

In [5]: import sys

In [6]: nx.write_graphml(G,sys.stdout)
<?xml version="1.0" encoding="utf-8"?><graphml
xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key attr.name="weight" attr.type="int" for="edge" id="d0" />
<graph edgedefault="directed">
<node id="1" />
<node id="2" />
<edge source="1" target="2">
<data key="d0">22</data>
</edge>
</graph>
</graphml>

Aric

Denzil Correa

unread,
Sep 19, 2011, 11:23:19 AM9/19/11
to networkx...@googlegroups.com
Dan :

Highly unlikely. Here's how I create the graph :

G = nx.DiGraph()
G.add_edge(from_node, to_node, weight = wt)

Is there any way to check what kind of graph I have?  G.is_directed() returns True.

Denzil Correa

unread,
Sep 19, 2011, 11:26:30 AM9/19/11
to networkx...@googlegroups.com
Aric :

Rather surprisingly such an example (on command line) works for me. Is there any way I can understand the type of graph if loaded from a GraphML file? If not, I would propose this as a feature request. I was made aware of the parallel edges once I imported my GraphML into a social network analysis tool including Gephi and CMU-ORA

Btw, G.is_directed() returns True.

--
You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
To post to this group, send email to networkx...@googlegroups.com.
To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.

Aric Hagberg

unread,
Sep 19, 2011, 11:32:18 AM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 9:26 AM, Denzil Correa <den...@iiitd.ac.in> wrote:
> Aric :
>
> Rather surprisingly such an example (on command line) works for me. Is there
> any way I can understand the type of graph if loaded from a GraphML file? If
> not, I would propose this as a feature request. I was made aware of the
> parallel edges once I imported my GraphML into a social network analysis
> tool including Gephi and CMU-ORA

If the data in the GraphML format file has parallel edges you will get
a MultiDiGraph object returned from read_graphml() that contains those
parallel edges (see the read_graphml docs).

If you want to remove the parallel edges you can try
G=nx.DiGraph(nx.read_graphml(file)). That will arbitrarily remove all
but one (directed) edge between two nodes.

Aric

Denzil Correa

unread,
Sep 19, 2011, 11:38:02 AM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 9:02 PM, Aric Hagberg <ahag...@gmail.com> wrote:
On Mon, Sep 19, 2011 at 9:26 AM, Denzil Correa <den...@iiitd.ac.in> wrote:
> Aric :
>
> Rather surprisingly such an example (on command line) works for me. Is there
> any way I can understand the type of graph if loaded from a GraphML file? If
> not, I would propose this as a feature request. I was made aware of the
> parallel edges once I imported my GraphML into a social network analysis
> tool including Gephi and CMU-ORA

If the data in the GraphML format file has parallel edges you will get
a MultiDiGraph object returned from read_graphml() that contains those
parallel edges (see the read_graphml docs).

I did this and indeed I have a MultiDiGraph object. But, I never initialized a MultiDiGraph object to begin with. I am using a DiGraph object. How did this get converted to a MultiDiGraph object?

If you want to remove the parallel edges you can try
G=nx.DiGraph(nx.read_graphml(file)).  That will arbitrarily remove all
but one (directed) edge between two nodes.

I wouldn't mind doing this. Is there any heuristic (max. edge weight) to understand which edge this function would retain?
 

Aric

--
You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
To post to this group, send email to networkx...@googlegroups.com.
To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.

Aric Hagberg

unread,
Sep 19, 2011, 11:47:16 AM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 9:38 AM, Denzil Correa <den...@iiitd.ac.in> wrote:
>
> I did this and indeed I have a MultiDiGraph object. But, I never initialized
> a MultiDiGraph object to begin with. I am using a DiGraph object. How did
> this get converted to a MultiDiGraph object?

You don't get to choose with read_graphml(). That code tries to
figure out what kind of graph you have and choose the appropriate
container. In your case the right object is a multigraph (you have
parallel edges).

>> If you want to remove the parallel edges you can try

>> G=nx.DiGraph(nx.read_graphml(file)). &nbsp;That will arbitrarily remove all


>> but one (directed) edge between two nodes.
>
> I wouldn't mind doing this. Is there any heuristic (max. edge weight) to
> understand which edge this function would retain?

It's arbitrary (based on the arbitrary ordering of the Python
dictionary of dictionary storage). If you want more control over
which edges to keep you'll need to load the data as a MultiDiGraph,
initialize a new DiGraph(), and loop over the edges in the
MultiDiGraph keeping only the ones you want and adding to the DiGraph.

Aric

Denzil Correa

unread,
Sep 19, 2011, 11:52:42 AM9/19/11
to networkx...@googlegroups.com
Aric :

Before writing to GraphML format, I had a strict mention on the type of NetworkX graph object which was DiGraph in my case (since I didn't want parallel edges). Now, once the same object is read the basic properties of the graph (in my case DiGraph) should be retained. If this is not so, let me know if I am missing something.


Aric

--
You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
To post to this group, send email to networkx...@googlegroups.com.
To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.

Aric Hagberg

unread,
Sep 19, 2011, 11:58:55 AM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 9:52 AM, Denzil Correa <den...@iiitd.ac.in> wrote:
> Aric :
>
> Before writing to GraphML format, I had a strict mention on the type of
> NetworkX graph object which was DiGraph in my case (since I didn't want
> parallel edges). Now, once the same object is read the basic properties of
> the graph (in my case DiGraph) should be retained. If this is not so, let me
> know if I am missing something.

It's possible there is a bug in the chain somewhere.
Can you reproduce the behavior with a small example?

It works for the simple examples in the networkx tests, e.g.


In [1]: import networkx as nx

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

In [3]: G.add_edge(1,2,weight=7)

In [4]: G.add_edge(1,2,weight=22)

In [5]: repr(G)
Out[5]: '<networkx.classes.digraph.DiGraph object at 0x1a46390>'

In [6]: G.edges()
Out[6]: [(1, 2)]

In [7]: nx.write_graphml(G,'test.graphml')

In [8]: H=nx.read_graphml('test.graphml')

In [9]: repr(H)
Out[9]: '<networkx.classes.digraph.DiGraph object at 0x1a46850>'

In [10]: H.edges()
Out[10]: [('1', '2')]

Aric

Ben Edwards

unread,
Sep 19, 2011, 12:12:23 PM9/19/11
to networkx...@googlegroups.com
Late to the conversation. The graphml format has been a moving target for us, but glancing at the code I see what is going on. There is no easy way to tell if the graph stored in a graphml file is a Multigraph or not, so networkx defaults the the safest mode and creates a MultiGraph. This way no information is lost if there is parallel edges. Since you know for a fact that the graph you saved has no parallel edges, you can safely load your graph from the file and then convert it to a DiGraph. This is an extra step yes, but it is a consequence of using the graphml format. If you are only using the graph data yourself, you could consider simply pickling the data which would maintain the python types.

Ben

Aric Hagberg

unread,
Sep 19, 2011, 12:22:09 PM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 10:12 AM, Ben Edwards <BJEd...@gmail.com> wrote:
> Late to the conversation. The graphml format has been a moving target for
> us, but glancing at the code I see what is going on. There is no easy way to
> tell if the graph stored in a graphml file is a Multigraph or not, so
> networkx defaults the the safest mode and creates a MultiGraph. This way no
> information is lost if there is parallel edges. Since you know for a fact
> that the graph you saved has no parallel edges, you can safely load your
> graph from the file and then convert it to a DiGraph. This is an extra step
> yes, but it is a consequence of using the graphml format. If you are only
> using the graph data yourself, you could consider simply pickling the data
> which would maintain the python types.
>

The read_graphml() function does try to figure out if the input graph
has parallel edges. If not the type is switched to Graph or DiGraph
before return. There could be a bug there. But that should be easy
to fix if we can isolate the problem.
Aric

Ben Edwards

unread,
Sep 19, 2011, 12:41:32 PM9/19/11
to networkx...@googlegroups.com
Ah, I see now, I wasn't sure self.multigraph was being set in GraphMLReader.

Aric

Denzil Correa

unread,
Sep 19, 2011, 3:30:26 PM9/19/11
to networkx...@googlegroups.com
Aric :

It's difficult for me to reproduce the error as the nodes/edges are added vai Web 2.0 API calls. I don't have them stored on my disk. Saying that, I have narrowed down the issue.

Just before I write it into a GraphML file, I checked the type of my graph and it came out to be a DiGraph object. However, after writing it to a GraphML file and subsequently reading the file (using the read_graphml function) converts it to a MultiDiGraph object as reported earlier. In order to be very sure, I wrote the my DiGraph object to a gpickle format and tried reading it only to observe my original DiGraph object.

Based on my arcane debugging, I suspect and issue with the read/write GraphML functions. I am attaching the gpickle and GraphML files for my graph. Both of these represent the by object in memory. Any way to fix this?


Aric

--
You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
To post to this group, send email to networkx...@googlegroups.com.
To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.

2NW.graphml
2NW.gpickle

Denzil Correa

unread,
Sep 19, 2011, 3:35:30 PM9/19/11
to networkx...@googlegroups.com
Ben :

Thanks. Writing the data into GraphML format helps perform various analysis on my graphs which may be difficult in networkx. My graph is a social network and use social network analysis tools like CMU-ORA, Gephi, UCINet etc. to try to understand the structure and properties of my network (more so, in an interactive appealing way). I believe an efficient and robust implementation of writing native networkx graph objects into GraphML format would be a great value addition to networkx users like me.

Aric Hagberg

unread,
Sep 19, 2011, 4:50:36 PM9/19/11
to networkx...@googlegroups.com
On Mon, Sep 19, 2011 at 1:30 PM, Denzil Correa <den...@iiitd.ac.in> wrote:
> Aric :
>
> It's difficult for me to reproduce the error as the nodes/edges are added
> vai Web 2.0 API calls. I don't have them stored on my disk. Saying that, I
> have narrowed down the issue.
>
> Just before I write it into a GraphML file, I checked the type of my graph
> and it came out to be a DiGraph object. However, after writing it to a
> GraphML file and subsequently reading the file (using the read_graphml
> function) converts it to a MultiDiGraph object as reported earlier. In order
> to be very sure, I wrote the my DiGraph object to a gpickle format and tried
> reading it only to observe my original DiGraph object.
>
> Based on my arcane debugging, I suspect and issue with the read/write
> GraphML functions. I am attaching the gpickle and GraphML files for my
> graph. Both of these represent the by object in memory. Any way to fix this?
>

I think the problem is that you are mixing integer and node types in
your graph. e.g. from your data file:

In [55]: G=nx.read_gpickle('2NW.gpickle')

In [56]: G.nodes()[10:20]
Out[56]:
[79691779,
68331541,
145311766,
20123671,
'20429407',
'23695379',
131147806,
'48301904',
'35094823',
'110306287']

The nodes in the GraphML file (as far as I know) have to be of one
type so if you have a string and an integer that both represent the
same number value they will get conflated.

Aric

Denzil Correa

unread,
Sep 20, 2011, 7:34:11 AM9/20/11
to networkx...@googlegroups.com
Aric :

Thanks! You are right on the money. This was a rookie error. I have rectified the same and everything works well.


Aric

--
You received this message because you are subscribed to the Google Groups "networkx-discuss" group.
To post to this group, send email to networkx...@googlegroups.com.
To unsubscribe from this group, send email to networkx-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/networkx-discuss?hl=en.

Reply all
Reply to author
Forward
0 new messages