ggplot overlay is overwriting my x axis timeline, how to prevent? - r

I have a ggplot which is doing exactly as I want till I add an overlay to it. The data to replicate are below, here's the ggplot:
timeline <- ggplot(dataset, aes(x = Month, y = Sessions,fill = Channel, group = Channel)) +
geom_area(alpha = 0.3) +
stat_summary(aes(group = 2), fun.y = sum, geom = 'line', size = 2, alpha = 0.5) +
theme(axis.text.x=element_text(angle=90, hjust=1),
axis.title.x = element_blank())
Results:
So far so good. Note the x-axis showing months in order. Then I add an overlay (see example data below to generate the variables in the code):
# make overlay representing TV
tv_begin <- sample(mts, 4)
tv_end <- tv_begin %m+% months(1)
tv_overlay <- data.frame(start = format(tv_begin, "%b-%Y"), end = format(tv_end, "%b-%Y"))
Then:
timeline + geom_rect(data = tv_overlay, inherit.aes = FALSE,
aes(xmin = start, xmax = end,
ymin = -Inf, ymax = Inf,
alpha = "TV On"),
fill = "black")
Results:
Now my x axis months are not ordered and I don't know how to prevent this happening? How can I maintain the x axis OR how can I have the new overlay inherit from them so that adding the overlay does not change the x-axis?
----Here's the data to replicate variable "dataset"-----
## Build dummy data
library(dplyr)
# dimensions
channels <- c("Facebook", "Youtube", "SEM", "Organic", "Direct", "Email")
last_month <- Sys.Date() %m+% months(-1) %>% floor_date("month")
mts <- seq(from = last_month %m+% months(-23), to = last_month, by = "1 month")
yr_month <- format(mts, "%b-%Y")
dimvars <- expand.grid(Month = yr_month, Channel = channels)
# metrics
rws <- nrow(dimvars)
set.seed(42)
# generates variablility in the random data
randwalk <- function(initial_val, ...){
initial_val + cumsum(rnorm(...))
}
Sessions <- ceiling(randwalk(3000, n = rws, mean = 8, sd = 1500)) %>% abs()
Transactions <- ceiling(randwalk(200, n = rws, mean = 0, sd = 75)) %>% abs()
Revenue <- ceiling(randwalk(10000, n = rws, mean = 0, sd = 3500)) %>% abs()
Spend <- ceiling(randwalk(6000, n = rws, mean = 0, sd = 3500)) %>% abs()
# make primary df
dataset <- cbind(dimvars, Sessions, Transactions, Revenue, Spend) %>%
mutate(Spend = ifelse(Channel %in% c("Direct", "Organic"), NA, Spend))

Remove the format() calls from your code. It turns everything to strings/factors.
Here I have converted x-axis data with as.Date(), and formatted the x-Axis in the plot with scale_x_date():
library(tidyverse)
library(lubridate)
# dimensions
channels <- c("Facebook", "Youtube", "SEM", "Organic", "Direct", "Email")
last_month <- Sys.Date() %m+% months(-1) %>% floor_date("month") %>% as.Date()
mts <- seq(from = last_month %m+% months(-23), to = last_month, by = "1 month") %>% as.Date()
#yr_month <- format(mts, "%b-%Y")
yr_month <- mts # format(mts, "%b-%Y")
dimvars <- expand.grid(Month = yr_month, Channel = channels, stringsAsFactors = FALSE)
rws <- nrow(dimvars)
set.seed(42)
# generates variablility in the random data
randwalk <- function(initial_val, ...){
initial_val + cumsum(rnorm(...))
}
Sessions <- ceiling(randwalk(3000, n = rws, mean = 8, sd = 1500)) %>% abs()
Transactions <- ceiling(randwalk(200, n = rws, mean = 0, sd = 75)) %>% abs()
Revenue <- ceiling(randwalk(10000, n = rws, mean = 0, sd = 3500)) %>% abs()
Spend <- ceiling(randwalk(6000, n = rws, mean = 0, sd = 3500)) %>% abs()
# make primary df
dataset <- cbind(dimvars, Sessions, Transactions, Revenue, Spend) %>%
mutate(Spend = ifelse(Channel %in% c("Direct", "Organic"), NA, Spend))
glimpse(dataset)
# make overlay representing TV
tv_begin <- sample(mts, 4)
tv_end <- tv_begin %m+% months(1)
tv_overlay <- data.frame(start = tv_begin, end = tv_end)
glimpse(tv_overlay)
timeline <- ggplot(dataset, aes(x = Month, y = Sessions,fill = Channel, group = Channel)) +
geom_area(alpha = 0.3) +
stat_summary(aes(group = 2), fun.y = sum, geom = 'line', size = 2, alpha = 0.5) +
theme(axis.text.x=element_text(angle=90, hjust=1),
axis.title.x = element_blank()) +
scale_x_date(date_labels = "%b-%d", date_breaks = "1 month")
timeline + geom_rect(data = tv_overlay, inherit.aes = FALSE,
aes(xmin = start, xmax = end,
ymin = -Inf, ymax = Inf,
alpha = "TV On"),
fill = "black")

