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'))))
Related
I coded the following ggplot. The problem is that the design of the legend is flawed: The elements of the legend are interconnected with what appears to be dashed lines. How can this be removed? And furthermore, navy should be a dashed line, but it is shown as a solid one. Is there a possibility to change that? This is my code:
plot1 <- ggplot() +
geom_line(aes(x = datacom$Datum , y = datacom$`CDU/CSU`, colour = "black"),size=0.8) +
geom_line(aes(x = datacom$Datum , y = datacom$SPD, colour = "red"),size=0.8) +
geom_line(aes(x = datacom$Datum , y = datacom$GRÜNE, col = "green"),size=0.8) +
geom_line(aes(x = datacom$Datum , y = datacom$FDP, col = "gold1"),size=0.8) +
geom_line(aes(x = datacom$Datum , y = datacom$`Linke/PDS`, col = "darkred"),size=0.8) +
geom_line(aes(x = datacom$Datum[154:168] , y = datacom$Piraten[154:168], col = "tan1"),size=0.8) +
geom_line(aes(x = datacom$Datum[169:272] , y = datacom$AfD[169:272], col = "blue"),size=0.8) +
geom_line(aes(x = datacom$Datum , y = datacom$Sonstige, col = "grey"),size=0.8) +
geom_vline(aes(xintercept = datacom$Datum[263], color = "navy"), linetype="longdash",size = 0.5)+
geom_vline(xintercept = datacom$Datum[215], color = "navy", size = 0.5,linetype="longdash")+
geom_vline(xintercept = datacom$Datum[167], color = "navy", size = 0.5,linetype="longdash")+
geom_vline(xintercept = datacom$Datum[127], color = "navy", size = 0.5,linetype="longdash")+
geom_vline(xintercept = datacom$Datum[79], color = "navy", size = 0.5,linetype="longdash")+
geom_vline(xintercept = datacom$Datum[44], color = "navy", size = 0.5,linetype="longdash")+
scale_color_identity(name = NULL, labels = c(black = "CDU/CSU", red = "SPD",green="Die Grünen",gold1="FDP",darkred = "Die Linke/PDS",tan1="Piraten",blue="AfD",grey="Sonstige",navy="Bundestagswahlen"), guide = "legend") +
theme_bw() +
theme(legend.position = "bottom") +
theme(axis.text.x = element_text(angle = 90)) +
labs(title="Forsa-Sonntagsfrage Bundestagswahl in %")+ylab("Prozent")+xlab("Jahre")
plot1
Thanks in advance
Your code has a lot of unnecessary repetition and you are not taking advantage of the syntax of ggplot.
The reason for the vertical dashed lines in the legend is that one of your geom_vline calls includes a color mapping, so its draw key is being added to the legend. You can change its key_glyph to draw_key_path to fix this. Note that you only need a single geom_vline call, since you can have multiple x intercepts.
ggplot(datacom, aes(x = Datum)) +
geom_line(aes(y = `CDU/CSU`, colour = "black"), size = 0.8) +
geom_line(aes(y = SPD, colour = "red"), size = 0.8) +
geom_line(aes(y = GRÜNE, col = "green"), size = 0.8) +
geom_line(aes(y = FDP, col = "gold1"), size = 0.8) +
geom_line(aes(y = `Linke/PDS`, col = "darkred"),size = 0.8) +
geom_line(aes(y = Piraten, col = "tan1"),
data = datacom[154:168,], size = 0.8) +
geom_line(aes(y = AfD, col = "blue"),
data = datacom[169:272,], size = 0.8) +
geom_line(aes(y = Sonstige, col = "grey"), size = 0.8) +
geom_vline(data = datacom[c(263, 215, 167, 127, 79, 44),],
aes(xintercept = Datum, color = "navy"), linetype = "longdash",
size = 0.5, key_glyph = draw_key_path)+
scale_color_identity(name = NULL,
labels = c(black = "CDU/CSU", red = "SPD",
green = "Die Grünen", gold1 = "FDP",
darkred = "Die Linke/PDS",
tan1 = "Piraten", blue = "AfD",
grey = "Sonstige",
navy = "Bundestagswahlen"),
guide = "legend") +
theme_bw() +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 90)) +
labs(title = "Forsa-Sonntagsfrage Bundestagswahl in %",
y = "Prozent",
x = "Jahre")
An even better way to make your plot would be to pivot the data into long format. This would mean only a single geom_line call:
library(tidyverse)
datacom %>%
mutate(Piraten = c(rep(NA, 153), Piraten[154:168],
rep(NA, nrow(datacom) - 168)),
AfD = c(rep(NA, 168), AfD[169:272],
rep(NA, nrow(datacom) - 272))) %>%
pivot_longer(-Datum, names_to = "Series") %>%
ggplot(aes(x = Datum, y = value, color = Series)) +
geom_line(size = 0.8, na.rm = TRUE) +
geom_vline(data = datacom[c(263, 215, 167, 127, 79, 44),],
aes(xintercept = Datum, color = "Bundestagswahlen"),
linetype = "longdash", size = 0.5, key_glyph = draw_key_path) +
scale_color_manual(name = NULL,
values = c("CDU/CSU" = "black", SPD = "red",
"GRÜNE" = "green", FDP = "gold1",
"Linke/PDS" = "darkred",
Piraten = "tan1", AfD = "blue",
Sonstige = "grey",
"Bundestagswahlen" = "navy")) +
theme_bw() +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 90)) +
labs(title = "Forsa-Sonntagsfrage Bundestagswahl in %",
y = "Prozent",
x = "Jahre")
Data used to create plot
Obviously, I had to create some data to get your code to run, since you didn't supply any. Here is my code for creating the data
var <- seq(5, 15, length = 280)
datacom <- data.frame(Datum = seq(as.POSIXct("1999-01-01"),
as.POSIXct("2022-04-01"), by = "month"),
`CDU/CSU` = 40 + cumsum(rnorm(280)),
SPD = 40 + cumsum(rnorm(280)),
GRÜNE = rpois(280, var),
FDP = rpois(280, var),
`Linke/PDS` = rpois(280, var),
Piraten = rpois(280, var),
AfD = rpois(280, var),
Sonstige = rpois(280, var), check.names = FALSE)
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))
foo <- function() {
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 = 'black', key_glyph = "cust") +
geom_hline(
aes(yintercept = 1, linetype = "dashed"),
colour = "blue", key_glyph = "cust"
) +
geom_hline(
aes(yintercept = -1, linetype = "dashed 2"),
colour = "purple", key_glyph = "cust"
) +
scale_linetype_manual(
name = 'lines',
values = c(2, 2, 1, 1),
guide = guide_legend(override.aes = list(colour = c('red', 'black', 'blue', "purple"))))
}
foo()
because draw_key_cust is defined inside of foo, it can't find it. If I define it inside of the global environment, then it will work.
How to make it work without having to define the function in the global environment?
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 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))
I want to plot a graph. Several of my x-axis labels have a common label. So I want to add common text as label instead of several separate labels on x-axis as shown in the attached images. How can this be done?
library(dplyr)
library(forcats)
library(ggplot2)
df <- data.frame(conc = c(0, 10, 50, 100, "Positive Control"),
values = c(3, 3, 4, 5, 10),
name = c("TiO2 NP", "TiO2 NP", "TiO2 NP", "TiO2 NP", "Cyclophosamide"))
df$conc <- as.factor(df$conc)
labels2 <- paste0(df$conc, "\n", df$name)
df %>%
mutate(conc = fct_reorder(conc, values)) %>%
ggplot(aes(x = conc, y=values, fill = conc))+
geom_bar(stat = "identity",show.legend = FALSE, width = 0.6)+
scale_x_discrete(labels = labels2)+
labs(x = "\n Dose (mg/kg BW)")
I don't think there's a simple way. You have to play with ggplot2 for some time to make something really custom. Here's my example:
df %>%
mutate(
conc = fct_reorder(conc, values),
labels2 = if_else(
name == 'TiO2 NP',
as.character(conc),
paste0(conc, '\n', name)
)
) %>%
ggplot(aes(x=conc, y=values, fill = conc)) +
geom_bar(
stat = "identity",
show.legend = FALSE,
width = 0.6
) +
geom_rect(aes(
xmin = .4,
xmax = 5.6,
ymin = -Inf,
ymax = 0
),
fill = 'white'
) +
geom_text(aes(
y = -.4,
label = labels2
),
vjust = 1,
size = 3.4,
color = rgb(.3, .3, .3)
) +
geom_line(data = tibble(
x = c(.9, 4.1),
y = c(-1.2, -1.2)
),
aes(
x = x,
y = y
),
color = rgb(.3, .3, .3),
inherit.aes = FALSE
) +
geom_curve(data = tibble(
x1 = c(.8, 4.1),
x2 = c(.9, 4.2),
y1 = c(-.8, -1.2),
y2 = c(-1.2, -.8)
),
aes(
x = x1,
y = y1,
xend = x2,
yend = y2
),
color = rgb(.3, .3, .3),
inherit.aes = FALSE
) +
geom_text(aes(
x = 2.5,
y = -1.7,
label = 'TiO2 NP'
),
size = 3.4,
color = rgb(.3, .3, .3),
check_overlap = TRUE
) +
geom_text(aes(
x = 3,
y = -2.4,
label = '\n Dose (mg/kg BW)'
),
show.legend = FALSE,
check_overlap = TRUE
) +
theme_minimal() +
theme(
axis.text.x = element_blank(),
axis.title.x = element_blank()
) +
scale_y_continuous(
breaks = seq(0, 10, 2.5),
limits = c(-2.5, 10)
)
For a more automated approach, you can try placing the common variable in facet_grid with scales = "free", space = "free", to simulate a 2nd x-axis line. The rest of the code below are for aesthetic tweaks:
df %>%
mutate(conc = fct_reorder(conc, values)) %>%
ggplot(aes(x = conc, y = values, fill = conc)) +
geom_col(show.legend = F, width = 0.6) + #geom_col() is equivalent to geom_bar(stat = "identity")
facet_grid(~ fct_rev(name),
scales = "free", space = "free",
switch = "x") + #brings the facet label positions from top (default) to bottom
scale_x_discrete(expand = c(0, 0.5)) + #adjusts the horizontal space at the ends of each facet
labs(x = "\n Dose (mg/kg BW)") +
theme(axis.line.x = element_line(arrow = arrow(ends = "both")), #show line (with arrow ends) to
#indicate facet label's extent
panel.spacing = unit(0, "cm"), #adjusts space between the facets
strip.placement = "outside", #positions facet labels below x-axis labels
strip.background = element_blank()) #transparent background for facet labels