This question was also asked on StackOverflow

I have a phylogenetic tree made with a Newick format

((a:1,b:1):2, (c:1, d:1):3):1;

The output will be

enter image description here

I have drawn this with http://etetoolkit.org/treeview/, but output with R will be same.

What I want to do is apply colors to a certain branch.

That would be

enter image description here

For example, enter image description here

Since the Newick input doesn't include any information other than the branch (c,d) has length 3, is there any way I can include multiple color information on the branch?

I usually use ggtree for making trees, but other suggestions can be helpful.

The main script for this kind of tree building is like this, but I can't figure out how this works.

(Full script Github link: https://github.com/seongyeol-park/Human_Lineage_Tracing/blob/main/Rscripts/HSC_commitment.R)

ggtree(tree) %<+% m_lng_dt + theme_tree2()+
  coord_cartesian(xlim = c(-1,35))+
  geom_text2(aes(subset = is.na(Source_class2) == F, x=x-n_pointmt+3, y = y+0.25, label = Source_class2), size=2.5, color="red")+
  geom_segment2(aes(subset = is.na(VAF1) == F, x=x-n_pointmt, xend = x -n_pointmt +1, y = y, yend = y, color = VAF1))+
  geom_text2(aes(subset = is.na(VAF1) == F, x=x-n_pointmt, y = y, label = VAF1), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF2) == F, x=x-n_pointmt+1, xend = x -n_pointmt +2, y = y, yend = y, color = VAF2))+
  geom_text2(aes(subset = is.na(VAF2) == F, x=x-n_pointmt+1, y = y, label = VAF2), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF3) == F, x=x-n_pointmt+2, xend = x -n_pointmt +3, y = y, yend = y, color = VAF3))+
  geom_text2(aes(subset = is.na(VAF3) == F, x=x-n_pointmt+2, y = y, label = VAF3), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF4) == F, x=x-n_pointmt+3, xend = x -n_pointmt +4, y = y, yend = y, color = VAF4))+
  geom_text2(aes(subset = is.na(VAF4) == F, x=x-n_pointmt+3, y = y, label = VAF4), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF5) == F, x=x-n_pointmt+4, xend = x -n_pointmt +5, y = y, yend = y, color = VAF5))+
  geom_text2(aes(subset = is.na(VAF5) == F, x=x-n_pointmt+4, y = y, label = VAF5), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF6) == F, x=x-n_pointmt+5, xend = x -n_pointmt +6, y = y, yend = y, color = VAF6))+
  geom_text2(aes(subset = is.na(VAF6) == F, x=x-n_pointmt+5, y = y, label = VAF6), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF7) == F, x=x-n_pointmt+6, xend = x -n_pointmt +7, y = y, yend = y, color = VAF7))+
  geom_text2(aes(subset = is.na(VAF7) == F, x=x-n_pointmt+6, y = y, label = VAF7), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF8) == F, x=x-n_pointmt+7, xend = x -n_pointmt +8, y = y, yend = y, color = VAF8))+
  geom_text2(aes(subset = is.na(VAF8) == F, x=x-n_pointmt+7, y = y, label = VAF8), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF9) == F, x=x-n_pointmt+8, xend = x -n_pointmt +9, y = y, yend = y, color = VAF9))+
  geom_text2(aes(subset = is.na(VAF9) == F, x=x-n_pointmt+8, y = y, label = VAF9), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF10) == F, x=x-n_pointmt+9, xend = x -n_pointmt +10, y = y, yend = y, color = VAF10))+
  geom_text2(aes(subset = is.na(VAF10) == F, x=x-n_pointmt+9, y = y, label = VAF10), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF11) == F, x=x-n_pointmt+10, xend = x -n_pointmt +11, y = y, yend = y, color = VAF11))+
  geom_text2(aes(subset = is.na(VAF11) == F, x=x-n_pointmt+10, y = y, label = VAF11), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF12) == F, x=x-n_pointmt+11, xend = x -n_pointmt +12, y = y, yend = y, color = VAF12))+
  geom_text2(aes(subset = is.na(VAF12) == F, x=x-n_pointmt+11, y = y, label = VAF12), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF13) == F, x=x-n_pointmt+12, xend = x -n_pointmt +13, y = y, yend = y, color = VAF13))+
  geom_text2(aes(subset = is.na(VAF13) == F, x=x-n_pointmt+12, y = y, label = VAF13), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF14) == F, x=x-n_pointmt+13, xend = x -n_pointmt +14, y = y, yend = y, color = VAF14))+
  geom_text2(aes(subset = is.na(VAF14) == F, x=x-n_pointmt+13, y = y, label = VAF14), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF15) == F, x=x-n_pointmt+14, xend = x -n_pointmt +15, y = y, yend = y, color = VAF15))+
  geom_text2(aes(subset = is.na(VAF15) == F, x=x-n_pointmt+14, y = y, label = VAF15), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF16) == F, x=x-n_pointmt+15, xend = x -n_pointmt +16, y = y, yend = y, color = VAF16))+
  geom_text2(aes(subset = is.na(VAF16) == F, x=x-n_pointmt+15, y = y, label = VAF16), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF17) == F, x=x-n_pointmt+16, xend = x -n_pointmt +17, y = y, yend = y, color = VAF17))+
  geom_text2(aes(subset = is.na(VAF17) == F, x=x-n_pointmt+16, y = y, label = VAF17), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF18) == F, x=x-n_pointmt+17, xend = x -n_pointmt +18, y = y, yend = y, color = VAF18))+
  geom_text2(aes(subset = is.na(VAF18) == F, x=x-n_pointmt+17, y = y, label = VAF18), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF19) == F, x=x-n_pointmt+18, xend = x -n_pointmt +19, y = y, yend = y, color = VAF19))+
  geom_text2(aes(subset = is.na(VAF19) == F, x=x-n_pointmt+18, y = y, label = VAF19), size=2.5)+
  geom_segment2(aes(subset = is.na(VAF20) == F, x=x-n_pointmt+19, xend = x -n_pointmt +20, y = y, yend = y, color = VAF20))+
  geom_text2(aes(subset = is.na(VAF20) == F, x=x-n_pointmt+19, y = y, label = VAF20), size=2.5)+
  scale_color_gradientn(colors = my_palette, breaks = col_breaks)+
  theme(axis.text = element_text(size=15, angle=45, hjust=1), plot.title = element_text(size=20), plot.margin= unit(c(0.2,0,0.2,0.2),"cm"))
  • $\begingroup$ I added a random colour tree, which is what I think you might want excepting the legend. $\endgroup$
    – M__
    Jul 9, 2022 at 7:11

