Removing lines within filled.contour legend - r

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.

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)

Linear function axis scaling in R

I have the following function
C=15
S=seq(0,12,.1)
pA=1
pS=0.5
A <- function(S) (C/pA)-(pA/pS)*S
plot (S, A(S), type="l", col="red", ylim=c(0,15), xlim=c(0,15), xlab="S", ylab="A")
text(8, 11.5, "Function", col = "red", cex=.9)
text(11, 10.2, expression(A==frac(C,p[S])-frac(p[A],p[S])%.%S), cex=.9, col = "red")
grid()
How can I scale the axis so that I can "zoom out" a bit. I am looking for a function similar to ylim but where I could say: ylim=c(0,15, by=1).
Update
It seems your "zoom out" is meant for the grid lines, not for the axis or anything. I'll keep the previous answer below, but this should address it, I think.
# no change yet
plot (S, A(S), type="l", col="red", ylim=c(0,15), xlim=c(0,15), xlab="S", ylab="A")
text(8, 11.5, "Function", col = "red", cex=.9)
text(11, 10.2, expression(A==frac(C,p[S])-frac(p[A],p[S])%.%S), cex=.9, col = "red")
# no call to grid, since we want to control it a little more precisely
abline(h = seq(0, 15), col = "lightgray", lty = "dotted", lwd = par("lwd"))
abline(v = seq(0, 15, by = 5), col = "lightgray", lty = "dotted", lwd = par("lwd"))
You can do just abline(h=seq(...)) and not set col=, lty=, or lwd=, but realize that abline's default values are different from grid's defaults. I used those values to mimic grid's look and feel.
Old answer
I think you mean to change the y axis labels, not the y axis limits (which is all that ylim= can effect).
Using base R graphics:
plot (S, A(S), type="l", col="red", ylim=c(0,15), xlim=c(0,15), xlab="S", ylab="A",
yaxt = "n") # this is new
text(8, 11.5, "Function", col = "red", cex=.9)
text(11, 10.2, expression(A==frac(C,p[S])-frac(p[A],p[S])%.%S), cex=.9, col = "red")
grid()
axis(2, at = 1:15, las = 2)
Explanation:
plot(..., yaxt = "n") means to not plot the y-axis ticks and labels, see ?par.
axis(...) adds an axis to a side. By itself, it will just add a default axis.
at= sets where the ticks and labels are placed.
labels= sets what to put at each tick. If absent (like it is above), it just prints the at value.
las=2 rotates the number so that it is perpendicular to the axis line. I did this to show more of the numbers, otherwise they will mask a bit more.
While this shows every-other, that is affected by the size of the canvas; if you do the same plot in full-screen, it'll show every number.

Align grid() to plot ticks

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."

Calculating the appropriate inset value for legends automatically

Is it possible to obtain the appropriate value of inset automatically so that the left corner of legend will always be just outside of the top right corner of plot?
In the plot below I had to try several values for inset manually. It would be nice to not have to do it manually since I have to make multiple plots.
graphics.off()
windows(width = 5, height = 5)
set.seed(42)
par(mar = c(5,5,1,10))
plot(rnorm(50,15,5), rnorm(50,15,3),
xlim = c(0,30), ylim = c(5,25),
pch = 19, col = c("red","blue"))
par(xpd = TRUE)
legend("topright", inset = c(-.80, 0),
pch = 19, col = c("red","blue"),
legend = c("LEGEND 1","Second Legend"))
After the plot call, before adding the legend, use par("usr")* to extract the coordinates of the plotting region.
Then, instead of positioning the legend using a 'keyword' and inset, use x and y with the top-right coordinates of the plotting region obtained from par("usr"). Adjust x with a suitable coefficient.
coord <- par("usr")
legend(x = coord[2] * 1.05, y = coord[4],
pch = 19, col = c("red", "blue"),
legend = c("LEGEND 1", "Second Legend"))
And just for fun, a more convoluted alternative.
After plotting, call legend with position topright, but without plotting it to the device (plot = FALSE), and assign it to an object.
Extract the left x and the top y coordinate of the legend box, and its width (see Value section in ?legend), to be used in x and y in legend:
leg <- legend("topright", pch = 19, col = c("red", "blue"),
legend = c("LEGEND 1", "Second Legend"),
plot = FALSE)
legend(x = (leg$rect$left + leg$rect$w) * 1.05, y = leg$rect$top,
pch = 19, col = c("red", "blue"),
legend = c("LEGEND 1", "Second Legend"))
*From ?par
usr A vector of the form c(x1, x2, y1, y2) giving the extremes of the user coordinates of the plotting region.
The position calculations that are made when inset parameter(s) have been specified, are in fact based on par("usr") (see line 188-199 in the legend code).

Modifying width of outline in a pie chart in R--what is the equivalent of lwd parameter for pie()?

I'm using base R plotting functions to produce a pie chart and I want to change the line thickness of the outlines of each pie segment. ?pie seems to indicate that I can add optional graphic parameters, but adding lwd= does not appear to work. Anyone have any clues as to how I might be able to do this. I'm not yet proficient in producing pie charts in ggplot, and would like to stick with base R plotting (if possible).
library(RColorBrewer)
x1 <- data.frame(V1 = c(200, 100)) ## generate data
row.names(x1) <- c("A", "B")
x1$pct <- round((x1$V1/sum(x1$V1))*100, 1)
lbls1 <- paste(row.names(x1), "-(",x1$pct, '%)', sep='') ## add some informative stuff
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd= 3)
Notice lwd= does not increase line thickness like it would in other base plotting.
Anyone have any clues?
The call to polygon and lines within pie does not pass ... or lwd
...
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
P <- t2xy(mean(x[i + 0:1]))
lab <- as.character(labels[i])
if (!is.na(lab) && nzchar(lab)) {
lines(c(1, 1.05) * P$x, c(1, 1.05) * P$y)
....
You can get around this by setting par(lwd = 2) (or whatever) outside and prior to your call to pie
i.e.
# save original settings
opar <- par(no.readonly = TRUE)
par(lwd = 2)
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1)
par(lwd = 3)
# reset to original
par(opar)
At the moment, the function inside pie that does the actual drawing is polygon and here is how it is called:
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
Notice there is no lwd argument and more critically no ... argument to accept arguments that might not have been hard coded.
Create a new pie2 function. First type pie, copy the code and make a few changes:
pie2 <-
function (x, labels = names(x), edges = 200, radius = 0.8, clockwise = FALSE,
init.angle = if (clockwise) 90 else 0, density = NULL, angle = 45,
col = NULL, border = NULL, lty = NULL, main = NULL, lwd=1,...)
{
................
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i], lwd=lwd )
.................
}
pie2(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd=5)

Resources