Related

gganimate - have geom_rect adjust each frame

I have the following data:
library(ggplot2)
library(gganimate)
library(tidyverse)
createData<- function(vintage, id){#create data
# Generate a sequence of dates from 2010-01-01 to 2025-12-31 with a quarterly frequency
Dates <- seq(from = as.Date("2010-01-01"), to = as.Date("2025-12-31"), by = "quarter")
RLG<- cumsum(sample(c(-1, 1), 64, TRUE))
df<- data.frame( Dates,RLG, vintage,id)
return(df)
}
#createData
df<- createData("2018-01-01",1) %>%
rbind(createData("2019-01-01",2))%>%
rbind(createData("2020-01-01",3)) %>%
rbind(createData("2021-01-01",4))%>%
rbind(createData("2022-01-01",5))%>%
rbind(createData("2023-01-01",6))%>%
rbind(createData("2024-01-01",7))%>%
rbind(createData("2025-01-01",8))
Which I use to make the following chart:
options(gganimate.nframes = 8*length(unique(df$vintage)), gganimate.res = 30)
p<- ggplot(df) +
aes(x = Dates, y = RLG, group = as.Date(vintage), colour = "RLG") +
geom_line()+
scale_y_continuous(labels = \(x) paste0(x, "%"))+
theme(axis.title = element_blank(),legend.position="none")+
transition_time(id)+
exit_fade(alpha = 0.5)+
shadow_mark(alpha = 0.2)
animate(p, end_pause = 30)
I would like to add a geom_rect which goes from vintage to max(Dates). At each frame, vintage will increase, so the geom_rect will shrink slightly. How can I do this without interfering with the shadow_mark and exit_fades which I am applying to the lines?
If you mean something like a progress bar you could do it like so:
create an DF for the geom which is a subset of the original
df_geom <- df |>
mutate(vintage = as.Date(vintage)) |>
group_by(id) |>
slice(n())
Use geom_segment with the DF from above.
If you want to leave shadow_mark in you can do shadow_mark(exclude_layer = 2).
p <- ggplot(df) +
aes(x = Dates, y = RLG, group = as.Date(vintage), colour = RLG) +
geom_line()+
scale_y_continuous(labels = \(x) paste0(x, "%"))+
theme(axis.title = element_blank(),legend.position="none") +
geom_segment(
data = df_geom,
mapping = aes(x=vintage, xend=Dates,
y = 18, yend = 18),
size = 10, alpha =.4, color ='lightblue'
) +
transition_time(id)+
exit_fade(alpha = 0.5)
# shadow_mark(alpha = 0.2)
animate(p)

How can I view the exact values I generated in my graph?

