Grid line consistent with ticks on axis - r

I am embarrassed to ask this simple question, but has been in kicking my mind for several days whenever I create a plot:
plot (x = 1:10, y = rnorm (10, 5, 2))
grid (10,10, lty = 6, col = "cornsilk2")
I want to position the grids right at where axis are labelled, i.e. at 2, 4, 6, 8, 10 in x axis and similarly 3, 4, 5, 6, 7, 8 in y axis.
I want to automate the process as whenever the plot size changes the default label behaviour changes. See the following plot:

From ?grid description of the nx and ny arguments:
When NULL, as per default, the grid aligns with the tick marks on the
corresponding default axis (i.e., tickmarks as computed by axTicks)
plot (x = 1:10, y = rnorm (10, 5, 2))
grid (NULL,NULL, lty = 6, col = "cornsilk2")

For reference, there is a way to control the grid and axes parameters directly from the plot() command, if we are not defining a custom tick interval:
plot(x = 1:10, y = rnorm(10, 5, 2), xlim=c(1, 10), ylim=c(1, 10), panel.first=grid())
The plot.default() documentation gives more information about these parameters.
When using a custom ticks interval, the easiest is to draw the grid using abline:
plot(x = 1:10, y = rnorm(10, 5, 2), xaxp=c(1, 10, 10), yaxp=c(1, 10, 10), axes=FALSE)
axis(1, 1:10)
axis(2, 1:10)
abline(h=1:10, v=1:10, col="gray", lty=3)
More information about custom tick intervals in this thread and here for grid alignment.

For posterity, here is the long-winded way of doing it manually:
plot (x = 1:10, y = rnorm (10, 5, 2))
grid (lty = 6, col = "cornsilk2")
xaxp <- par("xaxp")
yaxp <- par("yaxp")
abline(v=seq(xaxp[1], xaxp[2], (xaxp[2]-xaxp[1])/xaxp[3]), lty=6, col = "cornsilk2")
abline(h=seq(yaxp[1], yaxp[2], (yaxp[2]-yaxp[1])/yaxp[3]), lty=6, col = "cornsilk2")

The answer provided here is much more straightforward, although you may dislike the lack of "free space" at each end of the axes. In brief,
The problem is that grid is putting nx grid lines in the user space,
but plot is adding 4% extra space on each side. You can take control
of this. Adding xaxs="i", yaxs="i" to your plot will turn off the
extra space. But then your upper right point will be cut off, so you
need to change the xlim and ylim values and change nx to match

Related

Adjusting Plot aspect ratio in R

Trying to change the aspect ratio of this plot so that its twice as long as it is tall, here is the code
plot(X,vw,
ylab= "Stress (MPa)",
xlab= "Strain (mm)")
title("Veronda-Westmann")
lines(X,s,col="red")
legend(x=0, y=17, c("Veronda-Westmann", "Experimental"),cex=.8,col=c("black","red"),pch=c(1,NA),lty=c(NA,1))
I used code to try and specify height and width, but this didtn appear to work. New to R so really sorry if this is a stupid Q
Without reproducible data it is a bit hard to exactly reproduce your plot, but you can set asp to your plot which means you can modify the width of the x-axis in any ratio to the y-axis you want. You can use the following code:
X <- c(0,1,2,3,4,5, 6, 7, 8, 9, 10)
vw <- c(0, 0.5, 0.75, 1, 1.5, 3, 5, 8, 10, 15, 22)
s <- c(0, 0.5, 0.75, 1, 1.5, 3, 5, 8, 10, 15, 22)
plot(X,vw,
ylab= "Stress (MPa)",
xlab= "Strain (mm)", asp = 2)
title("Veronda-Westmann")
lines(X,s,col="red")
legend("topleft",
c("Veronda-Westmann", "Experimental"),
cex=.8,col=c("black","red"),
pch=c(1,NA),
lty=c(NA,1))
Output:
Are you looking to export this figure? If so, you can simply specify this on export:
x <- seq(0,5, 0.1)
y <- seq(0,15, 0.3)
Plot 1: native aspect ratio
png("test.png") # or pdf, etc
plot(x, y)
dev.off()
Plot 2: twice as wide:
png("test2.png", width = 1000, height = 500) # random dimensions
plot(x, y)
dev.off()

Rotate y axis TEXT labels in plot.zoo

I would like to rotate the labelling of the y-labs to horizontal and can't find an answer without ggplot.
Is there a way to rotate them in plot.zoo?
The labels I mean are those ones called Series 1:5 and I have outlined them in red.
data <- xts(matrix(rnorm(1000), ncol = 5), order.by = as.Date(1:200))
plot.zoo(data)
Use las=1 like this:
plot.zoo(data, las = 1)
Update
The question later clarified that it was referring to the ylab. plot.zoo uses mtext for that and hard codes it; however, we could hack it using trace:
library(xts)
trace(plot.zoo,
quote(mtext <- function(...) graphics::mtext(..., cex = 0.7, las = 1)))
plot.zoo(data, oma = c(6, 5, 5, 0))
untrace(plot.zoo)

Aligning grid lines in R, bReeze package

