Include geom_segment in a legend in a separate group - r

How can I make the line (geom_segment) appear in the legend as a separate item in its own group?
The legend should look like:
Groups
g1
g2
Info
mean
The minimal code:
data_points <- tibble(x = c(rep(1:10, 2)), y = rnorm(20), group = c(rep("g1", 10), rep("g2", 10)))
data_line <- tibble(x = 1:10, y = 0.5)
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(aes(x = data_line$x[1], xend = data_line$x[10], y = data_line$y[1], yend = data_line$y[10]), color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red'))
Thanks in advance : )

Modified from Is it possible add legend for geom_point and geom_segment?.
library(ggplot2)
library(tibble)
data_points <- tibble(x = c(rep(1:10, 2)), y = rnorm(20), group = c(rep("g1", 10), rep("g2", 10)))
data_line <- tibble(x = 1:10, y = 0.5)
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(
aes(x = data_line$x[1], xend = data_line$x[10],
y = data_line$y[1], yend = data_line$y[10],
linetype = "mean"),
color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red')) +
scale_linetype_manual(name = "Info", values = c("mean" = 1))
change the order of legends
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(
aes(x = data_line$x[1], xend = data_line$x[10],
y = data_line$y[1], yend = data_line$y[10],
linetype = "mean"),
color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red')) +
scale_linetype_manual(name = "Info", values = c("mean" = 1)) +
guides(color = guide_legend(order = 2), linetype = guide_legend(order = 1))

Related

How to manually change line size and alpha values for ggplot2 lines (separated by factor)?

I want to create a graph where I can change the line size for each line c(1,2,3) and the alpha values for each line c(0.5,0.6,0.7). I tried to use scale_size_manual but it didn't make any difference. Any ideas on how to proceed?
var <- c("T","T","T","M","M","M","A","A","A")
val <- rnorm(12,4,5)
x <- c(1:12)
df <- data.frame(var,val,x)
ggplot(aes(x= x , y = val, color = var, group = var), data = df) +
scale_color_manual(values = c("grey","blue","black")) + geom_smooth(aes(x = x, y = val), formula = "y ~ x", method = "loess",se = FALSE, size = 1) + scale_x_continuous(breaks=seq(1, 12, 1), limits=c(1, 12)) + scale_size_manual(values = c(1,2,3))
To set the size and alpha values for your lines you have to map on aesthetics. Otherwise scale_size_manual will have no effect:
library(ggplot2)
ggplot(aes(x = x, y = val, color = var, group = var), data = df) +
scale_color_manual(values = c("grey", "blue", "black")) +
geom_smooth(aes(x = x, y = val, size = var, alpha = var), formula = "y ~ x", method = "loess", se = FALSE) +
scale_x_continuous(breaks = seq(1, 12, 1), limits = c(1, 12)) +
scale_size_manual(values = c(1, 2, 3)) +
scale_alpha_manual(values = c(.5, .6, .7))

Change ggplot2 legend order without changing the manually specified aesthetics

I need to make a graph with multiple kinds of data on it, and I'm plotting one type of data with lines and one type with points. I've added a manually specified legend to show which type is points and which is lines (admittedly, my approach is a bit hacky), and that's working except for the legend order. Here's a dummy example:
DF1 <- data.frame(X = 1:10,
Y = c(1:10*0.5, 1:10*0.25),
Fruit = rep(c("mango", "kiwi"), each = 10))
DF2 <- data.frame(X = 1:10,
Y = c(1:10*2, 1:10*4),
Cat = rep(c("tabby", "calico"), each = 10))
Empty <- data.frame(X = mean(DF$X),
Y = as.numeric(NA),
# Q = c(0, 1))
Type = c("Cat", "Fruit"))
Mygraph <- ggplot(DF1, aes(x = X, y = Y, color = Fruit)) +
geom_point() +
geom_line(data = DF2, aes(x = X, y = Y, linetype = Cat),
inherit.aes = F) +
labs(color = NULL, linetype = NULL) +
geom_point(data = Empty, aes(x = X, y = Y, alpha = Type),
inherit.aes = F) +
geom_line(data = Empty, aes(x = X, y = Y, alpha = Type),
inherit.aes = F) +
scale_alpha_manual(
name = "Type of item", values = c(1, 1),
breaks = c("Fruit", "Cat"),
guide = guide_legend(override.aes =
list(linetype = c("blank", "solid"),
shape = c(16, NA)))) +
theme_bw()
Mygraph
This graph looks pretty good:
But check out what happens to the "Type of item" bit when I try to specify the order:
Mygraph +
guides(alpha = guide_legend(order = 1),
linetype = guide_legend(order = 2),
color = guide_legend(order = 3))
Why do my specified aesthetics go away? How can I both specify what that part of the legend should look like and also specify that the order of the three parts of the legend should be 1. alpha, 2. linetype, and then 3. color?
You were attempting to override aesthetics for alpha in two places (ie guides() and scale_alpha...()), and ggplot was choosing to just interpret one of them. I suggest including your shape override with your legend order override, like this:
library(ggplot2)
ggplot(DF1, aes(x = X, y = Y, color = Fruit)) +
geom_point() +
geom_line(data = DF2, aes(x = X, y = Y, linetype = Cat), inherit.aes = F) +
labs(color = NULL, linetype = NULL) +
geom_point(data = Empty, aes(x = X, y = Y, alpha = Type), inherit.aes = F) +
geom_line(data = Empty, aes(x = X, y = Y, alpha = Type), inherit.aes = F) +
scale_alpha_manual(name = "Type of item", values = c(1, 1), breaks = c("Fruit", "Cat")) +
guides(alpha = guide_legend(order = 1,
override.aes=list(linetype = c("blank", "solid"),
shape = c(16,NA))),
linetype = guide_legend(order = 2),
color = guide_legend(order = 3)) +
theme_bw()
data:
DF1 <- data.frame(X = 1:10,
Y = c(1:10*0.5, 1:10*0.25),
Fruit = rep(c("mango", "kiwi"), each = 10))
DF2 <- data.frame(X = 1:10,
Y = c(1:10*2, 1:10*4),
Cat = rep(c("tabby", "calico"), each = 10))
Empty <- data.frame(X = mean(DF1$X),
Y = as.numeric(NA),
Type = c("Cat", "Fruit"))

ggplot with both `geom_vline` and `geom_hline`. Task: need separate legends

library(tidyverse)
library(lubridate)
y <- rnorm(100)
df <- tibble(y) %>%
mutate(os = factor(rep_len(1:5, 100)),
date = seq(from = ymd('2013-01-01'), by = 1, length.out = 100))
ggplot(df, aes(x = date, y = y, colour = os)) +
geom_line() +
geom_vline(
aes(xintercept = min(date), linetype = 'os 1'),
colour = 'red') +
geom_vline(
aes(xintercept = median(date), linetype = 'os 2'),
colour = 'blue') +
geom_hline(
aes(yintercept = 1, linetype = "dashed"),
colour = "black"
) +
scale_linetype_manual(
name = 'lines',
values = c('os 1' = 1, 'os 2' = 1),
guide = guide_legend(override.aes = list(colour = c('red', 'blue'))))
output:
What is wrong with output:
The geom_hline is missing.
The legend combines the vline and the hline to form a cross.
Correct output:
THe geom_hline should be drawn.
Need a separate legend for the vlines and hlines. i.e., lines in the vline legend should be vertical while lines in the hline legend should be horizontal.
This could be achieved by
Adding the hline to scale_linetype_manual
Making use of a custom key glyph as in this answer.
library(tidyverse)
library(lubridate)
set.seed(123)
y <- rnorm(100)
df <- tibble(y) %>%
mutate(os = factor(rep_len(1:5, 100)),
date = seq(from = ymd('2013-01-01'), by = 1, length.out = 100))
draw_key_cust <- function(data, params, size) {
if (data$colour %in% c("red", "blue"))
draw_key_vpath(data, params, size)
else
draw_key_path(data, params, size)
}
ggplot(df, aes(x = date, y = y, colour = os)) +
geom_line() +
geom_vline(
aes(xintercept = min(date), linetype = 'os 1'),
colour = 'red', key_glyph = "cust") +
geom_vline(
aes(xintercept = median(date), linetype = 'os 2'),
colour = 'blue', key_glyph = "cust") +
geom_hline(
aes(yintercept = 1, linetype = "dashed"),
colour = "black", key_glyph = "cust"
) +
scale_linetype_manual(
name = 'lines',
values = c('os 1' = 1, 'os 2' = 1, dashed = 2),
guide = guide_legend(override.aes = list(colour = c('red', 'blue', 'black'))))

Annotation on only the first facet of ggplot in R?

I have the following code that produce a ggplot that has text (i.e., "calibration") on both facets. I want the text be appeared on the first facet only. I tried a few things but didn't succeed. Any help would be appreciated.
library(ggplot2)
library(lubridate)
set.seed(123)
DF1 <- data.frame(Date = seq(as.Date("2001-01-01"), to = as.Date("2005-12-31"), by = "1 month"),
Ob = runif(60,1,5), L95 =runif(60, 0,4), U95 = runif(60,2,7), Sim = runif(60,1,5),
Loc = rep("Upstream", 60))
DF2 <- data.frame(Date = seq(as.Date("2001-01-01"), to = as.Date("2005-12-31"), by = "1 month"),
Ob = runif(60,1,5), L95 =runif(60, 0,4), U95 = runif(60,2,7), Sim = runif(60,1,5),
Loc = rep("Downstream", 60))
DF <- dplyr::bind_rows(DF1,DF2)
DF$Loc <- factor(DF$Loc, levels = c("Upstream","Downstream"))
ggplot(DF, aes(x = Date))+
geom_ribbon(aes(ymin = L95, ymax = U95), fill = "grey30", alpha = 0.4)+
geom_line(aes(y = Ob, color = "blue"), size = 1 )+
geom_line(aes(y = Sim, color = "black"), size = 1, linetype = "dashed")+
geom_vline(xintercept = as.Date("2004-12-01"),color = "red", size = 1.30)+
facet_wrap(~ Loc, ncol = 1, scales = "free_y")+
theme_bw()+
annotate(geom = "text", x = as.Date("2002-01-01"), y = 4, label = "Calibration")
Try this trick:
library(ggplot2)
#Code
ggplot(DF, aes(x = Date))+
geom_ribbon(aes(ymin = L95, ymax = U95), fill = "grey30", alpha = 0.4)+
geom_line(aes(y = Ob, color = "blue"), size = 1 )+
geom_line(aes(y = Sim, color = "black"), size = 1, linetype = "dashed")+
geom_vline(xintercept = as.Date("2004-12-01"),color = "red", size = 1.30)+
facet_wrap(~ Loc, ncol = 1, scales = "free_y")+
theme_bw()+
geom_text(data=data.frame(Date=as.Date("2002-01-01"),y=4,
label = "Calibration",Loc='Upstream'),
aes(y=y,label=label))
Output:
You can also use Loc=unique(DF$Loc)[1] in the geom_text() side. It will produce same output.

how to ggplot with upper and lower bound as shaded using facet_wrap in R?

I am trying to automate the process of plotting data using ggplot and the facet_wrap functionality. I want a single y-axis label instead individual plot Ob (i.e., A_Ob, B_ob etc) and also a single X-axis not all the plots having label for x-axis such as below. Below is my sample code using gridextra package. However, i would like to do it through facet_wrap as i have many other plots to draw which i think will save me sometime.
graphics.off()
rm(list = ls())
library(tidyverse)
library(gridExtra)
G1 = data.frame(A_Ob = runif(1000, 5, 50), A_Sim = runif(1000, 3,60), A_upper = runif(1000, 10,70), A_lower = runif(1000, 0, 45 ),
B_Ob = runif(1000, 5, 50), B_Sim = runif(1000, 3,60), B_upper = runif(1000, 10,70), B_lower = runif(1000, 0, 45 ),
C_Ob = runif(1000, 5, 50), C_Sim = runif(1000, 3,60), C_upper = runif(1000, 10,70), C_lower = runif(1000, 0, 45 ),
D_Ob = runif(1000, 5, 50), D_Sim = runif(1000, 3,60), D_upper = runif(1000, 10,70), D_lower = runif(1000, 0, 45 ),
Pos = 1:1000)
A1 = ggplot(data = G1, aes(x = Pos))+
geom_line(aes(y = A_Ob), col = "black")+
geom_line(aes(y = A_Sim), col = "blue")+
geom_vline(xintercept = 750, color = "red", size=1.5)+
geom_ribbon(aes(ymin = A_upper, ymax = A_lower), fill = "grey70")
B1 = ggplot(data = G1, aes(x = Pos))+
geom_line(aes(y = B_Ob), col = "black")+
geom_line(aes(y = B_Sim), col = "blue")+
geom_vline(xintercept = 750, color = "red", size=1.5)+
geom_ribbon(aes(ymin = B_upper, ymax = B_lower), fill = "grey70")
C1 = ggplot(data = G1, aes(x = Pos))+
geom_line(aes(y = C_Ob), col = "black")+
geom_line(aes(y = C_Sim), col = "blue")+
geom_vline(xintercept = 750, color = "red", size=1.5)+
geom_ribbon(aes(ymin = C_upper, ymax = C_lower), fill = "grey70")
D1 = ggplot(data = G1, aes(x = Pos))+
geom_line(aes(y = D_Ob), col = "black")+
geom_line(aes(y = D_Sim), col = "blue")+
geom_vline(xintercept = 750, color = "red", size=1.5)+
geom_ribbon(aes(ymin = D_upper, ymax = D_lower), fill = "grey70")
grid.arrange(A1,B1,C1,D1, nrow = 4)
Here is the result of the code
You need to reshape your dataframe into a longer format and separate values for Ob, Sim, upper and lower.
Using the function melt from data.table package can help you to achieve this:
library(data.table)
setDT(G1)
Ob_cols = grep("_Ob",colnames(G1),value = TRUE)
Sim_cols = grep("_Sim",colnames(G1),value = TRUE)
Upper_cols = grep("_upper",colnames(G1), value = TRUE)
Lower_cols = grep("_lower", colnames(G1), value = TRUE)
g.m <- melt(G1, measure = list(Ob_cols,Sim_cols,Upper_cols,Lower_cols), value.name = c("OBS","SIM","UP","LOW"))
levels(g.m$variable) <- c("A","B","C","D")
Pos variable OBS SIM UP LOW
1: 1 A 5.965488 29.167666 26.66783 29.97259
2: 2 A 23.855719 8.570245 43.75830 30.65616
3: 3 A 16.947887 51.201047 15.20758 39.76122
4: 4 A 49.883306 3.715319 34.38066 20.73177
5: 5 A 5.021938 3.102880 30.05036 32.05123
6: 6 A 19.887176 15.400853 53.67156 28.54982
and now, you can plot it:
library(ggplot2)
ggplot(g.m, aes(x = Pos))+
geom_line(aes(y = OBS), color = "black")+
geom_line(aes(y = SIM), color = "blue")+
geom_vline(xintercept = 750,color = "red", size = 1.5)+
geom_ribbon(aes(ymin = UP, ymax = LOW), fill = "grey70")+
facet_grid(variable~.)
EDIT: Adding annotations & renaming labels
To rename and replace facet labels, you can re-define levels of variable and use facet_wrap instead of facet_grid using ncol = 1 as argument.
To add multiple annotations on a single panel, you need to define a dataframe that you will use in geom_text.
Altogether, you have to do:
# renaming names of each facets:
levels(g.m$variable) <- c("M1","M2","M3","M4")
# Defining annotations to add:
df_text <- data.frame(label = c("Calibration", "Validation"),
x = c(740,760),
y = c(65,65),
hjust = c(1,0),
variable = factor("M1", levels = c("M1","M2","M3","M4")))
# Plotting
ggplot(g.m, aes(x = Pos))+
geom_line(aes(y = OBS), color = "black")+
geom_line(aes(y = SIM), color = "blue")+
geom_vline(xintercept = 750,color = "red", size = 1.5)+
geom_ribbon(aes(ymin = UP, ymax = LOW), fill = "grey70")+
facet_wrap(variable~., ncol = 1)+
theme(strip.text.x = element_text(hjust = 0),
strip.background = element_rect(fill = "white"))+
geom_text(data = df_text, aes(x = x, y = y, label = label, hjust = hjust), color = "red")
Does it look what you are expecting ?

Resources