Shade Region Between Two Lines with Ggplot

Shade region between two lines with ggplot

How about using geom_ribbon instead

ggplot(x, aes(x=x, y=twox)) + 
geom_line(aes(y = twox)) +
geom_line(aes(y = x2)) +
geom_ribbon(data=subset(x, 2 <= x & x <= 3),
aes(ymin=twox,ymax=x2), fill="blue", alpha=0.5) +
scale_y_continuous(expand = c(0, 0), limits=c(0,20)) +
scale_x_continuous(expand = c(0, 0), limits=c(0,5)) +
scale_fill_manual(values=c(clear,blue))

plot

How to color/shade the area between two lines in ggplot2?

I think it would be easier to keep the data into a wider format and then use geom_ribbon to create that shaded area:

df %>% 
as_tibble() %>%
ggplot +
geom_line(aes(Month, Model, color = 'Model')) +
geom_line(aes(Month, Observation, color = 'Observation')) +
geom_ribbon(aes(Month, ymax=`Upper Limit`, ymin=`Lower Limit`), fill="grey", alpha=0.25) +
scale_x_continuous(breaks = seq(1, 12, by = 1)) +
scale_y_continuous(breaks = seq(0, 140, by = 20)) +
scale_color_manual(values = c('Model' = 'yellow','Observation' = 'red')) +
ylab("Precipitation [mm]") +
theme_bw() +
theme(legend.title = element_blank())

Sample Image

How to highlight area between two lines? ggplot

A geom_ribbon is exactly what you need

ggplot(data = df,aes(time,x))+
geom_ribbon(aes(x=time, ymax=x.upper, ymin=x.lower), fill="pink", alpha=.5) +
geom_line(aes(y = x.upper), colour = 'red') +
geom_line(aes(y = x.lower), colour = 'blue')+
geom_line()

Sample Image

Shade area between two lines defined with function in ggplot

Try putting the functions into the data frame that feeds the figure. Then you can use geom_ribbon to fill in the area between the two functions.

mydata = data.frame(x=c(0:100),
func1 = sapply(mydata$x, FUN = function(x){20*sqrt(x)}),
func2 = sapply(mydata$x, FUN = function(x){50*sqrt(x)}))

ggplot(mydata, aes(x=x, y = func2)) +
geom_line(aes(y = func1)) +
geom_line(aes(y = func2)) +
geom_ribbon(aes(ymin = func2, ymax = func1), fill = "blue", alpha = .5)

Sample Image

Shade Area between crossing lines differently with ggplot

Try this. You have to condition the fill color on whether Q is on the left or on the right and use scale_fill_manual to set the fill colors:

#Break-even Chart
Q <- seq(0,50,1)
FC <- 50
P <- 7
VC <- 3.6
total_costs <- (FC + VC*Q)
total_revenues <- P*Q
BEP <- round(FC / (P-VC) + 0.5)

df_bep_chart <- as.data.frame(cbind(total_costs, total_revenues, Q))

library(ggplot2)

ggplot(df_bep_chart, aes(Q, total_costs)) +
geom_line(group=1, size = 1, col="darkblue") +
geom_line(aes(Q, total_revenues), group=1, size = 1, col="darkblue") +
theme_bw() +
geom_ribbon(aes(ymin = total_revenues, ymax = total_costs, fill = ifelse(Q <= BEP, "red", "green")), alpha = .5) +
scale_fill_manual(values = c(red = "red", green = "green")) +
guides(fill = FALSE) +
geom_vline(aes(xintercept = BEP), col = "green") +
geom_hline(aes(yintercept = FC), col = "red") +
labs(title = "Break-Even Chart",
subtitle = "BEP in Green, Fixed Costs in Red") +
xlab("Quanity") +
ylab("Money")

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

Use ggplot2 to shade the area between two straight lines

You need to use coord_casterian instead of scale_._continous not to remove some values.

ggplot(df,aes(x=x)) + 
geom_line(aes(y=yone)) +
geom_line(aes(y=ytwo)) +
geom_ribbon(aes(ymin = yone, ymax = ytwo),fill='blue',alpha=0.5) +
geom_hline(yintercept=17) +
geom_vline(xintercept=17) +
geom_hline(yintercept=18) +
geom_vline(xintercept=18) +
coord_cartesian(xlim = c(17,18), ylim = c(17,18))

Sample Image

Additional code

df %>%
rowwise %>%
mutate(ytwo = max(17, ytwo),
yone = min(18, yone)) %>%
ggplot(aes(x=x)) +
geom_line(aes(y=yone)) +
geom_line(aes(y=ytwo)) +
geom_ribbon(aes(ymin = yone, ymax = ytwo),fill='blue',alpha=0.5) +
theme_bw() +
geom_hline(yintercept=17) +
geom_vline(xintercept=17) +
geom_hline(yintercept=18) +
geom_vline(xintercept=18) +
coord_cartesian(xlim = c(17,18), ylim = c(17,18))

Sample Image

shade area between lines; ggplot

What you need is geom_ribbon, and for that you need to define ymin (lower bound) and ymax (upper bound). Now you can't read this information from your long format. Not sure how you want to label your graph, so the first solution I show is a quick fix without changing too much:

