Graphviz (xdot): How to make recursive nodes?
Asked Answered
F

1

6

I'm currently writing a graphs library in Java, and I would like a tool to visualize some graphs. I discovered Graph-viz, which happens to be a great - although buggy - way of doing this.

In my model, Graphs are composed of Nodes and Edges. Every Node have a certain number of Ports (I/O/IO) and Edges link those Ports together. Some special nodes are called GraphNodes and embed a Graph. The Ports of these GraphNodes are mapped to some Ports of the internal Nodes.

I'd like to provide several representation. The first of them, with which I am satisfied, is as follows: https://i.sstatic.net/ujU71.png

The input Ports are represented in green, the output ones in red, and the input-output ones in blue.

In this representation, the GraphNodes are not expanded and are displayed just as simple Nodes. In a second version, I would like to create something that looks like the following picture: https://i.sstatic.net/Cx624.png

The problem is that I can't manage to create a sub-graph (cluster) with fixed areas (it seems not to be possible). Another solution I tried was to embed a graph into a node. However, inserting some code into the <td> </td> part of a HTML label does not evaluate the code:

digraph graph0
{

    node1
    [
        label =
        <
            <table border="0" cellspacing="0">
                <tr>
                    <td cellpadding="0">
                        <table border="0" cellspacing="0">
                            <tr>
                                <td bgcolor="palegreen" border="1" port="port2">port2</td>
                                <td bgcolor="palegreen" border="1" port="port3">port3</td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td cellpadding="0">
                        <table border="0" cellspacing="0">
                            <tr>
                                <td cellpadding="0">
                                    <table border="0" cellspacing="0">
                                        <tr>
                                            <td bgcolor="skyblue" border="1" port="port5">port5</td>
                                        </tr>
                                    </table>
                                </td>
                                <td bgcolor="peachpuff" border="1">

                                    subgraph clusterTest
                                    {
                                        nodeTest
                                    }

                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td cellpadding="0">
                        <table border="0" cellspacing="0">
                            <tr>
                                <td bgcolor="lightpink" border="1" port="port4">port4</td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        >
        style = "invisible"
    ]

}

The previous code creates the following graph: https://i.sstatic.net/E9jQ1.png

Finally, the best solution I can come up with is the following: https://i.sstatic.net/VzS5g.png

However I am not satisfied with it, because the GraphNodes' Ports are placed in strange locations sometimes.

Do you please know how I can reach the target graph layout? Please ask for any other information if needed.


EDIT: I still didn't find any solution. A way to handle this would be to be able to fix the position of given nodes inside the containing cluster, but it seems not to be possible with "dot" layout. Any idea ?

Finedraw answered 28/6, 2013 at 11:20 Comment(0)
B
1

Using a digraph, one can specify the positions of nodes (relative to one another). This can be used to force certain elements to appear above others. While other nodes can be forced to appear on the same level ( port 101 and 102 in this example)

Fake nesting: This graph does not use nested plaintext/semi-html nodes because I don't think that is possible (not a feature). I'm not sure if any graphviz libraries support them either, but it may be worth looking into other libraries. I've never even used dot from Java or Python, otherwise I would make a suggestion.


nesting


digraph { nodesep = 0.2 ranksep = 0.8 pad = 0.1 node [ shape=square ] node [ style=filled ] edge [ arrowhead=none ]

//rankdir = LR

component_starter [ label = < port02 port03 port06 S port07 port08 port04 port05 > style = "invisible" ]

subgraph cluster_container { label="I/O device with components " color=orange

//margin = 0
edge [ style="invis"]
//edge [ len="0.5" minlen="1" ]
node [ height="0.5" width="2" fixedsize=true ];
node [ shape=rectangle style=filled ]
{ 
node [ color=palegreen ];
    { rank = same port101 -> port102 }
}
{
node [ color=skyblue];
    port103 port104 }
{
node [ height="1.5" width="2" fixedsize=true ];
node [ color=peachpuff];
    //notaport
}
{
node [ height="0.5" width="4" fixedsize=true ];
node [ color=lightpink];
    output
}

//--

//subgraph  cluster_inner {
    //label="abstractions"
    //color="black"
    //style="invis"
    component_a [ label = <
        <table border="0" cellspacing="0"><tr>
            <td border="1" bgcolor="white"   > </td>
            <td border="1" bgcolor="palegreen" port="port2">port2</td>
            <td border="1" bgcolor="palegreen" port="port3">port3</td>
        </tr><tr>
            <td border="1" bgcolor="skyblue"   port="port6">port6</td>
            <td border="1" bgcolor="peachpuff" rowspan="3" colspan="2">A</td>
        </tr><tr>
            <td border="1" bgcolor="skyblue"   port="port7">port7</td>
        </tr><tr>
            <td border="1" bgcolor="skyblue"   port="port8">port8</td>
        </tr><tr>
           <td border="1" bgcolor="lightpink" colspan="1" port="port4">port4</td>
           <td border="1" bgcolor="lightpink" colspan="2" port="port5">port5</td>
        </tr></table> > style = "invisible" ]

    component_b [ label = <
        <table border="0" cellspacing="0"><tr>
            <td border="1" bgcolor="white"   > </td>
            <td border="1" bgcolor="palegreen" port="port22">port22</td>
            <td border="1" bgcolor="palegreen" port="port23">port23</td>
        </tr><tr>
            <td border="1" bgcolor="skyblue"   port="port25">port25</td>
            <td border="1" bgcolor="peachpuff" colspan="2"> B </td>
        </tr><tr>
        <td border="1" bgcolor="lightpink" colspan="3" port="port24">port24</td>
        </tr></table> > style = "invisible" ]

//-

    component_c [ label = <
        <table border="0" cellspacing="0"><tr>
            <td border="1" bgcolor="white"   > </td>
            <td border="1" bgcolor="palegreen" port="port32">port32</td>
            <td border="1" bgcolor="palegreen" port="port33">port33</td>
        </tr><tr>
            <td border="1" bgcolor="skyblue"   port="port35">port35</td>
            <td border="1" bgcolor="peachpuff" colspan="2"> C </td>
        </tr><tr>
         <td border="1" bgcolor="lightpink" colspan="3" port="port34">port34</td>
        </tr></table> > style = "invisible" ]
//}


port101 -> port103
port102 -> component_a 
port102 -> component_b
port103 -> port104

component_a -> output;
component_b -> output;
component_c -> output;

edge [ style="" arrowhead="normal" color="#444444"]
component_a:port4 -> output;

component_c:port34 -> component_a:port3;
component_a:port5 -> component_b:port22;

port101 -> component_c:port33

//-

{ rank = same

    edge [ dir=back ]
    port104 -> component_a:port8
}

}

component_starter;
component_starter:port5 -> port101;

}

