If you don't know how to put text (using the text function so it can be more freely edited, not the legend function) at the top of each subplot in R when the coordinates vary and you don't know the y max or x max (e.g. for a histogram where you don't know the frequency in advance) how do you do it?
Addendum: Also, mtext uses margins, I am speaking of coordinate space here, not margin space.
You can use par ('usr'). It gives you the current coordinates of the plot. Really useful if you want text in a certain area of each subplot and you don't know the coordinates in advance (e.g. a histogram). The output looks like:
par('usr')
[1] -0.28 7.28 -3.00 78.00
wherein the x min is the first member of the list, the x max is the second, the y min is the third, and the y max is the fourth. You can treat par('usr') like a vector in R and if you want it to be in the top left you can do, say:
text(par('usr')[1]+2,.9*par('usr')[4],labels="blahblah")
From this it will be plotted in the upper 10% of the plot and +2 from the leftmost coordinate of the plot space. Of course you can adjust this, but that would be top left more or less.
Using this code for my data:
y <- rnorm(100)
z <- rnorm(100)
par(mfrow = c(1,2))
hist(y, breaks = 30)
text(.8 * par('usr')[2], .9 * par('usr')[4], labels = paste("mean:", round(mean(y), 2)))
text(.8 * par('usr')[2], .86 * par('usr')[4], labels = paste("median:", round(median(y), 2)))
hist(z, breaks = 30)
text(.8 * par('usr')[2], .9 * par('usr')[4], labels = paste("mean:", round(mean(z), 2)))
text(.8 * par('usr')[2], .86 * par('usr')[4], labels = paste("median:", round(median(z), 2)))
mtext("distributions", side = 3, line = -2, outer = TRUE, col = 2) # added mtext to show how I would use it to create a title
I got this image:
Assuming you want the text inside the plot region, you can use legend, and specify the position by keyword (see details in ?legend):
par(mfrow=c(2, 2))
sapply(1:4, function(i) {
plot(runif(10))
legend('top', paste('Plot', i), bty='n', text.font=2)
})
You could also use mtext:
mtext(paste('Plot', i), 3, line = -1.5)
Related
I've added an verticle line at some point on x-axis (as shown in line plot of below Fig.) using abline() function in R, and I want to either put a legend for it or add some text over it (vertically on the abline).
So, is it possible to do this? If yes, then how I can do this?
Use text with the indicated arguments. Alternately use the legend function as shown.
abline is classic graphics so it is assumed you want to use that plotting system but if you want ggplot2 see Add a horizontal line to plot and legend in ggplot2 and make the obvious modifications to change the horizontal line to vertical.
x <- y <- 1:10; v <- 5 # input
plot(x, y)
abline(v = v, col = "red")
text("Vertical Line", x = v, y = max(y), srt = -90, pos = 4) # near top
text("Vertical Line", x = v, y = min(y), srt = 90, adj = c(0, -0.5)) # near bottom
legend("topleft", legend = "Vertical Line", pch = "|", col = "red")
I am trying to display barchart overlayed with line plot on secondary y-axis. I was following example here: http://robjhyndman.com/hyndsight/r-graph-with-two-y-axes/. I successfully display my data, however the beginning of the y1 and y2 axis do not start on the common base (on the common 0), the y2 is located further up.
How to correctly align y1 and y2 axes on the common basis? Can I extent both of my y1 and y2 axis in the same size? And, how can I adjust the position of the points in the middle of the bars?
My dummy data:
x <- 1:5
y1 <- c(10,53,430,80,214)
y2 <- c(0.2,1.2,3.3, 3.5, 4.2)
# create new window
windows()
# set margins
par(mar=c(5,4,4,5)+.1)
# create bar plot with primary axis (y1)
barplot(y1, ylim= c(0,500))
mtext("y1",side=2,line=3)
# add plot with secondary (y2) axis
par(new=TRUE)
plot(x, y2,,type="b",col="red",xaxt="n",yaxt="n",xlab="",ylab="", ylim= c(0,10), lwd = 2, lty = 2, pch = 18)
axis(4)
mtext("y2",side=4,line=3)
When you check the documentation for par() you will find the options xaxsand yaxs with which you can control the interval calculation for both axes. Calling par(yaxs = 'i') prior to your plot() command or using the option directly as an argument to plot() will change the interval calculation in the following way:
Style "i" (internal) just finds an axis with pretty labels that fits
within the original data range.
Additional information for the TO concerning his comment:
In order to center the points of the line go with lines instead and you can use the x-axis created by barplot:
par(mar=c(5,4,4,5)+.1)
# create bar plot with primary axis (y1)
par(xpd = F)
ps <- barplot(y1, ylim= c(0,500), xpd = F)
axis(4, at = 0:5 * 100, labels = 0:5 * 2) # transform values
mtext('y1',side = 2, line = 3)
lines(x = ps, y = y2 * 50, type = 'b', col = 'red') # transform values
I used this code to make this plot:
plot(p, cv2,col=rgb(0,100,0,50,maxColorValue=255),pch=16,
panel.last=abline(h=67,v=1.89, lty=1,lwd=3))
My plot looks like this:
1.) How can I plot the value of the ablines in a simple plot?
2.) How can I scale my plot so that both lines appear in the middle?
to change scale of plot so lines are in the middle change the axes i.e.
x<-1:10
y<-1:10
plot(x,y)
abline(a=1,b=0,v=1)
changed to:
x<-1:10
y<-1:10
plot(x,y,xlim=c(-30,30))
abline(a=1,b=0,v=1)
by "value" I am assuming you mean where the line cuts the x-axis? Something like text? i.e.:
text((0), min(y), "number", pos=2)
if you want the label on the x axis then try:
abline(a=1,b=0,v=1)
axis(1, at=1,labels=1)
to prevent overlap between labels you could remove the zero i.e.:
plot(x,y,xlim=c(-30,30),yaxt="n")
axis(2, at=c(1.77,5,10,15,20,25))
or before you plot extend the margins and add the labels further from the axis
par(mar = c(6.5, 6.5, 6.5, 6.5))
plot(x,y,xlim=c(-30,30))
abline(a=1,b=0,v=1)
axis(2, at=1.77,labels=1.77,mgp = c(10, 2, 0))
Similar in spirit to the answer proposed by #user1317221, here is my suggestion
# generate some fake points
x <- rnorm(100)
y <- rnorm(100)
# positions of the lines
vert = 0.5
horiz = 1.3
To display the lines at the center of the plot, first compute the horizontal and vertical distances between the data points and the lines, then adjust the limits adequately.
# compute the limits, in order for the lines to be centered
# REM we add a small fraction (here 10%) to leave some empty space,
# available to plot the values inside the frame (useful for one the solutions, see below)
xlim = vert + c(-1.1, 1.1) * max(abs(x-vert))
ylim = horiz + c(-1.1, 1.1) * max(abs(y-horiz))
# do the main plotting
plot(x, y, xlim=xlim, ylim=ylim)
abline(h=horiz, v=vert)
Now, you could plot the 'values of the lines', either on the axes (the lineparameter allows you to control for possible overlapping):
mtext(c(vert, horiz), side=c(1,2))
or alternatively within the plotting frame:
text(x=vert, y=ylim[1], labels=vert, adj=c(1.1,1), col='blue')
text(x=xlim[1], y=horiz, labels=horiz, adj=c(0.9,-0.1), col='blue')
HTH
I have a plot that has $-amounts and dates on y and x axis respectively. Currently the dollar amounts range from $0-15 million. Something like this:
x <- rnorm(20)^2 * 1000000
plot(x)
R does stuff like '1.0e+07' instead of '10,000,000' and also orients the text vertically instead of horizontally.
My questions are:
1) how would I get the scale text to be horizontally oriented?
2) how would I get R to use 10MM instead of '10,000,000' or '1.0e+07'?
1) See the scipen option in ?options which is a penalty against the use of scientific notation. For better control, you need to plot the axis by hand with labels you want.
2) See las in ?par which controls to orientation crudely of axis labels.
For 1):
x <- rnorm(20)^2 * 10000000
layout(matrix(1:2, ncol = 2))
plot(x)
getOption("scipen")
opt <- options("scipen" = 20)
getOption("scipen")
plot(x)
options(opt)
layout(1)
which gives
To plot your own axis try
plot(x / 10000000, axes = FALSE)
axis(1)
pts <- pretty(x / 10000000)
axis(2, at = pts, labels = paste(pts, "MM", sep = ""))
box()
Which gives
Where we use pretty() to select pretty locations for the ticks just as R would and then add a custom axis. Notice how we suppress axis drawing in the plot() call and then add back the axes and the plot frame with calls to axis() and box().
For 2) combining with 1)
opt <- options("scipen" = 20)
op <- par(mar = c(5,7,4,2) + 0.1) ## extra margin to accommodate tick labs
x <- rnorm(20)^2 * 10000000
plot(x, las = 1, ylab = "") ## no y-axis label
title(ylab = "label", line = 5.5) ## need to plot the axis label
par(op)
options(opt)
Which gives
Notice how we use las in the plot() call, and we need to create some extra margin space to accommodate the tick labels. We also need to plot the label by hand otherwise R will stick it in amongst the tick labels.
For the custom axis labels, add the las = 1 to the axis() call:
op <- par(mar = c(5,5,4,2) + 0.1)
plot(x / 10000000, axes = FALSE, ylab = "")
axis(1)
pts <- pretty(x / 10000000)
axis(2, at = pts, labels = paste(pts, "MM", sep = ""), las = 1)
title(ylab = "my label", line = 4)
box()
par(op)
Which produces
Use axis with custom labels. First, divide your data by 1 million. And then create a series with the MM notation using paste()
y <-rnorm(20)^2 * 1000000 /1000000
x <-11:30
plot(x,y, yaxt="n")
my.axis <-paste(axTicks(2),"MM",sep="")
axis(2,at=axTicks(2), labels=my.axis)
The text is now horizontal. But if you run into a problem use, las=1 to force labels to be horizontal.
axis(2,at=axTicks(2), labels=my.axis, las=1)
I tried simply plotting some data in R with the y-axis label horizontal and left of the y-axis tick labels. I thought the code below would work:
set.seed(1)
n.obs <- 390
vol.min <- .20/sqrt(252 * 390)
eps <- rnorm(n = n.obs, sd = vol.min)
mar.default <- c(5,4,4,2) + 0.1
par(mar = mar.default + c(0, 4, 0, 0)) # add space to LHS of plot
pdf("~/myplot.pdf", width=5.05, height=3.8)
plot(eps, main = "Hello World!", las=1, ylab="") # suppress the y-axis label
mtext(text="eps", side=2, line=4, las=1) # add horiz y-axis label
# 4 lines into the margin
Instead, as you may see, the y-axis label almost fell completely outside of the graphics window. This phenomenon still exists no matter how much I expand the LHS margin.
Q: What am I doing wrong? Is there something I need to do with the oma parameter? What do I need to do to plot things the way I'm intending? I'm a little overwhelmed by all of this!
This is a classic one, maybe should be a FAQ. You have to set the par settings after the call to pdf, which creates the plotting device. Otherwise you're modifying the settings on the default device:
set.seed(1)
n.obs <- 390
vol.min <- .20/sqrt(252 * 390)
eps <- rnorm(n = n.obs, sd = vol.min)
# add space to LHS of plot
pdf("~/myplot.pdf", width=5.05, height=3.8)
mar.default <- c(5,4,4,2) + 0.1
par(mar = mar.default + c(0, 4, 0, 0))
plot(eps, main = "Hello World!", las=1, ylab="") # suppress the y-axis label
mtext(text="eps", side=2, line=4, las=1)
dev.off()