Adding label to secondary axis in R - r

I have this code:
# Plotting everything
plot( p1, col= "lightgreen", xlim=c(-2.5,4.5), ylim=c(0, 700), main="Daily Total Precipitation for AR and Oct-May", xlab="ln(x)" , ylab="Frequency", xaxt = "n") # first histogram
plot( p2, col="red", xlim=c(-2.5,4.5), ylim=c(0, 700), xaxt = "n" , add=T)
# Adding in text labels on top of the bars
text(x, y, paste(round(percents,2),"%"), cex=0.50, pos=3, offset=0.3, col="black")
axis(side=1, at=breaks) # new x-axis
# parameter that needs to be set to add a new graph on top of the other ones
par(new=T)
plot(x, percents, xlim=c(-2.5,4.5), type="l", col="yellow", lwd=3.0, axes=F, ylab=NA, xlab=NA)
axis(side=4, at=seq(0,100,by=10), col="yellow", col.axis="yellow") # additional y-axis
mtext("Percent", side=4, col="yellow")
# legend settings
legend("topleft", c("AR", "Oct-May"), lwd=10, col=c("red", "lightgreen"))
Which produces this graph:
And I can't seem to figure out how to get the secondary y-axis label to show up in the correct position. Any help or suggestions is greatly appreciated.
Edit: Using RStudio.

One option is to specify the line argument to mtext(). In the example below I add a couple more lines to the right (side = 4) margin of the plot using par(), and then I draw three labels using mtext() at the default (line = 0), line 3 (line = 3), and line -3 (line = -3):
op <- par(mar = c(5,4,4,4) + 0.1)
plot(1:10)
mtext("line0", side = 4)
mtext("line3", side = 4, line = 3)
mtext("line-3", side = 4, line = -3)
par(op)
Note that line numbers increase away from the plot region and that negative line values move into the plot region, or to the left of the right boundary of the plot region.
It takes a little playing with the number of margin lines (as set in par(mar = x)) and which line you want to draw on using mtext(), but a little trial and error should get you what you want.
Note also that you don't need to specify integer values for the line argument. You can specify fractions of lines too: line = 2.5.

Related

plottext on horizontal bar in R

I am trying to plot the barchart and want to show the percentage on horizontal line end.. Not able to get ..whats the mistake
y <- c('Others(27%)','Environment','Family Life & children','Combating terrorism','Pensions',
'Europe', 'Housing', 'Education', 'Tax','Benefits','Immigration & Assylum','Health','Economy')
x <- c(27,10,12,15,18,20,20,21,21,25,42,46,49)
mylabels <- c('....27%','10%','12%','15%','18%','20%','20%','21%','21%','25%','42%','46%','49%')
par(mar=c(5,10,4,2)+0.1)
usr <- par( "usr" )
my_bar<-barplot(x,main="British Voters Election Priority (2015)", horiz=TRUE,las = 1,
names.arg=y, xlim=c(0, 60), border = 'black',
col=rev(topo.colors(14)),
xlab="Percentage (%)")
abline(v=x, col='grey', type="l", lty=2)
#text(myvect1, b[1,], mylabels, col="white", adj=1)
text(my_bar, mylabels, cex=1)
If you want the numbers to be displayed at the end of the bars, just extract the numeric characters out of "mylabels" to get the appropiate x-coordinates and set pos = 4 to display them on the right of the bars. As for the colours for the bars, just pick some palette that suits your wishes or specify all 13 colors manually. There are tons of cheatsheets throughout the web with different color patterns for R.
my_bar<-barplot(x,main="British Voters Election Priority (2015)", horiz=TRUE,las = 1,
names.arg=y, xlim=c(0, 60), border = 'black',
col = palette(rainbow(13)),
xlab="Percentage (%)")
abline(v=x, col='grey', type="l", lty=2)
#text(myvect1, b[1,], mylabels, col="white", adj=1)
text(as.numeric(gsub("\\D", "", mylabels)), my_bar, mylabels, cex=1, pos = 4)
You did not specify x-coordinates for where the tekst should be plotted. Your code now took the values of my_bar for both the x-coordinates and the y-coordinates. If I am correct you want something like this.
Just use this line of code at the end in order to get that:
text(60, my_bar, mylabels, cex=1, pos = 2)

