pythongraphvizdotpydot

How to color a specific path in a graphviz dot file using python


Hello I am iterating a dot file in python using pydot package. I want to color all nodes and edges in a graph who are a parent of particular node unto the starting root. the images below describes the goal.

Actual Graph is following

The actual graph

Required Output assuming given node is _ZL3WTFv

Required goal

Python code is following

import pydot
import sys

def Clean(inp):
    return inp.replace('"{', '').replace('}"', '')

def GetNode(path):
    graph = pydot.graph_from_dot_file(path)
    graph = graph[0]
    nodesList = graph.get_nodes() 
    for e in nodesList:
        tempAttr = e.get_attributes()
        print('Checking', Clean(tempAttr['label']))
        if Clean(tempAttr['label']) == '_ZL3WTFv':
            #how to mark all nodes & paths to the top level parents from here e.g. _ZL3WTFv          
            print('Node Found!')
            break

if len(sys.argv) > 1:
    GetNode(sys.argv[1])
else:
    print('Dot file path Missing!')

The graphviz dot file code is following

digraph "Call graph" {
    label="Call graph";

    Node0x163ebe0 [shape=record,label="{external node}"];
    Node0x163ebe0 -> Node0x163b270;
    Node0x163ebe0 -> Node0x1605360;
    Node0x163ebe0 -> Node0x16052c0;
    Node0x163ebe0 -> Node0x160e2a0;
    Node0x163ebe0 -> Node0x160e600;
    Node0x163ebe0 -> Node0x160eb00;
    Node0x160eb00 [shape=record,label="{_GLOBAL__sub_I_test.cpp}"];
    Node0x160eb00 -> Node0x163b200;
    Node0x163b200 [shape=record,label="{__cxx_global_var_init}"];
    Node0x163b200 -> Node0x163b270;
    Node0x163b200 -> Node0x16052c0;
    Node0x163b270 [shape=record,label="{_ZNSt8ios_base4InitC1Ev}"];
    Node0x163b270 -> Node0x163e480;
    Node0x1605360 [shape=record,label="{_ZNSt8ios_base4InitD1Ev}"];
    Node0x1605360 -> Node0x163e480;
    Node0x16052c0 [shape=record,label="{__cxa_atexit}"];
    Node0x16052c0 -> Node0x163e480;
    Node0x160e2a0 [shape=record,label="{main}"];
    Node0x160e2a0 -> Node0x160e310;
    Node0x160e310 [shape=record,label="{_ZL1Av}"];
    Node0x160e310 -> Node0x160e3b0;
    Node0x160e310 -> Node0x160e450;
    Node0x160e3b0 [shape=record,label="{_ZL1Bv}"];
    Node0x160e3b0 -> Node0x160e3e0;
    Node0x160e450 [shape=record,label="{_ZL1Gv}"];
    Node0x160e450 -> Node0x160e530;
    Node0x160e3e0 [shape=record,label="{_ZL1Cv}"];
    Node0x160e3e0 -> Node0x160e5d0;
    Node0x160e3e0 -> Node0x160e670;
    Node0x160e530 [shape=record,label="{_ZL1Mv}"];
    Node0x160e530 -> Node0x160e850;
    Node0x160e5d0 [shape=record,label="{_ZL3WTFv}"];
    Node0x160e5d0 -> Node0x160e600;
    Node0x160e670 [shape=record,label="{_ZL1Xv}"];
    Node0x160e670 -> Node0x160e750;
    Node0x160e600 [shape=record,label="{_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc}"];
    Node0x160e600 -> Node0x163e480;
    Node0x160e750 [shape=record,label="{_ZL1Yv}"];
    Node0x160e750 -> Node0x160e5d0;
    Node0x160e850 [shape=record,label="{_ZL1Nv}"];
    Node0x160e850 -> Node0x160e8f0;
    Node0x160e8f0 [shape=record,label="{_ZL1Ov}"];
    Node0x160e8f0 -> Node0x160e990;
    Node0x160e990 [shape=record,label="{_ZL1Pv}"];
    Node0x160e990 -> Node0x160ea30;
    Node0x160ea30 [shape=record,label="{_ZL1Sv}"];
    Node0x160ea30 -> Node0x160e5d0;
}

the main problem is I am able to iterate graph but can't mark the path from root to the required node


Solution

  • I don't use the Python interface, but on a quick read this should work:
    write a recursive function that uses gv.firstin and gv.nextin to chase the incoming edges back towards the root/parent node. start at your target node and off you go. Color each node and edge as you go. Also keep track of the nodes so you don't get caught in loops