When using geom_ribbon()
with the shape aesthetic, there appears to be a difference in the opacity on the shaded area creating blocks in the region.
I have recreated the problem where I identified that these opacity changes are only present when the shape aesthetic is included.
Data set up:
alpha <- c("A","B","C","D", "E", "F", "G")
percent <- c(0.012, -0.02, 0.015, -0.01, 0.89, 0.12, -0.25)
flow <- c(-5, 2, -3, 3, 1, 4, -2)
shape <- c("D", "D", "L", "L", "L", "D", "L")
df <- data.frame(alpha,percent,flow, shape)
x_min = min(df$percent)
x_min = round(x_min/0.01)*0.01 - 0.01
x_max = max(df$percent)
x_max = round(x_max/0.01)*0.01 + 0.01
y_min = min(df$flow)
y_min = round(y_min)
y_max = max(df$flow)
y_max = round(y_max)
n_row = nrow(df)
Chart with no shape aesthetic, geom_ribbon() works:
df %>%
ggplot(aes(x = percent, y = flow, label = alpha)) +
geom_point() +
geom_text_repel(show.legend = FALSE, size = 3) +
scale_size_continuous(labels = scales::percent) +
theme_bw() +
scale_x_continuous(labels = scales::percent_format(accuracy = 0.1L)) +
scale_y_continuous(labels = scales::dollar_format(negative_parens = TRUE, suffix = "m")) +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = 0, ymax = y_max), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "green") +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = y_min, ymax = 0), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "red")
Chart with shape aesthetic, geom_ribbon() seems not to work:
df %>%
ggplot(aes(x = percent, y = flow, label = alpha, shape = shape)) +
geom_point() +
geom_text_repel(show.legend = FALSE, size = 3) +
scale_size_continuous(labels = scales::percent) +
theme_bw() +
scale_x_continuous(labels = scales::percent_format(accuracy = 0.1L)) +
scale_y_continuous(labels = scales::dollar_format(negative_parens = TRUE, suffix = "m")) +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = 0, ymax = y_max), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "green") +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = y_min, ymax = 0), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "red")
The issue is some kind of overplotting and the way you add the background fills via geom_ribbon
. Basically, by adding shape
as a global aesthetic your data gets grouped and your ribbons are drawn multiple times, once for each group. To solve this issue make shape
a local aes by moving it inside geom_point
:
library(ggplot2)
ggplot(df, aes(x = percent, y = flow, label = alpha)) +
geom_point(aes(shape = shape)) +
ggrepel::geom_text_repel(show.legend = FALSE, size = 3) +
scale_size_continuous(labels = scales::percent) +
theme_bw() +
scale_x_continuous(labels = scales::percent_format(accuracy = 0.1L)) +
scale_y_continuous(labels = scales::dollar_format(negative_parens = TRUE, suffix = "m")) +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = 0, ymax = y_max), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "green") +
geom_ribbon(aes(x = seq(x_min, x_max + 0.01, length.out = n_row), ymin = y_min, ymax = 0), alpha = 0.04, linetype = 0, show.legend = FALSE, fill = "red")
However, instead of making use of geom_ribbon
in my opinion you could get your result much easier and less error prone by adding your background rectangles via annotate
, which depending on your desired result does not even require to compute the min and max values. Instead you could simply use -Inf
and Inf
:
ggplot(df, aes(x = percent, y = flow, label = alpha, shape = shape)) +
geom_point() +
ggrepel::geom_text_repel(show.legend = FALSE, size = 3) +
scale_size_continuous(labels = scales::percent) +
theme_bw() +
scale_x_continuous(labels = scales::percent_format(accuracy = 0.1)) +
scale_y_continuous(labels = scales::dollar_format(negative_parens = TRUE, suffix = "m")) +
annotate(geom = "rect", xmin = -Inf, xmax = Inf, ymin = 0, ymax = Inf, alpha = 0.04, fill = "green") +
annotate(geom = "rect", xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = 0, alpha = 0.04, fill = "red")