I'm interested in using TikZ to draw rooted trees whose leaves should all be on the same level, pretty much like this:

alt text

Please don't pay attention to the fancy style and colours, I'm only interested in having all leaves at the same level. Anyone knows how to do this? I've looked into the manual and the appropriate section on Texample, but had no luck so far.

UPDATE: a while after this question was answered, I found out about the LaTeX newicktree package, which allows you to draw such trees in an extremely simple way, just by specifying them in the format people in phylogenetics already use. This is obviously much simpler than resorting to TikZ, but thanks anyway to everyone who contributed to helping me.

  • From Matthew's response, it appears that this isn't going to be possible using the standard tree syntax of TikZ. I can imagine lots of ways to achieve the same end, but exactly which route to take would depend on how flexible you want it to be in terms of inputting your data. How much work would you be prepared to do, and how much do you want TikZ to do? (For example, do you want TikZ to work out the order of the nodes, or are you happy to put that in?) – Andrew Stacey Nov 8 '10 at 19:39
  • Hard to say... I don't feel like reinventing the wheel or writing hundreds of lines either, so if it really gets too complicated, I'm open to other suggestions (other packages, converting trees from nexus to dot and then using dot2tex, ...) as long as the result is good looking - or modifiable without too much pain to make it look good. – Anthony Labarre Nov 8 '10 at 20:12
  • If you want to specify the minimum amount of extra information then I would take a look at graphviz and dot2tex since I know that all this is possible with graphviz. But if you're willing to put in more structural information, then solutions such as Matthew's are possible. – Andrew Stacey Nov 9 '10 at 19:25
  • 1
    There was a recent related thread on pgf-users, perhaps it will help. – Matthew Leingang Jan 11 '11 at 15:40

Here's an alternative if you're prepared to tell TikZ the order of the labels across the top. It's a bit klunky, especially in that it draws several lines twice (or more!). Also, I've taken you at your word and ignored the fancy styles.



