Home > Software design >  Apply color gradient to axis lines in connected scatterplot
Apply color gradient to axis lines in connected scatterplot

Time:01-06

OK, I have code to generate a connected scatterplot, and I would like to have a color gradient along the bottom and left edges of the chart area, and I need the viewable portion of the gradient to be based on the values contained in the chart (the values the gradient is based on is static).

Adding lines with the proper weight in the location I need to the chart is no problem, and I can specify a single color for the line (as seen for the y axis), but when I attempt to apply a gradient to the line using scale_colour_gradientn() it doesn't do anything (the provided code is attempting to apply the gradient to the line on the bottom of the chart).

If there's a way to capture the limits of x & y as rendered by the chart (not the min & max values displayed, as the label locations will exceed them), I could make something work using other ggplot features, but it doesn't appear those are knowable values.

sample code:

parent <- c('A','A','A','B','B','B','C','C','C')
pd_identifier <- c('2021_10','2022_03','2022_08','2021_10','2022_03','2022_08','2021_10','2022_03','2022_08')
PtChg <- c(-15.3,-19.4,-16.0,-9.83,-11.9,-13.4,0.876,2.10 ,2.24)
Impact  <- c(-0.684 ,-0.860 ,-0.558 ,-1.55  ,-2.00  ,-2.68  ,-0.165 ,-0.0730,-0.0816)
label <- c(NA,'A',NA,NA,NA,'B',NA,NA,'C')
nudge_x <- c(NA,-0.984,NA,NA,NA,-0.400,NA,NA,0.944)
nudge_y <- c(NA,0.0352,NA,NA,NA,-0.183,NA,NA,0.0659)
df <- as.data.frame(cbind(parent,pd_identifier,label,PtChg,Impact,nudge_x,nudge_y))
df[, 4:ncol(df)] <- lapply(4:ncol(df), function(x) as.numeric(df[[x]]))

ggplot(df, aes(PtChg, Impact))  
  theme_bw()  
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid = element_line(linetype = "dashed",colour = "#D3D3D3"))  
  scale_colour_gradientn(
    colors=c("#C00000","#C00000","#FFFF00","#00B050","#00B050"),
    values=c(0,0.425,0.5,0.575,1))    
  theme(axis.line.x.bottom = element_line(color = (PtChg   100)/200,size = 4))  
  theme(axis.line.y.left = element_line(color = "#D3D3D3",size = 4))  
  geom_vline(aes(xintercept = 0),size = 1,colour = "#D3D3D3")  
  geom_hline(aes(yintercept = 0),size = 1,colour = "#D3D3D3")  
  
  geom_path(aes(group=parent),
            colour="#E20074",
            arrow = arrow(length=unit(0.3,"cm"),
                          ends="last",
                          type = "closed"))   
  geom_text_repel(data = df,
                  aes(label = label),
                  min.segment.length = 0.1,
                  nudge_x = df$nudge_x,
                  nudge_y = df$nudge_y,
                  direction = "both",
                  force = 100,
                  force_pull = 1,
                  max.time = 500,
                  max.iter = 1000000,
                  # verbose = TRUE,
                  na.rm = TRUE
  )

SOLUTION: Final code for ggplot (and calculating boundaries):

x_min = if((floor(min(df$PtChg)/5)*5 - min(df$PtChg)) >= 2.5)
{floor(min(df$PtChg)/5)*5} else {floor(min(df$PtChg)/5)*5 - 2.5}
x_max = if((ceiling(max(df$PtChg)/5)*5 - max(df$PtChg)) >= 2.5)
{ceiling(max(df$PtChg)/5)*5} else {ceiling(max(df$PtChg)/5)*5   2.5}
y_min = if((floor(min(df$Impact)/.5)*.5 - min(df$Impact)) >= 0.25)
{floor(min(df$Impact)/.5)*.5} else {floor(min(df$Impact)/.5)*.5 - 0.25}
y_max = if((ceiling(max(df$Impact)/.5)*.5 - max(df$Impact)) >= 2.5)
{ceiling(max(df$Impact)/.5)*.5} else {ceiling(max(df$Impact)/.5)*.5   0.25}

ggplot(df, aes(PtChg, Impact))  
  theme_bw()  
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid = element_line(linetype = "dashed",colour = "#D3D3D3"))  

  geom_vline(aes(xintercept = 0),size = 1,colour = "#D3D3D3")  
  geom_hline(aes(yintercept = 0),size = 1,colour = "#D3D3D3")  
  
  geom_path(aes(group=parent),
            colour="#E20074",
            arrow = arrow(length=unit(0.3,"cm"),
                          ends="last",
                          type = "closed"))   
    geom_text_repel(data = df,
                  aes(label = label),
                  min.segment.length = 0.1,
                  nudge_x = df$nudge_x,
                  nudge_y = df$nudge_y,
                  direction = "both",
                  force = 100,
                  force_pull = 1,
                  max.time = 500,
                  max.iter = 1000000,
                  na.rm = TRUE
  )  
  ggforce::geom_link2(data = data.frame(PtChg = seq(-100,100), Impact = y_min),
                      aes(color = (PtChg 100)/200), size = 8)  
  theme(axis.line.x = element_blank())  
  scale_colour_gradientn(
    colors = c("#C00000","#C00000","#FFFF00","#00B050","#00B050"),
    values = c(0,0.425,0.5,0.575,1), guide = "none")  
  new_scale_color()  
  ggforce::geom_link2(data = data.frame(PtChg = x_min,Impact = seq(-10,10)),
    aes(color = (Impact 10)/20), size = 8)  
    theme(axis.line.y = element_blank())  
  scale_colour_gradientn(
    colors = c("#C00000","#C00000","#FFFF00","#00B050","#00B050"),
    values=c(0,0.45,0,0.55,1), guide = "none")  
  coord_cartesian(xlim = c(x_min,x_max),ylim = c(y_min,y_max), expand = FALSE)

so it looks like this:

enter image description here

CodePudding user response:

You can specify the exact limits of your plot with coord_cartesian, which allows you to draw a gradient line exactly along the x axis, for example with geom_link2 from ggforce

ggplot(df, aes(PtChg, Impact))  
  theme_bw()  
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid = element_line(linetype = "dashed",colour = "#D3D3D3"))  
  scale_colour_gradientn(
    colors = c("#C00000","#C00000","#FFFF00","#00B050","#00B050"),
    values = c(0,0.425,0.5,0.575,1), guide = "none")    
  geom_vline(aes(xintercept = 0),size = 1,colour = "#D3D3D3")  
  geom_hline(aes(yintercept = 0),size = 1,colour = "#D3D3D3")  
  
  geom_path(aes(group=parent),
            colour="#E20074",
            arrow = arrow(length=unit(0.3,"cm"),
                          ends="last",
                          type = "closed"))   
  coord_cartesian(ylim = c(-2.75, 0.1), expand = FALSE)  
  geom_text_repel(data = df,
                  aes(label = label),
                  min.segment.length = 0.1,
                  nudge_x = df$nudge_x,
                  nudge_y = df$nudge_y,
                  direction = "both",
                  force = 100,
                  force_pull = 1,
                  max.time = 500,
                  max.iter = 1000000,
                  na.rm = TRUE
  )  
  ggforce::geom_link2(data = data.frame(PtChg = seq(-20, 5), Impact = -2.75),
                      aes(color = PtChg), linewidth = 8)  
  theme(axis.line.x = element_blank())

enter image description here

  • Related