Home > Software engineering >  Gradient line segment using ggplot in R?
Gradient line segment using ggplot in R?

Time:12-02

I am trying to add a line segment intervals to a ggplot. However, I am trying to make the line segments a gradient that fades the alpha to zero at each end of the interval.

For example, if I create a plot that includes some intervals, like so:

    library(ggplot2)
library(dplyr)

df <- data.frame(
  name = c('x1', 'x2', 'x3'),
  value = c(0.251, 0.207, 0.182),
  seg = c(0.027, 0.028, 0.049)
)

p <- df %>%
  ggplot()   aes(x=name, y=value)  
  geom_segment(aes(x=name, xend=name, y=(value - seg), yend=(value   seg),
                   col = name), 
               size = 5)  
  geom_point(aes(x=name, y = value), shape = 18, size = 5, color = "black")  
  theme_bw()  
  xlab('Name')  
  ylab("Value") 

p

This produces a plot like this: interval plot

However, I am trying to figure out a way to turn those line segments into a thicker bar, that fades the alpha to zero at each end.

Something like the plot below (which can be found gradient interval

For clarity, I am just trying to recreate the coloured gradient intervals from the plot above.

EDIT

As per one of the comments, I tried using geom_link for this... but I cant seem to get it to work correctly.

To begin, I created a vector of alpha values to pass to geom_link like so:

alpLow <- seq(from = 0, to = 1, length.out = 150)
alpHigh <- rev(alpLow)
alp <- c(alpLow, alpHigh)

And then used this in geom_link:

p <- df %>%
  ggplot()   aes(x=name, y=value)  
  geom_link(aes(x = name, y = (value - seg),
                xend = name, yend = (value   seg), 
                colour = stat(index)), lineend = "round", size = 5, alpha = alp)

Which produces this: gradient seqment

As you can see, it only applies the gradient at the start and end of the 1st and last line segment.

Furthermore, Im not entirely pleased with the aesthetic of using geom_link as it seems to link together points (which are visible when you zoom in)... I was really hoping for a solid bar that fades the alpha.

CodePudding user response:

Use ggforce::geom_link

alpha = stat(index) is just one option, from the documentation.

library(tidyverse)
library(ggforce)

df <- data.frame(
  name = c('x1', 'x2', 'x3'),
  value = c(0.251, 0.207, 0.182),
  seg = c(0.027, 0.028, 0.049)
)


df %>%
  ggplot(aes(x=name, y=value))  
  geom_link(aes(x=name, xend=name, yend=value   seg,
                   col = name, alpha = rev(stat(index))), 
               size = 5)  
  geom_link(aes(x=name, xend=name, yend=value - seg,
                   col = name, alpha = rev(stat(index))), 
               size = 5)  
  
  geom_point(aes(x=name, y = value), shape = 18, size = 5, color = "black")  
  theme_bw()  
  labs(x= 'Name', y = "Value") 


enter image description here

CodePudding user response:

I hope the below is sufficiently different to merit a new answer. I have had a bit more time to look into the link which you have provided. {ggdist} has those gradient interval stats - they need the underlying data and not summary data for calculation of their density.

Assuming that you have summarised data in a way that those values represent the distribution of your data (e.g., a normal distribution), you can use this in order to recreate data based on those values. I have here created normal distributions for each group, using your values as mean and standard deviation, and then you can use ggdist::stat_gradientinterval. But you can also create other distributions of course.

library(tidyverse)
library(ggdist)

df <- data.frame(
  name = c('x1', 'x2', 'x3'),
  value = c(0.251, 0.207, 0.182),
  seg = c(0.027, 0.028, 0.049)
)

df_norm <- 
df %>%
  split(., .$name) %>%
  map(function(x) rnorm(100, x$value, x$seg)) %>%
  bind_rows() %>%
  pivot_longer(everything(), names_to = "name", values_to = "value")
  
ggplot(df_norm, aes(x=name, y=value, fill= name))  
  ggdist::stat_gradientinterval()  
  theme_bw()  
  labs(x= 'Name', y = "Value") 

Created on 2021-12-01 by the reprex package (v2.0.1)

  • Related