I have made a graph but I don't know how to view the exact values of the bars on the graph. Here is my code in case it is needed. I also have a picture of my graph.
Step 1: Load the tidyverse and tidyquant:
install.packages("tidyverse")
install.packages("tidyquant")
library("tidyverse")
library("tidyquant")
#STEP 2: Getting stocks data:
stocks <- c("TSLA", "UPST", "PLTR", "SPOT", "SHOP", "SPY", "BND")
stocks_df <- tq_get(stocks, from = '2017-01-01')
#Step 3: Group data:
port <- tq_get(c("TSLA", "UPST", "PLTR", "SPOT", "SHOP", "SPY", "BND"),
from = '2017-01-01')%>%
group_by(symbol) %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = "daily",
col_rename = "ret")
#Step 4: Computing portfolio returns:
myport <- port %>% tq_portfolio(symbol,ret, c(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0))
benchmark <- port %>% tq_portfolio(symbol, ret, c(0, 0, 0, 0, 0, 0.6, 0.4))
#Step 5: Computing portfolio measure:
mVaR <- myport %>% tq_performance(portfolio.returns,
performance_fun = VaR,
p = 0.95,
method = "historical",
portfolio_method = "single") %>%
add_column(symbol = "MyPort", .before = 1)
bVaR <- benchmark %>% tq_performance(portfolio.returns,
performance_fun = VaR,
p = 0.95,
method = "gaussian",
portfolio_method = "single") %>%
add_column(symbol = "Benchmark", .before = 1)
#Step 6: Computing portfolio measure: Expected Shortfall (ES):
mES <- myport %>% tq_performance(portfolio.returns,
performance_fun = ES,
p = 0.95,
method = "historical",
portfolio_method = "single") %>%
add_column(symbol = "MyPort", .before = 1)
bES <- benchmark %>% tq_performance(portfolio.returns,
performance_fun = ES,
p = 0.95,
method = "gaussian",
portfolio_method = "single") %>%
add_column(symbol = "Benchmark", .before = 1)
#Step 7: Combining the results into a single table using rbind (row bind):
bothVaR <- rbind(mVaR, bVaR)
bothES <- rbind(mES, bES)
results <- inner_join(bothVaR, bothES)
#Step 8: Re-shaping the table into a data frame suitable for plotting:
results <- results %>%
pivot_longer(!symbol, names_to = "measure", values_to = "value")
#Step 9: Plot the results:
results %>% ggplot(aes(x = measure, y = abs(value), fill = symbol)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Value at Risk Approach to Measure a Diversified Portfolio",
x = "Risk Measure", y = " ", fill = " ") + theme_minimal() +
theme(plot.title = element_text(hjust = 0.5), legend.position = "top")
I tried looking up on Google but the examples they give is for a specific set of data with different names and values. I don't know to implement it into my code for my specific script and graph.
If you want to plot the values on the plot, this could work:
library(ggrepel)
results %>% ggplot(aes(x = measure, y = abs(value), fill = symbol)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Value at Risk Approach to Measure a Diversified Portfolio",
x = "Risk Measure", y = " ", fill = " ") + theme_minimal() +
theme(plot.title = element_text(hjust = 0.5), legend.position = "top") +
geom_text_repel(aes(label = round(abs(value), digits = 3)),
position = position_dodge(width = 1), direction = "y", size = 2.5)
One way to visualize the values when you hover over them is to use ggplotly as follow:
install.packages("plotly")
library(plotly)
Once you load the library, you store then your plot in a variable that I name
p
and do following:
plotly(p)

Legend for combined graph

