Monday, May 22, 2017

Hack to fix some or all internal node values in make.simmap (versión español)

Hace unos días alguien me preguntó el siguiente:

“Existe en phytools alguna función que permita asignar un determinado estado a los nodos ancestrales? Es decir, se puede crear un simmap según como uno quiera? O tendría que por ejemplo modificar los mapped.edge directamente? Sólo encontré la función getStates. No existe una que sea setStates?”

La respuesta es que no, hasta ahora no existe ninguna opción en la función make.simmap para especificar ni valores fijos ni probabilidades previas por los nodos interiores en un análisis en que estamos generando mapas estocásticas por la evolución de un rasgo discreto sobre el árbol - con la excepción del raíz global que si podemos ya fijar utilizando el argumento pi.

Pero… si hay una manera en que podemos hacerlo y sea posible que yo pueda adicionar esta funcionalidad como opción en make.simmap al futuro. En este momento, la sola manera de hacerlo es a través de un poquito de codificación básica en R, aka. "scripting."

La idea con esta solución es que voy a adicionar ramas de longitud cero a cada nodo interior por cuáles sabemos sus estados. Como ninguna evolución puede ocurrir a través de una rama de longitud de cero, esta manipulación nos permite de efectivamente fijar los estados por los nodos interiores correspondientes porque tendrán que asumir los valores que pondremos en los tips nuevos de nuestro árbol modificado. Al final, después de correr nuestro análisis make.simmap, podemos remover todas esas ramas adicionadas de nuestros árboles finales.

En este ejemplo, estoy imaginando que tengamos valores que queramos fijar por todos los nodos interiores - pero el lógico, y el algoritmo computacional, deben funcionar igual por casos un que deseemos fijar ciertos pero no todos los nodos.

Empezando con un árbol (tree) y los valores por las especies (en x) y los nodos interiores (en y), continuamos así:

library(phytools)
tree
## 
## Phylogenetic tree with 26 tips and 25 internal nodes.
## 
## Tip labels:
##  A, B, C, D, E, F, ...
## 
## Rooted; includes branch lengths.
x
##   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   P   Q   R 
## "b" "b" "b" "b" "b" "a" "a" "b" "a" "a" "b" "b" "b" "a" "a" "a" "a" "b" 
##   S   T   U   V   W   X   Y   Z 
## "b" "b" "b" "b" "a" "b" "a" "a"
y
##  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44 
## "a" "a" "b" "b" "b" "b" "a" "a" "b" "b" "b" "b" "a" "b" "a" "a" "b" "b" 
##  45  46  47  48  49  50  51 
## "b" "b" "b" "b" "b" "b" "b"
dotTree(tree,x,colors=setNames(c("blue","red"),c("a","b")))
nodelabels(pie=to.matrix(y,c("a","b")),piecol=c("blue","red"),cex=0.5)

plot of chunk unnamed-chunk-1

for(i in 1:length(y)){
    if(i==1) new.tree<-tree
    M<-matchNodes(tree,new.tree,method="distances")
    node<-M[which(as.numeric(names(y)[i])==M[,1]),2]
    new.tree<-bind.tip(new.tree,names(y)[i],edge.length=0,where=node)
}

Ya tenemos nuestro árbol modificado. Solo para tener una idea de la manipulación que hemos hecho podemos visualizar el árbol:

plotTree(new.tree)

plot of chunk unnamed-chunk-2

Y finalmente estamos listos para correr nuestro análisis make.simmap:

trees<-make.simmap(new.tree,c(x,y),nsim=100)
## make.simmap is sampling character histories conditioned on the transition matrix
## 
## Q =
##           a         b
## a -1.186413  1.186413
## b  1.186413 -1.186413
## (estimated using likelihood);
## and (mean) root node prior probabilities
## pi =
##   a   b 
## 0.5 0.5
## Done.
trees<-lapply(trees,drop.tip.simmap,tip=names(y))
class(trees)<-c("multiSimmap","multiPhylo")
trees
## 100 phylogenetic trees with mapped discrete characters

Al final, tenemos un objeto multiSimmap en que hemos fijado los estados de todos o algunos de los nodos interiores y sobre que podemos realizar cualquier análisis subsecuente disponible. Por ejemplo:

obj<-summary(trees)
obj
## 100 trees with a mapped discrete character with states:
##  a, b 
## 
## trees have 18.46 changes between states on average
## 
## changes are of the following types:
##       a,b   b,a
## x->y 7.73 10.73
## 
## mean total time spent in each state is:
##              a         b    total
## raw  6.2708890 9.5060241 15.77691
## prop 0.3974725 0.6025275  1.00000
plot(obj,colors=setNames(c("blue","red"),c("a","b")))

plot of chunk unnamed-chunk-4

densityMap(trees,lwd=6)
## sorry - this might take a while; please be patient

plot of chunk unnamed-chunk-4

Chévere!

Los datos y el árbol por este ejemplo fueron simulados utilizando el código que sigue:

tree<-pbtree(n=26,tip.label=LETTERS,scale=2)
Q<-matrix(c(-1,1,1,-1),2,2,dimnames=list(letters[1:2],letters[1:2]))
ttree<-sim.history(tree,Q)
x<-getStates(ttree,"tips")
y<-getStates(ttree,"nodes")

Tuesday, May 16, 2017

Plotting a traitgram using phenogram with custom axis labels

This morning I received the following question about the phytools function phenogram for plotting a 'traitgram' (a projection of the tree into a one-dimensional phenotype space with time as the second dimension):

