Adding Legend to Ggplot When Lines Were Added Manually

Adding legend to ggplot when lines were added manually

Just set the color name in aes to whatever the line's name on the legend should be.

I don't have your data, but here's an example using iris a line with random y values:

library(ggplot2)

line.data <- data.frame(x=seq(0, 10, length.out=10), y=runif(10, 0, 10))

qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y, color="My Line"), data=line.data)

Sample Image

The key thing to note is that you're creating an aesthetic mapping, but instead of mapping color to a column in a data frame, you're mapping it to a string you specify. ggplot will assign a color to that value, just as with values that come from a data frame. You could have produced the same plot as above by adding a Species column to the data frame:

line.data$Species <- "My Line"
qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y), data=line.data)

Either way, if you don't like the color ggplot2 assigns, then you can specify your own using scale_color_manual:

qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y, color="My Line"), data=line.data) +
scale_color_manual(values=c("setosa"="blue4", "versicolor"="red4",
"virginica"="purple4", "My Line"="gray"))

Sample Image

Another alternative is to just directly label the lines, or to make the purpose of the lines obvious from the context. Really, the best option depends on your specific circumstances.

How to add a legend manually for line chart

The neatest way to do it I think is to add colour = "[label]" into the aes() section of geom_line() then put the manual assigning of a colour into scale_colour_manual() here's an example from mtcars (apologies that it uses stat_summary instead of geom_line but does the same trick):

library(tidyverse)

mtcars %>%
ggplot(aes(gear, mpg, fill = factor(cyl))) +
stat_summary(geom = "bar", fun = mean, position = "dodge") +
stat_summary(geom = "line",
fun = mean,
size = 3,
aes(colour = "Overall mean", group = 1)) +
scale_fill_discrete("") +
scale_colour_manual("", values = "black")

Sample Image

Created on 2020-12-08 by the reprex package (v0.3.0)

The limitation here is that the colour and fill legends are necessarily separate. Removing labels (blank titles in both scale_ calls) doesn't them split them up by legend title.

In your code you would probably want then:

...
ggplot(data = impact_end_Current_yr_m_actual, aes(x = month, y = gender_value)) +
geom_col(aes(fill = gender))+
geom_line(data = impact_end_Current_yr_m_plan,
aes(x=month, y= gender_value, group=1, color="Plan"),
size=1.2)+
scale_color_manual(values = "#288D55") +
...

(but I cant test on your data so not sure if it works)

Adding manual legend to ggplot2

Instead of answering the question about how to add a manual legend, I'll give an example of the typical way to add legends.

I suppose you have data of the following structure:

library(ggplot2)

df_density0 <- density(rnorm(100))
df_density0 <- data.frame(
x = df_density0$x,
y = df_density0$y
)

df_density1 <- density(rnorm(100, mean = 1))
df_density1 <- data.frame(
x = df_density1$x,
y = df_density1$y
)

You can just set aes(colour = ...) to text that you want your legend label to be. Then in the scale, you can set the actual colour that you want to use.

ggplot(mapping = aes(x = x, y = y)) +
geom_line(data = df_density0, aes(colour = "Target = 0")) +
geom_line(data = df_density1, aes(colour = "Target = 1")) +
scale_colour_manual(
values = c("darkred", "steelblue")
)

Sample Image

Created on 2021-04-10 by the reprex package (v1.0.0)

ggplot Adding manual legend to plot without modifying the dataset

If you want to have a legend then you have to map on aesthetics. Otherwise scale_color/fill_manual will have no effect:

vec <- c(rep(1, 100), rep(2, 100), rep(3, 80), rep(4, 70), rep(5, 60))
tbl <- data.frame(value = vec)

mean_vec <- mean(vec)

cols <- c(
"Frequency" = "grey",
"mean" = "blue"
)

library(ggplot2)

ggplot(tbl) +
aes(x = value) +
geom_histogram(aes(fill = "Frequency"), binwidth = 1) +
geom_vline(aes(color = "mean", xintercept = mean_vec), size = 1) +
theme_minimal() +
scale_color_manual(values = "blue") +
scale_fill_manual(name = "Test", values = "grey")

Sample Image

ggplot2: add legend manually to existing legend

Here's a solution to your second bullet point:

ggplot(data=dat2, aes(x=x, y=y, fill=z)) +
geom_bar(stat="identity", position=position_dodge2(preserve = "single")) +
geom_line(aes(y=roll_mean, color=z),size=1.1, linetype = 2) +
theme_classic() +
scale_colour_manual(name="3 day moving average",
values=c("A" = "#F8766D", "B" = "#00BA38", "C" = "#619CFF"),
guide = guide_legend(override.aes=aes(fill=NA))) +
theme(legend.key.size = unit(0.5, "in"))

Sample Image

Adding manual legend to a ggplot

To get a legend simply make one dataframe out of your five and do the plotting in one step instead of adding layers in a loop.

My approach uses purrr::map to set up the datasets by sample size and bind them using dplyr::bind_rows. After these preparation steps we get the legend automatically by mapping sample size on color. Try this:

