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!
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)