2 Answers 2


The simple solution is Figtree a GUI that easily colours trees on a 'point and click' basis. In linux this can be driven via CLI, which is useful.

The easy coding solution is to use extended Newick format (NHX) to colour the tree.

(((a:1,b:1[&NHX:C=2.2.2]):2[&NHX:C=2.2.2], (c:1[&NHX:C=100.100.100], d:1[&NHX:C=100.100.100]):3[&NHX:C=10.10.10]):1);

enter image description here

The next thing is a viewer that accepts NHX format and here I used 'Icytree' here

The alternative format a tree viewer might take is:

(((a:1,b:1[&&NHX:C=2.2.2]):2[&&NHX:C=2.2.2], (c:1[&&NHX:C=100.100.100], d:1[&&NHX:C=100.100.100]):3[&&NHX:C=10.10.10]):1);

I noted you'd used ETE3 toolkit website for your tree. Just to mention ETE3 has two levels,

  • the underlying raw Python library
  • the website GUI

The underlying raw Python is cool, except it was written to v3.6 because you combine it with your own code, the website is alright, but I think there's better.

Using NHX allows the branch width to be set as well:

(((a:1,b:1[&NHX:C=2.2.2:W=3]):2[&NHX:C=2.2.2:W=3], (c:1[&NHX:C=100.100.100:W=3], d:1[&NHX:C=100.100.100:W=3]):3[&NHX:C=10.10.10:W=3]):1);

Sadly you can't set the font (which you obviously can in ggtree

NHX normally used for auxiliary information, such as species name, or a particular phenotype.

In summary, I do prefer NHX if you are coding over R.

Note For tree colouring you have to set the use NHX format BTW in the options, a tree browser will not do it automatically.

The basic ggtree first step is to make the tree ...

tree <- read.tree(text = "(((a:1,b:1):2, (c:1, d:1):3):1);") # my bracketing might be wrong

Then use ggplot2 style functions to overlay the presentation, I'm assuming you do understand ggplot2. What the code you showed was doing was individually changing every font and the position of every branch in the tree. This is definitely not cool code and I wouldn't consider it further, i.e. its not even worth bothering with, that ain't how graphs nor trees are supposed to be represented.

In any case, overall ggplot2 style code is always fiddly and to be honest I gave up using it, but you increment/or layer the changes you want as the code you supplied describes. Honestly I don't want to get into the fiddly incremental layered changes that ggplot2 graphs require.

ETE3 is good and does do coloured trees, which are described here, http://etetoolkit.org/docs/latest/tutorial/tutorial_drawing.html. The only hassle it was written for Python 3.6 - that long ago, but you can access it via conda and set the Python version.

ETE4 will be very cool but its badly delayed in its release date, they did get funding for this so the delay is not cool, maybe never who knows. Getting it up to Python 3.10 would be useful at the very least.

My personal take is ETE3 is useful for automating the tree output so you can manually assess the iterations, its quite critical for e.g. testing and debugging. Whether you are turning that into publication quality - which is universally how graphs are handled - I personally find excessive. The difference is that complex graphs represent loads of information which is not always immediately obvious to a casual observer, therefore gamma (transparency), plot type loads of stuff are relevant. A tree is a tree and 'dressing up a tree' makes not a jot of difference for an experienced observer. If someone wasn't quite clear about a tree, they'd just ask you for the tree file and file it through 'Figtree'.


See change colors or line types of arbitrarily selected branches in ggtree documentation for details. Here's my R code for applying a color to a specific branch in ggtree:

# read tree data
tree <- read.newick('tree.nwk')
# create a dataframe of the default color (black) for branches
branchColor <- data.frame(node = 1:Nnode2(tree), colour = 'black')
# set a color for the specifc branch
branchColor[7, 2] <- 'blue'
branchColor[3, 2] <- 'orange'
branchColor[6, 2] <- 'purple'
branchColor[c(1, 2), 2] <- 'red'
# plot tree
ggtree(tree, size = 1) %<+%
  branchColor +
  aes(colour = I(colour)) +
  geom_tippoint(size = 2, color = 'black') +
  geom_tiplab(size = 5, color = 'black') +
  geom_treescale(x = 0, y = 0, width = 0.5, fontsize = 5, linesize = 1)

The tree looks like this: enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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