Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of plots generated in ggplot2 using scale_color_gradientn have wrong coloring

Tags:

r

ggplot2

I'm attempting to use library(scales) and scale_color_gradientn() to create a custom mapping of colors to a continuous variable, in an attempt to limit the effect of outliers on the coloring of my plot. This works for a single plot, but does not work when I use a loop to generate several plots and store them in a list.

Here is a minimal working example:

library(ggplot2)
library(scales)

data1 <- as.data.frame(cbind(x = rnorm(100),
                             y = rnorm(100),
                             v1 = rnorm(100, mean = 2, sd = 1),
                             v2 = rnorm(100, mean = -2, sd = 1)))

#add outliers
data1[1,"v1"] <- 200
data1[2,"v1"] <- -200
data1[1,"v2"] <- 50
data1[2,"v2"] <- -50

#define color palette
cols <- colorRampPalette(c("#3540FF","black","#FF3535"))(n = 100)

#simple color scale
col2 <- scale_color_gradient2(low = "#3540FF",
                              mid = "black",
                              high = "#FF3535"
                              )

#outlier-adjusted color scale
{
    aa <- min(data1$v1)
    bb <- quantile(data1$v1, 0.05)
    cc <- quantile(data1$v1, 0.95)
    dd <- max(data1$v1)

    coln <- scale_color_gradientn(colors = cols[c(1,5,95,100)],
               values = rescale(c(aa,bb,cc,dd),
                    limits = c(aa,dd))
                                                                 )
}

Plots:

1. Plot with simple scales - outliers cause scales to stretch out.

ggplot(data1, aes(x = x, y = y, color = v1))+
   geom_point()+
   col2

Plot with simple scales - outliers cause scales to stretch out

2. Plot with outlier-adjusted scales - correct color scaling.

ggplot(data1, aes(x = x, y = y, color = v1))+
    geom_point()+
    coln

Plot with outlier-adjusted scales - correct color scaling

3. The scales for v1 do not work for v2 as the data is different.

ggplot(data1, aes(x = x, y = y, color = v2))+
    geom_point()+
    coln

The scales for v1 do not work for v2 as the data is different

#loop to produce list of plots each with own scale
{
    plots <- list()
    k <- 1
    for (i in c("v1","v2")){
        aa <- min(data1[,i])
        bb <- quantile(data1[,i],0.05)
        cc <- quantile(data1[,i], 0.95)
        dd <- max(data1[,i])

        colm <- scale_color_gradientn(colors = cols[c(1,5,95,100)],
                     values = rescale(c(aa,bb,cc,dd),
                         limits = c(aa,dd)))

        plots[[k]] <- ggplot(data1, aes_string(x = "x",
                                               y = "y",
                                                   color = i
                                                   ))+
                     geom_point()+
                     colm

        k <- k + 1
    }
}

4. First plot has the wrong scales.

plots[[1]]

First plot has the wrong scales

5. Second plot has the correct scales.

plots[[2]]

Second plot has the correct scales

So I'm guessing this has something to do with the scale_color_gradientn() function being called when the plotting takes place, rather than within the loop.

If anyone can help with this, it'd be much appreciated. In base R I would bin the continuous data and assigning hex colors into a vector used for fill color, but I'm unsure how I can apply this within ggplot.

like image 572
DJM123 Avatar asked Jan 24 '26 23:01

DJM123


1 Answers

You need to use a closure (function with associated environment):

{
  plots <- list()
  k <- 1
  for (i in c("v1", "v2")){
    colm <- function() {
      aa <- min(data1[, i])
      bb <- quantile(data1[, i], 0.05)
      cc <- quantile(data1[, i], 0.95)
      dd <- max(data1[, i])

      scale_color_gradientn(colors = cols[c(1, 5, 95, 100)],
                            values = rescale(c(aa, bb, cc, dd),
                            limits = c(aa, dd)))
    }

    plots[[k]] <- ggplot(data1, aes_string(x = "x",
                                           y = "y",
                                           color = i)) +
                    geom_point() +
                    colm()
    k <- k + 1
  }
}

plots[[1]]

enter image description here

plots[[2]]

enter image description here

like image 63
Claus Wilke Avatar answered Jan 27 '26 12:01

Claus Wilke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!