Search code examples
pythongraphgraphvizdirected-acyclic-graphs

Clear and automatic DAG visualization


I am trying to draw a DAG (directed acyclic graph) starting from a dataframe with 212 attributes. I am able to draw it using graphviz

import graphviz

G = graphviz.Digraph()

for col in graph_df.columns:
    for row in graph_df.index:
        if graph_df.loc[row, col] == 1:
            G.edge(col, row)

G.render('graph', format='pdf', cleanup=True)

But the final pdf looks like this enter image description here

If I zoom I can read everything, but I would like to stretch vertically the final DAG to have it tidier. Can you help me please?


Solution

  • You can use ratio and size, if you need vertically long graph display:

    G = graphviz.Digraph(graph_attr={'rankdir': 'TB', 'ratio': 'fill', 'size': '50,200'})
    

    Code:

    import pandas as pd
    import graphviz
    
    
    def get_plot(graph_df):
        G = graphviz.Digraph(graph_attr={'rankdir': 'TB', 'ratio': 'fill', 'size': '10,30'})
        for i, col in enumerate(graph_df.columns):
            for j, row in enumerate(graph_df.index):
                if i != j and graph_df.loc[row, col] == 1:  # Ensure not connecting a node to itself
                    G.edge(col, row)
    
        G.render('graph', format='pdf', cleanup=True)
    
    
    V = 26
    nodes = [chr(ord('A') + i) for i in range(V)]
    edges = {name: [1 if i != j else 0 for j in range(V)] for i, name in enumerate(nodes)}
    df = pd.DataFrame(edges, index=nodes)
    get_plot(df)
    
    

    Actual Size

    enter image description here

    • You can change the size to get what's expected.

    • node_attr() and graph_attr() has everything that you need to customize your view:
    import pandas as pd
    import graphviz
    
    
    def get_plot(graph_df):
        G = graphviz.Digraph(
            graph_attr={
                'rankdir': 'TB',
                'ratio': 'fill',
                'size': '100,200',
                'nodesep': '1.0',
                'ranksep': '1.5'
            },
            node_attr={
                'fixedsize': 'true',
                'width': '10.0',
                'height': '10.0',
                'fontsize': '300'
            }
        )
        for i, col in enumerate(graph_df.columns):
            for j, row in enumerate(graph_df.index):
                if i != j and graph_df.loc[row, col] == 1:
                    G.edge(col, row)
    
        G.render('graph', format='pdf', cleanup=True)
    
    
    V = 26
    nodes = [chr(ord('A') + i) for i in range(V)]
    edges = {name: [1 if i != j else 0 for j in range(V)] for i, name in enumerate(nodes)}
    df = pd.DataFrame(edges, index=nodes)
    get_plot(df)
    
    

    10% view (of the actual size)

    enter image description here