Gregory
Gregory

Reputation: 4279

How to map different aspects of single scale_color* to different variables in ggplot2?

I want to simultaneously visualize the mean and error (variance) of predictions in spatial data. One possible method for doing this would be to map the mean to hue and the error to either saturation or luminance. Although I'm doing this in maps, I'll offer a much simpler minimal working example here adapted from ggplot2's documentation.

library(ggplot2)
library(RColorBrewer)
dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
dsub$var <- dsub$x
dsub$diff <-  with(dsub, sqrt(abs(x-y))* sign(x-y))
d <- qplot(x, y, data=dsub, colour=diff)
d + scale_color_gradientn(colours=brewer.pal(7,"YlOrRd"))

One variable mapped to color

What I would like to see, rather than the attached plot, is a version where the luminance or the saturation of the color ramp is mapped to the variable "var" in the data. Ideally, such a plot would include a 2-dimensional legend.

Upvotes: 4

Views: 739

Answers (2)

ssp3nc3r
ssp3nc3r

Reputation: 3822

You can also just use scale_fill_identity(), convert your data to a valid visual channel range, and then map your values with a function for the fill:

df <- expand.grid(H = c(30, 50, 230, 250),
                  S = seq(0, 100, by = 10),
                  L = seq(0, 100, by = 10))

ggplot(df) +
  
  facet_wrap(~ H ) +
  
  scale_x_continuous(
    name = 'Luminance',
    breaks = seq(0, 100, by = 20), 
    expand = c(0,0),
    sec.axis = sec_axis(~., name = 'Hue')) +
  
  scale_y_continuous(
    name = 'Saturation',
    breaks = seq(0, 100, by = 20), 
    expand = c(0,0)) + 
  
  scale_fill_identity() +
  
  geom_raster(
    mapping = aes(
      x = L, 
      y = S,
      fill = hcl(H, S, L)), 
     )

Upvotes: 1

mmk
mmk

Reputation: 514

One solution that's worked for me has been to use a couple layers to represent the data (in this example I'm more or less using hue and value as the two aesthetics, but saturation could be substituted for value by switching the black layer to white), and then generate a custom 2D legend. So, using the data you provided:

# main plot
main <- ggplot(dsub) +
  geom_tile(aes(x, y, fill=diff)) +
  scale_fill_gradient(high="red", low="blue") +
  geom_tile(aes(x, y, alpha=var)) +
  theme(legend.position="none")

# 2d legend
diff <- range(dsub$diff)
var <- range(dsub$var)
legdata <- expand.grid(diff=seq(diff[1], diff[2], (diff[2]-diff[1])/20),
                   var=seq(var[1], var[2], (var[2]-var[1])/20))
legend <- ggplot(legdata) +
  geom_tile(aes(diff, var, fill=diff)) +
  scale_fill_gradient(high="red", low="blue") +
  geom_tile(aes(diff, var, alpha=var)) +
  scale_x_continuous(expand=c(0,0)) +
  scale_y_continuous(expand=c(0,0)) +
  theme(panel.background=element_blank(), panel.grid=element_blank(),
        legend.position="none") +
  coord_fixed() +
  labs(title="legend")

# combine plot and legend
library(gridExtra)
plt <- arrangeGrob(main, legend, nrow=1, widths=c(3, 1))
print(plt)

enter image description here

Upvotes: 5

Related Questions