Home > front end >  How to create a horizontal gradient under a curve?
How to create a horizontal gradient under a curve?

Time:11-18

I'm attempting to recreate the following plot styling in R:

enter image description here

The data doesn't need to map onto the gradient in any meaningful way (though I guess technically it somewhat maps on to the categorical steps of the x-axis, with the colour gradually changing as the date/month changes).

I've tried scale_colour_gradient() and scale_fill_gradient(), but I'm not having any luck. Any guidance on how I could achieve something similar would be appreciated!

Sample data:

    views <- tribble(
      ~month, ~views,
      "Jan", 374,
      "Feb", 500,
      "Mar", 416,
      "Apr", 603,
      "May", 389,
      "Jun", 510) %>%
      transform(month = factor(month, levels=c("Jan","Feb","Mar","Apr","May","Jun")))

    views %>%
      ggplot(., aes(x = month, y = views, group=1))  
      geom_line(color="red")  
      scale_y_continuous(breaks=seq(0, 1000, by = 200),
                             limits = c(0, 1000))

CodePudding user response:

You can make a horizontal gradient by creating segments along your "polygon" - its lower boundaries are the x axis, the upper boundaries your connecting line. The trick is to find the coordinates for the connecting lines - I am approximating (!) them with approx.

For the color gradient in geom_line, you can use ggforce::geom_link2 - conveniently, you can use the same color scale for both segments and geom_link2.

library(tidyverse)
views <- tribble(
  ~month, ~views,
  "Jan", 374,
  "Feb", 500,
  "Mar", 416,
  "Apr", 603,
  "May", 389,
  "Jun", 510) %>%
  transform(month = factor(month, levels=c("Jan","Feb","Mar","Apr","May","Jun")))

foo <- data.frame(approx(1:6, views$views, n = 2000))

ggplot(views, aes(x = month, y = views, group=1))  
  ggforce::geom_link2(aes(color = as.integer(month)), linewidth = 1)  
  geom_segment(data = foo, aes(x, xend = x, y = 0, yend = y, color = x), alpha = .5, linewidth = .1)  
  scale_color_gradientn(colours = c("#83DFEF", "#6F9EF2", "#815BF6"))  
  theme(legend.position = "none") 

Created on 2022-11-17 with reprex v2.0.2

CodePudding user response:

First credit to @tjebo for a great approach with segments. Another option using geom_line by converting the months first to digits. Later you can convert the digits back to months on axis like this:

# Data from tjebo 
foo <- data.frame(approx(1:6, views$views, n = 2000))

library(ggplot2)
library(dplyr)
views %>%
  mutate(month_dig = as.numeric(unclass(month))) %>%
  ggplot(.)  
  geom_segment(data = foo, aes(x, xend = x, y = 0, yend = y, color = x), alpha = .5, size = .1)  
  scale_colour_gradient(low = 'lightblue', high = 'purple')  
  geom_line(aes(x = month_dig, y = views, group=1, colour = month_dig))  
  scale_x_continuous(breaks = seq(1,6,1), labels = month.abb[1:6])  
  scale_y_continuous(breaks=seq(0, 1000, by = 200), limits = c(0, 1000))  
  theme_bw()  
  labs(x = 'Month', y = 'Views', fill = 'Gradient')
#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
#> ℹ Please use `linewidth` instead.

Created on 2022-11-17 with reprex v2.0.2

  • Related