Tlatwork
Tlatwork

Reputation: 1525

Gradient fill in ggplot2

Say if have the following plot.

library(ggplot2)
n <- 1169
df22 <- data.frame(x = 1:n, val = seq(0, 0.5, length.out = n), type = 1)

ggplot(df22, aes(x = x, y = val)) +
  geom_ribbon(aes(ymax = val, ymin = 0, fill = type, group = type))

Instead of the blue color i would like to have a Gradient fill (from blue to red - vertically. So starting with blue at the bottom and red on top with a Parameter to Control the smoothness of Color change).

I found the following resource: https://ggplot2.tidyverse.org/reference/scale_gradient.html

Unfortunately, it didnt work out for me as my data is not continous(?).

Upvotes: 7

Views: 8100

Answers (2)

stefan
stefan

Reputation: 124013

Using ggplot2 >= 3.5.0 (and R >= 4.2.0) which adds support for gradient fills this can now more easily be achieved.

As a first step this requires to sepeify a gradient fill using e.g. grid::linearGradient where the direction of the gradient can be set via the x1, x2, y1 and y2 argument, e.g. in your case we have to deviate from the defaults by setting x2 = unit(0, "npc") to get a gradient in the vertical direction.

This gradient could then be applied to the geom by passing it to the fill= argument:

library(ggplot2)
library(grid)

grad_ungroup <- linearGradient(
  c("blue", "red"),
  x1 = unit(0, "npc"), y1 = unit(0, "npc"),
  x2 = unit(0, "npc"), y2 = unit(1, "npc")
)

ggplot(df22, aes(x = x)) +
  geom_ribbon(aes(ymax = val, ymin = 0),
    fill = grad_ungroup
  )

Upvotes: 2

Taher A. Ghaleb
Taher A. Ghaleb

Reputation: 5240

The following code will do it (but horizontally):

library(scales) # for muted
ggplot(df22, aes(x = x, y = val)) +
  geom_ribbon(aes(ymax = val, ymin = 0, group = type)) +
  geom_col(aes(fill = val)) +
  scale_fill_gradient2(position="bottom" , low = "blue", mid = muted("blue"), high = "red", 
                       midpoint = median(df22$val)) 

Ribbon-Horizontally

If you want to make it vertically, you may flip the coordinates using coord_flip() upside down.

ggplot(df22, aes(x = val, y = x)) +
  geom_ribbon(aes(ymax = val, ymin = 0)) +
  coord_flip() +
  geom_col(aes(fill = val)) +
  scale_fill_gradient2(position="bottom" , low = "blue", mid = muted("blue"), high = "red", 
                       midpoint = median(df22$val)) 

Ribbon-Vertically

Or, if you want it to be horizontal with a vertical gradient (as you requested), you might need to go around it by playing with your data and using the geom_segment() instead of geom_ribbon(), like the following:

vals <- lapply(df22$val, function(y) seq(0, y, by = 0.001))
y <- unlist(vals)
mid <- rep(df22$x, lengths(vals))
d2 <- data.frame(x = mid - 1, xend = mid + 1, y = y, yend = y)

ggplot(data = d2, aes(x = x, xend = xend, y = y, yend = yend, color = y)) +
  geom_segment(size = 1) +
  scale_color_gradient2(low = "blue", mid = muted("blue"), high = "red", midpoint = median(d2$y)) 

This will give you the following:

enter image description here

Hope you find it helpful.

Upvotes: 11

Related Questions