library(ggplot2)
library(dplyr)
library(purrr)

N <- 100
gamma <- 1/12 #scale parameter
beta <- 0.6 #shape parameter

make_lorenz <- function(N, gamma, beta) {
u <- runif(N)
v <- runif(N)

tau <- -gamma*log(u)*(sin(beta*pi)/tan(beta*pi*v)-cos(beta*pi))^(1/beta)

OX <- sort(tau)
CumWealth <- cumsum(OX)/sum(tau)
PoorPopulation <- c(1:N)/N
index <- c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.99,0.999,0.9999,0.99999,0.999999,1)*N
QQth <- CumWealth[index]
x <- PoorPopulation[index]
data.frame(x, QQth)
}

sample_sizes <- c(100, 1000, 10000, 100000)

Lorenzdf <- purrr::map(sample_sizes, make_lorenz, gamma = gamma, beta = beta) %>%
setNames(sample_sizes) %>%
bind_rows(.id = "N")

cols <- c("100"="blue","1000"="green","10000"="red", "1e+05" = "black")

g <- ggplot(data=Lorenzdf, aes(x=x, y=QQth, color = N)) +
geom_point() +
geom_line() +
ggtitle(paste("Convergence of empirical Lorenz curve for Beta = ", beta, sep = " ")) +
xlab("Cumulative share of people from lowest to highest wealth") +
ylab("Cumulative share of wealth") +
scale_color_manual(name="Sample size",values=cols)
g

Sample Image

Created on 2020-06-27 by the reprex package (v0.3.0)

Adding legend manually to R/ggplot2 plot without interfering with the plot

Maybe this is what you want.. Plot 1 is definitely not a clever and ggplot-y way of plotting (essentially, you are not visualising dimensions of your data). Below another option (plot 2)...

Below - creating new data frame and plot with scale_color_identity. Use a data point of your second plot, which comes second and overplots the first plot, so the point disappears.

library(tidyverse)
the_colors <- c("#e6194b", "#3cb44b", "#ffe119", "#0082c8", "#f58231", "#911eb4", "#46f0f0", "#f032e6",
"#d2f53c", "#fabebe", "#008080", "#e6beff", "#aa6e28", "#fffac8", "#800000", "#aaffc3",
"#808000", "#ffd8b1", "#000080", "#808080", "#ffffff", "#000000")

color_df <- data.frame(the_colors, the_labels = seq_along(the_colors))

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=c(1, 2, 3, 4))

#the_plot <-
ggplot() +
geom_point(data = color_df, aes(x = the_df$col1[[1]], y = the_df$col2[[1]], color = the_colors)) +
scale_color_identity(guide = 'legend', labels = color_df$the_labels) +
geom_point(data=the_df, aes(x=col1, y=col2), color=the_colors[[4]])

Sample Image

a more ggplot-y way

Now, the last plot is really peculiar, because as you say, "the colors have nothing to do with the plot" [with the data] and thus, showing them is absolutely pointless. What you actually want is to visualise dimensions of your data.

So what I believe and hope is that you have some link of those values to your plotted data. I am considering col3 to be the variable of choice, that will be represented by color.

First, create a named vector, so you can pass this as your values argument in scale_color. The names should be the values of your column which will be represented by color, in this case col3.

names(the_colors) <- str_pad(seq_along(the_colors), width = 2, pad = '0')

the_df <- data.frame("col1"=c(1, 2, 2, 1), "col2"=c(2, 2, 1, 1), "col3"=str_pad(c(1, 2, 3, 4), width = 2,pad='0'))

ggplot() +
geom_point(data=the_df, aes(x=col1, y=col2, color = col3)) +
scale_color_manual(limits = names(the_colors), values = the_colors)

Sample Image

Created on 2020-03-28 by the reprex package (v0.3.0)

Construct a manual legend for a complicated plot

You need to map attributes to aesthetics (colours within the aes statement) to produce a legend.

cols <- c("LINE1"="#f04546","LINE2"="#3591d1","BAR"="#62c76b")
ggplot(data=data,aes(x=a)) +
geom_bar(stat="identity", aes(y=h, fill = "BAR"),colour="#333333")+ #green
geom_line(aes(y=b,group=1, colour="LINE1"),size=1.0) + #red
geom_point(aes(y=b, colour="LINE1"),size=3) + #red
geom_errorbar(aes(ymin=d, ymax=e, colour="LINE1"), width=0.1, size=.8) +
geom_line(aes(y=c,group=1,colour="LINE2"),size=1.0) + #blue
geom_point(aes(y=c,colour="LINE2"),size=3) + #blue
geom_errorbar(aes(ymin=f, ymax=g,colour="LINE2"), width=0.1, size=.8) +
scale_colour_manual(name="Error Bars",values=cols) + scale_fill_manual(name="Bar",values=cols) +
ylab("Symptom severity") + xlab("PHQ-9 symptoms") +
ylim(0,1.6) +
theme_bw() +
theme(axis.title.x = element_text(size = 15, vjust=-.2)) +
theme(axis.title.y = element_text(size = 15, vjust=0.3))

Sample Image

