Shading region between vertical and diagonal lines in ggplot - r

I am trying to use ggplot to shade the region between the vertical line and the diagonal line as shown below. Is there a way to do this?
df <- data.frame(x=c(1,-1), y=c(1,-1))
ggplot(df, aes(x, y)) +
geom_point() +
geom_abline(slope=-1) +
geom_vline(xintercept = 0)

It is a bit tricky, but if you know the coordinates of the area (Inf), you can use them to fill the shades using geom_polygon like this:
library(ggplot2)
df <- data.frame(x=c(1,-1), y=c(1,-1))
upper_area <- data.frame(x=c(-Inf,0,0),y=c(Inf,Inf,0))
down_area <- data.frame(x=c(0,0,Inf),y=c(0,-Inf,-Inf))
ggplot(df, aes(x, y)) +
geom_point() +
geom_abline(slope=-1) +
geom_vline(xintercept = 0) +
geom_polygon(aes(x=x, y=y), data=upper_area, fill="red") +
geom_polygon(aes(x=x, y=y), data=down_area, fill="blue")
Created on 2022-07-15 by the reprex package (v2.0.1)
old answer
It is a bit tricky, but if you know the coordinates of the area, you can use them to fill the shades using geom_polygon like this:
library(ggplot2)
df <- data.frame(x=c(1,-1), y=c(1,-1))
upper_area <- data.frame(x=c(-1,0,0),y=c(1,1,0))
down_area <- data.frame(x=c(0,0,1),y=c(0,-1,-1))
ggplot(df, aes(x, y)) +
geom_point() +
geom_abline(slope=-1) +
geom_vline(xintercept = 0) +
geom_polygon(aes(x=x, y=y), data=upper_area, fill="red") +
geom_polygon(aes(x=x, y=y), data=down_area, fill="blue")
Created on 2022-07-15 by the reprex package (v2.0.1)

One option would be to use annotate with geom="ribbon":
df <- data.frame(x=c(1,-1), y=c(1,-1))
library(ggplot2)
ggplot(df, aes(x, y)) +
geom_point() +
# 1.1 = 1 + default expansion of 5 % of the data range, i.e. .05 * 2 (= 1 - (-1))
annotate(geom="ribbon", x = c(-Inf, 0), ymin = c(1.1, 0), ymax = Inf, fill = "grey45") +
annotate(geom="ribbon", x = c(0, Inf), ymin = -Inf, ymax = c(0, -1.1), fill = "grey45") +
geom_vline(xintercept = 0) +
geom_abline(slope=-1) +
coord_cartesian(xlim = c(-1, 1), ylim = c(-1, 1))

For a more robust example that works with any flexible slope, intercept and axis limits.
library(ggplot2)
df <- data.frame(x = c(1,-1), y = c(1,-1))
slope <- -0.5
intercept <- 0.5
limit_x <- 4
limit_y <- 4
ggplot(df, aes(x, y)) +
annotate(geom = "ribbon", x = c(-Inf, intercept), ymin = c(-limit_x * slope, slope * intercept), ymax = Inf, fill = "red") +
annotate(geom = "ribbon", x = c(intercept, Inf), ymin = -Inf, ymax = c(slope * intercept, limit_x * slope), fill = "blue") +
scale_x_continuous(limits = c(-limit_x, limit_x), expand = c(0, 0)) +
scale_y_continuous(limits = c(-limit_y, limit_y), expand = c(0, 0)) +
geom_point() +
geom_abline(slope = slope) +
geom_vline(xintercept = intercept)

Related

How to fill the background of a stat_poly_eq equation (ggpmisc) using ggplot2?

Is there a way to fill the background of a stat_poly_eq equation ggpmisc with white color (or any other color) so that the black lines of the panel.grid are hidden?
# Data
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
df$yy <- 2 + 3 * df$x + 0.1 * df$x^2 + rnorm(100, sd = 40)
# Graph
library(ggplot2)
library(ggpmisc)
ggplot(data = df, aes(x = x, y = y)) +
scale_x_continuous(limits = c(0,100), expand = c(0,0)) +
scale_y_continuous(limits = c(0,400), expand = c(0,0)) +
theme(panel.grid.major=element_line(colour="black",size=0.1)) +
stat_poly_line() +
stat_poly_eq(aes(
label = paste(after_stat(eq.label),
after_stat(rr.label), sep = "*\", \"*")), size = 6, label.x = 0.07, label.y = 0.78) +
geom_point()
Below is the graph as I would like:
Thanks for help
This could be achieved by switching the default geom used by stat_poly_eq to add the label. By default ggpp::geom_text_npc is used but there is also a geom_label_npc:
library(ggplot2)
library(ggpmisc)
ggplot(data = df, aes(x = x, y = y)) +
scale_x_continuous(limits = c(0,100), expand = c(0,0)) +
scale_y_continuous(limits = c(0,400), expand = c(0,0)) +
theme(panel.grid.major=element_line(colour="black",size=0.1)) +
stat_poly_line() +
stat_poly_eq(aes(
label = paste(after_stat(eq.label),
after_stat(rr.label), sep = "*\", \"*")),
size = 6, label.x = 0.07, label.y = 0.78,
geom = "label_npc", label.size = 0) +
geom_point()