I am trying to reproduce this figure (without the Portugal highlight):
The data (and figure) can be found in this link: https://stat.link/uz49al.
I imported and reshaped the data into a long format, but then I got stuck on how it would be possible to rearrange the legend entries in the same order as in the original.
I would very much appreciate your help!
Thanks!
Here is where I got:
# load data
f5_5_data_before <-
read_excel("uz49al.xlsx", sheet = "Figure1.20", range = "A32:E68")
names(f5_5_data_before)[1] <- "Country"
names(f5_5_data_before)[2] <- "Odds_ratio"
names(f5_5_data_before)[3] <- "SE"
names(f5_5_data_before)[4] <- "sig"
names(f5_5_data_before)[5] <- "non_sig"
f5_5_data_before$Country <- as.factor(f5_5_data_before$Country)
f5_5_data_before <- f5_5_data_before %>%
mutate(
category = case_when(
is.na(sig) ~ "Non-significant",
!is.na(sig) ~ "Significant"
),
value = case_when(
category == "Non-significant" ~ non_sig,
category == "Significant" ~ sig
)
)
f5_5_data_before$group2 <- "Before accounting for reading performance"
f5_5_data_after <-
read_excel("uz49al.xlsx", sheet = "Figure1.20", range = "A32:I68")
f5_5_data_after <- f5_5_data_after[, c(1, 6:9)]
names(f5_5_data_after)[1] <- "Country"
names(f5_5_data_after)[2] <- "Odds_ratio"
names(f5_5_data_after)[3] <- "SE"
names(f5_5_data_after)[4] <- "sig"
names(f5_5_data_after)[5] <- "non_sig"
f5_5_data_after$Country <- as.factor(f5_5_data_after$Country)
f5_5_data_after <- f5_5_data_after %>%
mutate(
category = case_when(
is.na(sig) ~ "Non-significant",
!is.na(sig) ~ "Significant"
),
value = case_when(
category == "Non-significant" ~ non_sig,
category == "Significant" ~ sig
)
)
f5_5_data_after$group2 <- "After accounting for reading performance"
# appending in long format
f5_5_data <- rbind(f5_5_data_after, f5_5_data_before)
# shaded rectangle
rect1 <- data.frame(
xmin = 14.5,
xmax = 15.5,
ymin = -Inf,
ymax = Inf
)
# figure
f5_5 <- ggplot() +
geom_col(data = f5_5_data %>% filter(group2 == "After accounting for reading performance"),
aes(x = reorder(Country,-Odds_ratio),
y = value,
fill = category,
colour = group2),
width=0.5,
) +
geom_point(
data = f5_5_data %>% filter(group2 == "Before accounting for reading performance"),
aes(x = Country,
y = value,
fill = category,
colour = group2),
shape = 23,
size = 3,
) +
geom_rect(
data = rect1,
aes(
xmin = xmin,
xmax = xmax,
ymin = ymin,
ymax = ymax
),
alpha = 0.5,
inherit.aes = FALSE
) +
scale_y_continuous(breaks = pretty_breaks(),
limits = c(0, 25),
expand = c(0, 0)) +
labs(x = NULL,
y = "Odds ratio") +
theme(axis.text.x = element_text(angle = 90))
print(f5_5)
This yields the following output:
As you can see, the legend looks substantially different and essentially I got stuck.
One option to achieve your desired result would be via the ggnewscale package which allows for multiple scales for the same aesthetic. Doing so we could map category on the fill aes in both the geom_col and the geom_point but have two different legends:
Note: I simplified your data wrangling code a bit.
library(readxl)
library(dplyr)
library(ggplot2)
library(ggnewscale)
url <- "https://stat.link/uz49al"
download.file(url, destfile = "uz49al.xlsx")
dat <- read_excel("uz49al.xlsx", sheet = "Figure1.20", range = "A32:I68")
dat <- list(
before = setNames(dat[, 1:5], c("Country", "Odds_ratio", "SE", "sig", "non_sig")),
after = setNames(dat[, c(1, 6:9)], c("Country", "Odds_ratio", "SE", "sig", "non_sig"))
) %>%
bind_rows(.id = "group2")
dat <- dat %>%
mutate(
category = if_else(is.na(sig), "nonsig", "sig"),
value = if_else(is.na(sig), non_sig, sig)
) %>%
select(-sig, -non_sig)
group2_labels <- c(after = "After accounting for reading performance", before = "Before accounting for reading performance")
rect1 <- data.frame(xmin = 14.5, xmax = 15.5, ymin = -Inf, ymax = Inf)
ggplot(dat, aes(x = reorder(Country,-Odds_ratio), y = value)) +
geom_col(data = ~filter(.x, group2 == "after"), aes(fill = category), width = 0.5) +
scale_fill_manual(labels = NULL, values = c(sig = "darkblue", nonsig = "steelblue"),
name = group2_labels[["after"]], guide = guide_legend(title.position = "right")) +
new_scale_fill() +
geom_point(data = ~filter(.x, group2 == "before"), aes(fill = category), size = 3, shape = 23, color = "lightblue") +
geom_rect(data = rect1, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.5, inherit.aes = FALSE) +
scale_fill_manual(labels = NULL, values = c(nonsig = "white", sig = "lightblue"), breaks = c("sig", "nonsig"),
name = group2_labels[["before"]], guide = guide_legend(title.position = "right")) +
scale_y_continuous(breaks = scales::pretty_breaks(), limits = c(0, 25), expand = c(0, 0)) +
labs(x = NULL, y = "Odds ratio") +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
legend.position = "top")

