R image2d: Changing x, y, z axes labels - r

I found this awesome tutorial on changing the x and y axes labels in ggplot and used it successfully on bar charts and scatterplots:
http://www.moeding.net/archives/32-Metric-prefixes-for-ggplot2-scales.html#comments
I would like to extend this capability to this 'heat map' that I have developed as well. Here is the code:
library(plot3D)
format_si <- function(x,...) {
# Format a vector of numeric values according
# to the Semi-International System of Units.
#
# Based on code by Ben Tupper
# https://stat.ethz.ch/pipermail/r-help/2012-January/299804.html
# Args:
# ...: Args passed to format()
function(x) {
limits <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12,
1e-9, 1e-6, 1e-3, 1e0, 1e3,
1e6, 1e9, 1e12, 1e15, 1e18,
1e21, 1e24)
prefix <- c("y", "z", "a", "f", "p",
"n", "ยต", "m", "", "k",
"M", "B", "T", "P", "E",
"Z", "Y")
# Vector with array indices according to position in intervals
i <- findInterval(abs(x), limits)
# Set prefix to "" for very small values < 1e-24
i <- ifelse(i==0, which(limits == 1e0), i)
return(paste(format(round(x/limits[i], 1),
trim=TRUE, scientific=FALSE, ...),
prefix[i], sep=""))
}
}
#Generate some data
xs<-rnorm(50000)*100000
ys<-rnorm(50000)*100000
zs<-sin(xs)*10000000
df<-as.data.frame(cbind(xs,ys,zs))
#Heat Map
df$x<-cut(df$xs, breaks=50, labels=FALSE)
df$y<-cut(df$ys, breaks=50, labels=FALSE)
df.max<-expand.grid(x=1:50, y=1:50)
df.max<-merge(df.max, aggregate(zs~x+y, df, max), all.x=TRUE)
z<-t(matrix(df.max$zs, nr=50, nc=50))
x.values <- min(df$xs)+(0:49)*diff(range(df$xs))/50
y.values <- min(df$ys)+(0:49)*diff(range(df$ys))/50
image2D(x=x.values, y=y.values, z, rasterImage = TRUE, contour = list(lwd = 2, col = jet.col(11)),
main="Random Data", xlab="random xs",ylab="random ys", clab="zs=sin(xs)", ylim=c(0,max(df$ys)*1.05),
xlim=c(0,max(df$xs)*1.05))
In ggplot, I would just add scale_y_continuous(labels=format_si()) to my plot and it the axis labels would be 1M instead of 1.0e6 or 1000000. I have tried turning the labels off inside of image2d and then using axes(1, format_si()) but that doesn't work either. Has anybody tried this before?

Related

what's wrong with this small decision tree using C5.0?

I'm trying to make simple decision tree using C5.0 in R.
data has 3 columns(including target data) and 14 rows.
This is my 'jogging' data. target variable is 'CLASSIFICATION'
WEATHER JOGGED_YESTERDAY CLASSIFICATION
C N +
W Y -
Y Y -
C Y -
Y N -
W Y -
C N -
W N +
C Y -
W Y +
W N +
C N +
Y N -
W Y -
or as dput result:
structure(list(WEATHER = c("C", "W", "Y", "C", "Y", "W", "C",
"W", "C", "W", "W", "C", "Y", "W"), JOGGED_YESTERDAY = c("N",
"Y", "Y", "Y", "N", "Y", "N", "N", "Y", "Y", "N", "N", "N", "Y"
), CLASSIFICATION = c("+", "-", "-", "-", "-", "-", "-", "+",
"-", "+", "+", "+", "-", "-")), class = "data.frame", row.names = c(NA,
-14L))
jogging <- read.csv("Jogging.csv")
jogging #training data
library(C50)
jogging$CLASSIFICATION <- as.factor(jogging$CLASSIFICATION)
jogging_model <- C5.0(jogging[-3], jogging$CLASSIFICATION)
jogging_model
summary(jogging_model)
plot(jogging_model)
but it does not make any decision tree.
I thought that it should have made 2 nodes(because of 2 columns except target variables)
I want to know what's wrong :(
For this answer I will use a different tree building package partykit just for the reason that I am more used to it. Let's do the following:
jogging <- read.table(header = TRUE, text = "WEATHER JOGGED_YESTERDAY CLASSIFICATION
C N +
W Y -
Y Y -
C Y -
Y N -
W Y -
C N -
W N +
C Y -
W Y +
W N +
C N +
Y N -
W Y -",
stringsAsFactors = TRUE)
library(partykit)
ctree(CLASSIFICATION ~ WEATHER + JOGGED_YESTERDAY, data = jogging,
minsplit = 1, minbucket = 1, mincriterion = 0) |> plot()
That will print the following tree:
That is a tree that uses up to three levels of splits and still does not find a perfect fit. The first split has a p-value of .2, indicating that there is not nearly enough data to justify even this first split, let alone those following it. This is a tree that is very likely to massively overfit the data and overfitting is bad. That is why usual tree algorithms come with measures to prevent overfitting and in your case, that prohibits growing a tree. I disabled those with the arguments in the ctree call.
So in short: You have not enough data. Just predicting - all the time is the most reasonable thing a classification tree can do.

