I feel like this is a very basic question but I have spent a lot of time looking for an answer and haven't found one. So, if this is answered somewhere else I would love to be redirected rather than downvoted, please.
Anyway, my problem is that when I graph in R, often the y-axis will fail to extend to the end of my data. A sample graphic is below, where you can see that it would be better for the axis to go all the way to 30 rather than 20. However, submitting ylim = c(0,30) doesn't do anything and I cannot think of or find another command that would do the trick?
Here is a reproducible example. If ylim usually works then I am assuming something is breaking because of the aesthetic changes I've made?
set.seed(1)
x<-runif(1:1000, min=1, max=10)
hist(x, breaks=100, main=NA, axes=F, xlab = NA, ylab = NA)
axis(side = 1, tck= -.01, labels=NA)
axis(side = 2, tck=-.01, labels=NA)
axis(side = 1, lwd=0, line= -.4, cex.axis=1.4)
axis(side = 2, lwd=0, line=-.4, las=1, cex.axis=1.4)
mtext(side = 1, "Percent pathogenic bacteria", line = 2.5, cex=1.8)
mtext(side = 2, "Frequency", line = 2.5, cex=1.8)
Use ylim to specify the y axis range:
set.seed(3)
f <- function(y, ...)
hist(y, breaks=20, ...)
ylim <- range(pretty(ceiling(f(y <- rchisq(1000, 3), plot=FALSE)$counts/10)*10))
f(y, ylim=ylim) # versus f(y)
Related
I get the code for plotting with two y-axis from the following website:
https://www.r-bloggers.com/2015/04/r-single-plot-with-two-different-y-axes/
Here is my code after referencing the code in the link:
par(mar = c(5,5,2,5))
with(df, plot(Date, get(element), type="l", col="red3", ylab="beta_mkt"))
par(new = T)
with(df, plot(Date, NBER, type="l", axes=F, xlab=NA, ylab=NA, cex=1.2))
axis(side = 4)
mtext(side = 4, line = 3, "NBER")
This code prints out a plot, but I wanted to save this plot in a variable so I can reference it later. Anyone know how to achieve it?
Thanks.
Gin
I have plotted five graphs and a legend. The graphs work just fine, however the legens disappears without an error.
My preview in RStudio looks like this
When I zoom in, the area where the legend should be is blank.
I use the following code:
opar <- par (no.readonly = TRUE)
par (mfrow = c(3, 2))
library(deSolve)
# Plot A
LotVmod <- function (Time, State, Pars) {
with(as.list(c(State, Pars)), {
dx = (b*x) - (b*x*x/K) - (y*(x^k/(x^k+C^k)*(l*x/(1+l*h*x))))
dy = (y*e*(x^k/(x^k+C^k)*(l*x/(1+l*h*x)))) - (m*y)
return(list(c(dx, dy)))
})
}
Pars <- c(b = 1.080, e = 2.200, K = 130.000, k = 20.000, l = 2.000,
h = 0.030, C = 2.900, m = 0.050)
State <- c(x = 0.25, y = 2.75)
Time <- seq(1, 9, by = 1)
out <- as.data.frame(ode(func = LotVmod, y = State, parms = Pars, times = Time))
matplot(out[,-1], type = "l", xlim = c(1, 9), ylim = c(0, 45),
xlab = "time",
ylab = "population",
main = "Compartment A")
mtext ( "Coefficient of Variance 4.96", cex = 0.8 )
x <- c(# Validation data)
y <- c(# Validation data)
lines (Time, x, type="l", lty=1, lwd=2.5, col="black")
lines (Time, y, type="l", lty=1, lwd=2.5, col="red")
# Legend
plot.new()
legend("center", c(expression (italic ("F. occidentalis")*" observed"),
expression (italic ("M. pygmaeus")*" observed"),
expression (italic ("F. occidentalis")*" simulated"),
expression (italic ("M. pygmaeus")*" simulated")),
lty = c(1, 1, 1, 2),
col = c(1, 2, 1, 2),
lwd = c(2.5, 2.5, 1, 1),
box.lwd = 0, bty = "n")
# Plot C to F = same as A
par(opar)
My output doesn't give an error. I have used the exact same code before without any trouble, thus I restarted R, removed all objects, cleared all plots and restarted both RStudio and my computer.
Try to add xpd=TRUE in your legend statement. I.e.
legend("center", c(expression (italic ("F. occidentalis")*" observed"),
expression (italic ("M. pygmaeus")*" observed"),
expression (italic ("F. occidentalis")*" simulated"),
expression (italic ("M. pygmaeus")*" simulated")),
lty = c(1, 1, 1, 2),
col = c(1, 2, 1, 2),
lwd = c(2.5, 2.5, 1, 1),
box.lwd = 0, bty = "n", xpd=TRUE)
By default, the legend is cut off by the plotting region. This xpd parameter enables plotting outside the plot region. See e.g. ?par for more on xpd.
This is due to how the plot canvas is set up and how rescaling that device works. The way you do it, you add the legend in the plotting region of the top right plot. The plotting region is however not the complete device, but only the part inside the space formed by the axes. If you rescale, that plotting region will be rescaled as well. The margins around the plotting region don't change size though, so zooming in makes your plotting region so small that it doesn't fit the legend any longer. It is hidden by the margins around the plotting region.
For that reason AEBilgrau is very right you need to add xpd = TRUE. This allows the legend to extend outside of the plotting region, so it doesn't disappear behind the margins when resizing the plotting device.
I am working on this graph in R:
However as you see I am getting these solid dashes instead of nice lines. Here is the code I used to make this graph:
par(mar = c(5,5,2,5))
with(bedtimes, plot(trap, funestus, type="l", col="red3",
ylab=expression(italic(p))),
ylim=c(0,3))
par(new = T)
with(bedtimes, plot(trap, bed, pch=16, axes=F, xlab=NA, ylab=NA, cex=1.2))
axis(side = 4)
mtext(side = 4, line = 3, 'Proportion in bed')
polygon(bedtimes$bed,col=transp("gray", 0.3), border = NA)
And here is the dput of the data I am using:
(removed)
I realise that this is occurring because my x axis is a factor and not numeric. However, trying to change this (e.g. using as.POSIXct(paste0("2016-07-12",bedtimes$trap)) is causing me all sorts of problems, as I had to ake sure R plotted these factors in the correct order originally by using bedtimes$trap <- factor(bedtimes$trap, levels = bedtimes$trap)
How can I produce this same graph but with lines instead of these dashes?
I eventually want a graph that looks similar to this, to give you an idea (though not exactly the same):
Thank you!
As I said in comments, you can try to use the levels of your factor variable:
par(mar = c(5,5,2,5))
with(bedtimes, plot(as.numeric(trap), funestus, type="l", col="red3",
ylab=expression(italic(p))),
ylim=c(0,3))
par(new = T)
with(bedtimes, plot(as.numeric(trap), bed, type="l", axes=F, xlab="", ylab=NA, cex=1.2))
axis(4)
axis(side = 1, at=1:length(levels(bedtimes$trap)), levels(bedtimes$trap))
mtext(side = 4, line = 3, 'Proportion in bed')
polygon(bedtimes$bed,col="gray", border = NA)
I am plotting forecasts at the end of a time series, so I think it is more convenient to have y ticks on the right, because they would be closer to the forecasted part of the path.
Is there a way to avoid to do this:
set.seed(1)
x <- 1:10
y <- sample(1:15, 10)
par(mar = c(5.1, 2.1, 4.1, 4.1))
plot(x, y, yaxt="n", ylab=NA)
axis(4)
mtext("my y", 4, line = 2)
Any suggestion is welcome.
You could just construct a function that does what you like.
Start with something like this, and then customize it further if you want, for example, further control over which side the axis is plotted on, the number/placement of axis ticks, or whatever:
myPlot <- function(..., yaxt = "n", ylab = NA) {
plot(x, y, yaxt = "n", ylab = NA)
axis(4)
mtext(ylab, 4, line = 2)
}
myPlot(x, y, ylab="my y")
Earlier I asked about creating a gradient of n values in base graphics (LINK). Now I'd like to create a gradient legend that goes with it. My ideal would be something like ggplot2's gradient legends:
Here's some code similar to what I'm working with:
colfunc <- colorRampPalette(c("red", "blue"))
plot(1:20, 1:20, pch = 19, cex=2, col = colfunc(20))
Here is an example of how to build a legend from first principles using rasterImage from grDevices and layout to split the screen
layout(matrix(1:2,ncol=2), width = c(2,1),height = c(1,1))
plot(1:20, 1:20, pch = 19, cex=2, col = colfunc(20))
legend_image <- as.raster(matrix(colfunc(20), ncol=1))
plot(c(0,2),c(0,1),type = 'n', axes = F,xlab = '', ylab = '', main = 'legend title')
text(x=1.5, y = seq(0,1,l=5), labels = seq(0,1,l=5))
rasterImage(legend_image, 0, 0, 1,1)
Late to the party, but here is a base version presenting a legend using discrete cutoffs. Thought it might be useful for future searchers.
layout(matrix(1:2,nrow=1),widths=c(0.8,0.2))
colfunc <- colorRampPalette(c("white","black"))
par(mar=c(5.1,4.1,4.1,2.1))
plot(1:10,ann=FALSE,type="n")
grid()
points(1:10,col=colfunc(10),pch=19,cex=1.5)
xl <- 1
yb <- 1
xr <- 1.5
yt <- 2
par(mar=c(5.1,0.5,4.1,0.5))
plot(NA,type="n",ann=FALSE,xlim=c(1,2),ylim=c(1,2),xaxt="n",yaxt="n",bty="n")
rect(
xl,
head(seq(yb,yt,(yt-yb)/10),-1),
xr,
tail(seq(yb,yt,(yt-yb)/10),-1),
col=colfunc(10)
)
mtext(1:10,side=2,at=tail(seq(yb,yt,(yt-yb)/10),-1)-0.05,las=2,cex=0.7)
And an example image:
The following creates a gradient color bar with three pinpoints without any plot beforehand and no alien package is needed. Hope it is useful:
plot.new()
lgd_ = rep(NA, 11)
lgd_[c(1,6,11)] = c(1,6,11)
legend(x = 0.5, y = 0.5,
legend = lgd_,
fill = colorRampPalette(colors = c('black','red3','grey96'))(11),
border = NA,
y.intersp = 0.5,
cex = 2, text.font = 2)
As a refinement of #mnel's great answer, inspired from another great answer of #Josh O'Brien, here comes a way to display the gradient legend inside the plot.
colfunc <- colorRampPalette(c("red", "blue"))
legend_image <- as.raster(matrix(colfunc(20), ncol=1))
## layer 1, base plot
plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20), main='
Awesome gradient legend inside')
## layer 2, legend inside
op <- par( ## set and store par
fig=c(grconvertX(c(0, 10), from="user", to="ndc"), ## set figure region
grconvertY(c(4, 20.5), from="user", to="ndc")),
mar=c(1, 1, 1, 9.5), ## set margins
new=TRUE) ## set new for overplot w/ next plot
plot(c(0, 2), c(0, 1), type='n', axes=F, xlab='', ylab='') ## ini plot2
rasterImage(legend_image, 0, 0, 1, 1) ## the gradient
lbsq <- seq.int(0, 1, l=5) ## seq. for labels
axis(4, at=lbsq, pos=1, labels=F, col=0, col.ticks=1, tck=-.1) ## axis ticks
mtext(sq, 4, -.5, at=lbsq, las=2, cex=.6) ## tick labels
mtext('diff', 3, -.125, cex=.6, adj=.1, font=2) ## title
par(op) ## reset par