Mikko
Mikko

Reputation: 7755

Map shape, size and color to the same legend in ggplot2

I am trying to make a figure in ggplot where color, shape and size are mapped to a variable as follows: 0 values are shown as red crosses. Values > 0 are shown as circles with the circle size and color scaled to the variable (i.e. the larger the circle, the higher the value). I want to use a binned viridis scale for the color. The values mapped to color vary randomly, so the scaling should not be hardcoded. Here is the figure:

library(tidyverse)

x <- tibble(x = sample(1:100, 10), y = sample(1:100, 10), z = c(0, sample(1:1e6, 9)))

color_breaks <- sort(unique(c(0, 1, pretty(x$z, n = 5), ceiling(max(x$z)))))

ggplot(x, aes(x = x, y = y, color = z, shape = z == 0, size = z)) +
  geom_point(stroke = 1.5) +
  scale_shape_manual(values = c(`TRUE` = 3, `FALSE` = 21), guide = "none") +
  scale_size(range = c(1, 8),
             breaks = color_breaks,
             limits = c(0, ceiling(max(x$z)))
  ) +
  binned_scale(aesthetics = "color",
               scale_name = "stepsn",
               palette = function(x) c("red", viridis::viridis(length(color_breaks) - 3)),
               limits = c(0, ceiling(max(x$z))),
               breaks = color_breaks,
               show.limits = TRUE
  ) +
  guides(color = guide_legend(), size = guide_legend()) +
  theme_bw()  

Created on 2022-03-31 by the reprex package (v2.0.1)

How do I combine the variables to a single legend, which should look like this (edited in Illustrator)? enter image description here

Upvotes: 4

Views: 562

Answers (1)

Allan Cameron
Allan Cameron

Reputation: 173793

You can override the aesthetics inside guides:

x <- tibble(x = sample(1:100, 10), y = sample(1:100, 10), z = c(0, sample(1:1e6, 9)))

color_breaks <- sort(unique(c(0, pretty(x$z, n = 5)[-6], ceiling(max(x$z)) + 1)))

ggplot(x, aes(x = x, y = y, color = z, shape = z == 0, size = z)) +
  geom_point(stroke = 1.5) +
  scale_shape_manual(values = c(`TRUE` = 3, `FALSE` = 21), guide = "none") +
  scale_size(range = c(1, 8),
             breaks = color_breaks,
             limits = c(-1, ceiling(max(x$z)) + 2)
  ) +
  binned_scale(aesthetics = "color",
               scale_name = "stepsn",
               palette = function(x) c("red", viridis::viridis(length(color_breaks) - 1)),
               limits = c(-1, ceiling(max(x$z)) + 2),
               breaks = color_breaks,
               show.limits = FALSE
  ) +
  guides(color = guide_legend(),
         size = guide_legend(override.aes = list(shape = c(3, rep(16, 5))))) +
  theme_bw()  

enter image description here

Upvotes: 5

Related Questions