How to smooth out a time-series geom_area with fill in ggplot?

I have the following graph and code:
Graph
ggplot(long2, aes(x = DATA, y = value, fill = variable)) + geom_area(position="fill", alpha=0.75) +
scale_y_continuous(labels = scales::comma,n.breaks = 5,breaks = waiver()) +
scale_fill_viridis_d() +
scale_x_date(date_labels = "%b/%Y",date_breaks = "6 months") +
ggtitle("Proporcions de les visites, només 9T i 9C") +
xlab("Data") + ylab("% visites") +
theme_minimal() + theme(legend.position="bottom") + guides(fill=guide_legend(title=NULL)) +
annotate("rect", fill = "white", alpha = 0.3,
xmin = as.Date.character("2020-03-16"), xmax = as.Date.character("2020-06-22"),
ymin = 0, ymax = 1)
But it has some sawtooth, how am I supposed to smooth it out?
I believe your situation is roughly analogous to the following, wherein we have missing x-positions for one group, but not the other at the same position. This causes spikes if you set position = "fill".
library(ggplot2)
x <- seq_len(100)
df <- data.frame(
x = c(x[-c(25, 75)], x[-50]),
y = c(cos(x[-c(25, 75)]), sin(x[-50])) + 5,
group = rep(c("A", "B"), c(98, 99))
)
ggplot(df, aes(x, y, fill = group)) +
geom_area(position = "fill")
To smooth out these spikes, it has been suggested to linearly interpolate the data at the missing positions.
# Find all used x-positions
ux <- unique(df$x)
# Split data by group, interpolate data groupwise
df <- lapply(split(df, df$group), function(xy) {
approxed <- approx(xy$x, xy$y, xout = ux)
data.frame(x = ux, y = approxed$y, group = xy$group[1])
})
# Recombine data
df <- do.call(rbind, df)
# Now without spikes :)
ggplot(df, aes(x, y, fill = group)) +
geom_area(position = "fill")
Created on 2022-06-17 by the reprex package (v2.0.1)
P.S. I would also have expected a red spike at x=50, but for some reason this didn't happen.

ggplot2 and log scale don't show values = 1

I want to plot a diagram with a log scales y axis:
data <- data.frame(x = seq_len(5), y = c(2,1,100,500,30))
ggplot(data) + aes(x,y) + geom_col() + scale_y_log10()
But because the horizontal axis always crosses the vertical axis at y = 1, the bar for y = 1 is never drawn.
I know that log(1) = 0, but can I set the plot base to 0.1 to let the bar start below 1?
Can't you just multiply the values of y by 10 but divide the labels by the same amount?
ggplot(data) + aes(x, y * 10) + geom_col() +
scale_y_log10(labels = function(x) x/10, name = "y")
You could do the same with a histogram:
set.seed(2)
ggplot(data.frame(x = rnorm(1000)), aes(x)) +
geom_histogram(aes(y = ..count.. * 10), color = "black", fill = "gold") +
scale_y_log10(labels = function(x) x/10, name = "count")
An alternative solution is to place the bottom of the bars at -Inf, so that the log10(1) still shows up. This is a bit tricky, because you have to reparameterise the bars as rectangles and get the geom to understand that the -Inf is after scale transformation.
library(ggplot2)
data <- data.frame(x = seq_len(5), y = c(2,1,100,500,30))
ggplot(data) +
geom_rect(
aes(xmin = x - 0.45, xmax = x + 0.45,
ymin = stage(1, after_scale = -Inf), ymax = y)
) +
scale_y_log10()
Created on 2020-11-03 by the reprex package (v0.3.0)

ggplot2 - how to limit panel and axis?

