I want to make a legend on my graph, which is generated by plot() function. The original legend() function will generate a list which has only 1 column. How can I make a legend which has 2 columns?
I could not find a way to do that within a single call to legend for standard plots.
Here's an option, drawing two separate legends: one with lines and points, one with labels. x.intersp can be used to tweak distance between labels and lines.
plot(cumsum(runif(n = 100)))
# draw legend with lines and point but without labels and box. x.intersp controls horizontal distance between lines
L = legend(x = 'bottom', legend = rep(NA,4), col=1:2, lty=c(1,1,2,2), ncol=2, bty='n', x.intersp=0.5, pch=c(1,2,1,2), inset=0.02)
# use position data of previous legend to draw legend with invisble lines and points but with labels and box. x.intersp controls distance between lines and labels
legend(x = L$rect$left, y = L$rect$top, legend = c('Group A', 'Group B'), col=rep(NA,2), lty=c(1,1), ncol=1, x.intersp = 3, bg = NA)
Check this:
library(lattice)
myPCH <- 15:17
Data <- rnorm(50)
Index <- seq(length(Data))
xyplot(Data ~ Index,
pch = myPCH, col=1:2,
key = list(space = "right", adj=1,
text = list(c("a", "b", "c"), cex=1.5),
points = list(pch = myPCH),
points = list(pch = myPCH,col=2)))
It looks like Victorp answered this in the comments of the original post. The ncol argument in the legend function works for me:
legend(locator(1), legend=c("name1","name2", "name3", "name4"), lty=2, col=c("black", "blue", "dark green", "orange"), ncol=2)
enter image description here
Related
I am using vegan library to make some plots, with this code:
raremax <- min(colSums(mydata))
col <- palette()
lty <- c("solid", "dashed", "longdash", "dotdash")
pars <- expand.grid(col = col, lty = lty, stringsAsFactors = FALSE)
out <- with(pars[1:18, ], rarecurve(mydata, step = 100, sample = raremax,
cex =0.6, ylab="OTUs", label=F, col=col, lty=lty, lwd=2))
Then I add a legend using this code:
legend("bottomright", names(mydata), col=pars[1:18,1], lty= pars[1:18,2],
lwd=2, cex=0.5, xjust=1, ncol=2, x.intersp=0.5, y.intersp=0.5, bg="white")
The resulting graph looks like this:
I would like to reduce the space between legend columns, also reducing the size of the legend box, but I can't find a way to do that.
Anyone could provide me some help?
A combination of the legend() parameters "x.intersp" and "text.width" should be helpful.
Decreasing "x.intersp" (default value = 1, for me 0.25 looked good) should move your the legend labels closer to their respective points. Decreasing "text.width" (default value=NULL, for me 0.045 looked good) moves the columns closer together.
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).
I have one time series which is represented by a black line and one which is represented by a red curve. Then I have single points which have the pch symbol of 8 in R. These are stars. See the following plot:
Currently I have the following legend:
legend("bottomleft",
legend=c("log loss","daily VaR","exceedance"),
bty = "n",lwd=2, cex=1.2,y.intersp=1.4, col=c("black","red","blue"), lty=c(1,1,1))
But I don't want to have a blue line in the legend for exceedance, but just the stars in the plot. I have to use the pch=8. I just want to have the stars in the legend, not the stars with a line. So not these solutions: R legend issue, symbols of points are masked by lines
Try this. You set lty to display only first two lines, and pch to display only the last point.
plot(1:10, rnorm(10) * 1:10)
legend("bottomleft", legend = c("entry1", "entry2", "something cpl different"), bty = "n",
lwd = 2, cex = 1.2, col = c("black", "blue", "red"), lty = c(1, 1, NA), pch = c(NA, NA, 8))
heights1=c(5,5,4.5,4,4,4,4.5,2,4,4)
opar <- par(lwd = 0.3)
barplot(heights1,xlim=c(0,3), ylim=c(0,5), width=0.1,
main="Langauges(Verbal & Non-verbal)",
names.arg=c("Spanish", "Speak" , "English","Speak", "Hindi",
"Speak", "Arabic", "Speak", "Body Lang", "Speak"), ylab="Skill level ",
xlab="Language starting with mostly used", col=c("darkblue","red"),
cex.names=0.7,space=c(2,0,2,0,2,0,2,0,2,0))
legend("top", c("darkblue","red"), c("reading/Writing", "Speaking") );
Blue is for "reading/writing" and red is for "speaking". How do I make correction in legend? (I do not want to define legend inside barplot function)
You can use the fill argument for your colors. As with David Robinson's answer, I would also suggest placing the legend in the top right in this case.
legend("topright",
legend = c("reading/Writing", "Speaking"),
fill = c("darkblue", "red"))
Looking at some of your other questions, you might also want to spend some time getting your data into a more appropriate form before plotting.
Here's an example:
Here is your data:
heights1 = c(5, 5, 4.5, 4, 4, 4, 4.5, 2, 4, 4) # Your data
Here is your data as a matrix with appropriate dimnames
mydata <- matrix(heights1, ncol = 2, byrow = TRUE,
dimnames = list(c("Spanish", "English", "Hindi",
"Arabic", "Body Lang"),
c("Reading/Writing", "Speaking")))
mydata # Much more meaningful to look at than a simple vector
# Reading/Writing Speaking
# Spanish 5.0 5
# English 4.5 4
# Hindi 4.0 4
# Arabic 4.5 2
# Body Lang 4.0 4
Define your colors (optional, but useful if you are working with more than just a pair of bars per group)
colors <- c("darkblue", "red") # Define the colors you're using
Plot your data adding a little bit of extra space at the top and suppressing your axes. Not sure why you don't want to include the legend at this stage, but it could easily be done by adding the following arguments: legend.text = TRUE, args.legend = list(x = "topright", bty = "n")
barplot(t(mydata), beside = TRUE, col = colors,
ylim = c(0, 6), axes = FALSE,
xlab = "Language starting with mostly used",
main = "Languages (Verbal & Non-verbal)")
Reintroduce your y-axis and add your legend
axis(2, at = 0:5, labels = 0:5)
legend("topright", colnames(mydata), fill = colors, bty = "n")
Change your legend line to
legend("topright", c("reading/Writing", "Speaking"), col=c("darkblue","red"), lwd=10);
The lwd argument says the legend should have lines of 10 pixel thickness of each of the corresponding colors. It's a good idea to use "topright" rather than "top" in your case so that the legend doesn't appear under the bars.
Context and Question:
I want to add a legend to a lattice plot in R that shows the density of two groups.
I've changed the default colours to black and gray. However, the legend has not updated the colours.
How can I get the lattice plot to use my updated colours in the legend?
How can I control the position of the legend (I'd like to be able to place it inside the plot area)?
Working example:
set.seed(4444)
x1 <- rep("Group A", 50)
x2 <- rep("Group B", 50)
y1 <- rnorm(50, 0, 2)
y2 <- rnorm(50, 1, 2)
dtf <- data.frame(x=c(x1, x2), y =c(y1, y2))
print(densityplot(~y, groups=x, data=dtf,
pch=".",
cex=2,
col=c("black", "gray"),
auto.key=TRUE,
xlab="Y"))
The legend color is a well-known annoyance in lattice. It looks like it is difficult to correct, because Deepayan recommends simpleTheme as a solution. For positioning, see Josh's answer.
print(densityplot(~y, groups=x, data=dtf,
pch=".",
cex=2,
par.settings=simpleTheme(col=c("gray","black")),
auto.key=TRUE,
xlab="Y"))
There might be a more elegant solution, but this works well enough. Notice that the corner= argument can be used to place the legend anywhere inside the plot.
densityplot(~y, groups = x, data = dtf,
pch = ".",
cex = 2,
col = c("black", "gray"),
par.settings = list(superpose.line = list(col=c("black", "grey"))),
auto.key = list(corner = c(0.95, 0.95)),
xlab = "Y")