Related
I am mapping using the "oce" package in R and want to add color to the ocean. I can manipulate the land color but not the ocean, and the mapping function omits "bg" to add background color. Here is my current code and parameters:
library(oce)
library(ocedata)
data("coastlineWorldFine")
par(mar=c(2, 2, 1, 1))
lonlim <- c(-79, -76)
latlim <- c(33, 35)
mapPlot(coastlineWorldFine,
projection="+proj=moll",
col = "lightgray",
longitudelim=lonlim,
latitudelim=latlim,
grid = FALSE,
bg = "lightblue")
Any suggestions on how to change the color of the ocean from white to a light blue?
Thanks!
Bit of a hack, but you can plot a rectangle the same size as the plotting area, then use par(new = TRUE) to plot mapPlot on top:
par(mar=c(2, 2, 1, 1))
plot(0, 0, type="n", ann=FALSE, axes=FALSE)
user <- par("usr")
rect(user[1], user[3], user[2], user[4],
col="lightblue", border=NA)
par(new = TRUE)
lonlim <- c(-79, -76)
latlim <- c(33, 35)
mapPlot(coastlineWorldFine,
projection="+proj=moll",
col = "lightgray",
longitudelim=lonlim,
latitudelim=latlim,
grid = FALSE)
When adding ticks to a plot (more ticks than default), how does one get the grid() to align the grid to the ticks?
plot(1:10,las=1,xaxp = c(0, 10, 10),xlim=c(0,10), ylim=c(0,10))
grid(lwd=2, nx=10, ny=10)
Tried changed the xlim and different numbers for the nx arg in grid (number of cells), but the grid simply doesn't line up.
Related, but doesn't answer question: Aligning grid lines in R, bReeze package
Related, and uses workaround: Align grid with ticks
Is the workaround the most efficient option?
You could use abline to draw grids. You can specify where the grids should be with h (for horizontal lines) and v (for vertical lines)
#Plot
plot(1:10,las=1,xaxp = c(0, 10, 10),xlim=c(0,10), ylim=c(0,10))
#Add horizontal grid
abline(h = c(0,2,4,6,8,10), lty = 2, col = "grey")
#Add vertical grid
abline(v = 1:10, lty = 2, col = "grey")
Another workaround is to use axis where tck value is 1. With axis, you can specify where the grids should be with at
#Plot
plot(1:10,las=1,xaxp = c(0, 10, 10),xlim=c(0,10), ylim=c(0,10))
#Add horizontal grid
axis(2, at = c(0,2,4,6,8,10), tck = 1, lty = 2, col = "grey", labels = NA)
#Add vertical grid
axis(1, at = 1:10, tck = 1, lty = 2, col = "grey", labels = NA)
#Add box around plot
box()
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. Final code is:
plot(1:10,las=1,xaxp = c(0, 10, 10),xlim=c(0,11), ylim=c(0,11),
xaxs="i", yaxs="i")
grid(lwd=2, nx=11, ny=11)
The answer to your question
When adding ticks to a plot (more ticks than default), how does one get the grid() to align the grid to the ticks?
is:
Using function axis to obtain the x axis tick locations created by plot function in combination with abline
Concretely, you substitute the line
grid(lwd=2, nx=10, ny=10)
by the following three lines
x_ticks <- axis(1, 0:10, labels = FALSE)
grid(lwd = 2, ny = NULL, nx = NA)
abline(v = x_ticks, lwd = 2, lty = 3, col = "lightgray")
and the result will be
You can control both x ticks and y ticks and get rid of the grid function. In this case the 3 lines would be
x_ticks <- axis(1, 0:10, labels = FALSE)
y_ticks <- axis(2, labels = FALSE)
abline(v = x_ticks, h = y_ticks, lwd = 2, lty = 3, col = "lightgray")
I would vote for the workaround. Because if you look at manual from ?grid, it has this statement,
"Note: If more fine tuning is required, use ‘abline(h = ., v = .)’
directly."
I have a legend in my plot, but I'm trying to increase the font size so it fit the legend-box. When I try to increase the cex as defined below. The box gets bigger, while the text is still small.
Code:
legend(0,16, c("Available vCPUs", "Added vCPUs (1 per iteration ) "),
col=c('red', 'black'), cex=0.39, lty=1:1, lwd=2)
Excerpt from plot:
First approach:
Try to set the font size before to plot the legend.
x <- y <- rnorm(100, 0, 1)
plot(x, y, type = "n")
## here you set the font size default to `x`, in this example 0.5
## save defaults in `op`
op <- par(cex = 0.5)
legend("topright", legend = "foo legend", pch = 1, bty = "n")
## here you set cexto 1.5
## save new defaults in `op`
op <- par(cex = 1.5)
legend("topright", legend = "foo legend", pch = 1, bty = "n")
Second approach:
Holding the pt.cex parameter to 1, while trying different values for cex inside the legend call. Remember to delete op.
x <- rnorm(100, 10, 4)
y <- rnorm(100, 10, 4)
plot(x, y, type = "n")
## I tried to feed cex with 1.5 and 0.5. The font size changes while the points remain unchanged.
legend("topleft", "Legend", cex=0.5, pch=1, pt.cex = 1)
You can use cex to determine font size, use bty='n' to indicate no lines around the legend, then draw a rectangle separately on the graph with rect(). For example:
with(data, legend(-10,7, legend=c("Name_of_Legend"), bty = 'n', col=c("red"), lty=0, pch=20, cex=0.75))
with(data, rect(-10,6.2,-3,7))
I think you can try using the
y.intersp in legend, when the intervals between different text lines are reduced, you could increase text size without changing the size of legend box.
legend(0,16, c("Available vCPUs","Added vCPUs (1 per iteration )
"),col=c('red','black'),cex=0.39,lty=1:1,lwd=2, y.intersp = 0.3)
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
I might be missing something simple here... I can't find anyway to remove the lines that cross the legend differentiating different colours; following on the from the volcano topography example in ?filled.contour, I've got this:
x <- 10*1:nrow(volcano)
y <- 10*1:ncol(volcano)
filled.contour(x, y, volcano, color = terrain.colors,
plot.title = title(main = "The Topography of Maunga Whau",
xlab = "Meters North", ylab = "Meters West"),
plot.axes = { axis(1, seq(100, 800, by = 100))
axis(2, seq(100, 600, by = 100)) },
key.title = title(main="Height\n(meters)"),
key.axes = axis(2,
labels=FALSE,
at=FALSE,
lty=NULL,
tick=FALSE,
col="white",
col.ticks=NULL)
)
mtext(paste("filled.contour(.) from", R.version.string),side = 1, line = 4, adj = 1, cex = .66)
I've managed to remove all the labels and tick-marks from the axis, but the lines still exist (incidentally, the effect I'm trying to achieve is (I believe) the default in Matlab!)
If you examine the code for filled.contour you'll see this line:
rect(0, levels[-length(levels)], 1, levels[-1L], col = col)
that draws the color key rectangle. It's vectorized, so it's drawing each of the individual color boxes. The function rect accepts an argument border, which if you set to NA will omit the internal borders of the rectangles. So create your own version of the function and change this line to :
rect(0, levels[-length(levels)], 1, levels[-1L], col = col, border = NA)
or make it an argument, rather than hard coding. When I do this, I get the following graph:
You don't even need to change the filled.contour hardcode. Apparently the argument border in the function rect relies on par("fg"). Just set par(fg = NA) to remove those black lines.