Re: [R-sig-phylo] ape package: improvement suggestion in color handling for mosaic in phydataplot?

2017-05-26 Thread Emmanuel Paradis

Elizabeth,

Thanks a lot for the detailed account of this problem. I've just made 
these modifications to the code of phydataplot:


1/ Replaced:

lgd <- as.character(ux)

with:

lgd <- sort(as.character(ux))

2/ These two lines:

conames <- names(co)
if (!is.null(conames)) co <- co[lgd]

were inserted after:

co <- funcol(nux)

These seem to produce the effects you requested. Particularly, using 
either f or fb as argument to funcol produces the same output:


f <- function(n) c("yellow", "blue", "red")
fb <- function(n) c("3" = "red", "2" = "blue", "1" = "yellow")

I'll soon upload a patch to ape's site (will be version 4.1-0.4). A 
Windows version will follow soon.


Cheers,

Emmanuel

Le 24/05/2017 à 06:17, Elizabeth Purdom a écrit :

Dear all,

I am trying to use the phydataplot function in the ape package with the 
style mosaic. I am having difficulty getting the colors of the 
rectangles to be the color I desire in an automatic way. I have come to 
the conclusion that I can’t do and it would have to be an enhancement to 
the package, though I would be glad to know I am wrong.


Here is the example in phydataplot for how to set the colors

set.seed(1378923)
## use type = "mosaic" on a 30x5 matrix:
tr <- rtree(n <- 30)
p <- 5
x <- matrix(sample(3, size = n*p, replace = TRUE), n, p)
dimnames(x) <- list(paste0("t", 1:n), LETTERS[1:p])
plot(tr, x.lim = 35, align.tip = TRUE, adj = 1)
phydataplot(x, tr, "m", 2, width = 2, border = "white", lwd = 3, legend 
= "side")

f <- function(n) c("yellow", "blue", "red")
phydataplot(x, tr, "m", 18, width = 2, border = "white", lwd = 3,
 legend = "side", funcol = f)