I want to know how to turn this plot:
Into this plot:
As you can see the panel and axis on the 2nd plot are limited to the data extent. I made the second graph using design software but want to know the code.
Ive already limited the x and y axis using
xlim and ylim but no difference.
Please see my code below, sorry its so messy, first time using r studio. Thanks!
ggplot() +
geom_errorbar(data = U1483_Coiling_B_M_Removed_R, mapping = aes(x = `Age (Ma) Linear Age Model`, ymin = `Lower interval*100`, ymax = `Upper interval*100`), width = 0.025, colour = 'grey') +
geom_line(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Percent Dextral`)) +
geom_point(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Percent Dextral`), colour = 'red') +
geom_point(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Lab?`)) +
theme(axis.text.x=element_text(angle=90, size=10, vjust=0.5)) +
theme(axis.text.y=element_text(angle=90, size=10, vjust=0.5)) +
theme_classic() +
theme(panel.background = element_rect(colour = 'black', size = 1)) +
xlim(0, 2.85) +
ylim(0, 100)
You can use expand when specifying axis scales, like so:
# Load library
library(ggplot2)
# Set RNG
set.seed(0)
# Create dummy data
df <- data.frame(x = seq(0, 3, by = 0.1))
df$y <- 100 - abs(rnorm(nrow(df), 0, 10))
# Plot results
# Original
ggplot(df, aes(x, y)) +
geom_line() +
geom_point(colour = "#FF3300", size = 5)
# With expand
ggplot(df, aes(x, y)) +
geom_line() +
geom_point(colour = "#FF3300", size = 5) +
scale_y_continuous(expand = c(0, 0))

How do i make an errorbar for a geom_hline using geom_ribbon in ggplot2?

I want to have an error bar for my geom_hline and thought that a geom_ribbon with opacity would look best. but i cant figure out how to make it reach the ends of the plot. I want the geom_ribbon to touch the sides of the plot as the geom_hline does. Here is the example code:
library('ggplot2')
x <- c(1,2,3,4,5,6,7,8,9,10)
y <- c(1,2,3,4,5,6,7,8,9,10)
data <- data.frame(x,y)
p1 <- ggplot(data,aes(x = x, y = y)) + geom_line() + geom_hline(yintercept=5)
p1 + geom_ribbon(aes(y = y[5],ymin = y[5]-0.5, ymax = y[5]+0.5, fill = 'red'), alpha = 0.4)
Use annotate with infinite x-values:
ggplot(data, aes(x, y)) +
geom_line() +
geom_hline(yintercept = 5) +
annotate('ribbon', x = c(-Inf, Inf), ymin = 5 - 0.5, ymax = 5 + 0.5,
alpha = 0.4, fill = 'red')
If you need a legend, use geom_ribbon directly, like so:
ggplot(data, aes(x, y)) +
geom_line() +
geom_hline(yintercept = 5) +
geom_ribbon(
aes(x, y = NULL, ymin = ymin, ymax = ymax, fill = 'my_label'),
data.frame(x = c(-Inf, Inf), ymin = 5 - 0.5, ymax = 5 + 0.5),
alpha = 0.4
)
There is no way in geom_hline() to set xlim, instead the horizontal line goes from end of the plot to the other. You can use geom_segment instead, which allows you to control the x-range and y-range of the line by specifying segment's start coordinate (x, y) and end coordinate (xend, yend)
This works:
library('ggplot2')
x <- c(1,2,3,4,5,6,7,8,9,10)
y <- c(1,2,3,4,5,6,7,8,9,10)
data <- data.frame(x,y)
p1 <- ggplot(data, aes(x = x, y = y)) + geom_line() + geom_segment(aes(x = x[1], xend = x[10], y = y[5], yend = y[5]))
p1 + geom_ribbon(aes(y = y[5],ymin = y[5]-0.5, ymax = y[5]+0.5, fill = 'red'), alpha = 0.4)
Couple options:
1) Use geom_hline instead of geom_ribbon like so (probably best option):
p1 + geom_hline(yintercept = y[5], color = 'red', size = 8, alpha = 0.4)
2) Remove area between plot area and axis by adding scale_x_continuous(expand=c(0,0)) like so (credit to https://stackoverflow.com/a/22945857/5727278):
p1 + geom_ribbon(aes(y = y[5],ymin = y[5]-0.5, ymax = y[5]+0.5, fill = 'red'), alpha = 0.4) +
scale_x_continuous(expand=c(0,0))

Resources