Defining limits of box around a barplot in R - r

I have created a barplot with 24 bars on the x-axis (0-23) and background shading using the following code:
#Data
Hours = seq(from=0, to=23)
Mean = rnorm(24, mean=5, sd=2)
#Create number seq for tick mark locations
at_tick = seq_len(length(Hours)+1)
#Plot with background rectangle shading
x=barplot(Mean,names.arg=Hours, border="white", ylab="Freq", xlab="Hour",
ylim=c(0,10), axes=FALSE, space=0, col="grey50")
X = c(0,5)
Y = c(0,10)
rect(X[1], Y[1], X[2], Y[2], border = "gray80", col = "gray80")
X2 = c(19,24)
Y2 = c(0,10)
rect(X2[1], Y2[1], X2[2], Y2[2], border = "gray80", col = "gray80")
barplot(Mean,names.arg=Hours, ylim=c(0,10), border="white", ylab="", xlab="", axes=FALSE, space=0, col="gray50", add=TRUE)
axis(2, las=2, pos=0)
axis(1, at = at_tick -1, pos=0, labels = FALSE)
box(which="plot", bty="]") #add a box around the plot
This creates a plot with a surrounding box that extends beyond the limits of the x-axis in both directions. Instead, I would like to add a box around the plot that aligns with the axis limits (i.e. x-axis: 0-23, y-axis: 0-10). I have spent ages trying to find a way to do this with no luck. Any help would be really appreciated. Thanks!

How about drawing individual lines? You can use the segment function instead of box to do this:
segments(24,10, 24,0)
segments(0,10, 24,10)
Complete code:
#Data
Hours = seq(from=0, to=23)
Mean = rnorm(24, mean=5, sd=2)
#Create number seq for tick mark locations
at_tick = seq_len(length(Hours)+1)
#Plot with background rectangle shading
x=barplot(Mean,names.arg=Hours, border="white", ylab="Freq", xlab="Hour",
ylim=c(0,10), axes=FALSE, space=0, col="grey50")
X = c(0,5)
Y = c(0,10)
rect(X[1], Y[1], X[2], Y[2], border = "gray80", col = "gray80")
X2 = c(19,24)
Y2 = c(0,10)
rect(X2[1], Y2[1], X2[2], Y2[2], border = "gray80", col = "gray80")
barplot(Mean,names.arg=Hours, ylim=c(0,10), border="white", ylab="", xlab="", axes=FALSE, space=0, col="gray50", add=TRUE)
axis(2, las=2, pos=0)
axis(1, at = at_tick -1, pos=0, labels = FALSE)
segments(24,10, 24,0)
segments(0,10, 24,10)

Related

Reduce space between names.arg and axis (box) in barplot

I created a simple barplot surrounded by a box. Is there any way to move my names closer to the box (space marked in blue)?
MWE:
set.seed(1)
count <- runif(n = 3, min = 0, max = 10)
names <- letters[seq(from = 1, to = 3)]
barplot(height = count,
names.arg = names,
horiz = TRUE,
las = 1)
box()
Here are two ways to do this. You can use rect instead of box to move the box boundary to the left:
barplot(height=count, names.arg=names, horiz=TRUE, las=1)
bounds <- par("usr")
rect(bounds[1]-.1, bounds[3], bounds[2], bounds[4], xpd=NA)
Or you can add the y-axis separately which lets you control where the labels are plotted:
x <- barplot(height=count, horiz=TRUE, las=1)
box()
axis(2, x, names, las=1, tick=FALSE, mgp=c(2, .35, 0))
Adjust the middle value in mgp to position the labels (see ?par)

How to find y value in line-and-dots plot?

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

How to shift bars from y-axis using barplot() R

