I have plotted the below graph but the cannot adjust the labels of the seconds Y axis. Does anybody have any idea how that is possible?
Also my right hand Y axis has limit from 1 to 14 *10^8 but when I set it, it only goes from zero to 1.4. Cannot find why!
Here is the code I used to make the plot
fdic <- data.frame(matrix(scan(text ="1 16.70833333 1329877000
2 17.20370370 1118256000
3 16.61111111 1047726000
4 19.05555556 972202000
5 15.50925926 269648386
6 0.07407407 248606000
7 3.00925926 220576899
8 5.83796296 188132575"), 8, 3, byrow = T))
colnames(fdic) <- c("id", "botnets_per_wk", "Deposits")
plot <- plot(fdic$id, fdic$botnets_per_wk, pch=16, axes=FALSE, ylim=c(0,25), xlab="", ylab="",
type="l",col="dark blue")
axis(2, col="black",las=1)
mtext("Average # of botnets attacking banks per week",side=2,line=2.5)
box()
par(new=TRUE)
plot(fdic$id, fdic$Deposits, pch=15, xlab="", ylab="", ylim=c(1,1400000000),
axes=FALSE, type="l", col="red")
mtext("Deposits (USD, logged)",side=4,col="red",line=4)
axis(4, ylim=c(1,1400000000), col="black",col.axis="black",las=1)
axis(1,at = seq(1, 50, by = 1))
mtext("bank",side=1,col="black",line=2.5)
legend("topleft",legend=c("Average # of botnets attacking banks per week","Deposits"),
text.col=c("black","red"),pch=c(16,15),col=c("black","red"))
Actually that "1.4" you see is 1.4e+09, the scientific notation for 1.4 billion. Use options(scipen=999) to turn off scientific notation in R (this resets after reboot of R) and then adjust the left margins with par(mai=c(...)) for the long numbers to be completely visible:
fdic <- data.frame(matrix(scan(text ="1 16.70833333 1329877000
2 17.20370370 1118256000
3 16.61111111 1047726000
4 19.05555556 972202000
5 15.50925926 269648386
6 0.07407407 248606000
7 3.00925926 220576899
8 5.83796296 188132575"), 8, 3, byrow = T))
colnames(fdic) <- c("id", "botnets_per_wk", "Deposits")
options(scipen=999)
par(mai = c(1, 1, 1, 2))
plot <- plot(fdic$id, fdic$botnets_per_wk, pch=16, axes=FALSE, ylim=c(0,25), xlab="", ylab="", type="l",col="dark blue")
axis(2, col="black",las=1)
mtext("Average # of botnets attacking banks per week",side=2,line=2.5)
box()
par(new=TRUE)
plot(fdic$id, fdic$Deposits, pch=15, xlab="", ylab="", ylim=c(1,1400000000), axes=FALSE, type="l", col="red")
mtext("Deposits (USD, logged)",side=4,col="red",line=4)
axis(4, ylim=c(1,1400000000), col="black",col.axis="black",las=1)
axis(1,at = seq(1, 50, by = 1))
mtext("bank",side=1,col="black",line=2.5)
legend("topleft",legend=c("Average # of botnets attacking banks per week","Deposits"), text.col=c("black","red"),pch=c(16,15),col=c("black","red"))
But actually I would leave the 1.4-scale and label that axis with "Deposits (in billion US Dollar, logged)", because those long numbers with the many zeros are hard to read (I had to put my finger on them and count the zeros, and you don't want your readers to have to do that).
Related
I have this line-and-dots plot:
#generate fake data
xLab <- seq(0, 50, by=5);
yLab <- c(0, sort(runif(10, 0, 1)));
#this value is fixed
fixedVal <- 27.3
#new window
dev.new();
#generate the plot
paste0(plot(xLab, yLab, col=rgb(50/255, 205/255, 50/255, 1), type="o", lwd=3,
main="a line-and-dots plot", xlab="some values", ylab="a percentage",
pch=20, xlim=c(0, 50), ylim=c(0, 1), xaxt="n", cex.lab=1.5, cex.axis=1.5,
cex.main=1.5, cex.sub=1.5));
#set axis
axis(side = 1, at=c(seq(min(xLab), max(xLab), by=5)))
#plot line
abline(v=fixedVal, col="firebrick", lwd=3, lty=1);
now, I would like to find the y coordinate of the intersection point between the green and the red lines.
Can I achieve the goal without the need of a regression line? Is there a simple way of getting the coordinates of that unknown point?
You can use approxfun to do the interpolation:
> approxfun(xLab,yLab)(fixedVal)
[1] 0.3924427
Alternatively, just use approx:
> approx(xLab,yLab,fixedVal)
$x
[1] 27.3
$y
[1] 0.3924427
Quick fix like #JohnColeman said:
# find the two points flanking your value
idx <- findInterval(fixedVal,xLab)
# calculate the deltas
y_delta <- diff(yLab[idx:(idx+1)])
x_delta <- diff(xLab[idx:(idx+1)])
# interpolate...
ycut = (y_delta/x_delta) * (fixedVal-xLab[idx]) + yLab[idx]
ycut
[1] 0.4046399
So we try it on the plot..
paste0(plot(xLab, yLab, col=rgb(50/255, 205/255, 50/255, 1), type="o", lwd=3,
main="a line-and-dots plot", xlab="some values", ylab="a percentage",
pch=20, xlim=c(0, 50), ylim=c(0, 1), xaxt="n", cex.lab=1.5, cex.axis=1.5,
cex.main=1.5, cex.sub=1.5));
#set axis
axis(side = 1, at=c(seq(min(xLab), max(xLab), by=5)))
#plot line
abline(v=fixedVal, col="firebrick", lwd=3, lty=1);
abline(h=ycut, col="lightblue", lwd=3, lty=1);
I have the following code for a double y axis plot in r. Everything works fine, but I want to change the x axis from every 18 months to every 12 months. I have tried every "axis(side=1, at=....)" I could think of. Any random number between 0:1.5 will work for "Data$Monthly_Gen" and 0:100 for Data$Ave_GenXXXX" for reproducing. Thanks.
Data2 <- ts(Data$Monthly_Gen, start=c(2005,1),end=c(2012,12),frequency=12)
Data2B <- ts(Data$Ave_Gen_MonthSOCO, start=c(2005,1),end=c(2012,12),frequency=12)
Data2C <- ts(Data$Ave_Gen_MonthTVA, start=c(2005,1),end=c(2012,12),frequency=12)
Data2D<-ts(Data$Monthly_Gen_Othersx10,start=c(2005,1),end=c(2012,12),frequency=12)
Data2E <- ts(Data$Monthly_Gen_Othersx9, start=c(2005,1),end=c(2012,12),frequency=12)
par(mar=c(4, 4, 2, 4) + 0.1)
plot(as.xts(Data2), major.format = "%Y-%m",ylab="",las=1,ylim=c(0,2))
lines(as.xts(Data2D), major.format = "%Y-%m", xlab="", ylab="",
type="l", col="black",main="",lty="dotted" ,lwd=2)
lines(as.xts(Data2E), major.format = "%Y-%m", xlab="", ylab="",
type="l", col="black",main="",lty="longdash" ,lwd=2)
mtext("Generation",side=2,line=3)
box()
par(new=TRUE)
plot(as.xts(Data2B), major.format = "%Y-%m", xlab="", ylab="",
axes=FALSE, type="l", col="#E69F00",main="",lwd=2,ylim=c(0,130))
mtext("Monthly Average Lambda",side=4,col="black",line=2.5)
axis(4, col="black",col.axis="black",las=1)
lines(as.xts(Data2C), major.format = "%Y-%m", xlab="", ylab="",
type="l", col="#56B4E9",main="",lwd=2.5)
mtext("Date",side=1,col="black",line=3)
legend("topright",legend=c("Total Generation","X1 Generation","X2 Generation","Area Lambda","X2 Area Lambda"),text.col=c("black","black","black","#E69F00","#56B4E9"),col=c("black","black","black","#E69F00","#56B4E9"),cex=.75,lty=c("solid","longdash","dotted","solid","solid"))`
This is easy to do with zoo. In my opinion, zoo is more powerful than ts.
#Create zoo series
Data2 <- zooreg(runif(96,0,1.5), start = as.yearmon(2005),end = as.yearmon(2012), freq = 12)
Data2B <- zooreg(runif(96,0,100), start = as.yearmon(2005),end = as.yearmon(2012), freq = 12)
#Create 12-month sequence for axis
twelve <-seq(1,length(Data2),12)
plot(Data2,ylab="",las=1,ylim=c(0,2),xaxt = "n")
#add x-axis at 12 months
axis(1,at=index(Data2)[twelve],labels=format(index(Data2)[twelve],"%Y-%m"))
par(new=TRUE)
plot(Data2B,xlab="",ylab="",las=1,ylim=c(0,130),xaxt = "n",yaxt = "n",col="blue")
#add yy axis
axis(4, col="black",col.axis="black",las=1)
Here's a solution using only the base plot() functions. I think what you really want is seq.Date() for something like this
set.seed(123)
nn <- 7*12 # months
x1 <- ts(rnorm(nn),start=c(2005,1),freq=12)
x2 <- ts(rpois(nn,20),start=c(2005,1),freq=12)
tt <- seq.Date(from=as.Date("2005-01-01"),by="month",length.out=nn)
plot(tt, x1, col="blue", type="l", xaxt="n", xlab="", ylab="")
par(new=TRUE)
plot(tt, x2, col="red", type="l", xaxt="n", yaxt="n", xlab="", ylab="")
axis(4)
dates <- seq(from=as.Date("2005-01-01"), to=as.Date("2012-12-01"), by="18 month")
axis(1, at=dates, labels = format(dates, "%Y-%m"))
I'm trying to get rid of the double labels in the x axis when using the plot function in R with my data.
Sample data can be created like this:
Data=read.table(textConnection("
Geslacht y x1 x2 x3 x4 x5 x6 x7 x8 x9
M 0.00 5 6 16 9 5 13 14 5 7
M 0.25 6 7 17 9 5 13 17 5 7
M 0.67 12 12 28 14 7 21 24 13 13
"),head=TRUE)
I've used the following code so far:
Data <- read.table(Data, header=TRUE, sep="\t", na.string="NA", strip.white=TRUE)
par(new=T)
plot(Data$y, Data$x1, xlab="Chronological Age", ylab="%DNA methylation", cex = 0.9, col="black", pch=20, xlim=c(0, 100), ylim=c(0, 100), font.lab=2)
par(new=T)
plot(Data$y, Data$x2, pch=20, axes=F, ylab="", cex= 0.9, col="blue", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x3, pch=20, axes=F, ylab="", cex= 0.9, col="red", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x4, pch=20, axes=F, ylab="", cex= 0.9, col="green", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x5, pch=20, axes=F, ylab="", cex= 0.9, col="coral4", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x6, pch=20, axes=F, ylab="", cex= 0.9, col="darkgrey", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x7, pch=20, axes=F, ylab="", cex= 0.9, col="darkorchid1", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x8, pch=20, axes=F, ylab="", cex= 0.9, col="darkgoldenrod1", xlim=c(0, 100), ylim=c(0, 100))
par(new=T)
plot(Data$y, Data$x9, pch=20, axes=F, ylab="", cex= 0.9, col="forestgreen", xlim=c(0, 100), ylim=c(0, 100))
legend("bottomright", title="CpG regions", cex=.8, c("CpG1 ELOVL2","CpG2 ELOVL2","CpG3 ELOVL2", "CpG4 ELOVL2", "CpG5 ELOVL2", "CpG6 ELOVL2", "CpG7 ELOVL2", "CpG8 ELOVL2", "CpG9 ELOVL2"),
pch=c(20,20,20,20,20,20,20,20,20),col=c("black","blue", "red", "green", "coral4", "darkgrey","darkorchid1","darkgoldenrod1","forestgreen",horiz=FALSE))
I can't post the picture due to being a newbie...
Does anyone know why I get the double label in the x axis? The second label is "Data$y" even though I specify the xlabel in code line 3.
What are you trying to do here? Looks like you are trying to plot several sets of points in different colours on the same axes in one graph.
There are better ways...
Use plot to set the axis limits with xlim and ylim. Plot nothing, but name your axes:
plot(NA,xlab="my x",ylab="my y",xlim=c(1,23),ylim=c(99,1000))
Then use points(x,y,col=....) to add points to the current plot. Don't use par(new=T)!
Or
matplot
Or
rearrange your data into three columns, x, y, and col. Then plot(d$x, d$y, col=d$col) will do most of the job in one line.
Or
with the same rearrangement, you can use ggplot2 and make a pretty plot.
Here's how to do that rearrangement using reshape2 package:
library(reshape2)
md = melt(Data,id="y",measure=names(Data)[-(1:2)],value.name="x")
md is now a "long" data frame. Now convert the x1 variable to numeric:
md$icol = as.numeric(substr(md$variable,2,20))
define your colour palette:
col=c("black","blue", "red", "green", "coral4", "darkgrey","darkorchid1","darkgoldenrod1","forestgreen")
set the point colour by explicit lookup:
md$colour = col[md$icol]
and plot. Tweak axis labels, limits, title, etc to taste, simmer for 20 minutes and stir in a legend:
plot(md$y,md$x,col=md$colour,pch=19,xlim=c(0,100),ylim=c(0,100))
I have a plot with two y-axes and the corresponding x values run from 1 to 18, in steps of 1.
I want to change the x-axis with a scale ranging from 2 to 16 with steps of 1. When I'm trying to alter the scale, the right end of x-scale is empty after 16, as R automatically replaces the old values with the new ones and leaves the empty spaces at the right end open.
par(mar=c(5, 4, 4, 6) + 0.1)
plot(section, c, pch=16, axes=FALSE, ylim=c(-22,-18), xlab=" ", ylab=" ", type="b", col="black", main="BG")
axis(2, ylim=c(-22,-18), col="black", las=1)
mtext(expression(paste(delta^{13}, "C (‰)")),side=2, line=2.5)
box()
par(new=TRUE)
plot(section, n, pch=15, xlab=" ", ylab=" ", ylim=c(10,13), axes=FALSE, type="b", col="red")
axis(4, ylim=c(10,13), col="red", col.axis="red", las=1)
mtext(expression(paste(delta^{15}, "N (‰)")), side=4, col="red", line=4)
axis(1, at=floor(seq(from=2.5, to=15.5, length.out=13)))
axis(1, pretty(range(section), 18))
These last two don't give me the result I'm looking for(can't post my image?).
Any ideas on how to fix this? I would very much appreciate it.
I think you are looking for the xlim parameter.
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.