Notice we set the colors with the function  c("yellow", "blue", "red”). 
However, we see when we plot them, that this assignment resulted in 
2=yellow, 3=blue, 1=red. If instead I want 1=yellow, 2=blue, 3=red, I 
can use this plot I just made to see how they should be ordered to get 
my desired color assignment, and rearrange the colors:


plot(tr, x.lim = 35, align.tip = TRUE, adj = 1)
phydataplot(x, tr, "m", 2, width = 2, border = "white", lwd = 3, legend 
= "side")

f <- function(n) c("blue", "red", "yellow")
phydataplot(x, tr, "m", 18, width = 2, border = "white", lwd = 3,
 legend = "side", funcol = f)

However, I see no way to do this without first plotting them, manually 
looking at the arbitrary order created, and then fixing it.Yet, I would 
like to do this in an automatic fashion — I’m trying to build a function 
on top of this function — so I need to know ahead of time how 
phydataplot will assign the colors (and so if my tree changes it will 
still give the desired colors).Looking at the internal function, the 
relevant stream of code is the following (i.e. cutting away the parts 
not needed for determining the colors) and shows that the assignment of 
colors to data is entirely dependent on the order of the data after the 
function internally matches it to the tree:


lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
x <- .matchDataPhylo(x, phy)
n <- length(phy$tip.label)
one2n <- seq_len(n)
lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
y1 <- lastPP$yy[one2n]
o <- order(y1)
x <- if (style == "image") x[o, o]
else if (is.vector(x)) x[o]
else x[o, ]
nux <- length(ux <- unique.default(x))
x <- match(x, ux)
co <- funcol(nux)
rect(xl, yb, xr, yt, col = co[x], xpd = TRUE, ...)

This means that the colors provide by the user are assigned to the 
values of unique(x) *after* x is reordered internally by .matchDataPhylo 
and then again reordered x[o,], where o is the order of the tips of the 
tree in the plot, I believe. This is not something returned to the user, 
unfortunately, by plot.phylo, but is assigned to an hidden environment 
variable :

 assign("last_plot.phylo", c(L, list(edge = xe, xx = xx, yy = yy)),
 envir = .PlotPhyloEnv)

These seems to make it next to impossible to get the right colors 
without just trying it out interactively. If anyone had any other 
alternatives I’d love to hear them.


I’ve tried making a little function:
getColFun<-function(x,phy,namedColors){
x <- ape:::.matchDataPhylo(x, phy)
n <- length(phy$tip.label)
one2n <- seq_len(n)
lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
y1 <- lastPP$yy[one2n]
o <- order(y1)
ux<-unique.default(x[o])
m<-match(as.character(ux),names(namedColors))
function(n){namedColors[m]}
}
But it’s a bit awkward because it relies on .PlotPhyloEnv which is not 
always available if you haven’t loaded the package, as well as the 
internal function .matchDataPhylo. This is problematic for putting it 
into a package. Is there a function I’m not aware of that would be helpful?


In terms of enhancement, it would be nice if instead phydataplot 
accepted a named vector of colors, where the vector of colors is 
required to have names that match the values of the data in x, and then 
the phydataplot internally would figure out how to match them together. 
Less desirable would 

[R-sig-phylo] ape package: improvement suggestion in color handling for mosaic in phydataplot?

2017-05-23 Thread Elizabeth Purdom
Dear all,

I am trying to use the phydataplot function in the ape package with the style 
mosaic. I am having difficulty getting the colors of the rectangles to be the 
color I desire in an automatic way. I have come to the conclusion that I can’t 
do and it would have to be an enhancement to the package, though I would be 
glad to know I am wrong. 

Here is the example in phydataplot for how to set the colors

set.seed(1378923)
## use type = "mosaic" on a 30x5 matrix:
tr <- rtree(n <- 30)
p <- 5
x <- matrix(sample(3, size = n*p, replace = TRUE), n, p)
dimnames(x) <- list(paste0("t", 1:n), LETTERS[1:p])
plot(tr, x.lim = 35, align.tip = TRUE, adj = 1)
phydataplot(x, tr, "m", 2, width = 2, border = "white", lwd = 3, legend = 
"side")
f <- function(n) c("yellow", "blue", "red")
phydataplot(x, tr, "m", 18, width = 2, border = "white", lwd = 3,
legend = "side", funcol = f)

Notice we set the colors with the function  c("yellow", "blue", "red”). 
However, we see when we plot them, that this assignment resulted in 2=yellow, 
3=blue, 1=red. If instead I want 1=yellow, 2=blue, 3=red, I can use this plot I 
just made to see how they should be ordered to get my desired color assignment, 
and rearrange the colors: 

plot(tr, x.lim = 35, align.tip = TRUE, adj = 1)
phydataplot(x, tr, "m", 2, width = 2, border = "white", lwd = 3, legend = 
"side")
f <- function(n) c("blue", "red", "yellow")
phydataplot(x, tr, "m", 18, width = 2, border = "white", lwd = 3,
legend = "side", funcol = f)

However, I see no way to do this without first plotting them, manually looking 
at the arbitrary order created, and then fixing it. Yet, I would like to do 
this in an automatic fashion — I’m trying to build a function on top of this 
function — so I need to know ahead of time how phydataplot will assign the 
colors (and so if my tree changes it will still give the desired colors). 
Looking at the internal function, the relevant stream of code is the following 
(i.e. cutting away the parts not needed for determining the colors) and shows 
that the assignment of colors to data is entirely dependent on the order of the 
data after the function internally matches it to the tree:

lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
x <- .matchDataPhylo(x, phy)
n <- length(phy$tip.label)
one2n <- seq_len(n)
lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
y1 <- lastPP$yy[one2n]
o <- order(y1)
x <- if (style == "image") x[o, o]
else if (is.vector(x)) x[o]
else x[o, ]
nux <- length(ux <- unique.default(x))
x <- match(x, ux)
co <- funcol(nux)
rect(xl, yb, xr, yt, col = co[x], xpd = TRUE, ...)

This means that the colors provide by the user are assigned to the values of 
unique(x) *after* x is reordered internally by .matchDataPhylo and then again 
reordered x[o,], where o is the order of the tips of the tree in the plot, I 
believe. This is not something returned to the user, unfortunately, by 
plot.phylo, but is assigned to an hidden environment variable :
assign("last_plot.phylo", c(L, list(edge = xe, xx = xx, yy = yy)), 
envir = .PlotPhyloEnv)

These seems to make it next to impossible to get the right colors without just 
trying it out interactively. If anyone had any other alternatives I’d love to 
hear them.

I’ve tried making a little function:
getColFun<-function(x,phy,namedColors){
x <- ape:::.matchDataPhylo(x, phy)
n <- length(phy$tip.label)
one2n <- seq_len(n)
lastPP <- get("last_plot.phylo", envir = .PlotPhyloEnv)
y1 <- lastPP$yy[one2n]
o <- order(y1)
ux<-unique.default(x[o])
m<-match(as.character(ux),names(namedColors))
function(n){namedColors[m]}
}
But it’s a bit awkward because it relies on .PlotPhyloEnv which is not always 
available if you haven’t loaded the package, as well as the internal function 
.matchDataPhylo. This is problematic for putting it into a package. Is there a 
function I’m not aware of that would be helpful?

In terms of enhancement, it would be nice if instead phydataplot accepted a 
named vector of colors, where the vector of colors is required to have names 
that match the values of the data in x, and then the phydataplot internally 
would figure out how to match them together. Less desirable would be if the 
output of plot.phylo returned the information in ‘L’ that is saved in the 
.PlotPhyloEnv, then I could at least recreate a more stable version of my 
little function above.

(it would also be nice if the legend of the colors was in some reasonable 
sorted order, i.e. 1,2,3, and not in the arbitrary order)

Thanks,
Elizabeth Purdom






[[alternative HTML version deleted]]

___
R-sig-phylo mailing list - R-sig-phylo@r-project.org
https://stat.ethz.ch/mailman/listin