How to keep the space between tick and label minimum?

i've got a tiny problem in here, which i would like to have some hints on.
How can i change the space between ticks and labels? (indicated with 1 & 2)
my current structure looks as follows:
par(mfrow=c(5,2),oma=c(0,0,2,0),las=1,mar=c(3,5,2,1),cex.lab=0.9, cex.axis=0.7)
plot(sapply(ERRORS.train.fast[[1]],mean),main="Pipe 63569",type="l", ylab="", xlab="",xaxt="n")
axis(1, at=1:29,labels=seq(2,30,1))
title(ylab= "RMSE (-)",line=3)
title(xlab= "K-Value",line=2)
highly appreciate your help!
cheers,
Olli
You can use the padj argument for "adjustment for each tick label perpendicular to the reading direction." (from ?axis)
par(mfrow = c(1, 2))
plot(1:5, axes = F)
axis(1)
plot(1:5, axes = F)
axis(1, padj = -.75)
Unfortunately, the directions are different for the different axes (because it is relative what is "up" for the text), so to move the labels closer to the ticks, you will want lower padj values for the horizontal axis, but higher padj values for the vertical axis.
If you rotate the labels (as shown in your example plot on the vertical axis), you will use hadj instead of padj. Overall, I would expect you want something like:
plot(1:5, axes = F)
axis(1, padj = -.75)
axis(2, hadj = 0, las = 1)
You can use the mpg par.
par(mfrow=c(1,2))
plot(iris[,3:4], pch=20, col=rainbow(3)[iris$Species],
ylab="", xlab="",xaxt="n")
axis(1, at=1:7)
plot(iris[,3:4], pch=20, col=rainbow(3)[iris$Species],
ylab="", xlab="", xaxt="n")
axis(1, at=1:7, mgp=c(0,0.5,0))

Change the number of tick marks on a figure in R

