# Seeking Guidance on RankDir (Layout)

**URL:** <https://forum.graphviz.org/t/seeking-guidance-on-rankdir-layout/400>\
**Category:** Help\
**Created:** [October 25, 2020, 6:25pm UTC](https://forum.graphviz.org/t/seeking-guidance-on-rankdir-layout/400 "2020-10-25T18:25:14Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![charley](https://avatars.discourse-cdn.com/v4/letter/c/97f17d/32.png) [@charley](https://forum.graphviz.org/u/charley)\
**Post date:** [October 25, 2020, 6:25pm UTC](https://forum.graphviz.org/t/seeking-guidance-on-rankdir-layout/400/1 "2020-10-25T18:25:14Z")

</div>

Below I am trying to model a state diagram as FSA/FSM I have just started using GraphViz in the hope of keeping the state diagrams as source. The layout I want is eluding me. I would like the subgraph `clusterPreGame` and `clusterGame` to have a `rankDir` of “TB” but these are inherited from the parent graph as “LR”. Any guidance on better layout algorithms or techniques is appreciated.

Setup: I am rendering this using vscode plugin “Graphviz Preview” [EFanZh] which renders a preview on MacOS via a brew installed implementation of dot.

any help appreciated.

[dot]

```auto
digraph cardtable {
    size=5.5
    node [shape=record]
    compound=true;
    rankdir="LR";

    
    subgraph clusterPreGame {
        label="Pregame";
        rank=same;
        InRoom [label="\<\<State\>\> \n InRoom | bool:public"];
        InLobby[label="\<\<State\>\> \n InLobby"];
        InSelector[label="\<\<State\>\> \n InGameSelector | enum: local \| remote"];   
    }

    subgraph clusterGame {
        label="Game";
        subgraph clusterDealing {
            label="Cut For Deal";
            CutForDeal;
            AwaitDeal;
            CutForDeal -> AwaitDeal;
     }

      subgraph clusterNthState {
            nthStateNode;
            label="nthState";
            rankdir="TB";
            rank=same;
        }
    }

    InLobby -> InSelector -> InRoom;
    InRoom -> CutForDeal [lhead=clusterDealing label="startGame"];
    AwaitDeal -> nthStateNode[label="nthTransition" lhead=clusterNthState];
    
}

```

[/dot]

```auto
digraph cardtable {
    size=5.5
    node [shape=record]
    compound=true;
    rankdir="LR";

    
    subgraph clusterPreGame {
        label="Pregame";
        rank=same;
        InRoom [label="\<\<State\>\> \n InRoom | bool:public"];
        InLobby[label="\<\<State\>\> \n InLobby"];
        InSelector[label="\<\<State\>\> \n InGameSelector | enum: local \| remote"];   
    }
    subgraph clusterGame {
        label="Game";
        subgraph clusterDealing {
            label="Cut For Deal";
            CutForDeal;
            AwaitDeal;
            CutForDeal -> AwaitDeal;

      subgraph clusterNthState {
            nthStateNode;
            label="Numerals";
            rankdir="TB";
            rank=same;
        }
     }
        
        
    }

    InLobby -> InSelector -> InRoom
    InRoom -> CutForDeal [lhead=clusterDealing label="startGame"];
    WaitForDeal -> nthStateNode[lhead=clusterNthState label="nthTransition"];

    
    
    
}

```

---

<div class="post-metadata">

**Author:** ![erg](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/erg/32/34_2.png) [@erg](https://forum.graphviz.org/u/erg)\
**Post date:** [October 27, 2020, 8:14pm UTC](https://forum.graphviz.org/t/seeking-guidance-on-rankdir-layout/400/2 "2020-10-27T20:14:13Z")

</div>

Unfortunately, rankdir is only applicable in the root graph. Second, the implementation of rankdir=LR lays out the graph using rankdir=TB and then rotates the layout 90 degrees counterclockwise. This means that flat edges end up pointing up rather than down. Also, using shape=record should only be used in the simplest cases. In particular, record shapes don’t work well with rankdir. The preferred construct is HTML-like labels. I have supplied a solution below. As a final “unfortunately,” it appears to trigger a bug where an edge is drawn using two splines.

```
digraph cardtable {
    compound=true;
    rankdir="LR";
    newrank="true";

    subgraph clusterPreGame {
        label="Pregame";
        rank=same;
        InRoom [margin=0 shape=none label=< <table cellborder="0"><tr><td>&lt;&lt;State&gt;&gt; <BR/> InRoom </td></tr> <hr/> <tr><td>bool:public</td></tr></table> >];
        InLobby [margin=0 shape=box label=< &lt;&lt;State&gt;&gt; <BR/> InLobby >];
        InSelector [margin=0 shape=none label=< <table cellborder="0"><tr><td>&lt;&lt;State&gt;&gt; <BR/> InGameSelector </td></tr> <hr/> <tr><td>enum: local | remote</td></tr></table> >];
        InRoom -> InSelector -> InLobby [dir=back]
    }
    subgraph clusterGame {
        label="Game";
        node[shape=box]
        rank=same;
        subgraph clusterDealing {
            label="Cut For Deal";
            CutForDeal;
            AwaitDeal;
            AwaitDeal -> CutForDeal [dir=back]
        }
      subgraph clusterNthState {
            nthStateNode;
            label="Numerals";
      }

      AwaitDeal -> nthStateNode [lhead=clusterNthState xlabel="nthTransition"];
    }

    InRoom -> CutForDeal [lhead=clusterDealing label="startGame"];
}

```

 ![out](https://global.discourse-cdn.com/graphviz/original/1X/18500768b31e46ea43bb7f790f68ae8a363bd3f3.png)