\node[coordinate] (start) at (0,0) {};
\foreach \n/\l in {
  rayfinned fish/rf,
} {
  \node[transform shape,below right] (\l) at (\pl.south west) {\n};

\foreach \a/\b in {
} {
  \draw (\a.mid west) |- (\b.mid west);

This produces:

alt text

Explanation of how it works

  1. The first thing to understand is the rotations. This code draws the lines by using a certain type of path which is constrained to be only horizontal and vertical. However, in the desired outcome, the lines are diagonal. Solution: rotate the picture so that the diagonals are the internal "horizontal" and "vertical".

  2. The second thing to understand is the double rotation. The external rotation (on the tikzpicture environment) deals with the conversion of diagonals to horizontal and verticals. The second rotation (on the first scope) is to get the nodes pointing upwards. To do this properly, we add the transform shape key to the actual nodes. This means that the nodes are rotated 45 degrees with respect to everything outside that scope.

  3. Now the node positioning. We define a starting coordinate (start) at (0,0). Then we loop over the nodes, setting \n to be the node contents and \l to be a shorthand for that node (its label). The macro \pl holds the label of the previous node, which at the first iteration is set to the starting coordinate. We want the nodes to line up so that they look like a list all lined up. To achieve this, we place the north west anchor of the current node at the south west anchor of the previous node. The below right key on the node says "Use the north west anchor for positioning this node" and the (\pl.south west) says "Place it at the south west anchor of the previous node". Lastly, we set \pl to be the label of the current node, which becomes the next node on the next iteration (note the \xdef, if we used \edef it would be local to the iteration which isn't what we want).

  4. Lastly, the lines. We loop over the connected pairs, drawing a line from the mid west anchor of one node to the mid west anchor of the other. We specify the pairs with the "upper" node first, and draw a line that is first "vertical" and then "horizontal" (remembering that those will rotate to the diagonals in the final rendering). Using the mid west anchor means that the lines will end at half an ex above the baseline. Since our lines are so strictly defined, the fact that we sometimes draw over the top of another one should not be too noticeable.

| improve this answer | |
  • Creative solution! – Caramdir Nov 9 '10 at 19:50
  • Very nice result! – Anthony Labarre Nov 10 '10 at 8:28
  • @Anthony: Thanks. It's not perfect, but I'm not sure how to improve it without knowing more about how your data is generated and how you're prepared to specify it. I feel that you're really drawing a lattice or a poset rather than a graph. – Andrew Stacey Nov 10 '10 at 8:33
  • @Andrew: I'm a novice to TikZ and am puzzled by one thing: Why are the labels in your solution so nicely aligned, whereas in Matthew's (otherwise nice) solution the alignment is not so great? (Caramdir explained a bit about the descenders, but you don't have this problem here.) – Hendrik Vogt Nov 10 '10 at 13:14
  • 2
    @Hendrik: I've added an explanation of how it works (I wasn't sure if anyone would like it so didn't do it first time round). The point about the 'mid west' and 'south west' is that the 'south west' is for positioning the nodes whilst the 'mid west' is for positioning the lines. The key to getting the positioning right overall (in my solution) is to position the nodes first and do the lines afterwards. – Andrew Stacey Nov 10 '10 at 21:29

Great question! TikZ is not set up to do this kind of tree. It assumes that the position of each child node is a function of the number of the child node and the total number of child nodes. To define the tree you have with a single child node for each leaf won't work because the rayfinned fish leaf needs to get further from the root when you add the mammals leaf.

But you can trick it by creating invisible nodes at regular points. Your tree would need to be 10 levels deep, I think.

Or, you can hack by using a custom growth function (See section 42 of the PGF 2.00 manual or section 53 of the 2.10 manual):

    grow via three points={% 
        one child at (-0.5,1) and two children at (-0.5,1) and (0.5,1)},
        rectangle,inner sep=0pt,outer sep=1pt, minimum width=5pt,minimum height=5pt,fill,
        label={[black,anchor=west,rotate around={90:(-2.5pt,0)}
\node[coordinate] {} [%
         grow via three points={one child at (0,0) and two children at (-4.5,9) and (0.5,1)},
         very thick,yellow
     child {node[genus=rayfinned fish] {}}
     child {
         [grow via three points={one child at (0,0) and two children at (-4,8) and (0.5,1)}]     
         child {node[genus=lungfish] {}}
         child {
             [grow via three points={one child at (0,0) and two children at (-3,6) and (1,2)}]      
             child {
                 [grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
                 child {node[genus=salamanders] {}}
                 child {node[genus=frogs] {}}    
             child[blue] {
                 [grow via three points={one child at (0,0) and two children at (-2.5,5) and (0.5,1)}]
                 child {node[genus=turtles] {}}
                 child {
                     [grow via three points={one child at (0,0) and two children at (-0.5,1) and (2,4)}]
                     child {
                         [grow via three points={one child at (0,0) and two children at (-1,2) and (1,2)}]
                         child {
                             [grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
                             child {node[genus=lizards] {}}
                             child {node[genus=snakes] {}}
                         child {
                             [grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
                             child {node[genus=crocodiles] {}}
                             child {node[genus=birds] {}}
                     child {node[genus=mammals] {}}   

tree using code sample above

That should probably be cleaned up--I think you can create a named coordinate in each direction and scale.

| improve this answer | |
  • Yes, that's the workaround I had in mind. – Anthony Labarre Nov 8 '10 at 20:10
  • I have one put together but I'm still debugging it. Having that many levels and empty nodes is giving me a popsicle headache. – Matthew Leingang Nov 9 '10 at 10:12
  • Great work! But I wonder why some of the labels are so badly aligned. – Hendrik Vogt Nov 9 '10 at 13:53
  • @Hendrik: see “16.5 Positioning Nodes” in the (current) TikZ manual. Basically, anchor=west in the genus definition has to be replaced by anchor=base west or anchor=mid west. In both cases the rotation center has to be moved a bit to give nice results. @Matthew: great answer! btw, a new version of TikZ was released a few weeks ago. In the current manual it is section 53. – Caramdir Nov 9 '10 at 16:41
  • @Caramdir: thanks for pointing that out. I'm still behind the curve using version 2.0. I should have given the name of the section instead of the number. And the labels were getting to be more trouble than they were worth so I gave up. – Matthew Leingang Nov 9 '10 at 17:08

I've found this answere at the official maillist. As far as I understand, it's a different approach than the ones proposed here, but at least the question was the same. Nevertheless I could reproduce the desired result. But it might be useful for somebody, so I wanted to link it here.

Also another useful hint which doesn't answer the question: if you use PStricks, you can use the command \skiplevel.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.