ggjoy facet with ggtree
之前介绍了《joyplot:一种波涛汹涌,哦不对,是山峰叠峦的可视化方式》,最近有人问怎么和ggtree搞基,像这样的问题,大家应该不陌生,因为我在《align genomic features with phylogenetic tree》一文中已经直播了和ggbio的搞基过程。
我在《how to bug author》一文中,就强调了在社区里问问题的重要性,想要ggjoy和ggtree搞基的问题,就没有直接问我,而是在同性交友网站stackoverflow上问,在我回答之前,就已经有非常好的解答贴出来了,这就是社区的好处!公开交流比私下邮件好多了。
问题
Is it possible to add a joyplot as a panel to a plot that includes a ggtree, as shown in these examples? Examples of joyplots are here.
https://guangchuangyu.github.io/2016/10/facet_plot-a-general-solution-to-associate-data-with-phylogenetic-tree/
https://katherinemwood.github.io/post/joy/
I realize that I could manually put the species labels for the joyplot in the same order as the tree tip labels, but I am looking for an automatic solution. I would like to associate the joyplot rows with the tips of the trees automatically, akin to how the boxplot data are associated with the tip labels.
I think that Guangchuang Yu’s examples at the above link provide suitable data:
require(ggtree)
require(ggstance)# generate tree
tr <- rtree(30)# create simple ggtree object with tip labels
p <- ggtree(tr) + geom_tiplab(offset = 0.02)
# Generate categorical data for each "species"
d1 <- data.frame(id=tr$tip.label, location=sample(c("GZ", "HK", "CZ"), 30, replace=TRUE))
#Plot the categorical data as colored points on the tree tips
p1 <- p %<+% d1 + geom_tippoint(aes(color=location))
# Generate distribution of points for each species
d4 = data.frame(id=rep(tr$tip.label, each=20),
val=as.vector(sapply(1:30, function(i)
rnorm(20, mean=i)))
)
# Create panel with boxplot of the d4 data
p4 <- facet_plot(p1, panel="Boxplot", data=d4, geom_boxploth,
mapping = aes(x=val, group=label, color=location))
plot(p4)
This produces the plot below:
Is it possible to create a joyplot in place of the boxplot?
Here is code for a quick joyplot of the demo dataset d4 above:
require(ggjoy)
ggplot(d4, aes(x = val, y = id)) +
geom_joy(scale = 2, rel_min_height=0.03) +
scale_y_discrete(expand = c(0.01, 0)) + theme_joy()
The result is:
I am new to ggplot2, ggtree, and ggjoy so I am totally at a loss with how to even begin doing this.
解答
It looks like you can just replace geom_boxplot with geom_joy in facet_plot:
facet_plot(p1, panel="Joy Plot", data=d4, geom_joy,
mapping = aes(x=val, group=label, fill=location), colour="grey50", lwd=0.3)
If you’re new to ggplot2, the visualization chapter of Data Science with R (an open-source book by the author of ggplot2) should be helpful for learning the basics.
ggjoy and ggtree extend the capabilities of ggplot2. When such extensions are done well, the “obvious” thing to do (in terms of the usual ggplot “grammar of graphics”) often works, because the extension package is written in a way that tries to be faithful to the underlying ggplot2 approach.
Here, my first thought was to just substitute geom_joy for geom_boxplot, which turned out to get the job done. Each geom is just a different way to visualize the data, in this case box plot vs. density plot. But all of the other “structure” of the plot stays the same, so you can just change geoms and get a new plot that follows the same axis ordering, color mappings, etc. This will make more sense once you get some experience with the ggplot2 grammar of graphics.
Here’s a slightly different labeling approach for the left-hand plot:
p1 = ggtree(tr) %<+% d1 +
geom_tippoint(aes(color=location), size=6) +
geom_tiplab(offset=-0.01, hjust=0.5, colour="white", size=3.2, fontface="bold")
facet_plot(p1, panel="Joy Plot", data=d4, geom_joy,
mapping = aes(x=val, group=label, fill=location), colour="grey40", lwd=0.3)
UPDATE: This is in response to your comment asking how to get the same custom colors in both facet panels. Here’s code to do that with the example data in your question:
p1 = ggtree(tr) %<+% d1 +
geom_tippoint(aes(color=location), size=5) +
geom_tiplab(offset=-0.01, hjust=0.5, colour="white", size=3, fontface="bold") +
scale_colour_manual(values = c("grey", "red3", "blue")) +
scale_fill_manual(values = c("grey", "red3", "blue"))
facet_plot(p1, panel="Joy Plot", data=d4, geom_joy,
mapping = aes(x=val, group=label, fill=location), colour="grey40", lwd=0.3)