How I can set the size and/or color of symbols in a R plotrix::polar.plot on the basis of a data frame column?

I have a data frame "df" with three columns: distance, azimuth, intensity.
Through plotrix:polar.plot I got a plot using the following code
polar.plot(df$distance, df$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=4, cex = 1.2)
Is there a way to have the size (or color) of symbols changing with the "intensity" column value?
since I didn't find any "direct" solution I have divided the dataframe in several dataframes using subset() and after I plotted every dataframe with different "cex"/"point.col" setting to "TRUE" the "add" parameter.
df3 <- subset(outPutDeg, intensity <= 3)
df5 <- subset(outPutDeg, intensity > 3 & intensity <= 5)
df7 <- subset(outPutDeg, intensity > 5 & intensity <= 7)
df9 <- subset(outPutDeg, intensity > 7 & intensity <= 9)
df11 <- subset(outPutDeg, intensity > 9)
polar.plot(df3$distance, df3$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=5, cex = 0.6)
polar.plot(df5$distance, df5$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=4, cex = 0.6, add = T)
polar.plot(df7$distance, df7$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=3, cex = 0.6, add = T)
polar.plot(df9$distance, df9$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=2, cex = 0.6, add = T)
polar.plot(df11$distance, df11$azimuth, radial.lim=c(0,450),start=90,rp.type = "s", clockwise=TRUE, point.col=1, cex = 0.6, add = T)
crude and effective

How change the numeric format of axis on R chord diagram to 1k, 2k, etc?

I'm trying to display the numeric values on the axis of an R chord diagram so that thousands are represent with a k. For example, 1000 would display as 1K, 2000 would display 2k, etc. Can anyone kindly advise how and / or if this is possible?
I've created the following function to convert numeric inputs into this 'k' format, but am unable to implement it correctly in the circos.trackPlotRegion portion of the chord diagram.
First, I created a function to make this conversion:
require(sitools)
f2si2 <- function(number,rounding=F){
lut <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06,
0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21,
1e+24)
pre <- c("y", "z", "a", "f", "p", "n", "u", "m", "", "k",
"M", "G", "T", "P", "E", "Z", "Y")
ix <- findInterval(number, lut)
if (lut[ix]!=1) {
if (rounding==T) {
sistring <- paste(round(number/lut[ix]), pre[ix])
} else {
sistring <- paste(number/lut[ix], pre[ix])
}
}else{
sistring <- as.character(number)
}
return(sistring)
}
How can I use the above function (or anything else) in the circos.axis() #function so that it transforms the output to 1k, etc?
# Here's some very crude code as an example. I'd want the 1000 to read #1k,
10000 to read 10k, etc. along the axis.
library(circlize)
# create test data
mat = matrix(1:200, 10, 20)
rownames(mat) = paste0("S", 1:10)
colnames(mat) = paste0("E", 1:20)
# create chord diagram
circos.par(canvas.ylim=c(-1.5, 1.5),
track.margin = c(0.01, 0))
chordDiagram(mat, annotationTrack = "grid") #, grid.col = grid.col)
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
xlim = get.cell.meta.data("xlim")
ylim = get.cell.meta.data("ylim")
sector.name = get.cell.meta.data("sector.index")
# print axis
circos.axis(h = "top", labels.cex = 0.7, major.tick.percentage = 0.2
, sector.index = sector.name, track.index = 1)
# print sector label
circos.text(mean(xlim), ylim[1] + 3, sector.name, facing = "clockwise",
niceFacing = TRUE, adj = c(0, 0.5))
}, bg.border = NA)

