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))
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())
plot() in R - how to shade an area between two vertical lines?
I'd use ggplot doing this:
library(ggplot2)
df = cbind(1980:2019,runif(40,0,1))
df=as.data.frame(df)
ggplot() +
geom_rect(aes(xmin=1990, xmax=2001,ymin=-Inf,ymax=Inf), fill='red', alpha= 0.3)+
geom_line(data=df,aes(x=V1,y = V2), color = "darkred")+
theme_classic()
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)
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))
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))
Fill area between multiple lines in plot
Here is an approach:
a = data.frame(time = c(1:100), x = rnorm(100))
b = data.frame(time = c(1:100), y = rnorm(100))
c = data.frame(time = c(1:100), z = rnorm(100))
calculate the pmin
and pmax
:
min_a <- pmin(a, b, c)
max_a <- pmax(a, b, c)
construct the polygon as usual:
polygon(c(c$time, rev(c$time)), c(max_a$x ,rev(min_a$x)), col = rgb(1, 0, 0,0.5) )
or using ggplot:
library(tidyverse)
data.frame(a, b, c) %>% #combine the three data frames
group_by(time) %>% # group by time for next step
mutate(max = max(x, y, z), # calculate max of x, y, z in each time
min = min(x, y, z)) %>% #same as above
select(-time.1, - time.2) %>% #discard redundant columns
gather(key, value, 2:4) %>% #convert to long format so you can color by key in the geom line call
ggplot()+
geom_ribbon(aes(x = time, ymin= min, ymax = max), fill= "red", alpha = 0.3)+
geom_line(aes(x = time, y = value, color = key))
shading area between two lines in r
If I understand you correctly, you can get what you want by using the little-known panel.first=
argument to plot.default()
:
plot(x,type="h",
panel.first = {
usr <- par('usr')
rect(c(1,7), usr[3], c(3,10), usr[4], col='green', border=NA)
})
Or, to avoid any mucking around with par('usr')
values, just do:
plot(x, type="h",
panel.first = rect(c(1,7), -1e6, c(3,10), 1e6, col='green', border=NA))
Graph with a shaded the area occupied by multiple lines
You just need to group per individual time unit and calculate the minimum / maximum values. This allows you to plot a geom_ribbon
:
example %>%
group_by(values) %>%
summarize(min = min(value), max = max(value)) %>%
ggplot() +
geom_ribbon(aes(x = values, ymin = min, ymax = max), size = 2,
fill = "#29c8e5", color = "black") +
theme_classic()
If you would rather have the ribbon overlying your original plot, you could do:
ribbon <- example %>%
group_by(values) %>%
summarize(min = min(value), max = max(value))
graph1 +
geom_ribbon(aes(x = values, ymin = min, ymax = max),
data = ribbon, size = 0, fill = "#29c8e5",
color = NA, alpha = 0.3, inherit.aes = FALSE)
For what it's worth, I think the first option is more visually striking.
Shade area between 2 curves
Because, in this case, there isn't really any curve to the line you could use something very simple (that highlights how polygon works).
x <- c(0,1,1,0)
y <- c(x[1:2]/2, x[3:4]/4)
polygon(x,y, col = 'green', border = NA)
Now, if you had a curve you'd need more vertices.
curve(x^2, from=0 , to =1, col="darkblue")
curve(x^4, from=0 , to =1, add=T, col="darkred")
x <- c(seq(0, 1, 0.01), seq(1, 0, -0.01))
y <- c(x[1:101]^2, x[102:202]^4)
polygon(x,y, col = 'green', border = NA)
(extend the range of that last curve and see how using similar code treats the crossing curves yourself)
R - Fill area between lines based on top value
The reason you're getting the wrong shading is probably because the data is a bit on the coarse side. My advice would be to interpolate the data first. Assuming dat1
is from your example.
library(ggplot2)
# From long data to wide data
dat2 <- tidyr::pivot_wider(dat1, values_from = value, names_from = var)
# Setup interpolated data (tibble because we can then reference column x)
dat3 <- tibble::tibble(
x = seq(min(dat2$month), max(dat2$month), length.out = 1000),
rainfall = with(dat2, approx(month, rainfall, xout = x)$y),
evaporation = with(dat2, approx(month, evaporation, xout = x)$y)
)
Then, we need to find a way to identify groups, and here is a helper function for that. Group IDs are based on the runs in run length encoding.
# Make function to identify groups
rle_id <- function(x) {
x <- rle(x)
rep.int(seq_along(x$lengths), x$lengths)
}
And now we can plot it.
ggplot(dat3, aes(x)) +
geom_ribbon(aes(ymin = pmin(evaporation, rainfall),
ymax = pmax(evaporation, rainfall),
group = rle_id(sign(rainfall - evaporation)),
fill = as.factor(sign(rainfall - evaporation))))
Created on 2021-02-14 by the reprex package (v1.0.0)
Related Topics
Build Word Co-Occurence Edge List in R
Why Does ".." Work to Pass Column Names in a Character Vector Variable
Ggplot2: Dashed Line in Legend
Calculating Standard Deviation Across Rows
Edit Individual Ggplots in Ggally::Ggpairs: How to Have the Density Plot Not Filled in Ggpairs
Running an R Script Using a Windows Shortcut
Split a File Path into Folder Names Vector
Add Columns to a Reactive Data Frame in Shiny and Update Them
Rmarkdown::Render() in a Loop - Cannot Allocate Vector of Size
Import All the Functions of a Package Except One When Building a Package
How to Use "Cast" in Reshape Without Aggregation
Error: X Must Be Atomic for 'Sort.List'
Use Object Names as List Names in R
Grouped Correlation with Dplyr (Works Only on Console)