How to get a ggplot2 function of discrete geom_rect to obey the alpha (transparency) values

I have just ask and answered a question that I need some more help with. Here is the link:
How to gradient fill an annotation shape in ggplot2
My problem is that for the code I have generated, the geom_rect are not obeying the alpha parameters. The gradient is too dark. Here is the plot with an alpha of 0.15 and no gradient applied:
Here is the new plot that has gradient rectangles (the highest alpha was set to 0.1), clearly it is darker than 0.15:
I have included my code below. I am not sure what I am doing wrong, or if there is some function that is overriding the alpha parameters for the geom_rect. Additionally, I get one set of errors:
"Warning messages:
1: Removed 50 rows containing missing values (geom_rect).
2: Removed 50 rows containing missing values (geom_rect).
3: Removed 50 rows containing missing values (geom_rect).
4: Removed 50 rows containing missing values (geom_rect).
5: Removed 50 rows containing missing values (geom_rect). "
I recognize that the error message may be pertaining to the fact that some of the lighter geom_rects were removed for some reason, but I am unsure how to proceed.
Any help would be appreciated.
#Generate a similar dataset to the one I am working with.
library(lubridate);library(ggplot2);library(extrafont);library(openair)
NoOfHours <- as.numeric(ymd_hms("2019-6-1 00:00:00") - ymd_hms("2018-3-1 00:00:00"))*24
data1 <- as.data.frame(ymd_hms("2018-3-01 8:00:00") + hours(0:NoOfHours))
colnames(data1) <- 'date'
set.seed(10)
data1$level <- runif(nrow(data1), min = 0, max = 400)
Hours <- format(as.POSIXct(strptime(data1$date,"%Y-%m-%d %H:%M:%S",tz="")) ,format = "%H:%M:%S")
data1$hours <- Hours
Date <- format(as.POSIXct(strptime(data1$date,"%Y-%m-%d %H:%M:%S",tz="")) ,format = "%Y-%m-%d")
data1$date_date <- Date#output
month <- format(as.POSIXct(strptime(data1$date,"%Y-%m-%d %H:%M:%S",tz="")) ,format = "%m-%d")
data1$month<- month
start <- ceiling_date(ymd(data1$date_date[1]), "day", change_on_boundary = FALSE)
startdate <- as.Date(start) %m+% days(1)
enddate1 <- as.Date(startdate) %m+% years(1)
enddate<- as.Date(enddate1) %m-% days(1)
yeardata <- selectByDate(data1, start = startdate, end = enddate, year = 2018:2019) #select for a defined set of years
graphlimit <- 400
graphlength <- graphlimit/(1350/1750)
innerlimit <- -(graphlength*(200/1750))
plotlimit <- graphlength+innerlimit
starttimedate <- ymd_hms(paste(startdate, "01:00:00"))
endtimedate <- ymd_hms(paste(enddate1, "01:00:00"))
#This section helps determine the rotation of the geom jitter to align January 1 at 00:00:00 at the top
NoOfhours <- as.numeric(ymd_hms(starttimedate) - ymd_hms("2018-01-01 00:00:00"))*24
NoOfHours <- (8760/12)*(month(startdate)-1)
NoOfHoursall <- as.numeric(ymd_hms(endtimedate) - ymd_hms(starttimedate))*24
date_vals <- seq(from = ceiling_date(ymd(startdate), "month", change_on_boundary = FALSE), length.out = 12, by = "months")
finalcell <- length(yeardata$date)
#Dataframes to encompass the seasons.
spring <- data.frame(matrix(ncol = 0, nrow = 1))
spring$seasonstartdate <- ((yeardata$date[1]))
spring$seasonenddates <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-6-1")))])
spring$colour <- "springgreen4"
summer <- data.frame(matrix(ncol = 0, nrow = 1))
summer$seasonstartdate <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-6-1")))])
summer$seasonenddates <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-9-1")))])
summer$colour <- "goldenrod2"
fall <- data.frame(matrix(ncol = 0, nrow = 1))
fall$seasonstartdate <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-9-1")))])
fall$seasonenddates <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-12-1")))])
fall$colour <- "orangered3"
winter <- data.frame(matrix(ncol = 0, nrow = 1))
winter$seasonstartdate <- (yeardata$date[min(which(yeardata$date_date == ymd("2018-12-1")))])
winter$seasonenddates <- (yeardata$date[min(which(yeardata$date_date == ymd("2019-3-1")))])
winter$colour <- "orangered3"
spring1 <- data.frame(matrix(ncol = 0, nrow = 1))
spring1$seasonstartdate <- (yeardata$date[min(which(yeardata$date_date == ymd("2019-3-1")))])
spring1$seasonenddates <- (yeardata$date[finalcell])
spring1$colour <- "springgreen4"
#This function enables geom rectangles to be gradient filled, independently of a gradient fill within a plot.
ggplot_grad_rects <- function(n, ymin, ymax) {
y_steps <- seq(from = ymin, to = ymax, length.out = n + 1)
alpha_steps <- seq(from = 0, to = 0.2, length.out = n)
rect_grad <- data.frame(ymin = y_steps[-(n + 1)],
ymax = y_steps[-1],
alpha = alpha_steps)
rect_total <- merge(spring, rect_grad)
rect_total2 <- merge(summer, rect_grad)
rect_total3 <- merge(fall, rect_grad)
rect_total4 <- merge(winter, rect_grad)
rect_total5 <- merge(spring1, rect_grad)
ggplot(yeardata)+
geom_rect(data=rect_total,
aes(xmin=(seasonstartdate), xmax=(seasonenddates),
ymin=ymin, ymax=ymax,
alpha=alpha), fill="springgreen4") +
geom_rect(data=rect_total2,
aes(xmin=(seasonstartdate), xmax=(seasonenddates),
ymin=ymin, ymax=ymax,
alpha=alpha), fill="goldenrod2") +
geom_rect(data=rect_total3,
aes(xmin=(seasonstartdate), xmax=(seasonenddates),
ymin=ymin, ymax=ymax,
alpha=alpha), fill="orangered3") +
geom_rect(data=rect_total4,
aes(xmin=(seasonstartdate), xmax=(seasonenddates),
ymin=ymin, ymax=ymax,
alpha=alpha), fill="cornflowerblue") +
geom_rect(data=rect_total5,
aes(xmin=(seasonstartdate), xmax=(seasonenddates),
ymin=ymin, ymax=ymax,
alpha=alpha), fill="springgreen4") +
guides(alpha = FALSE)
}
plot <- ggplot_grad_rects(100, graphlimit, graphlength) +
scale_colour_gradientn(limits = c(0,1000), colours = c("grey","yellow","orangered1","red","red4","black"), values = c(0,0.1,0.2,0.5,0.8,1), breaks = c(0, 100, 200, 500, 800, 1000), oob = scales::squish, name = expression(atop("",atop(textstyle("Level"^2*"")))))+
geom_jitter(aes(x=date, y=level, color = level), alpha = 0.2, size = 1) +
theme(text = element_text(family="Calibri"), axis.title=element_text(size=16,face="bold"), axis.text.x = element_blank(), axis.text.y = element_text(size = 12))+
labs(x = NULL, y = bquote('Level'))+
scale_y_continuous(breaks = seq(0, graphlimit, 200),
limits = c(innerlimit,plotlimit))+
scale_alpha_identity() +
coord_polar(start = ((2*NoOfhours/NoOfHoursall)*pi))+
theme(legend.title = element_text(color = "black", size = 14, face = "bold"), panel.background = element_rect(fill = "white"), panel.grid = element_blank())
plot
Now with this fix incorporated:
I don't see a scale_alpha_identity or scale_alpha_continuous(range = c(0, 0.2)), so I suspect ggplot is mapping your various alpha values to the default range of (0.1, 1), regardless of the range of the underlying values.
Here's a short example:
library(tidyverse); library(lubridate)
my_data <- tibble(
date = seq.Date(ymd(20190101), ymd(20191231), by = "5 day"),
month = month(date),
color = case_when(month <= 2 ~ "cornflowerblue",
month <= 5 ~ "springgreen4",
month <= 8 ~ "goldenrod2",
month <= 11 ~ "orangered3",
TRUE ~ "cornflowerblue"))
my_data %>%
uncount(20, .id = "row") %>%
mutate(alpha_val = row / max(row) * 0.2) %>%
ggplot(aes(date, 5 + alpha_val * 5, fill = color, alpha = alpha_val)) +
geom_tile(color = NA) +
scale_fill_identity() +
scale_alpha_identity() +
expand_limits(y = 0) +
coord_polar() +
theme_void()

