Mixed text-justification or tabstops in legends in R - r

I want a legend like this:
I created this with five (sic!) legend()s, placing them side-by-side. Here is a working code sample (without colors):
plot(1, 0, xlim=c(1,11), ylim=c(0,45))
legend(0.6, 46.75, c("KVT", "", "", "IPT", "", ""), pch = c(0, 1, 2), bty = "n")
legend(1.4, 46.75, c(expression(paste("t1: ", italic(M), " =")), "t3:", "t5:", "t1:", "t3:", "t5:"), bty = "n")
legend(3.35, 46.75, c(19.31, 9.91, 10.79, 19.36, 9.69, 2.82), bty = "n", adj = 1)
legend(3.6, 46.75, "n = ", bty = "n")
legend(4.7, 46.75, c(213, 208, 61, 186, 159, 11), bty = "n", adj = 1)
This works, as you can see, but I need to loop through several variables, with different means and scales (here: 0 to 45), and I don't want to manually adjust the placement of five legends each time.
How can I create a similar legend using only one legend("topleft", ...), employing something similar to tabstops in Word to place the text within each line, or, if that is not possible, automatically placing multiple text boxes similar to a float: left in CSS.
Note that the columns of numbers are right-justified.
I tried with the ncol argument in legend(), but could get neither the partial right-alignment nor the partial suppression of symbols to work.
Your solution need not use the given numbers, symbols or colors. They will only make the code confusing.

To my knowledge there is no way to specify tab stops, but you could use space padding to control alignment. Here is the closest I could get, with 2 caveats
There must be some syntax to make it evaluate italic(M) but, for convenience, I replaced it with the letter "M"
I had to use fidex-width fonts to make sure the spaces align
Here is my proposed solution:
# store components of each row in a separate vector
l1 <- c("KVT", "", "", "IPT", "", "")
l2 <- c("t1: M =", "t3:", "t5:", "t1:", "t3:", "t5:")
l3 <- c(19.31, 9.91, 10.79, 19.36, 9.69, 2.82)
l4 <- c("n =", rep("", 5))
l5 <- c(213, 208, 61, 186, 159, 11)
# merge everything together with suitable space padding
tags <- paste(sprintf("%3s", l1),
sprintf("%-8s", l2),
sprintf("%5s", l3),
sprintf("%-3s", l4),
sprintf("%3s", l5))
plot(1, 0, xlim=c(1,11), ylim=c(0,45))
par(family="mono") ## have to use monotype for spaces to align
legend(0.6, 46.75, tags, pch = c(0, 1, 2), bty = "n")
I hope that helps, even if it's not exactly what you requested.

Related

Barplot labels too long, is it possible to set a "label width"

I am trying to create a stacked barplot where beside = TRUE. Here is the data used to generate this figure;
significant <- c(27, 44, 25, 54, 40, 31, 25, 9, 57, 59)
annotated <- c(119, 267, 109, 373, 250, 173, 124, 20, 452, 478)
names <- c("mitochondrial gene expression","ncRNA metabolic process",
"mitochondrial translation", "translation",
"ribonucleoprotein complex biogenesis", "ribosome biogenesis",
"rRNA metabolic process", "transcription preinitiation complex asse...",
"peptide biosynthetic process", "amide biosynthetic process")
data = rbind(significant, annotated)
colnames(data) <- names
rownames(data) <- c("significant", "annotated")
My plotting code is;
printBarPlots <- function(input, main){
data = rbind(input[,4], input[,3])
colnames(data)= input[,2]
rownames(data)=c("Significant", "Annotated")
par(mar=c(5,9,4,2))
mybar = barplot(data, width = 3, xlab = "Number of genes", main = main,
horiz = T, cex.axis = 0.8, beside = TRUE, las = 1,
cex.names = 0.8, legend = T, args.legend = list(x="right"))
}
Using this code, the bar labels extend far to the left of my plot. My question is unlike this questionbecause splitting the bar names at each space would still require having to have a small cex.names. Is it possible to specify that rather than having something like "transcription preinitiation complex asse..." written on one line, it can be spread out over two lines, such as below, to make better use of space? Or perhaps, some sort of code to split names onto different lines following a certain amount of letters (e.g. start new line after 13 characters).
"transcription preinitiation
complex asse..."

