R how to make legend position independent from graph size - r

Here is my code; basically I am putting four graphs on the same plot device and putting a legend on each. [edit: I am working with RStudio]
dev.new()
par(mfrow=c(2,2), oma=c(0,0,2,0))
#plot1
plot(parameters...)
par(new=TRUE)
plot(parameters, col="red")
legend("bottomright", c("seed match", "background"), bty="n", lty=c(1,1),
col=c("red","black"), cex=0.8, inset=0)
#plot2
plot(parameters...)
par(new=TRUE)
plot(parameters..., col="red")
legend("bottomright", c("seed match", "background"), bty="n", lty=c(1,1),
col=c("red","black"), cex=0.8,inset=0)
#etc. same for plot2 and plot 3
title("bla bla bla", outer=TRUE)
I have two issues with this.
(1) even though I specified "bottomright", the legend doesn't seem to be aligned to the bottom right, the wider I resize the graph horizontally, the more space there is between the legend and the right of the graph.
(2) the amount of space the legend occupies is inadequate. I tried modifying cex= but that only takes care of font size, the overall space occupied by the legend remains, meaning that the smaller the font, the bigger the space between lines. I would like the legend to be a little less "spread out".
Illustration
This looks sort of OK, although I would like to decrease the space between lines inside the legend:
But when I resize horizontally it doesn't. I would like to tether the legend to the right of the graph.

(1):
As your graphs are all scaled the same way, you could use x and y coordinates to position the legend, not the key words. e.g.:
legend(x = 0.25, y = 35, c("seed match", "background"), bty="n", lty=c(1,1), col=c("red","black"), cex=0.8, inset=0)
(2):
I don't know if there exists a way to manipulate line spacing via legend(), I didn't find one. I always switch to manual generation of the legend via mtext(), abline() and such when the legend has to look really pretty. It is more work but you got control over every aspect of your legend.
One last comment: I guess you want your graph to like nice not on your screen but on some sort of paper or presentation. I always generate graphs with devices like cairo_ps(), svg() or jpeg() (jpeg only on rare occasions because it is raster, not vector-based). These functions give you more control about your graphs than exporting the R Graphics Device. But the way a graph looks changes with the device, each one needs to be configured separately. Better do it only for the one you are going to use in the end.
I hope this helps

Instead of using "bottomright", you could use legend() twice, for each legend element with position values you choose such as
legend(x1,y1,c("seed match"), bty="n", lty=1, col="red", cex=0.8)
for the first one. This way you can choose their position individually and therefore control the spacing between them. I think this solve your two issues.

Related

Use constant vertical adjustment for text() and legend() regardless of plot dimensions

To draw X-axis labels for barplots in R, I use text() like this:
text(mean(bp), par("usr")[3] - 0.05*yDiff, xpd=NA, labels=journey, cex=0.9, font=2)
To draw a legend, I use something like this:
legend("bottom", legend=abbrevLabels, fill=c(colors), xpd=NA, horiz=TRUE, bty="n",
cex=1.0, inset=c(0, -0.3), xjust=0, adj=0.035,
text.width=rep(meanLabelLen/7.5, length(legendLabels)))
Both vertical offsets here -- the 0.05*yDiff and the insert offset of -0.3 for the legend -- are in Y-axis space. For various reasons, that's a problem for me. Instead, I prefer offsets in units of pixels. That is, what I really want to say is: "render labels 10 pixels below the bottom of the graph".
How can this be done?
For constant vertical offset of horizontal, X-axis labels situated underneath bar plots (at the bottom of a larger grid of such plots), it turns out that using title with the line attribute has consistent behavior / placement independent of device size. Here is what I now do:
title(xlab=journey, line=0, cex=0.8, font.lab=2, xpd=NA)
where line is integral and 0 is nearest the plot, and a higher integer is further away (in the negative Y direction).
For the legend, I could not come up with a constant vertical offset that behaved independently of either grid dimensions or device size. Several points here:
yjust parameter to legend did not work at all. I looked online for examples, but no matter what value I used, yjust was a no-go.
y parameter does work, but regrettably, not in conjunction with a descriptive attribute for x; that is, if x is set to bottom, you cannot concurrently set y. I found this behavior disconcerting, as I would generally expect these coordinates to be independent of each other.
To work around these limitations, here is what I did:
yInset <- 0.4 * (1.075 - par("fin")[2] / dev.size("in")[2])
legend(x='bottom', yjust=-0.75, inset=c(0, -yInset), legend=abbrevLabels, fill=c(colors), xpd=NA, horiz=TRUE, bty="n", cex=1.0, adj=0.035, text.width=rep(meanLabelLen/7.5, length(legendLabels)))
This logic effectively sets up a sliding Y-offset in proportion to grid dimensions and device size. The empirically determined scaling / offset factors of 1.075 and 0.4 are truly gross, but for now suffice.
It would help in the future if some of the limitations for legend cited above are resolved (or possibly better explained in the case that I misunderstood the docs).

R core: legend surfaces horizontal boxes / labels only on large device dimensions, but truncates on smaller device sizes