I created a figure of two plots (two years) of climate data (temp and precip) that looks exactly like I want it, except that one of my axes has too many tick marks. With everything I have going on with this figure, I can't find a way to specify fewer tick marks without messing up other parts. I would also like to specify where the tick marks are. Here is the figure:
You can see that the tick marks for the top axis just blur together and the numbers chosen are not very meaningful to me. How can I tell R what I really want?
Here are the datasets I am using: cobs10 and
cobs11.
And here is my code:
par(mfrow=c(2,1))
par(mar = c(5,4,4,4) + 0.3)
plot(cobs10$day, cobs10$temp, type="l", col="red", yaxt="n", xlab="", ylab="",
ylim=c(-25, 30))
axis(side=3, col="black", at=cobs10$day, labels=cobs10$gdd)
at = axTicks(3)
mtext("Thermal Units", side=3, las=0, line = 3)
axis(side=2, col='red', labels=FALSE)
at= axTicks(2)
mtext(side=2, text= at, at = at, col = "red", line = 1, las=0)
mtext("Temperature (C)", side=2, las=0, line=3)
par(new=TRUE)
plot(cobs10$gdd, cobs10$precip, type="h", col="blue", yaxt="n", xaxt="n", ylab="",
xlab="")
axis(side=4, col='blue', labels=FALSE)
at = axTicks(4)
mtext(side = 4, text = at, at = at, col = "blue", line = 1,las=0)
mtext("Precipitation (cm)", side=4, las=0, line = 3)
par(mar = c(5,4,4,4) + 0.3)
plot(cobs11$day, cobs11$temp, type="l", col="red", yaxt="n", xlab="Day of Year",
ylab="", ylim=c(-25, 30))
axis(side=3, col="black", at=cobs11$day, labels=cobs11$gdd)
at = axTicks(3)
mtext("", side=3, las=0, line = 3)
axis(side=2, col='red', labels=FALSE)
at= axTicks(2)
mtext(side=2, text= at, at = at, col = "red", line = 1, las=0)
mtext("Temperature (C)", side=2, las=0, line=3)
par(new=TRUE)
plot(cobs11$gdd, cobs11$precip, type="h", col="blue", yaxt="n", xaxt="n", ylab="",
xlab="", ylim=c(0,12))
axis(side=4, col='blue', labels=FALSE)
at = axTicks(4)
mtext(side = 4, text = at, at = at, col = "blue", line = 1,las=0)
mtext("Precipitation (cm)", side=4, las=0, line = 3)
Thanks for thinking about it.
You've pretty much got the solution already:
axis(side=3, col="black", at=cobs10$day, labels=cobs10$gdd)
Except, you are asking to have ticks and labels at every single entry.
Take a look at the function pretty:
at <- pretty(cobs10$day)
at
# [1] 0 100 200 300 400
These are where the ticks should be placed on the x-axis. Now you need to find the corresponding labels. This is not straigtforward, but we will get:
lbl <- which(cobs10$day %in% at)
lbl
# [1] 100 200 300
lbl <- c(0, cobs10$gdd[lbl]
axis(side=3, at=at[-5], labels=lbl)
Update
I've been a bit annoyed by your use of three different series in a single plot. There are many reasons this is troublesome.
Having two y-values are always troublesome see this article from Stephen Few (go to page 5 for my favorite example); in your case it is not that serious due to the nature of the plots and your use of colours to indicate which y-axis the values belong to. But still, on principle.
Axis ticks should have a fixed function, e.g. linear or logarithm. With your Thermal Units, they appear "randomly" (I know that is not the case, but for an outsider they do).
We gotta do something about your x-axis ticks that just refer to "day of year".
First up, we take a look at your data and see what can be done naively. We recognize that your ''date'' variable is actual dates. Let's exploit it and make R aware of it!
cobs10 <- read.table('cobs10.txt',as.is=TRUE)
cobs10$date <- as.Date(cobs10$date)
plot(temp ~ date, data=cobs10, type='l')
Here, I really like the x-axis ticks and had some trouble replicating it. ''pretty'' on dates insisted on either 4 ticks or 12 ticks. But we will come back to that later.
Next, we can do something about the overlay plotting. Here I use ''par(mfrow=c(3,1))'' to instruct R to have three multiple plots stacked in a single window; with these multiple plots we can differentiate between inner and outer margins. The ''mar'' and ''oma'' arguments refers to the inner and outer margin.
Lets put all three variable together!
par(mfrow=c(3,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 1, 0))
plot(temp ~ date, data=cobs10, type='l', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', ylab='Precipitation (cm)')
plot(gdd ~ date, data=cobs10, type='l', ylab='Thermal units')
This looks okay, but not with ticks on top of the plots. Not good. Naturally, we can enable ticks in the first two plots (with ''plot(..., xaxt='n')''), but this will distort the bottom plot. So you will need to do so for all three plots and then add the axis to the outer plotting region.
par(mfrow=c(3,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 1, 0))
plot(temp ~ date, data=cobs10, type='l', xaxt='n', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', xaxt='n', ylab='Precipitation (cm)')
plot(gdd ~ date, data=cobs10, type='l', xaxt='n', ylab='Thermal units')
ticks <- seq(from=min(cobs10$date), by='2 months', length=7)
lbl <- strftime(ticks, '%b')
axis(side=1, outer=TRUE, at=ticks, labels=lbl)
mtext('2010', side=1, outer=TRUE, line=3, cex=0.67)
Since ''pretty'' doesn't behave as we want it to, we use ''seq'' to make the sequence of x-axis ticks. Then we format the dates to just display an abbreviation of the month name, but this is done with regard to local settings (I live in Denmark), see ''locale''.
To add the axis-ticks and a label to the outer region, we must remember to specify ''outer=TRUE''; otherwise it is added to the last subplot.
Also note that I specified ''cex=0.67'' to match the font size of the x-axis to the y-axis.
Now I agree that displaying the thermal units in a individual subplot is not optimal, although it is the correct way of displaying it. But there was the issue with the ticks. What we really want is to display some nice values that clearly display that they are not linear. But your data does not necessarily contain these nice values, so we will have to interpolate them ourselves.
For this, I use the ''splinefun''
lbl <- c(0, 2, 200, 1000, 2000, 3000, 4000)
thermals <- splinefun(cobs10$gdd, cobs10$date) # thermals is a function that returns the date (as an integer) for a requested value
thermals(lbl)
## [1] 14649.00 14686.79 14709.55 14761.28 14806.04 14847.68 14908.45
ticks <- as.Date(thermals(lbl), origin='1970-01-01') # remember to specify an origin when converting an integer to a Date.
Now the thermal ticks are in place, lets try it.
par(mfrow=c(2,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 4, 0))
plot(temp ~ date, data=cobs10, type='l', xaxt='n', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', xaxt='n', ylab='Precipitation (cm)')
usr <- par('usr')
x.pos <- (usr[2]+usr[1])/2
ticks <- seq(from=min(cobs10$date), by='2 months', length=7)
lbl <- strftime(ticks, '%b')
axis(side=1, outer=TRUE, at=ticks, labels=lbl)
mtext('2010', side=1, at=x.pos, line=3)
lbl <- c(0, 2, 200, 1000, 2000, 3000, 4000)
thermals <- splinefun(cobs10$gdd, cobs10$date) # thermals is a function that returns the date (as an integer) for a requested value
ticks <- as.Date(thermals(lbl), origin='1970-01-01') # remember to specify an origin when converting an integer to a Date.
axis(side=3, outer=TRUE, at=ticks, labels=lbl)
mtext('Thermal units', side=3, line=15, at=x.pos)
Update I changed the mtext function calls in the last code block to ensure that the x-axis texts are centred on the plotting region, not the entire region. You might want to tweak the vertical position by changing the line-argument.

Centring bar labels in bar plots in r

How can I centre the labels on the x-axis to match up with the bars? Also, how can I position the x axis label further down so it it is not obscured by the x-axis labels? Thanks!
par(mar= c(15,4,4,2) + 0.1)
barplot(58:1,xaxt="n",xlab="",ylab="Frequency", col=gray(5:0/5))
axis(1, labels=FALSE)
text(1:58, par("usr")[3] - 0.25, srt = 90, adj = 1,
labels = rep("Long Species Name",58), xpd = TRUE)
mtext(1, text = "Species", line=6)
Check out the return value of barplot() (by reading ?barplot). There we find that the mid points of the bars are returned by the function as a vector. Hence it is a simple matter of assigning the returned object (here to object bar) and then use that in a call to axis() to locate the tick marks.
In the axis() call, note that we specify both the labels argument and the at argument, with at being set to the bar mid points as stored in bar. las = 2 is used to rotate the labels relative to the axis, and cex.axis = 0.6 is used to reduce the label size.
The second part of your question is handled by title() and the line argument. First note that when you set the mar parameter you are setting the margin size in "lines", hence the margin on side 1 (bottom) is 15 lines. The line argument in title() specifies which of the margin lines you want to draw the axis label.
Putting this altogether with a modified example we have:
op <- par(mar= c(15,4,4,2) + 0.1)
bar <- barplot(58:1, xaxt="n", xlab="", ylab="Frequency", col=gray(5:0/5))
axis(1, labels = paste("Long Species Name", 1:58), at = bar,
las = 2, cex.axis = 0.6)
title(xlab = "Species", line=11)
par(op)
Which produces:

Plotting a grid behind data, not in front in R

I like to produce my own grid lines when plotting so I can control tick marks, etc. and I am struggling with this with the 'hist' plotting routine.
hist(WindSpeed, breaks=c(0:31), freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)",main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, tck=1, font.lab=2)
axis(1, tck=1, ,col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
Plot:
I have then just been able to use the 'lines' or 'points' command to replot the data over top for other types of plots, but with the histogram its not so easy.
Any help would be great.
I added my code below and image based upon John's response...
I added my code below and image based upon John's response...
hist(WindSpeed, breaks=30, freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)",main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, font.lab=2)
axis(1, tck=1, col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
hist(WindSpeed, add=TRUE, breaks=30, freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)", main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, font.lab=2)
Actually, R has a way to do this! It's the panel.first argument to plot.default, which hist calls to do most of the work. It takes an expression which is evaluated "after the plot axes are set up but before any plotting takes place. This can be useful for drawing background grids or scatterplot smooths," to quote from ?plot.default.
hist(WindSpeed, breaks=c(0:31), freq=TRUE, col="blue", xaxt="n", yaxt="n",
xlab="Wind Speed (m/s)", main="Foo",
cex.main=1.5, cex.axis=1, cex.lab=1, tck=1, font.lab=2,
panel.first={
axis(1, tck=1, col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
})
See How do I draw gridlines using abline() that are behind the data? for another question that uses this method.
This is relatively easy.
Generate the histogram but don't plot it.
h <- hist(y, plot = FALSE)
Now generate your base plot... I've added some features to make it look more like a standard historgram
plot(h$mids, h$counts, ylim = c(0, max(h$counts)), xlim = range(h$mids)*1.1,
type = 'n', bty = 'n', xlab = 'y', ylab = 'Counts', main = 'Histogram of y')
add your grid
grid()
add your histogram
hist(y, add = TRUE)
Or, as I discovered through this process... you can do it even easier
hist(y)
grid()
hist(y, add = TRUE, col = 'white')
This last method is just redrawing the histogram over the grid.
In R, order matters when you plot. As you've discovered, adding things to a plot adds on top of what you've plotted before. So we need a way to plot the grid first and then the histogram. Try something like this:
plot(1:10,1:10,type = "n")
grid(10,10)
hist(rnorm(100,5,1),add = TRUE)
I haven't recreated your example, since it isn't reproducible, but this general idea should work. But the key idea is to create an empty plot with the correct dimensions using the type = "n" option to plot, then add the grid, then add the histogram using the add = TRUE argument.
Note that the add argument is actually for plot.histogram, hist passes it along via ....
The base graphics solution suggested by #joran is fine. Alternatives:
d <- data.frame(x=rnorm(1000))
library(lattice)
histogram(~x,data=d,panel=function(...) {
panel.grid(...)
panel.histogram(...) }
)
Or:
library(ggplot2)
qplot(x,data=d,geom="histogram",binwidth=0.1)+theme_bw()+
labs(x="Wind speed", y="Frequency")
(But of course you will have to learn all the details of adjusting labels, titles, etc. ... I'm not actually sure how to do titles in ggplot ...)
Another methods for grid lines in background:
A)
hist( y, panel.first=grid() ) # see: help( plot.default )
box()
B)
plot.new() # new empty plot
nv <- length( pretty(x) ) - 1 # number of vertical grid lines (or set by hand)
nh <- length( pretty(y) ) - 1 # number of horizontal grid lines (or set by hand)
grid( nx = nv, ny = nh ) # preplot grid lines
par( new = TRUE ) # add next plot
plot( x, y ) # plot or hist, etc
box() # if plot hist
Arbitrary lines in background with abline:
C)
How do I draw gridlines using abline() that are behind the data?
D)
# first, be sure there is no +/-Inf, NA, NaN in x and y
# then, make the container plot with two invisible points:
plot( x = range( pretty( x ) ), y = range( pretty( y ) ), type = "n", ann = FALSE )
abline( h = hlines, v = vlines ) # draw lines. hlines, vlines: vectors of coordinates
par( new = TRUE ) # add next plot. It is not necessary with points, lines, segments, ...
plot( x, y ) # plot, hist, etc
box() # if plot hist

Resources