The above dot file, compressed. Use base64 -d nesting.bz2.base64 |bzcat to view it.

QlpoOTFBWSZTWd/epEIABCzfgHAwWAP/3zgkmAq/7//6UASZm8a7VNrQBQQlSDUaYjTINGjIyZAG
ho0aNMgkUZJpEIzUw0TTEzQBoAIwCTUiFT1NppDymGk0Pap6gMmCaAAcwAAAAAAAAAAFSRJoGp6B
TyNTyhABoD1DQ0aephLyAcTAhMSQiKogMBLsVaZBYIwUHIGFISYVKCMVkRgLypG2mhHPb5z0hBap
yN3HCL2iJVDYvXI6SykmzPN9LCaex+63c7jyTnk18c2KgvDZq6Kkz+WWf4DU4KoQsCQJ1gKpAcwC
mp5nGnmlI8wBNtgDi+Hmf0/g/v4PoNaZVrhy5cdWCavJkutPC0t50kljBJLHXrbQUjJMPPDCUKwN
NHO8aaiqKTus3tLEpprCW8Gzr68DtvyteHrqa7JJ9J46R4muUMuU39kJYPEgwJWwCSqsgMteezTo
ta1rr3va1sccdW/32OJUROFkmUzqeyHn+g96EccgEY5SfJixh2aJgQC0JVmWAtrdagoOkDZAViKA
qUpGZ1dXNJikmmsRZmAO16Kq9osW7KzzPZPS9IeLIqXo0cOoNwatry3Mi792YMRvA3oiKxe84ac7
EMGmdrabTaG0qqDpAMJJn5IeAbvMNiSJW8og7y+Ik+CExJBhLDZlKFSFKMBgIIMai57J5pLmgl5R
Qm261e797RF6qhy82NQypLEa8ktUVAL2R1hxThWC3pVB0jBThRxVLfHHJeZHv+pMEkxZ3P6KP+ho
QWyC9gtIM2cxJK2pIiiIooOPlxE0kkspJPijcgrHRHw6XvMpwy5ldiqlUpWzvymgxr78zAXh4vSW
L3jya8Hqc6ekwhhDROybThDBnIdmdlN6ClO8bo7ucxNqSVjHNGd8F8ocW2qmT0bJRujojA9MJqnC
TPg09tZlJ5d/am7W8E6GeU3TkyVC0N5nTgeXXn7Sj1UWijm1Q07OKeXiyPbENRSNcNzrnkyxkNeu
RgS5GWEXKkpTdIy8NenUhVYpqkbUCushe+cQ15oMcRIrb4GZscDDVmLk3LF7Txk6yFvmky8aoiK5
T+3pVRjVVVUtLRVFFI0q1lrpHlGqNnHKOVIKkktUYAuq2L1bekwQeG68LX3tK64kVNRw2tDb7rLn
acBl0J61Ld57HXXHKpXLjoqAo5yyRvQ/YxLdufjNCSaEk4mmYLcZp1ybI1BqDTum20PSm2cId4pU
Zx00pZzOJZwnSHjAqXNkWCM4s/+LuSKcKEhv71IhAA==
Brockbrocken answered 31/7, 2013 at 23:33 Comment(4)
I'm dropping this in your lap, because I have to run now. Let me know if there are questions (details) I can add to the answer...Swanner
Hi! Thanks for your answer, sorry I couldn't test it before. However I cannot manage to make it run. Looks like Python is failing on retreiving attribute 'width'. Which version of Xdot do you use to visualize it (mine is 0.4)? Or another soft? Anyway, your answer looks perfect to me!Finedraw
I rendered that directly with graphviz. dot - graphviz version 2.26.3Swanner
Yep, I just tested and it works perfectly! Looks like Xdot cannot handle fixed size elements. Thanks for all!Finedraw

© 2022 - 2024 — McMap. All rights reserved.