1

I want to make 4 side-by-side scatterplots in ggplot. In each plot, I am coloring the dots by a continuous variable. I would like to have the same values map to the same colors across the four plots so that I can compare the plots and use one common legend. Any suggestions? I tried scale_colour_gradientn() and played around with the "values" arguement but to no avail so far.

Here are the four plots:

library(tidyverse)
library(gridExtra)
set.seed(111)
n <- 100
X1 <- rnorm(n, mean=0,sd=2)
X2 <- rnorm(n, mean=0,sd=2)
y <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1) +
             15*(X1 > -1 & X2 > 2), sd=1)
y0 <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1), sd=1)
y40 <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1) +
               40*(X1 > -1 & X2 > 2), sd=1)
y20 <- rnorm(100, mean=10*(X1 < -1) - 20*(X1 > -1) +
               15*(X1 > -1 & X2 > 2), sd=1)

p1 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y)) + 
  scale_colour_gradientn(colours = hcl.colors(8, "BluGrn"))
p2 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y0)) + 
  scale_colour_gradientn(colours = hcl.colors(8, "BluGrn"))
p3 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y40)) + 
  scale_colour_gradientn(colours = hcl.colors(8, "BluGrn"))
p4 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y20)) + 
  scale_colour_gradientn(colours = hcl.colors(8, "BluGrn"))
grid.arrange(p1,p2,p3,p4, nrow=2)

Any suggestions on how to create a value->color continuous mapping that can be shared across y,y0,y40, and y20 would be super appreciated. Thanks!

acn
  • 65
  • 1
  • 5
  • 2
    Find the limits you need: `lims <- range(c(y, y0, y40, y20))`. Then supply those limits to any scale you want using `limits = lims`. – Axeman Nov 25 '20 at 05:29
  • Thank you so much! One additional question. In the real plot I am making, the range of y is much smaller than the range of y40. I want to have enough gradient colors in the y-plot to be able to see contrasts while saving the most extreme colors for the y40-plot. Can "limits" be combined with "values" to accomplish this unequal spread? Im still a little confused by "values". – acn Nov 25 '20 at 06:18

1 Answers1

1

Axeman's approach is correct, though I thought it might be helpful to post an approach with patchwork instead of gridExtra. You can use the & operator to apply a ggplot object (typically a scale or theme) to all previous plots. To 'collect' guides, they must share the same name, limits, breaks, colours etc., so you'd have to set the name argument to override the default.

The values argument can indeed be used to control the spread of colours. What is useful to keep in mind is that ggplot2 rescales the values to the [0,1] interval before applying colours and the values argument also operates on these rescaled values. With the 8 colours you're picking, they will be located at the positions scales::rescale(seq(0, 1, length.out = 8)). To have the middle values lying closer together, you could try something like values = c(0, seq(0.2, 0.8, length.out = 6), 1).

library(tidyverse)
library(patchwork)

set.seed(111)
n <- 100
X1 <- rnorm(n, mean=0,sd=2)
X2 <- rnorm(n, mean=0,sd=2)
y <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1) +
             15*(X1 > -1 & X2 > 2), sd=1)
y0 <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1), sd=1)
y40 <- rnorm(100, mean=10*(X1 < -1) - 10*(X1 > -1) +
               40*(X1 > -1 & X2 > 2), sd=1)
y20 <- rnorm(100, mean=10*(X1 < -1) - 20*(X1 > -1) +
               15*(X1 > -1 & X2 > 2), sd=1)

p1 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y))
p2 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y0))
p3 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y40))
p4 <- ggplot(data=NULL) + geom_point(aes(x=X1, y=X2, col=y20))

p1 + p2 + p3 + p4 + plot_layout(guides = "collect") &
  scale_colour_gradientn(colours = hcl.colors(8, "BluGrn"),
                         limits = range(y, y0, y40, y20),
                         values = c(0, seq(0.2, 0.8, length.out = 6), 1),
                         name = "Values")

Created on 2020-11-25 by the reprex package (v0.3.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63