subclassing Graph and dealing with subgraph

92 views
Skip to first unread message

Reckoner

unread,
Jan 28, 2009, 1:08:16 PM1/28/09
to networkx-discuss

I have subclassed Graph and added a bunch of extra properties to the
object. Since Graph's native subgraph produces another Graph (and not
the derived class I constructed), I usually have to add in the extra
properties as in

self.a = a
self.b = b

and so on. Naturally, there are also methods for the derived class.
The problem is that as a result of subsequent processing, there may be
different properties tacked onto the derived class so that I don't
know ahead of time if they are there or not. This means I can't simply
check, as part of the object's subgraph process, whether or not self
has the 'a' property which should be propagated down to the eventual
subgraph.

What I really need is a way to determine which properties self
( derived object) has that Graph doesn't have and then propagate these
down to the subgraph created from the derived object. Further
complicating matters is that doing

dir(derived_object) gives properties AND methods and I can't
distinguish between them.

Any advice appreciated.

Aric Hagberg

unread,
Jan 28, 2009, 1:51:52 PM1/28/09
to networkx...@googlegroups.com
On Wed, Jan 28, 2009 at 10:08:16AM -0800, Reckoner wrote:
> I have subclassed Graph and added a bunch of extra properties to the
> object. Since Graph's native subgraph produces another Graph (and not
> the derived class I constructed), I usually have to add in the extra
> properties as in

Subgraph returns the same graph class as the original class. So it
should give you an instance of your derived class.

> self.a = a
> self.b = b

Something like:

from networkx import Graph

class FooGraph(Graph):
def __init__(self,**kwds):
Graph.__init__(self,kwds)
self.a=10

then,

In [1]: import foograph

In [2]: F=foograph.FooGraph()

In [3]: FS=F.subgraph(None)

In [4]: FS.a
Out[4]: 10

In [5]: FS.get_a()
Out[5]: 10


Aric

Reckoner

unread,
Jan 29, 2009, 2:05:39 PM1/29/09
to networkx-discuss
The problem is if FooGraph in your example depends on keywords that
are not shared by Graph.

In this case, you wind up at line 703 of subgraph in graph.py where

701 # create new graph
702 if create_using is None: # Graph object of the same
type as current graph
-> 703 H=self.__class__()
704 else: # user specified graph
705 H=create_using

Thanks.

Aric Hagberg

unread,
Jan 29, 2009, 7:46:31 PM1/29/09
to networkx...@googlegroups.com
On Thu, Jan 29, 2009 at 11:05:39AM -0800, Reckoner wrote:
>
> The problem is if FooGraph in your example depends on keywords that
> are not shared by Graph.
>
> In this case, you wind up at line 703 of subgraph in graph.py where
>
> 701 # create new graph
> 702 if create_using is None: # Graph object of the same
> type as current graph
> -> 703 H=self.__class__()
> 704 else: # user specified graph
> 705 H=create_using
>

That isn't quite the same code as in the current subgraph()
method, but the current version also uses H=self.__class__() in
the same way to initialize a subgraph.

Do I understand correctly you want to be able to pass arguments to the
__class__() method there in order to initialize your (subclassed) Graph
object?

I don't think there would be any harm in passing keywords from
the subgraph() method through to the __class__() call.
Would that solve your problem?

def subgraph(self, nbunch, copy=True, **kwds):
...
H = self.__class__(**kwds)
...

Then you could use e.g. G.subgraph(nodes,foo='bar').

Can you give a simple concrete example?

Aric

Reckoner

unread,
Jan 29, 2009, 11:14:47 PM1/29/09
to networkx-discuss
Thanks for your reply.

Well. I guess the problem I have with your FooGraph class is that
self.a = 10 for all FooGraphs. In my case, I want the subgraph to
inherit whatever properties the parent has. I don't know what the best
way to do that is, however.

For example,
from networkx import Graph

class FooGraph(Graph):
def __init__(self,A,**kwds):
Graph.__init__(self,kwds)
self.a=A

and I want
w = FooGraph(A)
and
y = w.subgraph()
where

y.A = w.A

I hope that made sense.

thanks.

Dan Schult

unread,
Jan 29, 2009, 11:23:17 PM1/29/09
to networkx...@googlegroups.com
We used to handle this case by allowing a keyword argument to
subgraph called create_using. It was used similarly to how it is
still used for the generator functions. But I think the simple
passing through of keywords that Aric proposed is a good way to allow
this functionality without the disadvantage of create_using (which is
that people could try to convert to DiGraph and make a subgraph at
the same time causing confusion).

Anyway, +1 for passing kwds through subgraph to the self.__class__
instantiation.

Dan

Aric Hagberg

unread,
Jan 29, 2009, 11:42:59 PM1/29/09
to networkx...@googlegroups.com
On Thu, Jan 29, 2009 at 08:14:47PM -0800, Reckoner wrote:
>
> Well. I guess the problem I have with your FooGraph class is that
> self.a = 10 for all FooGraphs. In my case, I want the subgraph to
> inherit whatever properties the parent has. I don't know what the best
> way to do that is, however.
>
> For example,
> from networkx import Graph
>
> class FooGraph(Graph):
> def __init__(self,A,**kwds):
> Graph.__init__(self,kwds)
> self.a=A
>
> and I want
> w = FooGraph(A)
> and
> y = w.subgraph()
> where
>
> y.A = w.A

Maybe the simplest solution is to provide a subgraph method in
your subclass that does the same as the base class subgraph (could
just call it) and then afterwards performs whatever assignments you
need.

Here is one way:

from networkx import Graph

class FooGraph(Graph):
def __init__(self,**kwds):
Graph.__init__(self,kwds)
self.a=None

def set_a(self,A):
self.a=A

def subgraph(self, nbunch, copy=True):
H=Graph.subgraph(self,nbunch,copy)
H.a=self.a
return H

Then,

In [2]: G=FooGraph()

In [3]: G.set_a([1,2,3])

In [4]: H=G.subgraph(None)

In [5]: H.a
Out[5]: [1, 2, 3]

Aric


Reckoner

unread,
Jan 30, 2009, 7:32:11 AM1/30/09
to networkx-discuss
thanks.

This looks like a good idea.

Is there an easy way to filter the keywords between Graph and
FooGraph? in other words, FooGraph has additional keywords that Graph
does not have.

Thanks again.

Aric Hagberg

unread,
Jan 30, 2009, 8:31:23 AM1/30/09
to networkx...@googlegroups.com
On Fri, Jan 30, 2009 at 04:32:11AM -0800, Reckoner wrote:
> Is there an easy way to filter the keywords between Graph and
> FooGraph? in other words, FooGraph has additional keywords that Graph
> does not have.

I'm not sure what you mean by "filter". For your subclass you control
the __init__() method and can add whatever arguments you like.

If they are not optional keywords some of the NetworkX functions
or methods may not work since they expect to be able to init
the graph with __class__() [see create_empty_copy()]. We might
be able to fix that as Dan suggested in an earlier message.

Aric

Reply all
Reply to author
Forward
0 new messages