#create CI data for L
dataCI_L <- saisonEsiegFavgLTlong %>%
filter(grepl("^ciL",Variable)) %>%
spread(Variable,Wert)
#create CI data for T
dataCI_T <- saisonEsiegFavgLTlong %>%
filter(grepl("^ciT",Variable)) %>%
spread(Variable,Wert)

ggplot(saisonEsiegFavgLTlong,aes(x=Saison0719,y=Wert, color=Variable))+
geom_line()+
#first ribbon
geom_ribbon(data=dataCI_L,inherit.aes=FALSE,
aes(x=Saison0719,ymin=ciLuntergrenze,ymax=ciLobergrenze),alpha=0.4,fill="grey80")+
#second ribbon
geom_ribbon(data=dataCI_T,inherit.aes=FALSE,
aes(x=Saison0719,ymin=ciTuntergrenze,ymax=ciTobergrenze),alpha=0.4,fill="grey40")+
geom_vline(xintercept=2011, size = 0.35)+
scale_y_continuous(name="Gewinnwahrscheinlichkeit",limits = c(0.55,0.775),
breaks=c(0.55,0.575,0.6,0.6,0.625,0.65,0.675,0.7,0.725,0.75))+
scale_x_continuous(name = "Saison", limits = c(2007, 2018),
breaks = c(2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018))+
ggtitle("Gewinnwahrscheinlichkeit mit Konfidenzintervall")+
theme(panel.background = element_rect(fill = "white", colour = "black"))+
theme(panel.grid.major = element_line(size = 0.25, linetype = 'solid', colour = "light grey"))+
theme(axis.ticks = element_line(size = 1))+
theme(plot.title = element_text(lineheight=.8, face="bold"))+
scale_color_manual(values=c("grey80","grey80","grey40","grey40","red","blue"))

Sample Image

The solution is a bit messy, so would be better to start with the correct format:

# had to do this to get your data back
df<- spread(saisonEsiegFavgLTlong,Variable,Wert)
# put your L in one frame and T in another frame
# give each of them a group
df_L <- df[,c("Saison0719","EsiegFavgL","ciLobergrenze","ciLuntergrenze")]
colnames(df_L) <- c("Saison0719","EsiegFavg","obergrenze","untergrenze")
df_L$group = "EsiegFavgL"
df_T <- df[,c("Saison0719","EsiegFavgT","ciTobergrenze","ciTuntergrenze")]
colnames(df_T) <- c("Saison0719","EsiegFavg","obergrenze","untergrenze")
df_T$group = "EsiegFavgT"

# combine, and we create a similar group, used to label your CI
plotdf <- rbind(df_L,df_T)
plotdf$ci_group <- sub("EsiegFavg","CI_",plotdf$group)

#plot like before

ggplot(plotdf,aes(x=Saison0719,y=EsiegFavg))+
geom_line(aes(col=group)) +
geom_ribbon(aes(ymin=untergrenze,ymax=obergrenze,fill=ci_group),
alpha=0.4,linetype="dotted",col="grey60") +
scale_color_manual(values=c("red","blue"))+
scale_fill_manual(values=c("grey80","grey40"))

Sample Image

r - ggplot2 - create a shaded region between two geom_abline layers

Personally, I think that creating the data frames and using geom_ribbon is the elegant solution, but obviously opinions will differ on that score.

But if you take full advantage of plyr and ggplot things can get pretty slick. Since your slopes and intercepts are all nicely stored in a dataframe anyway, we can use plyr and a custom function to do all the work:

dat <- data.frame(cond1=c("a","a","b","b"),
cond2=c("c","d","c","d"),
x=c(1,5),
y=c(1,5),
sl=c(1,1.2,0.9,1.1),
int=c(0,0.1,0.1,0),
slopeU=c(1.1,1.3,1.2,1.2),
slopeL=c(.9,1,0.7,1))

genRibbon <- function(param,xrng){
#xrng is a vector of min/max x vals in original data
r <- abs(diff(xrng))
#adj for plot region expansion
x <- seq(xrng[1] - 0.05*r,xrng[2] + 0.05*r,length.out = 3)
#create data frame
res <- data.frame(cond1 = param$cond1,
cond2 = param$cond2,
x = x,
y = param$int + param$sl * x,
ymin = param$int + param$slopeL * x,
ymax = param$int + param$slopeU * x)
#Toss the min/max x vals just to be safe; needed them
# only to get the corresponding y vals
res$x[which.min(res$x)] <- -Inf
res$x[which.max(res$x)] <- Inf
#Return the correspondinng geom_ribbon
geom_ribbon(data = res,aes(x = x,y=y, ymin = ymin,ymax = ymax,
fill = cond1,colour = NULL),
alpha = 0.5)
}

ribs <- dlply(dat,.(cond1,cond2),genRibbon,xrng = c(1,5))

The extra slick thing here is that I'm discarding the generated data frames completely and just returning a list of geom_ribbon objects. Then they can simply be added to our plot:

p + ribs + 
guides(fill = guide_legend(override.aes = list(alpha = 0.1)))

I overrode the alpha aesthetic in the legend because the first time around you couldn't see the diagonal lines in the legend.

Sample Image

I'll warn you that the last line there that generates the plots also throws a lot of warnings about invalid factor levels, and I'm honestly not sure why. But the plot looks ok.



Related Topics



Leave a reply



Submit