This question already has answers here:
Add legend to ggplot2 line plot
(4 answers)
Closed 2 years ago.
I'm new to ggplot and I'm trying to figure out how to add a legend to a graph and re-label the x-axis. I've enclosed the plotting code and resulting graph . I would like to add a legend that explains what the blue line and the green and red dots are. I would also like the years on the x-axis to appear as 2018, 2019, ... , 2020 instead of 2017.5, 2010.0, ..., 2020.0. I can't find a solution in the online documentation. Thanks for your help.
ggplot(data = annual_rate_preds) +
geom_point(mapping = aes(x = year, y = predicted), color = 'green') +
geom_line(mapping = aes(x = year, y = observed), color = 'blue') +
geom_point(data = backfit_rate_preds, mapping = aes(x = target_year, y = rate_pred),
shape = 18, color = 'red', size = 2) +
theme(plot.title = element_text(size = 10))
Using some random example data this could be achieved like so:
Using scale_x_continuous(breaks = scales::pretty_breaks()) gives pretty x-axis breaks and labels
To get a legend you have to map on aesthetics, i.e. move color inside aes(). The color values can then be set via scale_color_manual
Labels for the axes, legend, ... can be set via labs()
Most tricky part is to get the legend right. To this end I make use of guides and guide_legend to adjust the legend such that for observed only a solid line is shown while for the other categories only points (shape 16) show up.
library(ggplot2)
set.seed(42)
annual_rate_preds <- data.frame(
predicted = runif(13, -.1, .1),
observed = runif(13, -.1, .1),
year = 2008:2020
)
backfit_rate_preds<- data.frame(
rate_pred = runif(13, -.1, .1),
target_year = 2008:2020
)
ggplot(data = annual_rate_preds) +
geom_point(mapping = aes(x = year, y = predicted, color = 'predicted')) +
geom_line(mapping = aes(x = year, y = observed, color = 'observed')) +
geom_point(data = backfit_rate_preds, mapping = aes(x = target_year, y = rate_pred, color = 'rate_pred'),
shape = 18, size = 2) +
scale_x_continuous(breaks = scales::pretty_breaks()) +
scale_color_manual(values = c(predicted = "green", observed = "blue", rate_pred = "red")) +
theme(plot.title = element_text(size = 10)) +
guides(color = guide_legend(override.aes = list(linetype = c("solid", "blank", "blank"), shape = c(NA, 16, 16)))) +
labs(x = "Year", y = NULL, color = NULL)
Related
I want to use ggplot to show points and lines, but I want there to be two legends - one for the points and one for the lines.
I managed to do this using the below code, but for some reason the 'size' option no longer responds in geom_point and they are stuck at the fairly ugly size you can see in the image
.
Note that I chose stroke = NA because I do not want the points to have a border. The code is below.
Any ideas?
ggplot(data = plot_data) +
geom_point(aes(x = z.1, y = obs, fill = treatcat), alpha = 0.4, shape = 21, stroke = NA, size = 1) +
geom_line(aes(x = z.1, y = under, colour = "True"), linetype = "dashed") +
geom_line(aes(x = z.1, y = crude, colour = "Crude"), size = 1.5) +
scale_fill_manual(name = "Treatment",
values = c("0" = "#F8766D", "1" = "#C77CFF"),
breaks = c("0", "1"),
labels = c("Untreated", "Treated")) +
scale_colour_manual(name = "Model",
values = c("Crude" = "orange", "True" = "black"),
breaks = c("Crude", "True"),
labels = c("Crude", "True")) +
ylim(-30,27.5) +
theme(plot.title = element_text(size = "12")) +
labs(title = "Fitted Values for Crude Model", x = "Z", y = "Y(1)")
Maybe you want two color scales, here a solution with ggnewscale. There are a couple of github packages with similar functionality on the horizon (relayer, and ggh4x), but currently this is the only CRAN option to my knowledge.
As per comment - I am using see::geom_point2 because I also don't like those strokes
library(ggplot2)
library(see)
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point2(aes(color = Petal.Width), alpha = 0.4, size = 10) +
ggnewscale::new_scale_color() +
geom_smooth(aes(color = Species), linetype = "dashed", method = "lm")
Currently, there is a bug in ggplot2 that makes it impossible to change size once stroke = NA (https://github.com/tidyverse/ggplot2/issues/4624). Apprarently, setting 'stroke = 0' also does not eliminate the border.
To do what you want, you need to set set color to 'transparent':
library(ggplot2)
df = data.frame(x=rnorm(100), y=rnorm(100))
ggplot(df, aes(x, y)) + geom_point(shape=21, stroke=0, fill="orange", color="transparent", size=8)
Created on 2021-09-20 by the reprex package (v2.0.1)
I'm having trouble setting a custom legend for confidence bands and dashed lines. This is my graph so far.
di<-matrix(ncol = 3,nrow = 5) %>% as.data.frame()
colnames(di)<-c('group','estimate','SE')
di<-di %>% mutate(group=1:5,
estimate=c(0.5,9.6,13,15,23.1),
SE=14)
ggplot(di, aes(x=group, y=estimate)) +
geom_point() +
geom_errorbar(width=.5, aes(ymin=estimate-(1.647*SE), ymax=estimate+(1.647*SE)), colour="black") +
xlab('Group') +
ylab('Treatment Effect') +
labs(title="GATE with confidence bands",
subtitle="Point estimates and confidence bands are derived using median of all splits") +
geom_hline(yintercept=c(7.83,22.55),
linetype="longdash",
col='darkred') +
geom_hline(yintercept=15.19,
linetype="longdash",
col='blue')
It looks like this:
However what I want it to look like is something like this, with the exact same legend:
Any advice on this?
This could be achieved like so:
As a general rule: If you want to have a legend you have to map something on aesthetics, e.g. move color=... into aes() for all four geoms
The desired color values can then be set via scale_color_manual
For the geom_hline we also have to pass yintercept as an aes() too. To this end these get something helper data frames with the desired values.
To fix the lines and shapes in the legend I make use of guide_legend's overide.aes to remove the undesired points in the legend as well as removing the line for the point. Additionally I set the number of rows for the legend to 2.
The labels and the order of the layers can be set via the labels and the breaks argument of scale_color_manual
Move the legend in the topleft and get rid of the background fill for the legend and the keys via theme options.
library(ggplot2)
di <- data.frame(
group = 1:5,
estimate = c(0.5, 9.6, 13, 15, 23.1),
SE = 14
)
labels <- c(point = "Point", error = "Error", blue = "Blue", darkred = "Red")
breaks <- c("blue", "darkred", "point", "error")
ggplot(di, aes(x = group, y = estimate)) +
geom_point(aes(color = "point"), size = 3) +
geom_errorbar(width = .5, aes(
ymin = estimate - (1.647 * SE),
ymax = estimate + (1.647 * SE),
color = "error"
)) +
scale_color_manual(values = c(
point = "black",
error = "black",
blue = "blue",
darkred = "darkred"
), labels = labels, breaks = breaks) +
labs(
title = "GATE with confidence bands",
subtitle = "Point estimates and confidence bands are derived using median of all splits",
x = "Group",
y = "Treatment Effect",
color = NULL, linetype = NULL, shape = NULL
) +
geom_hline(
data = data.frame(yintercept = c(7.83, 22.55)),
aes(yintercept = yintercept, color = "darkred"), linetype = "longdash"
) +
geom_hline(
data = data.frame(yintercept = 15.19),
aes(yintercept = yintercept, color = "blue"), linetype = "longdash"
) +
guides(color = guide_legend(override.aes = list(
shape = c(NA, NA, 16, NA),
linetype = c("longdash", "longdash", "blank", "solid")
), nrow = 2, byrow = TRUE)) +
theme(legend.position = c(0, 1),
legend.justification = c(0, 1),
legend.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA))
I am plotting a smooth to my data using geom_smooth and using geom_ribbon to plot shaded confidence intervals for this smooth. No matter what I try I cannot get a single legend that represents both the smooth and the ribbon correctly, i.e I am wanting a single legend that has the correct colours and labels for both the smooth and the ribbon. I have tried using + guides(fill = FALSE), guides(colour = FALSE), I also read that giving both colour and fill the same label inside labs() should produce a single unified legend.
Any help would be much appreciated.
Note that I have also tried to reset the legend labels and colours using scale_colour_manual()
The below code produces the below figure. Note that there are two curves here that are essentially overlapping. The relabelling and setting couours has worked for the geom_smooth legend but not the geom_ribbon legend and I still have two legends showing which is not what I want.
ggplot(pred.dat, aes(x = age.x, y = fit, colour = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci, fill = tagged), alpha = 0.2, colour = NA) +
theme_classic() +
labs(x = "Age (days since hatch)", y = "Body mass (g)", colour = "", fill = "") +
scale_colour_manual(labels = c("Untagged", "Tagged"), values = c("#3399FF", "#FF0033")) +
theme(axis.title.x = element_text(face = "bold", size = 14),
axis.title.y = element_text(face = "bold", size = 14),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
legend.text = element_text(size = 12))
The problem is that you provide new labels for the color-aesthetic but not for the fill-aesthetic. Consequently ggplot shows two legends because the labels are different.
You can either also provide the same labels for the fill-aesthetic (code option #1 below) or you can set the labels for the levels of your grouping variable ("tagged") before calling ggplot (code option #2).
library(ggplot2)
#make some data
x = seq(0,2*pi, by = 0.01)
pred.dat <- data.frame(x = c(x,x),
y = c(sin(x), cos(x)) + rnorm(length(x) * 2, 0, 1),
tag = rep(0:1, each = length(x)))
pred.dat$lci <- c(sin(x), cos(x)) - 0.4
pred.dat$uci <- c(sin(x), cos(x)) + 0.4
#option 1: set labels within ggplot call
pred.dat$tagged <- as.factor(pred.dat$tag)
ggplot(pred.dat, aes(x = x, y = y, color = tagged, fill = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci), alpha = 0.2, color = NA) +
scale_color_manual(labels = c("untagged", "tagged"), values = c("#F8766D", "#00BFC4")) +
scale_fill_manual(labels = c("untagged", "tagged"), values = c("#F8766D", "#00BFC4")) +
theme_classic() + theme(legend.title = element_blank())
#option 2: set labels before ggplot call
pred.dat$tagged <- factor(pred.dat$tag, levels = 0:1, labels = c("untagged", "tagged"))
ggplot(pred.dat, aes(x = x, y = y, color = tagged, fill = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci), alpha = 0.2, color = NA) +
theme_classic() + theme(legend.title = element_blank())
I have this plot
dat = data.frame(group = rep("A",3),subgroup= c("B","C","D"), value= c(4,5,6),avg = c(4.5,4.5,4.5))
ggplot(dat, aes(x= group, y =value, color = fct_rev(subgroup) ))+
geom_point()+
geom_point(data = dat ,aes(x = group, y = avg), color = "blue",pch = 17, inherit.aes = FALSE)
I need to show 2 legends: 1 for the fct_rev(subgroup) which I already there but there is no legend for "avg".
How can i add a legend that is a blue triangle pch 17 with the title "avg?
thank you
Maybe like this?
ggplot(dat, aes(x= group, y =value, color = fct_rev(subgroup) ))+
geom_point()+
geom_point(data = dat ,aes(x = group, y = avg,shape = "Mean"),
color = "blue", inherit.aes = FALSE) +
scale_shape_manual(values = c('Mean' = 17))
Using data from original post.
Legends do not work like that in ggplot. Why not add a geom_text at the average? I see that you have a column with the average being repeated. This seems like a bad way to handle the data, but irrelevant right now.
My proposed solution:
ggplot(dat)+
geom_point(aes(x= group, y =value, color = subgroup))+
geom_point(aes(x = group, y = avg), color = "blue",pch = 17, inherit.aes = FALSE) +
geom_text(aes(x=1, y = 4.5), label = "avg", nudge_x = .1)
You could also add a hline to symbolize the average, which would aesthetically look nicer.
I use bars and line to create my plot. The demo code is:
timestamp <- seq(as.Date('2010-01-01'),as.Date('2011-12-01'),by="1 mon")
data1 <- rnorm(length(timestamp), 3000, 30)
data2 <- rnorm(length(timestamp), 30, 3)
df <- data.frame(timestamp, data1, data2)
p <- ggplot()
p <- p + geom_histogram(data=df,aes(timestamp,data1),colour="black",stat="Identity",bindwidth=10)
p <- p + geom_line(data=df,aes(timestamp,y=data2*150),colour="red")
p <- p + scale_y_continuous(sec.axis = sec_axis(~./150, name = "data2"))
p <- p + scale_colour_manual(name="Parameter", labels=c("data1", "data2"), values = c('black', 'red'))
p <- p+ scale_shape_manual(name="Parameter", labels=c("data1", "data2"), values = c(15,95))
p
This results in a plot like this:
This figure does not have a legend. I followed this answer to create a customized legend but it is not working in my case. I want a square and line shape in my legend corresponding to bars and line. How can we get it?
I want legend as shown in below image:
For the type of data you want to display, geom_bar is a better fit then geom_histogram. When you to manipulate the appaerance of the legend(s), you need to place the colour = ... parts inside the aes. To get the desired result it probably best to use different types of legend for the line and the bars. In that way you are better able to change the appearance of the legends with guide_legend and override.aes.
A proposal for your problem:
ggplot(data = df) +
geom_bar(aes(x = timestamp, y = data1, colour = "black"),
stat = "Identity", fill = NA) +
geom_line(aes(x = timestamp, y = data2*150, linetype = "red"), colour = "red", size = 1) +
scale_y_continuous(sec.axis = sec_axis(~./150, name = "data2")) +
scale_linetype_manual(labels = "data2", values = "solid") +
scale_colour_manual(name = "Parameter\n", labels = "data1", values = "black") +
guides(colour = guide_legend(override.aes = list(colour = "black", size = 1),
order = 1),
linetype = guide_legend(title = NULL,
override.aes = list(linetype = "solid",
colour = "red",
size = 1),
order = 2)) +
theme_minimal() +
theme(legend.key = element_rect(fill = "white", colour = NA),
legend.spacing = unit(0, "lines"))
which gives: