2

I'm currently trying to change the colors of the points in a scatterplot. I want the color to go from white to another color (red, blue...) while the points are distancing themself from the 0 horizontal AND vertical axis. Here is an drawn example ! This is what kind of colors I want.

y <- c(rnorm(5000, mean = 0), rnorm(500, mean = 0))
df <- data.frame(x, y)
plot(df$x ~ df$y,xlim=c(-4,4),ylim=c(-4,4))
abline(h=0,lty=2);abline(v=0,lty=2)

I tried to work on the residuals from a linear model, but I couldn't figured out how to to what I wanted. I would prefer in basic R as i'm not using ggplot.

Thanks you very much !

1 Answers1

2

This base-R solution might work for you:

df <- data.frame(x = rnorm(500, mean = 0),
                 y = rnorm(500, mean = 0))
dist <- sapply(1:nrow(df),function(i){min(abs(df[i,c('x','y')]))})
dist <- dist/max(dist)
df$lightness <- (1-round(dist,2))
df$color <- with(df,ifelse(x >0, 
                           ifelse(y >0,rgb(lightness,1,lightness),rgb(1,lightness,lightness)),
                           ifelse(y >0,rgb(lightness,lightness,1),rgb(1,lightness,1))))

plot(df$x ~ df$y,xlim=c(-4,4),ylim=c(-4,4),col = df$color,pch =20)
abline(h=0,lty=2);abline(v=0,lty=2)


Edit:

It might even be a bit nicer if you just set the alpha-values like so:

df <- data.frame(x = rnorm(500, mean = 0),
                 y = rnorm(500, mean = 0))
dist <- sapply(1:nrow(df),function(i){min(abs(df[i,c('x','y')]))})
dist <- dist/max(dist)
df$lightness <- round(dist,2)
df$color <- with(df,ifelse(x >0, 
                           ifelse(y >0,rgb(.7,0,0,lightness),rgb(.8,.6,0,lightness)),
                           ifelse(y >0,rgb(.1,.4,.7,lightness),rgb(.1,.5,.1,lightness))))

plot(df$x ~ df$y,xlim=c(-4,4),ylim=c(-4,4),col = df$color,pch =20)
abline(h=0,lty=2);abline(v=0,lty=2)

This way you are completely free in your color-choice.


Edit 2

And using the vectorized minimum (from here) to be more efficient:

library(tidyverse)
df <- data.frame(x = rnorm(10000, mean = 0),
                 y = rnorm(10000, mean = 0))
dist <- pmin(abs(df$x), abs(df$y))
dist <- dist/max(dist)
df$lightness <- round(dist,2)
df$color <- with(df,ifelse(x >0, 
                           ifelse(y >0,rgb(.7,0,0,lightness),rgb(.8,.6,0,lightness)),
                           ifelse(y >0,rgb(.1,.4,.7,lightness),rgb(.1,.5,.1,lightness))))

plot(df$x ~ df$y,xlim=c(-4,4),ylim=c(-4,4),col = df$color,pch =20)
abline(h=0,lty=2);abline(v=0,lty=2)

Max Teflon
  • 1,760
  • 10
  • 16
  • That's a very smart and effective way to achieve what i wanted ! Thank very much – Arthur BAYLE Feb 27 '20 at 17:20
  • Even better thank you. Nontheless the line ```dist <- sapply(1:nrow(df),function(i){min(abs(df[i,c('x','y')]))})``` is quite slow on huge dataframe. I don't have any idea on how it could optimize as it is already using sapply. – Arthur BAYLE Feb 27 '20 at 18:12
  • 1
    I edited the answer with a more efficient solution. But you might want to not use the alpha-way if there are too many points. Otherwise the layering could destroy the shading. – Max Teflon Feb 27 '20 at 18:22