I have the following plot:
And would like to add a legend as follows:
This is the code I used to generate the plot:
library(data.table)
library(ggplot2)
blue <- "#4472C4"
green <- "#548235"
red <- "#C55A11"
redblood <- "#C00000"
DT <- data.table(student = c("Jane", "Sam", "Tim", "Kate", "Claire"),
grade = c(10, 14, 8, 9, 19))
b0 <- 13
DT[, gradeHat := b0]
DT[, e := grade - gradeHat]
DT[, SS := sum(e**2)]
DT[, id := 1:nrow(DT)]
DT[, xmin := id]
DT[, xmax := id + abs(e)/20*3]
DT[, ymin := min(grade, gradeHat), id]
DT[, ymax := max(grade, gradeHat), id]
DT[, student := factor(student, levels = student)]
gg <- ggplot(DT) +
geom_segment(aes(x = student, xend = student, y = grade, yend = gradeHat),
color = redblood, size = 1.3) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = redblood, alpha = .4) +
geom_hline(yintercept = b0, color = green, alpha = .7, size = 1, linetype = "dashed") +
geom_point(aes(student, grade), color = blue, size = 4) +
geom_point(aes(student, gradeHat), color = green, size = 4) +
scale_y_continuous(breaks = 0:20, limits = c(0, 20)) +
coord_fixed(.15) +
theme_classic()
plot(gg)
Not a full solution for your problem ... but the best I could come up with at the moment:
To get a legend in ggplot you have to map on aesthetics, i.e. instead of setting colors as arguments you have to map on color
or fill
inside aes()
. To this end you can make use of placeholders or labels, e.g. fill="SS"
in geom_rect
.
To get the colors right you can make use of scale_color/fill_manual
. Using the labels makes it easy to assign the right colors.
Next, to get the styling of the legend right you can make use of guide_legend
and its argument override.aes
to set the shapes and linetypes for the color legend.
By default there is some spacing between the color
and fill
legend, which however can be removed in theme()
via legend.spacing
and legend.margin
.
Final part is to color the legend labels. This could be achieved via the ggtext
package which via theme option legend.text = element_markdown()
allows to style the legend entries using HTML and CSS.
Unfortunately I was not able to figure out how to get the wide hat on your gradeHat
.
library(data.table)
library(ggplot2)
blue <- "#4472C4"
green <- "#548235"
red <- "#C55A11"
redblood <- "#C00000"
DT <- data.table(student = c("Jane", "Sam", "Tim", "Kate", "Claire"),
grade = c(10, 14, 8, 9, 19))
b0 <- 13
DT[, gradeHat := b0]
DT[, e := grade - gradeHat]
DT[, SS := sum(e**2)]
DT[, id := 1:nrow(DT)]
DT[, xmin := id]
DT[, xmax := id + abs(e)/20*3]
DT[, ymin := min(grade, gradeHat), id]
DT[, ymax := max(grade, gradeHat), id]
DT[, student := factor(student, levels = student)]
ggplot(DT) +
geom_segment(aes(x = student, xend = student, y = grade, yend = gradeHat, color = "error"),
, size = 1.3) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = "SS"), alpha = .4) +
geom_hline(yintercept = b0, color = green, alpha = .7, size = 1, linetype = "dashed") +
geom_point(aes(student, grade, color = "grade"), size = 4) +
geom_point(aes(student, gradeHat, color = "gradeHat"), size = 4) +
scale_color_manual(breaks = c("grade", "gradeHat", "error"),
values = c(grade = blue, gradeHat = green, error = red),
labels = c(grade = glue::glue("<span style = 'color: {blue};'>grade</span>"),
gradeHat = glue::glue("<span style = 'color: {green};'>gradeHat</span>"),
error = glue::glue("<span style = 'color: {red};'>error</span>"))) +
scale_fill_manual(values = c(SS = redblood), labels = c(SS = glue::glue("<span style = 'color: #C0000066; '>SS</span>"))) +
guides(color = guide_legend(order = 1, override.aes = list(shape = c(16, 16, NA), linetype = c("blank", "dashed", "solid")))) +
scale_y_continuous(breaks = 0:20, limits = c(0, 20)) +
coord_fixed(.15) +
theme_classic() +
theme(legend.position = "bottom",
legend.spacing = unit(0, "pt"),
legend.margin = margin(r = 0, l = 0),
legend.text = ggtext::element_markdown()) +
labs(color = NULL, fill = NULL)