R: Changing height/location of column labels

Using the following code, the column labels for my barplot overlap with the plot itself (see image). Changing the margin appears only to affect the axis label, but not the column labels. Did a search but couldn't find this question. Suggestions? Thank you! (P.S.--I'm a beginner!)
library(colorspace)
df <- matrix(c(20, 14, 26, 18, 14, 4, 19, 21, 13, 1, 5, 4), ncol = 4, byrow = TRUE)
rownames(df) <- c("Character", "Tree", "Distance")
colnames(df) <- c("nrITS", "trnH-\npsbA", "matK", "rbcL")
graph.dat <- as.table(df)
italic_latin2 <- c(expression(atop(italic("nrITS"), (104))),
expression(atop(italic("trnH-\npsbA"), (82))),
expression(atop(italic("matK"), (42))),
expression(atop(italic("rbcL"), (28))))
barplot(graph.dat, beside = TRUE, ylab = "Percent Identified",
xlab = "Locus", ylim = c(0, 30), col = rainbow_hcl(3),
names.arg = italic_latin2)
Look at where the ?barplot function arguments get sent by the ... parameter values. The ?axis page says there is a padj parameter to adjust vertical label positioning, so perhaps:
italic_latin2 <- expression( atop(italic("nrITS"), (104)),
atop(italic("trnH-\npsbA"), (82)),
atop(italic("matK"), (42)),
atop(italic("rbcL"), (28)) )
barplot(graph.dat, beside = TRUE, ylab = "Percent Identified",
xlab = "Locus", ylim = c(0, 30), col = rainbow_hcl(3),
names.arg = italic_latin2, padj=0.8)
Notice that I simplified the expression vector code as well. The arguments to expression are adequately separated by commas.

Change direction of axis title and label in 3dplots in R?

I have a question that might be easy for a person who is expert in R plot. I need to draw 3D plot in R. My data is as follows:
df <- data.frame(a1 = c(489.4, 505.8, 525.8, 550.2, 576.6),
a2 = c(197.8, 301, 389.8, 502, 571.2),
b1 = c(546.8, 552.6, 558.4, 566.4, 575),
b2 = c(287.2, 305.8, 305.2, 334.4, 348.6), c1 = c(599.6, 611.4,
623.6, 658, 657.4), c2 = c(318.8, 423.2, 510.8, 662.4, 656),
d1 = c(616, 606.8, 600.2, 595.6, 595),
d2 = c(242.4, 292.8, 329.2, 378, 397.2),
e1 = c(582.4, 580, 579, 579, 579),
e2 = c(214, 255.4, 281.8, 303.8, 353.8))
colnames(df) <- rep(c("V1", "V2"), 5)
df.new <- rbind(df[, c(1, 2)],df[, c(3, 4)],df[, c(5, 6)],
df[, c(7, 8)],df[, c(9, 10)])
df.new$Group <- factor(rep(c("a","b","c","d","e"), each = 5))
df.new$Class <- rep(c(1:5), 5)
I am drawing a 3D Plot using scatterplot3d package.
x=df.new$Class
y=V1
z=V2
scatterplot3d(x,y,z, pch = 16, color=colors,main="3D V1 v.s V2",xlab =
"Class",ylab = "V1", zlab = "V2")
Now I want to do 2 modifications. One is to make the vertical title of those axis horizontal and the next is to put a label for values of x and for example put a label "first interval" for 1 in x values and so one and so forth. How an I do it?
Also, how can I make the points linear or plane instead of dots.
One is to make the vertical title of those axis horizontal
To do this you need to hide the current label, and use the text() function to add a rotated label in the correct spot; as described here Rotate y-axis label in scatterplot3d (adjust to angle of axis)
set.seed(42)
scatterplot3d(rnorm(20), rnorm(20), rnorm(20), ylab = "")
text(x = 5, y = -2.5, "Y-axis", srt = 45)
and for example put a label "first interval" for 1 in x values and so one and so forth. How an I do it?
From the documentation - https://cran.r-project.org/web/packages/scatterplot3d/scatterplot3d.pdf
Use the x.ticklabs attribute, for example:
xlabs <- c("first interval", "second", "third", "fourth", "this is 5")
scatterplot3d(x,y,z, pch =16,main="3D V1 v.s V2",xlab = "Class",ylab = "V1", zlab = "V2", x.ticklabs=xlabs)
Also, how can I make the points linear or plane instead of dots.
Scatterplot3d offers "lines" and "vertical lines", for example:
scatterplot3d(x,y,z , type="l", lwd=5, pch=" ")
#or
scatterplot3d(x,y,z , type="h", lwd=5, pch=" ")

