What should I do to plot a picture - r

I want to plot a picture whose the beginning of xaxis and yaxis is 0.However, under my code, the result cann't match my requst. So I want to know where the mistakes are.Thanks!!
rm(list=ls())
axis.test<-function(){
t<-seq(0,200)
ntbase<-12/(1+exp(-(t-10)/25))
nt1<-12/(1+exp(-(t-30)/25))
nt2<-15.5334/(1+exp(-(t-20)/25))
nt3<-10.6997/(1+exp(-(t-5)/25))
nt4<-13.5906/(1+exp(-(t-30)/50))
nt<-data.frame(cbind(ntbase,nt1,nt2,nt3,nt4)) matplot(t,nt,col=1:5,type='l',lwd=2,lty=1:5,ylab="population(100,000)",xaxs='i',yaxs='i',xaxt='n',yaxt='n')
axis(side=1,at=c(0,20,40,60,80,100,120,140,160,180,200),labels=c(0,20,40,60,80,100,120,140,160,180,200),tck=0.03)
axis(side=2,at=c(0,5,10,15,20),labels=c(0,5,10,15,20),tck=0.03)
}
axis.test()

By "plotting a picture" I assume you mean plotting a graph. On a side note: I recommend using indentation and whitespaces to increase the readability of your code. Take a look at Hadley's Advanced R Style guide to improve your R coding style.
You can specify axis limits through matplot arguments xlim and ylim
matplot(
t, nt,
col=1:5,
type='l',
lwd=2,
lty=1:5,
ylab="population(100,000)",
xaxs='i', yaxs='i',
xaxt='n', yaxt='n',
xlim = c(0, 200),
ylim = c(0, 20))
axis(
side=1,
at=seq(0,200,20),
labels=seq(0,200,20),
tck=0.03)
axis(
side=2,
at=seq(0,20, 5),
labels=seq(0,20,5),
tck=0.03)

Related

Title box in Base R plot

Is it possible to add a grey box for the title to a base R plot, similar to the ones that come with facet_wrap in ggplot?
I cannot use ggplot for a graphic, but I would like to add the gray title box when combining several plots.
you can try a very hackish one.
plot(1)
legend(x = c(0.567, 1.432), y = c(1.542015, 1.432), legend="", xpd=T, bg="grey")
mtext("this is a title", side=3, line=1)
More general approach...but still need to find out the ratios to expand the limits manually.
xlim = c(1,11)
ylim = c(1,15)
plot(1, xlim=xlim, ylim=ylim)
legend(x = xlim*c(0.84,1.032), y = c(ylim[2]*1.04, ylim[2]*1.16), legend="", xpd=T, bg="grey")
mtext("this is a title", side=3, line=1)

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))

Barplot: Greek letters on y axis in R

This is a follow-up question to my other question on barplots:
Tornado plot in R
I realized the question about getting greek letters on the y-axis needed to be asked as an own question.
The question is:
I have the following barplot and need to change the y-axis to respective greek letters (and a V with a bar over).
I use the following code:
# Tornado plot
data <- matrix(c(-0.02,0.02,-0.01,0.01,-0.03,0.02,-0.01,0.04), ncol = 4)
rownames(data) <- c('+10%','-10%')
colnames(data) <- c('V_bar', 'alpha', 'rho','xi')
x <- seq(-0.04,0.04, length=10)
barplot(data[1,], horiz = T, las=1, xlim = c(-0.04,0.04), xaxt='n', ylab='',
beside=T, col=c('springgreen'))
barplot(data[2,], horiz = T, las=1, xlim = c(-0.04,0.04), xaxt='n',
yaxt='n', #To prevent double printing of y-labels.
beside=T, col=c('indianred2'), add = TRUE)
axis(1, at=pretty(x), lab=paste0(pretty(x) * 100," %"), las=TRUE)
To get the greek letters I have tried the following:
barplot(data[2,], horiz = T, las=1, xlim = c(-0.04,0.04), xaxt='n',
yaxt= c(expression(bar(V)), expression(alpha),expression(rho), expression(xi)),
beside=T, col=c('indianred2'), add = TRUE))
and
axis(2, at=c(1:4), lab = expression(xi ~ rho ~ alpha ~ bar(V)), las=T)
or
axis(2, at=pretty(x), lab = paste0(expression(xi ~ rho ~ alpha ~ bar(V)), las=T))
But no success. Anyone now the trick?
Note. I have seen this question: Adding greek character to axis title
But it focuses on the labels, not the y-axis "values".
Also, I have tried something like Putting greek letters in column names
with no success.
There's no need to call axis for labeling of the bars if you provide the argument names.arg to barplot:
barplot(data[1,], horiz = T, las=1, xlim = c(-0.04,0.04), xaxt='n', ylab='',
beside=T, col=c('springgreen'),
names.arg=c(expression(xi),expression(rho), expression(alpha), expression(bar(V))))
You just need to pass lab in axis as a vector of expressions.
axis(2, at=c(1:4), lab = c(expression(xi),
expression(rho), expression(alpha), expression(bar(V))), las=T)
Then you can play with the settings of the axis as needed.

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.

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