I understand where Roland is coming from, but since this is only 3 attributes, and complications arise from superimposing bars and error bars this may be reasonable to leave the data in wide format like it is. It could be slightly reduced in complexity by using geom_pointrange.


To change the background color for the error bars legend in the original, add + theme(legend.key = element_rect(fill = "white",colour = "white")) to the plot specification. To merge different legends, you typically need to have a consistent mapping for all elements, but it is currently producing an artifact of a black background for me. I thought guide = guide_legend(fill = NULL,colour = NULL) would set the background to null for the legend, but it did not. Perhaps worth another question.

ggplot(data=data,aes(x=a)) + 
geom_bar(stat="identity", aes(y=h,fill = "BAR", colour="BAR"))+ #green
geom_line(aes(y=b,group=1, colour="LINE1"),size=1.0) + #red
geom_point(aes(y=b, colour="LINE1", fill="LINE1"),size=3) + #red
geom_errorbar(aes(ymin=d, ymax=e, colour="LINE1"), width=0.1, size=.8) +
geom_line(aes(y=c,group=1,colour="LINE2"),size=1.0) + #blue
geom_point(aes(y=c,colour="LINE2", fill="LINE2"),size=3) + #blue
geom_errorbar(aes(ymin=f, ymax=g,colour="LINE2"), width=0.1, size=.8) +
scale_colour_manual(name="Error Bars",values=cols, guide = guide_legend(fill = NULL,colour = NULL)) +
scale_fill_manual(name="Bar",values=cols, guide="none") +
ylab("Symptom severity") + xlab("PHQ-9 symptoms") +
ylim(0,1.6) +
theme_bw() +
theme(axis.title.x = element_text(size = 15, vjust=-.2)) +
theme(axis.title.y = element_text(size = 15, vjust=0.3))

Sample Image


To get rid of the black background in the legend, you need to use the override.aes argument to the guide_legend. The purpose of this is to let you specify a particular aspect of the legend which may not be being assigned correctly.

ggplot(data=data,aes(x=a)) + 
geom_bar(stat="identity", aes(y=h,fill = "BAR", colour="BAR"))+ #green
geom_line(aes(y=b,group=1, colour="LINE1"),size=1.0) + #red
geom_point(aes(y=b, colour="LINE1", fill="LINE1"),size=3) + #red
geom_errorbar(aes(ymin=d, ymax=e, colour="LINE1"), width=0.1, size=.8) +
geom_line(aes(y=c,group=1,colour="LINE2"),size=1.0) + #blue
geom_point(aes(y=c,colour="LINE2", fill="LINE2"),size=3) + #blue
geom_errorbar(aes(ymin=f, ymax=g,colour="LINE2"), width=0.1, size=.8) +
scale_colour_manual(name="Error Bars",values=cols,
guide = guide_legend(override.aes=aes(fill=NA))) +
scale_fill_manual(name="Bar",values=cols, guide="none") +
ylab("Symptom severity") + xlab("PHQ-9 symptoms") +
ylim(0,1.6) +
theme_bw() +
theme(axis.title.x = element_text(size = 15, vjust=-.2)) +
theme(axis.title.y = element_text(size = 15, vjust=0.3))

Sample Image

how to add manually a legend to ggplot

The hardest part here was recreating your data set for demonstration purposes. It's always better to add a reproducible example. Anyway, the following should be close:

library(ggplot2)

set.seed(123)

ID1.4.5.6.7 <- data.frame(Time = c(rep(1, 3),
rep(c(2, 3, 4, 5), each = 17)),
mRNA = c(rnorm(3, 0.1, 0.25),
rnorm(17, 0, 0.25),
rnorm(17, -0.04, 0.25),
rnorm(17, -0.08, 0.25),
rnorm(17, -0.12, 0.25)))

lm_mRNATime <- lm(mRNA ~ Time, data = ID1.4.5.6.7)

Now we run your code with the addition of a custom colour guide:

predict_ID1.4.5.6.7 <- predict(lm_mRNATime, ID1.4.5.6.7)
ID1.4.5.6.7$predicted_mRNA <- predict_ID1.4.5.6.7

colors <- c("data" = "Blue", "predicted_mRNA" = "red", "fit" = "Blue")

p <- ggplot( data = ID1.4.5.6.7, aes(x = Time, y = mRNA, color = "data")) +
geom_point() +
geom_line(aes(x = Time, y = predicted_mRNA, color = "predicted_mRNA"),
lwd = 1.3) +
geom_smooth(method = "lm", aes(color = "fit", lty = 2),
se = TRUE, lty = 2) +
scale_x_discrete(limits = c('0', '20', '40', '60', '120')) +
scale_color_manual(values = colors) +
labs(title = "ID-1, ID-4, ID-5, ID-6, ID-7",
y = "mRNA", x = "Time [min]", color = "Legend") +
guides(color = guide_legend(
override.aes = list(shape = c(16, NA, NA),
linetype = c(NA, 2, 1)))) +
theme(plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
legend.key.width = unit(30, "points"))

Sample Image



Related Topics



Leave a reply



Submit