levelplot (R lattice package) with 2 yaxis labels

I want to place 2 sets of y-axis labels on the graph I created using levelplot function from lattice library at R. I was able to get two sets of labels to show but they are overlapping. Below please see a minimum example. I also tried a few options at par.settings such as ylab.axis.padding and axis.components padding, but nothing seemed to change the superimposition of 2 y-labels. Perhaps they have been overwritten somehow? Any ideas will be appreciated.
My example codes :
A = matrix( c(3, 1, 0, 1, 2, 3, 1, 0,
rep(1,4), 2, 0, 1), nrow=3, ncol=5, byrow = TRUE)
colnames(A)= c("XXX5", "XXX4", "XXX3", "XXX2", "XXX1")
axis.build=function(side,...){
if(side == "left"){
panel.axis(side=side, outside=TRUE, at=1:5,tck=0,
text.col="black", labels=colnames(A), text.cex=0.5)
panel.axis(side=side, outside=TRUE, at=1:5,tck=0,
text.col="brown", labels=seq(ncol(A)), text.cex=0.9 )
} else axis.default(side=side, ...)
}
levelplot(A, aspect="iso", shrink = c(0.8, 0.8),
scales= list(x=list(draw=F),cex=0.5, font=2),
axis=axis.build,, xlab= NULL, ylab=NULL,
col.regions=c("black", "orange", "red","purple"),
at=c(-1, 0, 1, 2, 3), colorkey = FALSE,
par.settings = list(axis.line=list(col="transparent"),
axis.components=list(bottom=list(pad1=1, pad2=3)) ))
I think I have found the solution. In case anyone interested : I changed the first tck=0 to tck=2, and added line.col= "transparent", thus two left axis are stacked next to each other. Voila ! However, I can't seem to find where the documentation is for using pad1 and pad2 parameters. Any suggestion?

R - add title to images with rasterImage

I have 12 twelve PNG files which I want to combine in a single plot with 4x3 grid in R.
So far I can create the grid with,
plot(c(0,4), c(0,3), type = "n", xaxt = "n", yaxt = "n", xlab = "", ylab = "")
and I can add images to it with,
rasterImage(readPNG("image1.png"), 0, 3, 1, 2)
rasterImage(readPNG("image2.png"), 1, 3, 2, 2)
etc.
I get what I want, but I also want to add a title to each image in the plot. Like image1 should have a. Image1 and image2 should have b. Image2 on top of the images. Is there a way to do in R?
Thanks in advance.
#BondedDust's suggestion to use text is perfect, but using the mfrow (or mfcol) graphic parameter in par to layout the grid of plots might be sensible. You can then use plot(..., main='foo') or title(main='foo') to add the titles. For example:
Download some example png graphics, and read them into a list:
library(png)
pngs <- lapply(LETTERS[1:12], function(x) {
u <- 'http://icons.iconarchive.com/icons/mattahan/umicons/64'
download.file(mode='wb', sprintf('%s/Letter-%s-icon.png', u, x),
f <- tempfile(fileext='.png'))
readPNG(f)
})
Use mfrow to set the plot to have 4 rows and 3 columns, and add an upper margin for titles with mar. Then use sapply (for example) to iterate over elements of pngs (well, actually the indexes, 1 through 12, of the elements), plotting each in turn:
par(mfrow=c(4, 3), mar=c(0, 0, 3, 0))
sapply(seq_along(pngs), function(i) {
plot.new()
plot.window(xlim=c(0, 1), ylim=c(0, 1), asp=1)
rasterImage(pngs[[i]], 0, 0, 1, 1)
title(paste0(letters[i], '. Image ', i), font.main=2)
})
Try this:
text(x=0.5,y=2.95, labels="a. Image1")
text(x=1.5,y=2.95, labels="b. Image1")
If it needed to be bold, then plotmath expressions are needed:
text(x=1.5,y=2.95, labels=expression( bold(b.~Image1) ) )

Resources