I have a barplot with the following code:
bp <- barplot(COL0.matrix,
beside=T,
col=col,
ylim=c(0,100), yaxt="n",
xlab="Time",ylab="Relative Electrolyte Leakage (%)",
las=1,xaxt = "n",
cex.axis=1.5, cex.names= 1.5, font=2, font.lab=2, cex.lab=1.5, family="A", space=c(0,0,1,0), xaxs = 'i')
axis(side=2, family="A", cex.axis=0.8, las=1, font=2, pos=0, tck=c(0), at=c(0,10,20,30,40,50,60,70,80,90,100), labels=c("0", "10","20","30","40","50","60","70","80","90","100"))
axis(side=2, at=c(0,10,20,30,40,50,60,70,80,90,100), labels = c(NA),tcl=c(-0.25),pos=0)
axis(side=2, at=c(0,10,20,30,40,50,60,70,80,90,100), labels = c(NA),tcl=c(0.25),pos=0)
axis(side=1, at=c(1.2, 4.2), labels = c("Dawn", "Dusk"),tck=c(0), family="A", cex.axis=1.5, font=2, pos=0)
This results in the following barplot:
I am trying to shift the bars which are right next to the y-axis away. I have tried changing space=(...) but this shifts the whole x-axis so that the x and y axis no longer join.
Is there a way of shifting the left two bars over?
You can use the line parameter to move the axis over instead of moving the bars. You want to remove the pos = 0 and define the y title outside the barplot function so you can also control its position. Also you will want to play with the par(mar = ... part so it looks right for your device. For if you save in a pdf device your margin and even the cex parameters probably will need adjusting to make it nice. Also I set the graphics parameter xpd = TRUE to allow the lines function in the last line to plot into the margin space. If you don't do that you'll have a x axis that doesn't meet the y axis. If you don't want that then remove the last line.
COL0.matrix <- structure(c(71.44109964, 78.43178612, 64.31581642, 70.3339388 ), .Dim = c(2L, 2L), .Dimnames = list(c("Control", "bold(\"Col-0 840g ha\"^\"-1\")" ), c("Dawn", "Dusk")))
col = c("white", "grey70", "white", "grey70")
par(mar = c(5,7,5,5), xpd = TRUE)
bp <- barplot(COL0.matrix,
beside=T,
col=col,
ylim=c(0,100), yaxt="n",
xlab="Time", ylab = "",
las=1,xaxt = "n",
cex.axis=1.5,
cex.names= 1.5,
font=2,
font.lab=2,
cex.lab=1.5,
family="A",
space=c(0,0,1,0),
xaxs = 'i')
mtext("Relative Electrolyte Leakage (%)", side = 2, font = 2, cex = 1.5, line = 4)
axis(side=2, family="A", cex.axis=0.8,
las=1, font=2, tck=c(0),
at=c(0,10,20,30,40,50,60,70,80,90,100),
labels=c("0", "10","20","30","40","50","60","70","80","90","100"),
line = 1)
axis(side=2, at=c(0,10,20,30,40,50,60,70,80,90,100), labels = c(NA),tcl=c(-0.25), line = 1)
axis(side=2, at=c(0,10,20,30,40,50,60,70,80,90,100), labels = c(NA),tcl=c(0.25), line = 1)
axis(side=1, at=c(1.2, 4.2), labels = c("Dawn", "Dusk"),tck=c(0), family="A", cex.axis=1.5, font=2, line = 0)
lines(x = c(-0.3, 5.3), y = c(0, 0))

How to align barplot and lineplot in dual Y-axis plot

I am trying to create a plot with dual Y-axis. I modified this wonderful answer given HERE by Ben Bolker and it worked perfectly.
Now, I want to replace one line plot with barplot but for some reason, my barplot and line plots are not aligning together well.
My code looks like this
## set up some fake test data
time <- seq(0,72,12)
betagal.abs <- c(0.05,0.18,0.25,0.31,0.32,0.34,0.35)
cell.density <- c(500,1000,2000,3000,4000,5000,6000)
se1 <- c(0.01,0.02,0.03,0.04,0.05,0.06,0.07)
se2 <- c(50,100,200,300,400,500,300)
## Plot first set of data and draw its axis
barCenters <- barplot(height = cell.density,
beside = TRUE,
las = 1,
ylim = c(0, 7000),
axes=FALSE,
type="b"
)
## a little farther out (line=4) to make room for labels
mtext("Relative expression",side=4,col="black",line=4, las=0)
axis(4, ylim=c(0,7000), col="black",col.axis="black",las=1)
segments(barCenters, cell.density - se2 * 2, barCenters,
cell.density + se2 * 2, lwd = 1.5)
arrows(barCenters, cell.density - se2 * 2, barCenters,
cell.density + se2 * 2, lwd = 1.5, angle = 90,
code = 3, length = 0.05)
## Allow a second plot on the same graph
par(new=TRUE)
plot(time, betagal.abs, pch=16, axes=FALSE, ylim=c(0,1), xlab="", ylab="",
type="b",col="black", main="Test data")
arrows(time, betagal.abs, time, betagal.abs + se1, length= 0.05,angle=90)
arrows(time, betagal.abs, time, betagal.abs - se1, length= 0.05,angle=90)
axis(2, ylim=c(0,1),col="black",las=1) ## las=1 makes horizontal labels
mtext("Relative activity",side=2,line=2.5)
box()
## Draw the time axis
axis(1,pretty(range(time),10))
mtext("Time (Hours)",side=1,col="black",line=2.5)
## Add Legend
legend("topleft",legend=c("Relative activity","Relative expression"),
text.col=c("black","black"),pch=c(16,15),col=c("black","black"))
Any suggestion will be helpful. Thanks

R: plotting untransformed data on a log x axis (similar to plotting on log graph paper)

I have 3 sets of data that I am trying to plot on a single plot. The first data set x values range from ~ 1 to 1700 whereas the other two data sets x values are less than 20. Therefore I want to plot them on a log axis to show variations in all the data sets. However I do not want to transform the data as I want to be able to read the values off the graph. The x axis labels I would like are 1, 10, 100 and 1000 all equally spaced. Does anyone know how to do this? I can only find examples where the data is log as well as the axis. I have attached the code I am currently using below:
Thanks in advance for any help given.
Holly
Stats_nineteen<-read.csv('C:/Users/Holly/Documents/Software Manuals/R Stuff/Stats_nineteen.csv')
attach(Stats_nineteen)
x<-Max
x1<-Min
x2<-Max
y1<-Depth
y2<-Depth
par(bg="white")
par(xlog=TRUE)
plot(x2,y1, type="n", ylim=c(555,0), log="x", axes=FALSE, ann=FALSE)
box()
axis(3, at=c(1,10,100,1000), label=c(1,10,100,1000), pos=0, cex.axis=0.6)
axis(1, at=c(1,10,100,1000), label=c(1,10,100,1000), cex.axis=0.6)
axis(2, at=c(600,550,500,450,400,350,300,250,200,150,100,50,0), label=c
(600,"",500,"",400,"",300,"",200,"",100,"",0), cex.axis=0.6)
mtext("CLAST SIZE / mm", side=3, line=1, cex=0.6, las=0, col="black")
mtext("DEPTH / m", side=2, line=2, cex=0.6, las=0, col="black")
grid(nx = NULL, ny = NULL, col = "lightgray", lty = "solid",
lwd = par("lwd"), equilogs = TRUE)
par(new=TRUE)
lines(x1,y1, col="black", lty="solid", lwd=1)
lines(x2,y2, col="black", lty="solid", lwd=1)
polygon(c(x1,rev(x2)), c(y1,rev(y2)), col="grey", border="black")
par(new=TRUE)
plot(x=Average,y=Depth, type="o",
bg="red", cex=0.5, pch=21,
col="red", lty="solid",
axes=FALSE, xlim=c(0,1670), ylim=c(555,0),
ylab = "",xlab = "")
par(new=TRUE)
plot(x=Mode,y=Depth, type="o",
bg="blue", cex=0.5, pch=21,
col="blue", lty="solid",
axes=FALSE, xlim=c(0,1670), ylim=c(555,0),
ylab = "",xlab = "")
You can do this in ggplot using scale_x_log
so something like:
myplot <- ggplot( StatsNinetee,
aes (x = myResponse,
y = myPredictor,
groups = myGroupingVariable) ) +
geom_point() +
scale_x_log()
myplot
also, avoid attach() it can give odd behavior.

Resources