I am using R core for plotting a grid of bar graphs. I use legend() to draw a horizontally adjacent sequence of four filled rectangles with associated labels (drawn to the right of said rectangles). When a new device / window is first created, legend() renders the two innermost elements (ie, 2 filled rectangles and associated labels) of the legend, while the left and right elements are truncated from the device view.
If I maximize the size of the device / window to fill my laptop screen, and then re-run the rendering / plotting logic from R, the legend then is properly surfaced -- comprising four columns and each element (ie, filled rectangle with label) is apportioned an equal swath of device space along the horizontal direction of the plot.
Why should device dimensions matter as to whether the legend() contains all elements on the device / window? Is there a way to fix this?
Here is the exact call I make:
legend("bottom", legendLabels, fill=c(colors), xpd=NA, horiz=TRUE, bty="n", cex=1.0, inset=c(0, -0.5), xjust=0)
I set xpd=NA because we are rendering the legend in the outer margins of the device view.
There are several adjustments in the horizontal direction that can be made in the call to legend. For compacting or expanding the allocated width for each label in the legend, I found the text.width parameter to be most effective. Again, there are other horizontal adjustments you can make, but for me, the one with the most notable impact for overall legend width was text.width:
legend(x='bottom', inset=c(0, -yInset), legend=abbrevLabels, fill=c(colors), xpd=NA, horiz=TRUE, bty="n", cex=1.0, adj=0.035, text.width=rep(meanLabelLen/7.5, length(legendLabels)))
See this related article concerning vertical adjustments.

R. Axis label for box plot stacking redundantly stacking over eachother

Making boxplot. Specifying the axes separately. Heres the code.
boxplot(data$overall~data$league, horizontal=T, las=2, axes='n', outpch=20,
outcex=.5, cex.axis=.5, col=rainbow(7, alpha=.5))
axis(1, lty=1, at=seq(45,90,5))
axis(2, at=data$league, labels=as.character(data$league), las=2, cex.axis=.3)
It takes a long time to run the line that puts the axis there, and the words look so weird and blurry. That makes me think they are getting stacked on top of each other. How do I prevent this?
Also, how do I flip the y-axis (data$league) from Z-A sort to an A-Z sort?

R Plot two graphs; One large, one small

I want to make a figure similar to this
See how the bottom portion is tiny... how do I do that?
I'm ok in ggplots2 so give me your expertise please.
I do not need to plot 2 values on the larger one. Essentially, I know how to generate everything I want from this figure, except how to make a tiny plot under a larger one (sans photoshop)
I have data.frames that contain the transcript information in the figure at the bottom, I'm only interested in one gene. To plot the genes you would do something like this
plot(transcript, type="l", lwd=2)
points(exons, type="l", lwd=3, col="blue")
points(utrExons, type="l", lwd=3)
To plot the large figure it would look like this
plot(genetic.variant, pch=16)
An exhaustive internet search turned into bupkis, how do you make two figures in the same plotting area with one of them being much smaller than the other?
With base graphics you can do something like this
dd<-data.frame(x=1:100, y1=runif(100), y2=cumsum(rnorm(100)))
layout(matrix(1:2, ncol=1), heights=c(3,1))
par(mar=c(0,3,3,2))
plot(y1~x,dd, xaxt="n", xlab="")
par(mar=c(3,3,0,2))
plot(y2~x,dd)
You can use layout
layout(c(1,2),widths=c(5,1),heights=c(5,1),T)
par(mar=c(1,1,1,1)
and just change the heights depending on your preference

barplot design issues

I am doing a barplot of 14 columns to represent some data, I set the names.arg option to show as vertical lables, unfortunately, this caused the new vertical lables to overlap with the "sub" and "xlab" options I have. How do I prevent this from happening?
Here's my command:
par(mar=c(6, 5, 4,7.5 ))
barplot(x, main=paste("title1 \n","subtitle"),
names.arg=c(1,2,3,4,5,6,7,8,9,10,11,12,13,14),las=2, sub=("overlapping text1"),
xlab="overlapping text2", col = c("red2","darkorange3"))
Another question on my mind is, I am using a 2-line title in "main" as you can see from the command. Is it possible to make the second line font smaller, whilst keeping the first line in the same format?
Thanks,
One solution to change font size for one of titles, is to use two calls of functions mtext() in different lines with different cex= values and remove main= from barplot(). To overcome problem with overlapping text, mtext() also can be used instead of xlab= and sub=. You just have to find the right line= and increase space around plot with par(mar=..).
x<-sample(letters[1:14],300,replace=TRUE)
par(mar=c(9,3,5,2))
barplot(table(x),
names.arg=paste0("very_long_",1:14),las=2,
col = c("red2","darkorange3"))
mtext(side=3,"Title1",line=2,cex=2)
mtext(side=3,"subtitle",line=1,cex=1.5)
mtext(side=1,"overlapping text1",line=6)
mtext(side=1,"overlapping text2",line=7)
Another option to look at is the staxlab function in the plotrix package.
Also look at the mgp argument to the par function for a way to set the default placement of the axis title.

Resources