Search code examples
pythonnetworkxgraphvizpygraphviz

pygraphviz or networkx: getting the name of all subgraphs given node


I want to know the subgraph structure for a given node.

I'm ok with a networkx solution also.

Here is my code.

import pygraphviz as pgv

class Test:
    subgraph1 = 'foo'
    subgraph2 = 'bar'

    def __init__(self):
        self.G = pgv.AGraph(directed=True)
        self.G.add_subgraph(label=self.subgraph1, name='cluster_' + self.subgraph1)

        s1 = self.G.get_subgraph('cluster_' + self.subgraph1)
        s1.add_subgraph(label=self.subgraph2, name='cluster_' + self.subgraph2)
        s1.add_node('s1 node')

        s2 = s1.get_subgraph('cluster_' + self.subgraph2)
        s2.add_node('s2 node')

    def main(self):
        print(self.G.subgraph('1st node'))
        print(self.G.subgraph_parent('1st node'))
        print(self.G.subgraph_root('1st node'))
        n = self.G.get_node('1st node')
        print(n.attr['subgraph'])
        print(n.attr['label'])


if __name__ == '__main__': Test().main()

I want a function that will return me a list of subgraphs given any node in the entire graph. Something like this...

In: subgraph_structure_as_list('s2 node')

Out: ['foo', 'bar']

In: subgraph_structure_as_list('s1 node')

Out: ['foo']


Solution

  • You can use a recursive approach like this:

    import pygraphviz as pgv
    
    class Test:
        subgraph1 = 'foo'
        subgraph2 = 'bar'
    
        def __init__(self):
            self.structure = []
            self.G = pgv.AGraph(directed=True)
            self.G.add_subgraph(label=self.subgraph1, name='cluster_' + self.subgraph1)
    
            s1 = self.G.get_subgraph('cluster_' + self.subgraph1)
            s1.add_subgraph(label=self.subgraph2, name='cluster_' + self.subgraph2)
            s1.add_node('s1 node')
    
            s2 = s1.get_subgraph('cluster_' + self.subgraph2)
            s2.add_node('s2 node')
    
        #  ... other methods here ...
    
        def get_structure(self, node_name, node=None):
            if node is None:
                node = self.G
            for subgraph in node.subgraphs():
                if node_name in subgraph.nodes():
                    self.structure.append(subgraph.node_attr['label'])
                self.get_structure(node_name, subgraph)
    
        def subgraph_structure_as_list(self, node_name):
            self.structure = []
            self.get_structure(node_name)
            return self.structure
    
    

    you can use the subgraph_structure_as_list as you want like this:

    a = Test()
    print(a.subgraph_structure_as_list('s2 node'))
    print(a.subgraph_structure_as_list('s1 node'))
    

    Output:

    ['foo', 'bar']
    ['foo']