Reputation: 2564
I would like to superimpose transparent boxes on top of the lines in the legend.
A small example:
xdata <- 1:7
y1 <- c(1,4,9,16,25,36,49)
y2 <- c(1, 5, 12, 21, 34, 51, 72)
y3 <- c(1, 6, 14, 28, 47, 73, 106 )
y4 <- c(1, 7, 17, 35, 60, 95, 140 )
plot(xdata, y1, type = 'l', col = "red")
lines(xdata, y2, type = 'l', col = "red", lty = 3)
lines(xdata, y3, type = 'l', col = "blue")
lines(xdata, y4, type = 'l', col = "blue", lty = 3)
# add legend with lines
legend("topleft", legend = c("Plot 1", "Plot 2", "Plot 3", "Plot 4"),
lty = c(1,3,1,3), lwd = rep(1.3 ,4),
col = c("blue", "blue", "red", "red") ,
pch = rep(NA, 4), cex = 0.8,
x.intersp = 0.7, y.intersp = 1.2, bty = 'n')
# add boxes
legend("topleft", legend = c("", "", "", ""), lty = rep(0, 4),
col = c(adjustcolor(blues9[3], alpha.f = 0.6),
adjustcolor(blues9[3], alpha.f = 0.6),
adjustcolor("red", alpha.f = 0.1),
adjustcolor("red", alpha.f = 0.1)),
pch = rep(15, 4), cex = 0.8, pt.cex = rep(2, 4),
x.intersp = 0.7, y.intersp = 1.2, bty = 'n')
which produces:
As you can see, the boxes are shifted to the left along the lines in the legend.
How can I set the alignment of the boxes, so that they become horizontally centered on top of the line symbols in the legend? Thanks!
Upvotes: 9
Views: 3083
Reputation: 67778
The clue here is to specify the same lwd
in both legend
calls, i.e. also in the call for the boxes where lty = 0
.
Here's a simpler example, with only the arguments relevant for your actual issue:
plot(1)
# lines
legend(x = "topleft",
legend = c("Plot 1", "Plot 2", "Plot 3", "Plot 4"), bty = 'n',
lty = c(1, 3), lwd = 1,
pch = NA,
col = rep(c("blue", "red"), each = 2))
# boxes
legend(x = "topleft",
legend = rep("", 4), bty = "n",
lty = 0, lwd = 1, # <- lwd = 1
pch = 15, pt.cex = 2,
col = c(rep(adjustcolor(blues9[3], alpha.f = 0.6), 2),
rep(adjustcolor("red", alpha.f = 0.1), 2)))
If you're fine with a coloured outline of the boxes, one legend
call is enough. Just use a pch
which accepts pt.bg
(here: 22):
plot(1)
legend(x = "topleft",
legend = c("Plot 1", "Plot 2", "Plot 3", "Plot 4"), bty = 'n',
lty = c(1, 3), col = rep(c("blue", "red"), each = 2),
pch = 22, pt.cex = 2,
pt.bg = c(rep(adjustcolor(blues9[3], alpha.f = 0.6), 2),
rep(adjustcolor("red", alpha.f = 0.1), 2)))
Upvotes: 9
Reputation: 11128
Here is what I have done using base R:
Below are some of the settings which you can do at your end to get the desired result.
seg.len
: It basically works with length of the legend line in the base R plotting graphics, I have taken this values as 1.25
pt.cex
: rep(4.4,4), so we have taken box as squares, I have adjusted the value of thse squares using 4.4
x.intersp
: It deals between the space between text of the legend and the legend shape
text.col
: This is an optional setting for the colour of the text of the legend if you comment it , You will get legend text it as black (like your answer)
xjust
: for the value of 0 the legend is left justified , for 0,5 it is centre justified and for 1 it is right justified
I have changed these settings iteratively to came with these as final result. I am hopeful that would be helpful to you. I have run this many times on machine to come up with this.
Above all the settings I have played with and came up with the below chart:
plot(xdata, y1, type = 'l', col = "red")
lines(xdata, y2, type = 'l', col = "red", lty = 3)
lines(xdata, y3, type = 'l', col = "blue")
lines(xdata, y4, type = 'l', col = "blue", lty = 3)
legend("topleft", legend = c("Plot 1", "Plot 2", "Plot 3", "Plot 4"),
lty = c(1,3,1,3), lwd = rep(1.3 ,4),
col = c("blue", "blue", "red", "red") ,
pch = rep(NA,4), cex = 0.8,
text.col = c("blue", "blue", "red","red"),
y.intersp=1.2, bty = 'n', x.intersp = .5,
seg.len = 1.265, xjust =1)
legend("topleft", legend = c("", "", "", ""), lty = rep(0, 4),
col = c(adjustcolor(blues9[3],alpha.f=0.6),
adjustcolor(blues9[3],alpha.f=0.6),
adjustcolor("red",alpha.f=0.1),
adjustcolor("red",alpha.f=0.1)),
pch = rep(15,4), bty ='n', cex = 0.8,
pt.cex = rep(4.3, 4), y.intersp = 1.2, x.intersp = 0.1,
xjust = 0)
Note: You have zoom the graph to see the correct effect in R Studio.
Upvotes: 5
Reputation: 50668
Since you explicitly welcome alternative solutions, here is a possibility using ggplot2
library(tidyverse);
data.frame(xdata, y1, y2, y3, y4) %>%
gather(key, y, -xdata) %>%
mutate(key = sub("y", "Plot ", key)) %>%
ggplot(aes(xdata, y, colour = key, linetype = key)) +
geom_line() +
geom_ribbon(aes(ymin = y, ymax = y, fill = key), alpha = 0.2, colour = NA) +
scale_colour_manual(
values = c("Plot 1" = "red", "Plot 2" = "red", "Plot 3" = "blue", "Plot 4" = "blue"),
name = "Legend") +
scale_linetype_manual(
values = c("Plot 1" = "solid", "Plot 2" = "dashed", "Plot 3" = "solid", "Plot 4" = "dashed"),
name = "Legend") +
scale_fill_manual(
values = c("Plot 1" = "red", "Plot 2" = "red", "Plot 3" = "blue", "Plot 4" = "blue"),
name = "Legend") +
theme_bw() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.justification = c(0, 1),
legend.position = c(0.02, 0.98),
legend.spacing.x = unit(0.5, 'cm'),
legend.title = element_blank())
Here is a summary of the key adjustments:
fill
aesthetic through a zero width geom_ribbon
. This will give us the coloured boxes in the legend. We use alpha = 0.2
to ensure transparency.colour
, linetype
, and fill
in one single legend.legend.position
and legend.justification
to make sure the legend is within the plot region in the top-left corner. These parameters require a bit of fine-tuning depending on the legend text,legend.title = element_blank()
,legend.spacing.x
; again this parameter may require a bit of manual fine-tuning depending on your personal preference.Lastly, we do some minor adjustments to increase aesthetic similarity with the base R plot, by removing grid lines (theme_bw
in combination with panel.grid.major = element_blank()
and panel.grid.minor = element_blank()
).
Upvotes: 8