ggplot with overlay - name the overlay with additional labels

I have a plot with labels on the y axis for the groups within the area plot. I added an overlay and want to name these.
Reproducible data at the bottom. For context I'm showing website session data and want to overlay when TV Campaigns are running.
Here's my ggplot and what it looks like. Below that is the commands to generate random data that I am using.
timeline <- ggplot(dataset, aes(x = Month, y = Sessions,fill = Channel, group = Channel)) +
geom_area(alpha = 0.2) +
stat_summary(aes(group = 2), fun.y = sum, geom = 'line', size = 2, alpha = 0.5) +
theme(axis.text.x=element_text(angle=90, hjust=1),
axis.title.x = element_blank()) +
geom_rect(data = tv_overlay, inherit.aes = FALSE,
aes(xmin = start, xmax = end,
ymin = -Inf, ymax = Inf),
fill = "black", alpha = 0.1)
This produces the following plot. Note the rectangle overlays which are meant to denote a TV campaign. How can I add a label to say "TV Campaign" to these:
Reproducible data which will allow the above commands for timeline <- to run
# dimensions
channels <- c("Facebook", "Youtube", "SEM", "Organic", "Direct", "Email")
last_month <- Sys.Date() %m+% months(-1) %>% floor_date("month")
mts <- seq(from = last_month %m+% months(-23), to = last_month, by = "1 month")
yr_month <- format(mts, "%b-%Y")
dimvars <- expand.grid(Month = yr_month, Channel = channels)
# metrics
rws <- nrow(dimvars)
set.seed(42)
# generates variablility in the random data
randwalk <- function(initial_val, ...){
initial_val + cumsum(rnorm(...))
}
Sessions <- ceiling(randwalk(3000, n = rws, mean = 8, sd = 1500)) %>% abs()
Transactions <- ceiling(randwalk(200, n = rws, mean = 0, sd = 75)) %>% abs()
Revenue <- ceiling(randwalk(10000, n = rws, mean = 0, sd = 3500)) %>% abs()
# make primary df
dataset <- cbind(dimvars, Sessions, Transactions, Revenue)
# make TV and Mass df for overlays
tv_begin <- sample(mts, 4)
tv_end <- tv_begin %m+% months(1)
tv_overlay <- data.frame(start = format(tv_begin, "%b-%Y"), end = format(tv_end, "%b-%Y"))
Map alpha to a character values to get an extra legend entry:
ggplot(dataset, aes(x = Month, y = Sessions,fill = Channel, group = Channel)) +
geom_area(alpha = 0.2) +
stat_summary(aes(group = 2), fun.y = sum, geom = 'line', size = 2, alpha = 0.5) +
geom_rect(aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf, alpha = "TV Campaign"),
tv_overlay, inherit.aes = FALSE, fill = "black") +
scale_alpha_manual(name = '', values = c("TV Campaign" = 0.1)) +
theme(axis.text.x=element_text(angle=90, hjust=1),
axis.title.x = element_blank())

Resources