I am trying to get grid lines work properly in the image below. Using the bReeze package to plot the power curves of the turbines with:
library(bReeze)
pc=pc("Vestas_V90_1.8MW.wtg")
plot(pc)
The output plot is:
but assigning grid lines to the plot with the help of:
grid()
gives the image below:
Any suggestions on how to fix the distorted grid lines?
If you don't give some arguments (e.g., mar, xlim, ylim),
plot(pc) uses par(mar = c(5, 5, 1, 5) and treats data.ranges as xlim and ylim. By using these properties, you can use grid().
pc.data = pc("Vestas_V90_1.8MW.wtg")
plot(pc.data)
par(mar = c(5, 5, 1, 5), new=T) # set par() and order to overlay
plot(pc.data[[1]], pc.data[[2]], type="n", ann=F, axes=F) # nothing but setting xy-cordinates
grid(NULL) # here, the same xy-coordinates are reproduced
# If you want to adjust grid lines to right y-axis, use berow code
:
par(mar = c(5, 5, 1, 5), new=T) # plot(pc) uses right ylim=c(0,1)
plot(pc.data[[1]], pc.data[[2]], ylim=c(0,1), type="n", ann=F, axes=F)
grid(NULL) # the xy(right)-coordinates are reproduced
# If you plot pc.object having single y-axis, use mar = c(5, 5, 1, 1)

Shade part of an R plot

I am trying to make a plot in R that has a portion of the plot grey to emphasize this area. Unlike other examples, I don't want to color an area under a plot, but instead color an area on a plot starting at one area and going to the end of the graph. When I try to use rect() or polygon() it obscures the plots I want to emphasize.
For example:
x_mean <- c(1, 2, 3, 4)
y_mean <- c(1, 1, 1, 1)
y_max <- c(4, 4, 4, 4)
y_min <- c(-4, -4, -4, -4)
x_shade <- c(2, 3, 4)
y_max_shade <- c(4, 4, 4)
y_min_shade <- c(-4, -4, -4)
plot(x=rep(x_mean, 3), y=c(y_mean, y_max, y_min), bty='n', type="n" )
arrows(x0=x_mean, y0=y_min, x1=x_mean, y1=y_max, length=0)
points( x=x_mean, y=y_mean, pch=16)
This will plot 4 lines on the graph. How do I draw a grey box in the background from the 2nd line to the end of the plot?
Just so that you're left with more than just a comment, here's a possible solution:
plot(x=rep(x_mean, 3), y=c(y_mean, y_max, y_min), bty='n', type="n" )
rect(2,-4,4,4,col = rgb(0.5,0.5,0.5,1/4))
arrows(x0=x_mean, y0=y_min, x1=x_mean, y1=y_max, length=0)
points( x=x_mean, y=y_mean, pch=16)
Note that I also demonstrated how to use alpha blending in the color specification (using rgb). This can also be useful for this sort of thing. Try moving the rect line to the end, and notice that the results still look ok, because the fill color is partially transparent.
I've found this answer to be pretty great for shading background parts of R.
Some context:
panel.first = rect(c(1,7), -1e6, c(3,10), 1e6, col='green', border=NA)
The first two arguments c(1,7) are the starting values for the shaded rectangle, and following arguments c(3,10) are where the shading ends. This creates a shaded region from 1-3 and 7-10.

Plotting multiple curves same graph and same scale

This is a follow-up of this question.
I wanted to plot multiple curves on the same graph but so that my new curves respect the same y-axis scale generated by the first curve.
Notice the following example:
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
# first plot
plot(x, y1)
# second plot
par(new = TRUE)
plot(x, y2, axes = FALSE, xlab = "", ylab = "")
That actually plots both sets of values on the same coordinates of the graph (because I'm hiding the new y-axis that would be created with the second plot).
My question then is how to maintain the same y-axis scale when plotting the second graph.
(The typical method would be to use plot just once to set up the limits, possibly to include the range of all series combined, and then to use points and lines to add the separate series.) To use plot multiple times with par(new=TRUE) you need to make sure that your first plot has a proper ylim to accept the all series (and in another situation, you may need to also use the same strategy for xlim):
# first plot
plot(x, y1, ylim=range(c(y1,y2)))
# second plot EDIT: needs to have same ylim
par(new = TRUE)
plot(x, y2, ylim=range(c(y1,y2)), axes = FALSE, xlab = "", ylab = "")
This next code will do the task more compactly, by default you get numbers as points but the second one gives you typical R-type-"points":
matplot(x, cbind(y1,y2))
matplot(x, cbind(y1,y2), pch=1)
points or lines comes handy if
y2 is generated later, or
the new data does not have the same x but still should go into the same coordinate system.
As your ys share the same x, you can also use matplot:
matplot (x, cbind (y1, y2), pch = 19)
(without the pch matplopt will plot the column numbers of the y matrix instead of dots).
You aren't being very clear about what you want here, since I think #DWin's is technically correct, given your example code. I think what you really want is this:
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
# first plot
plot(x, y1,ylim = range(c(y1,y2)))
# Add points
points(x, y2)
DWin's solution was operating under the implicit assumption (based on your example code) that you wanted to plot the second set of points overlayed on the original scale. That's why his image looks like the points are plotted at 1, 101, etc. Calling plot a second time isn't what you want, you want to add to the plot using points. So the above code on my machine produces this:
But DWin's main point about using ylim is correct.
My solution is to use ggplot2. It takes care of these types of things automatically. The biggest thing is to arrange the data appropriately.
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
df <- data.frame(x=rep(x,2), y=c(y1, y2), class=c(rep("y1", 5), rep("y2", 5)))
Then use ggplot2 to plot it
library(ggplot2)
ggplot(df, aes(x=x, y=y, color=class)) + geom_point()
This is saying plot the data in df, and separate the points by class.
The plot generated is
I'm not sure what you want, but i'll use lattice.
x = rep(x,2)
y = c(y1,y2)
fac.data = as.factor(rep(1:2,each=5))
df = data.frame(x=x,y=y,z=fac.data)
# this create a data frame where I have a factor variable, z, that tells me which data I have (y1 or y2)
Then, just plot
xyplot(y ~x|z, df)
# or maybe
xyplot(x ~y|z, df)

Resources