Plotting the row cells across the column cells in a matrix in R

I have a 2 x 3 matrix called a. I was wondering if there is a way I could plot this matrix such that I could see how the values of row cells ("m" and "f") change across the column cells ("a", "b", "c")?
A conceptual form of the desired plot is shown in the picture below.
(Note: I guess the idea is very similar to how interaction.plot() works)
Here is what I have tried with no success:
a = matrix(c(15,14, 16,40, 42,41), nrow = 2, dimnames = list(A = c("m", "f"), B = c("a", "b", "c")))
plot(a, xaxt = "n", ylab = "Scores", xlab = "B")
g = axTicks(1)
n = length(colnames(a))
u = diff(range(g))/n
d = seq(min(g), max(g), len = n)
axis(1, at = d, lab = dimnames(a)[[2]], font = 2)
lines(a[1,], a[2,])
Something like this???
a = matrix(c(15,14, 16,40, 42,41), nrow = 2,
dimnames = list(A = c("m", "f"), B = c("a", "b", "c")))
matplot(t(a), type = "b", pch=19, xaxt="n")
axis(1, at = 1:ncol(a), labels = colnames(a))

how to create a heatmap with a fixed external hierarchical cluster

I have a matrix data, and want to visualize it with heatmap. The rows are species, so I want visualize the phylogenetic tree aside the rows and reorder the rows of the heatmap according the tree. I know the heatmap function in R can create the hierarchical clustering heatmap, but how can I use my phylogenetic clustering instead of the default created distance clustering in the plot?
First you need to use package ape to read in your data as a phylo object.
library(ape)
dat <- read.tree(file="your/newick/file")
#or
dat <- read.tree(text="((A:4.2,B:4.2):3.1,C:7.3);")
The following only works if your tree is ultrametric.
The next step is to transform your phylogenetic tree into class dendrogram.
Here is an example:
data(bird.orders) #This is already a phylo object
hc <- as.hclust(bird.orders) #Compulsory step as as.dendrogram doesn't have a method for phylo objects.
dend <- as.dendrogram(hc)
plot(dend, horiz=TRUE)
mat <- matrix(rnorm(23*23),nrow=23, dimnames=list(sample(bird.orders$tip, 23), sample(bird.orders$tip, 23))) #Some random data to plot
First we need to order the matrix according to the order in the phylogenetic tree:
ord.mat <- mat[bird.orders$tip,bird.orders$tip]
Then input it to heatmap:
heatmap(ord.mat, Rowv=dend, Colv=dend)
Edit: Here is a function to deal with ultrametric and non-ultrametric trees.
heatmap.phylo <- function(x, Rowp, Colp, ...){
# x numeric matrix
# Rowp: phylogenetic tree (class phylo) to be used in rows
# Colp: phylogenetic tree (class phylo) to be used in columns
# ... additional arguments to be passed to image function
x <- x[Rowp$tip, Colp$tip]
xl <- c(0.5, ncol(x)+0.5)
yl <- c(0.5, nrow(x)+0.5)
layout(matrix(c(0,1,0,2,3,4,0,5,0),nrow=3, byrow=TRUE),
width=c(1,3,1), height=c(1,3,1))
par(mar=rep(0,4))
plot(Colp, direction="downwards", show.tip.label=FALSE,
xlab="",ylab="", xaxs="i", x.lim=xl)
par(mar=rep(0,4))
plot(Rowp, direction="rightwards", show.tip.label=FALSE,
xlab="",ylab="", yaxs="i", y.lim=yl)
par(mar=rep(0,4), xpd=TRUE)
image((1:nrow(x))-0.5, (1:ncol(x))-0.5, x,
xaxs="i", yaxs="i", axes=FALSE, xlab="",ylab="", ...)
par(mar=rep(0,4))
plot(NA, axes=FALSE, ylab="", xlab="", yaxs="i", xlim=c(0,2), ylim=yl)
text(rep(0,nrow(x)),1:nrow(x),Rowp$tip, pos=4)
par(mar=rep(0,4))
plot(NA, axes=FALSE, ylab="", xlab="", xaxs="i", ylim=c(0,2), xlim=xl)
text(1:ncol(x),rep(2,ncol(x)),Colp$tip, srt=90, pos=2)
}
Here is with the previous (ultrametric) example:
heatmap.phylo(mat, bird.orders, bird.orders)
And with a non-ultrametric:
cat("owls(((Strix_aluco:4.2,Asio_otus:4.2):3.1,Athene_noctua:7.3):6.3,Tyto_alba:13.5);",
file = "ex.tre", sep = "\n")
tree.owls <- read.tree("ex.tre")
mat2 <- matrix(rnorm(4*4),nrow=4,
dimnames=list(sample(tree.owls$tip,4),sample(tree.owls$tip,4)))
is.ultrametric(tree.owls)
[1] FALSE
heatmap.phylo(mat2,tree.owls,tree.owls)
First, I create a reproducible example. Without data we can just guess what you want. So please try to do better next time(specially you are confirmed user). For example you can do this to create your tree in newick format:
tree.text='(((XXX:4.2,ZZZ:4.2):3.1,HHH:7.3):6.3,AAA:13.6);'
Like #plannpus, I am using ape to converts this tree to a hclust class. Unfortunatlty, it looks that we can do the conversion only for ultrametric tree: the distance from the root to each tip is the same.
library(ape)
tree <- read.tree(text='(((XXX:4.2,ZZZ:4.2):3.1,HHH:7.3):6.3,AAA:13.6);')
is.ultrametric(tree)
hc <- as.hclust.phylo(tree)
Then I am using dendrogramGrob from latticeExtra to plot my tree. and levelplot from lattice to draw the heatmap.
library(latticeExtra)
dd.col <- as.dendrogram(hc)
col.ord <- order.dendrogram(dd.col)
mat <- matrix(rnorm(4*4),nrow=4)
colnames(mat) <- tree$tip.label
rownames(mat) <- tree$tip.label
levelplot(mat[tree$tip,tree$tip],type=c('g','p'),
aspect = "fill",
colorkey = list(space = "left"),
legend =
list(right =
list(fun = dendrogramGrob,
args =
list(x = dd.col,
side = "right",
size = 10))),
panel=function(...){
panel.fill('black',alpha=0.2)
panel.levelplot.points(...,cex=12,pch=23)
}
)
I adapted plannapus' answer to deal with more than one tree (also cutting out some options I didn't need in the process):
library(ape)
heatmap.phylo <- function(x, Rowp, Colp, breaks, col, denscol="cyan", respect=F, ...){
# x numeric matrix
# Rowp: phylogenetic tree (class phylo) to be used in rows
# Colp: phylogenetic tree (class phylo) to be used in columns
# ... additional arguments to be passed to image function
scale01 <- function(x, low = min(x), high = max(x)) {
x <- (x - low)/(high - low)
x
}
col.tip <- Colp$tip
n.col <- 1
if (is.null(col.tip)) {
n.col <- length(Colp)
col.tip <- unlist(lapply(Colp, function(t) t$tip))
col.lengths <- unlist(lapply(Colp, function(t) length(t$tip)))
col.fraction <- col.lengths / sum(col.lengths)
col.heights <- unlist(lapply(Colp, function(t) max(node.depth.edgelength(t))))
col.max_height <- max(col.heights)
}
row.tip <- Rowp$tip
n.row <- 1
if (is.null(row.tip)) {
n.row <- length(Rowp)
row.tip <- unlist(lapply(Rowp, function(t) t$tip))
row.lengths <- unlist(lapply(Rowp, function(t) length(t$tip)))
row.fraction <- row.lengths / sum(row.lengths)
row.heights <- unlist(lapply(Rowp, function(t) max(node.depth.edgelength(t))))
row.max_height <- max(row.heights)
}
cexRow <- min(1, 0.2 + 1/log10(n.row))
cexCol <- min(1, 0.2 + 1/log10(n.col))
x <- x[row.tip, col.tip]
xl <- c(0.5, ncol(x)+0.5)
yl <- c(0.5, nrow(x)+0.5)
screen_matrix <- matrix( c(
0,1,4,5,
1,4,4,5,
0,1,1,4,
1,4,1,4,
1,4,0,1,
4,5,1,4
) / 5, byrow=T, ncol=4 )
if (respect) {
r <- grconvertX(1, from = "inches", to = "ndc") / grconvertY(1, from = "inches", to = "ndc")
if (r < 1) {
screen_matrix <- screen_matrix * matrix( c(r,r,1,1), nrow=6, ncol=4, byrow=T)
} else {
screen_matrix <- screen_matrix * matrix( c(1,1,1/r,1/r), nrow=6, ncol=4, byrow=T)
}
}
split.screen( screen_matrix )
screen(2)
par(mar=rep(0,4))
if (n.col == 1) {
plot(Colp, direction="downwards", show.tip.label=FALSE,xaxs="i", x.lim=xl)
} else {
screens <- split.screen( as.matrix(data.frame( left=cumsum(col.fraction)-col.fraction, right=cumsum(col.fraction), bottom=0, top=1)))
for (i in 1:n.col) {
screen(screens[i])
plot(Colp[[i]], direction="downwards", show.tip.label=FALSE,xaxs="i", x.lim=c(0.5,0.5+col.lengths[i]), y.lim=-col.max_height+col.heights[i]+c(0,col.max_height))
}
}
screen(3)
par(mar=rep(0,4))
if (n.col == 1) {
plot(Rowp, direction="rightwards", show.tip.label=FALSE,yaxs="i", y.lim=yl)
} else {
screens <- split.screen( as.matrix(data.frame( left=0, right=1, bottom=cumsum(row.fraction)-row.fraction, top=cumsum(row.fraction))) )
for (i in 1:n.col) {
screen(screens[i])
plot(Rowp[[i]], direction="rightwards", show.tip.label=FALSE,yaxs="i", x.lim=c(0,row.max_height), y.lim=c(0.5,0.5+row.lengths[i]))
}
}
screen(4)
par(mar=rep(0,4), xpd=TRUE)
image((1:nrow(x))-0.5, (1:ncol(x))-0.5, x, xaxs="i", yaxs="i", axes=FALSE, xlab="",ylab="", breaks=breaks, col=col, ...)
screen(6)
par(mar=rep(0,4))
plot(NA, axes=FALSE, ylab="", xlab="", yaxs="i", xlim=c(0,2), ylim=yl)
text(rep(0,nrow(x)),1:nrow(x),row.tip, pos=4, cex=cexCol)
screen(5)
par(mar=rep(0,4))
plot(NA, axes=FALSE, ylab="", xlab="", xaxs="i", ylim=c(0,2), xlim=xl)
text(1:ncol(x),rep(2,ncol(x)),col.tip, srt=90, adj=c(1,0.5), cex=cexRow)
screen(1)
par(mar = c(2, 2, 1, 1), cex = 0.75)
symkey <- T
tmpbreaks <- breaks
if (symkey) {
max.raw <- max(abs(c(x, breaks)), na.rm = TRUE)
min.raw <- -max.raw
tmpbreaks[1] <- -max(abs(x), na.rm = TRUE)
tmpbreaks[length(tmpbreaks)] <- max(abs(x), na.rm = TRUE)
} else {
min.raw <- min(x, na.rm = TRUE)
max.raw <- max(x, na.rm = TRUE)
}
z <- seq(min.raw, max.raw, length = length(col))
image(z = matrix(z, ncol = 1), col = col, breaks = tmpbreaks,
xaxt = "n", yaxt = "n")
par(usr = c(0, 1, 0, 1))
lv <- pretty(breaks)
xv <- scale01(as.numeric(lv), min.raw, max.raw)
axis(1, at = xv, labels = lv)
h <- hist(x, plot = FALSE, breaks = breaks)
hx <- scale01(breaks, min.raw, max.raw)
hy <- c(h$counts, h$counts[length(h$counts)])
lines(hx, hy/max(hy) * 0.95, lwd = 1, type = "s",
col = denscol)
axis(2, at = pretty(hy)/max(hy) * 0.95, pretty(hy))
par(cex = 0.5)
mtext(side = 2, "Count", line = 2)
close.screen(all.screens = T)
}
tree <- read.tree(text = "(A:1,B:1);((C:1,D:2):2,E:1);((F:1,G:1,H:2):5,((I:1,J:2):2,K:1):1);", comment.char="")
N <- sum(unlist(lapply(tree, function(t) length(t$tip))))
set.seed(42)
m <- cor(matrix(rnorm(N*N), nrow=N))
rownames(m) <- colnames(m) <- LETTERS[1:N]
heatmap.phylo(m, tree, tree, col=bluered(10), breaks=seq(-1,1,length.out=11), respect=T)
This exact application of a heatmap is already implemented in the plot_heatmap function (based on ggplot2) in the phyloseq package, which is openly/freely developed on GitHub. Examples with complete code and results are included here:
http://joey711.github.io/phyloseq/plot_heatmap-examples
One caveat, and not what you are explicitly asking for here, but phyloseq::plot_heatmap does not overlay a hierarchical tree for either axis. There is a good reason not to base your axis ordering on hierarchical clustering -- and this is because of the way indices at the end of long branches can still be next to each other arbitrarily depending on how branches are rotated at the nodes. This point, and an alternative based on non-metric multidimensional scaling is explained further in an article about the NeatMap package, which is also written for R and uses ggplot2. This dimension-reduction (ordination) approach to ordering the indices in a heatmap is adapted for phylogenetic abundance data in phyloseq::plot_heatmap.
While my suggestion for phlyoseq::plot_heatmap would get you part of the way there, the powerful "ggtree" package can do this, or more, if representing data on trees is really what you are going for.
Some examples are shown on the top of the following ggtree documentation page:
http://www.bioconductor.org/packages/3.7/bioc/vignettes/ggtree/inst/doc/advanceTreeAnnotation.html
Note that I am not affiliated with ggtree dev at all. Just a fan of the project and what it can already do.
After communication with #plannapus, I've modified (just a few) the code to remove some extra xlab="" information on the above code.
Here you will find the code. You can see the commented lines having the extra code and now the new lines just erasing them.
Hope this can help new users like me! :)
heatmap.phylo <- function(x, Rowp, Colp, ...){
# x numeric matrix
# Rowp: phylogenetic tree (class phylo) to be used in rows
# Colp: phylogenetic tree (class phylo) to be used in columns
# ... additional arguments to be passed to image function
x <- x[Rowp$tip, Colp$tip]
xl <- c(0.5, ncol(x) + 0.5)
yl <- c(0.5, nrow(x) + 0.5)
layout(matrix(c(0,1,0,2,3,4,0,5,0),nrow = 3, byrow = TRUE),
width = c(1,3,1), height = c(1,3,1))
par(mar = rep(0,4))
# plot(Colp, direction = "downwards", show.tip.label = FALSE,
# xlab = "", ylab = "", xaxs = "i", x.lim = xl)
plot(Colp, direction = "downwards", show.tip.label = FALSE,
xaxs = "i", x.lim = xl)
par(mar = rep(0,4))
# plot(Rowp, direction = "rightwards", show.tip.label = FALSE,
# xlab = "", ylab = "", yaxs = "i", y.lim = yl)
plot(Rowp, direction = "rightwards", show.tip.label = FALSE,
yaxs = "i", y.lim = yl)
par(mar = rep(0,4), xpd = TRUE)
image((1:nrow(x)) - 0.5, (1:ncol(x)) - 0.5, x,
#xaxs = "i", yaxs = "i", axes = FALSE, xlab = "", ylab = "", ...)
xaxs = "i", yaxs = "i", axes = FALSE, ...)
par(mar = rep(0,4))
plot(NA, axes = FALSE, ylab = "", xlab = "", yaxs = "i", xlim = c(0,2), ylim = yl)
text(rep(0, nrow(x)), 1:nrow(x), Rowp$tip, pos = 4)
par(mar = rep(0,4))
plot(NA, axes = FALSE, ylab = "", xlab = "", xaxs = "i", ylim = c(0,2), xlim = xl)
text(1:ncol(x), rep(2, ncol(x)), Colp$tip, srt = 90, pos = 2)
}

Resources