Setup

library(ggtreeExtra)
library(ggstar)
library(ggplot2)
library(ggtree)
library(treeio)
library(ggnewscale)

1. Introduction

Phylogenetic trees was often used with associated data in various biological studies. ggtree, a flexible R package to visualize phylogenetic tree, had been developed by GuangChuang Yu (Yu et al. 2017). It provided geom_facet function to align associated graphs to the tree (Yu et al. 2018; Yu 2020). However, This function did not support the tree created using circular, fan or radial layout. To solve the problem, We developed ggtreeExtra, which can align associated graphs to circular, fan or radial and other rectangular layout tree. ggtreeExtra provides function, geom_fruit to align graphs to the tree. But the associated graphs will align in different position. So we also developed geom_fruit_list to add multiple layers in the same position. Furthermore, axis of external layers can be added using the axis.params=list(axis="x",...) in geom_fruit. The grid lines of external layers can be added using the grid.params=list() in geom_fruit. These functions are based on ggplot2 using grammar of graphics (Wickham 2016). More vignettes can be found on the chapter10 of online book.

2. Install

You can use the following to install it

# for devel
if(!requireNamespace("remotes", quietly=TRUE)){
    install.packages("remotes")
}
remotes::install_github("YuLab-SMU/ggtreeExtra")

# for release
if (!requireNamespace("BiocManager", quietly=TRUE))
    install.packages("BiocManager")
    
## BiocManager::install("BiocUpgrade") ## you may need this
BiocManager::install("ggtreeExtra")

3. Usage

To show the package profiling, I will use a tree file downloaded from plotTree. The associated datasets were simulated.

3.1 add single layer

# The path of tree file.
trfile <- system.file("extdata", "tree.nwk", package="ggtreeExtra")
# The path of file to plot tippoint.
tippoint1 <- system.file("extdata", "tree_tippoint_bar.csv", package="ggtreeExtra")
# The path of first layer outside of tree.
ring1 <- system.file("extdata", "first_ring_discrete.csv", package="ggtreeExtra")
# The path of second layer outside of tree.
ring2 <- system.file("extdata", "second_ring_continuous.csv", package="ggtreeExtra")

# The tree file was import using read.tree. If you have other format of tree, you can use corresponding function of treeio to read it.
tree <- read.tree(trfile)

# This dataset will to be plotted point and bar.
dat1 <- read.csv(tippoint1)
knitr::kable(head(dat1))
ID Location Length Group Abundance
DE0655_HCMC_2001 HK 0.1786629 Yes 12.331055
MS0111_HCMC_1996 HK 0.2105236 Yes 9.652052
MS0063_HCMC_1995 HK 1.4337983 Yes 11.584822
DE0490_HCMC_2000 HK 0.3823731 Yes 7.893231
DE0885_HCMC_2001 HK 0.8478901 Yes 12.117232
DE0891_HCMC_2001 HK 1.5038646 Yes 10.819734
# This dataset will to be plotted heatmap
dat2 <- read.csv(ring1)
knitr::kable(head(dat2))
ID Pos Type
DE0846_HCMC_2001 8 type2
MS0034_HCMC_1995 8 type2
EG1017_HCMC_2009 6 type2
KH18_HCMC_2009 5 type2
10365_HCMC_2010 7 type2
EG1021_HCMC_2009 1 type1
# This dataset will to be plotted heatmap
dat3 <- read.csv(ring2)
knitr::kable(head(dat3))
ID Type2 Alpha
MS0004_HCMC_1995 p3 0.2256195
DE1150_HCMC_2002 p2 0.2222086
MS0048_HCMC_1995 p2 0.1881510
HUE57_HCMC_2010 p3 0.1939088
DE1486_HCMC_2002 p2 0.2018493
DE1165_HCMC_2002 p3 0.1812997
# The format of the datasets is the long shape for ggplot2. If you have short shape dataset,
# you can use melt of reshape2 or pivot_longer of tidyr to convert it.

# We use ggtree to create fan layout tree. 
p <- ggtree(tree, layout="fan", open.angle=10, size=0.5)
#> Scale for 'y' is already present. Adding another scale for 'y', which will
#> replace the existing scale.
p


# Next, we can use %<+% of ggtree to add annotation dataset to tree.
p1 <- p %<+% dat1
p1

# We use geom_star to add point layer outside of tree.
p2 <- p1 + 
      geom_star(
          mapping=aes(fill=Location, size=Length, starshape=Group),
          starstroke=0.2
      ) +
      scale_size_continuous(
          range=c(1, 3),
          guide=guide_legend(
                     keywidth=0.5, 
                     keyheight=0.5, 
                     override.aes=list(starshape=15), 
                     order=2)
      ) + 
      scale_fill_manual(
          values=c("#F8766D", "#C49A00", "#53B400", "#00C094", "#00B6EB", "#A58AFF", "#FB61D7"),
          guide="none" # don't show the legend.
      ) + 
      scale_starshape_manual(
          values=c(1, 15),
          guide=guide_legend(
                    keywidth=0.5, # adjust width of legend
                    keyheight=0.5, # adjust height of legend
                    order=1 # adjust the order of legend for multiple legends.
                ),
          na.translate=FALSE # to remove the NA legend.
      ) 
p2


# Or if we don't use %<+% to add annotation dataset, instead of data parameter of geom_fruit. 
# You should specify the y column (tip label), here is y=ID.
p2 <- p + 
      geom_fruit(
          data=dat1,
          geom=geom_star,
          mapping=aes(y=ID, fill=Location, size=Length, starshape=Group),
          position="identity",
          starstroke=0.2
      ) + 
      scale_size_continuous(
          range=c(1, 3), # the range of size.
          guide=guide_legend(
                    keywidth=0.5, 
                    keyheight=0.5,
                    override.aes=list(starshape=15),
                    order=2
                )
      ) +
      scale_fill_manual(
          values=c("#F8766D", "#C49A00", "#53B400", "#00C094", "#00B6EB", "#A58AFF", "#FB61D7"),
          guide="none"
      ) + 
      scale_starshape_manual(
          values=c(1, 15),
          guide=guide_legend(
                    keywidth=0.5,
                    keyheight=0.5,
                    order=1
                )
      )
p2