“I have a very quick question about constructing phenograms with ancestral states using phytools. I am trying to change the font size in the x and y labels as well as in the numerical values of both axes, but I can't. I have tried arguments such as 'cex.lab', which usually work in other plots, without success. I was wondering if you could share with me the commands/arguments/script to change the font size in these labels and numerical values of these nice phenograms.”

There are multiple options to do this. Here are two that should work, depending on the flexibility desired.

Option 1: The par function.

library(phytools)
tree
## 
## Phylogenetic tree with 26 tips and 25 internal nodes.
## 
## Tip labels:
##  A, B, C, D, E, F, ...
## 
## Rooted; includes branch lengths.
x
##           A           B           C           D           E           F 
##  0.71834934  0.77516371 -1.15527055 -1.20178011 -1.44344168 -0.20245893 
##           G           H           I           J           K           L 
## -0.48830753 -0.60784770  0.24882588  0.19768991  0.40526574  0.07893109 
##           M           N           O           P           Q           R 
## -1.42560735 -1.73332436 -1.38883804 -2.29045453 -0.08663248  0.12563454 
##           S           T           U           V           W           X 
##  0.62373799  0.45686318 -1.38973670 -1.47254717 -2.21400886 -1.64686733 
##           Y           Z 
##  0.67458737  0.55373959
## first, our standard traitgram plot for reference:
phenogram(tree,x)

plot of chunk unnamed-chunk-1

## change the axis label size using par(cex.lab):
par(cex.lab=1.4,cex.axis=0.8,mar=c(5.1,5.1,2.1,1.1))
phenogram(tree,x)

plot of chunk unnamed-chunk-1

Option 2: Plot without axes & add them in after.

par(xaxt="n",yaxt="n",mar=c(5.1,5.1,2.1,1.1))
phenogram(tree,x,xlab="",ylab="")
par(xaxt="s",yaxt="s",font.lab=4)
axis(1)
title(xlab="time since the root",cex.lab=1.4)
axis(2)
title(ylab="reconstructed or observed phenotype",cex.lab=1.2)

plot of chunk unnamed-chunk-2

The second option is a bit more laborious, but obviously also offers considerably more flexibility.

That's it!

Friday, May 12, 2017

More on mapping different genera with different colors (versión español)

En respuesta a la solución para colorear los miembros de cada género en un árbol que puse el otro día en este blog, el preguntador original me comentó:

“Es bastante cercano a lo que necesito. Sin embargo, me quedan dos dudas. 1. Se podría considerar que son rasgos discretos en lugar de continuos? 2. Se podría recuperar el color asignado en cada nodo del árbol?”

La solución que puse anteriormente a mí me pareció bastante elegante, aunque con ciertas fallas. Por ejemplo, a veces la interpolación de colores entre clados resultó en unos cambios de colores entre y dentro de géneros del árbol bastante extraños.

Por consiguiente, identifique otra solución completamente distinta. La idea con esta solución es de mapear la historia completa de cada clado sobre el árbol, con ramas compartidas entre género (básicamente, ramas que tienen en común dos o más géneros en sus historias completas respectivas desde el raíz global hacia el presente) coloreadas con colores semitransparentes, resultando en la percepción de colores intermedios sobre las ramas conectando géneros distintos.

Por ejemplo:

library(phytools)
library(RColorBrewer)
library(phangorn)
tree
## 
## Phylogenetic tree with 35 tips and 34 internal nodes.
## 
## Tip labels:
##  Abc_wzsgrx, Abc_xwezmb, Abc_bmdyhc, Abc_vblodn, Bcd_disnjy, Bcd_kpgdrq, ...
## 
## Rooted; includes branch lengths.
genera<-sapply(strsplit(tree$tip.label,"_"),function(x) x[1])
GENERA<-unique(genera)
colors<-setNames(brewer.pal(length(GENERA),"Paired"),GENERA)
plotTree(tree,color="transparent",ftype="i")
xlim<-get("last_plot.phylo", envir = .PlotPhyloEnv)$x.lim
for(i in 1:length(GENERA)){
    MRCA<-findMRCA(tree,tree$tip.label[grep(GENERA[i],tree$tip.label)])
    if(!is.null(MRCA)) TREE<-paintSubTree(tree,MRCA,"2","1",stem=TRUE)
    else TREE<-paintSubTree(tree,MRCA<-which(genera==GENERA[i]),
        "2","1",stem=TRUE)
    aa<-Ancestors(tree,MRCA,"all")
    cols<-c("transparent",colors[GENERA[i]])
    if(length(aa)>1){
        aa<-aa[1:(length(aa)-1)]
        for(i in 1:length(aa)){
            TREE<-paintBranches(TREE,aa[i],i+2)
            dd<-getDescendants(tree,aa[i])
            ng<-length(unique(genera[dd[dd<=Ntip(tree)]]))
            cols[i+2]<-make.transparent(cols[2],1/ng)
        }
    }
    cols<-setNames(cols,1:length(cols))
    plot(TREE,cols,add=TRUE,split.vertical=TRUE,ftype="off",xlim=xlim,
        lwd=6)
}

plot of chunk unnamed-chunk-1

Para mejor visualizar la manera en que estamos realizando este efecto, podemos “pausar” (y en efecto animar) el proceso de graficar, paso por paso, las historias distintas de nuestros géneros. El resultado tuve que capturar en la forma de un video:

Extraer los colores en los nodos o sobre las ramas interiores sería otra cosa todavía. Los colores dentro de cada clado son fijos, pero los colores sobre las ramas interiores corresponden no a colores particulares conocidos por R pero de una mezcla de colores resultando por el efecto de pintar un color semitransparente sobre otros.