Unfortunately, Graphviz does not include a tree model (see How to lay out binary tree / hierarchicy? - #3 by steveroush and Provide a collection of simple tree layouts (#2032) · Issues · graphviz / graphviz · GitLab).
However, here is a post-processor program for binary trees (not well tested). It is pretty simple-minded, defaulting to single-edges-always-go-left rule. (single-edges-always-go-right is equally easy). The problem with these simple rules is that they tend to be very lop-sided (see bottom).
To allow for more symmetric layouts, the post-processor allows the user to explicitly direct an edge right or left using a new edge attribute: side. Values: L|l|R|r|U|u|D|d
The post-processor is written in the GVPR (https://www.graphviz.org/pdf/gvpr.1.pdf) language - part of the Graphviz package. The GVPR output is passed to neato -n
(see FAQ | Graphviz). Somewhat convoluted, but you should not have to mess with anything other than your input.
Command-line (Linux) (Windows should be similar):
dot -Tdot myfile.gv | gvpr -c -f binaryTree.gvpr | neato -n -Tpng >myfile.png
binaryTree.gvpr:
BEGIN{
int left_right, Right[], Left[];
float shiftFactor;
node_t Head, Tail;
}
BEG_G{
left_right=0;
if ((hasAttr($G, "rankdir")) && ($G.rankdir!="") && $G.rankdir=="@(LR|RL)") left_right = 1;
shiftFactor=1.1*72; // effectively sets the angle (eyeballed, no trig)
}
E{
Head=$.head;
Tail=$.tail;
// legal values for side: left(L|l) or right(R|r) or up(U|u) or down(D|d)
// current value testing is incomplete
// awkwardly written, but seemingly correct
if (Left[Tail]!=1 && (((!((hasAttr($, "side")) && ($.side!=""))) || Right[Tail]==1 || ((hasAttr($, "side")) && ($.side!="") && $.side=="@(L|l|D|d)")))){
print("// LEFT/UP");
Left[Tail]=1;
if (left_right==0)
Head.pos=(string)(Tail.X-(shiftFactor*(float)Head.width)) + "," + (string)Head.Y;
else
Head.pos=(string)Head.X + "," + (string)(Tail.Y-(shiftFactor*(float)Head.height)) ;
}else{
print("// RIGHT/DOWN");
Right[Tail]=1;
if (left_right==0)
Head.pos=(string)(Tail.X+(shiftFactor*(float)Head.width)) + "," + (string)Head.Y;
else
Head.pos=(string)Head.X + "," + (string)(Tail.Y+(shiftFactor*(float)Head.height)) ;
}
$.pos="";
}
Your file, modified:
graph{
node [shape=circle]
1 -- 2;
2 -- 5;
2 -- 4;
5 -- 7;
7 -- 6;
6 -- 13 [side=R] // added a new attribute (side), send this edge to the right
13 -- 11;
11 -- 12 [side=R] // this edge to the right
12 -- 14;
4 -- 8;
4 -- 3;
3 -- 9;
9 -- 10 [side=R] // this edge to the right
}
Giving:
Default (lop-sided) version from the program: