0

This code obviously does not work (it uses the same legend and colour scheme for both categorical variables.

require(ggplot2)

dt <- ggplot2::diamonds ; dt <- dt [1:20,];dt 
ggplot(dt) + 
  geom_point(aes(depth,carat, col=cut)) + 
  geom_point(aes(depth,carat, col=clarity)) +
  scale_colour_brewer("greens", name="cut") +  
  scale_colour_brewer("Reds", name="cut") +
  guides(colour= guide_legend("CUT")) + 
  guides(colour = guide_legend("CLARITY"))

What's the correct way to plot this?

tjebo
  • 21,977
  • 7
  • 58
  • 94
IVIM
  • 2,167
  • 1
  • 15
  • 41

1 Answers1

3

There is no correct way to do this. Ggplot isn't intended to be used this way since you are trying to map two variables to the same scale. However, you could circumvent the limitations of ggplot to some extend by hijacking the fill scale to do the job for you:

ggplot(dt) +
  geom_point(aes(depth, carat, fill = cut), shape = 21, colour = "transparent") +
  geom_point(aes(depth, carat, colour = clarity)) +
  scale_colour_brewer(palette = "Greens", name = "cut") +
  scale_fill_brewer(palette = "Reds", name = "clarity")

enter image description here

The trick is to use a shape that has a fill and use that fill to map your variable. The downside is that this trick can't be extended to any number of variables. There are a few packages out there that can achieve what you want, namely ggnewscale or relayer.

An example with the ggnewscale package:

library(ggnewscale)

ggplot(dt) +
  geom_point(aes(depth, carat, colour = cut)) +
  scale_colour_brewer(palette = "Greens", name = "cut") +
  new_scale_color() +
  geom_point(aes(depth, carat, colour = clarity)) +
  scale_colour_brewer(palette = "Reds", name = "clarity")

enter image description here

For the relayer variant:

library(relayer)

ggplot(dt) +
  rename_geom_aes(geom_point(aes(depth, carat, cut = cut)), new_aes = c("colour" = "cut")) +
  rename_geom_aes(geom_point(aes(depth, carat, clarity = clarity)), new_aes = c("colour" = "clarity")) +
  scale_colour_brewer(palette = "Greens", aesthetics = "cut") +
  scale_colour_brewer(palette = "Reds", aesthetics = "clarity")
Warning: Ignoring unknown aesthetics: cut
Warning: Ignoring unknown aesthetics: clarity

enter image description here

Hope this helped!

EDIT: obviously on the plots above only one of the colours show on the points because you are overplotting the same x and y coordinates on top of each other. I felt like I needed to point this out.

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Thanks for trying. "Ggplot isn't intended to be used this way " Hmmm... This is strange. - I see my simple example being very very common task - like showing Best 5 and Worse 5 points from the same dataset in the same graph. There must be good way of doing it... I would think. (btw, this is how I extract Best/Worst 5, which I need to visualize now: https://stackoverflow.com/questions/56166410/show-top-bottom-k-in-each-group-using-data-table) – IVIM May 16 '19 at 14:03
  • 2
    Well, labeling the 5 best and worst points on a graph isn't exactly the same as mapping multiple variables to separate colour scales, which is what I interpreted your question to be. You can easily add a `label`-column to `dt` with a factor indicating what are the best and worst five points and put that as your colour mapping in conjuction with a `scale_colour_manual()`. – teunbrand May 16 '19 at 14:11