4
votes

Solved the jitter problem, now I want to make the points more visible. I chose pch=21 to have a black circle filled with colors. But, the boxes changed to the same color scheme. How can I change the box colors back? I'd like to have the same box colors in Figure A as in Figure B.

library(tidyverse)
library(ggpubr)
mtcars$cyl=factor(mtcars$cyl)

p1=mtcars %>% ggplot(aes(x=cyl, y=mpg, fill=cyl))+  
  geom_boxplot(show.legend = F, aes(fill=cyl))+
  geom_point(position=position_jitterdodge(jitter.width=2, dodge.width = 0), 
             pch=21, aes(fill=factor(wt)), show.legend = F)

p2=mtcars %>% ggplot(aes(x=cyl, y=mpg, fill=cyl))+  
  geom_boxplot(show.legend = F)+
  geom_point(position=position_jitterdodge(jitter.width=0, dodge.width = 0.3), 
             aes(color=factor(wt)), show.legend = F)

ggarrange(p1,p2,labels=c("A","B"))

enter image description here

3
The basic design in ggplot only allows you to map each aesthetic ones. See e.g. Hadley's answer here Multiple fill scales with seperate legends. Various work-arounds are therefore needed.Henrik

3 Answers

5
votes

You can use the scale_colour_manual() to manually choose the colours. However, it is difficult to with this example as you have used factor(wt) as the fill aesthetic for geom_point() which has about 30 levels so you have to specify each level's colour manually. To demonstrate, I have changed the fill aesthetic to vs :

p1=mtcars %>% ggplot(aes(x=cyl, y=mpg))+  
  geom_boxplot(show.legend = F, aes(fill=cyl))+
  geom_point(position=position_jitterdodge(jitter.width=2, dodge.width = 0), 
             pch=21, aes(fill=factor(vs)), show.legend = F) +
  scale_fill_manual(values = c("4" = "red",
                               "6" = "green",
                               "8" = "yellow",
                               "0" = "lightblue",
                               "1" = "black"))
p1

output

2
votes

One quick way to get around the colour vs. fill tangle is to hack the appearance of the outlined points, by adding a slightly larger black point under each colored point. Below is a modification of p2:

mtcars %>% ggplot(aes(x=cyl, y=mpg, fill=cyl))+  
  geom_boxplot(show.legend = F) +

  # add new geom_point layer BELOW the coloured version, using the same parameters,
  # jittered to the same positions (set the same seed), but with larger size
  geom_point(position=position_jitterdodge(jitter.width=0, dodge.width = 0.3, seed = 1234), 
             aes(group = factor(wt)), show.legend = F, size = 2) +

  geom_point(position=position_jitterdodge(jitter.width=0, dodge.width = 0.3, seed = 1234),
             aes(color=factor(wt)), show.legend = F)

plot

Note: this hack won't work as well if you have many overlapping points in close proximity to one another, as the black "outlines" would be completely under the overlapped portions. (Though a less cluttered visualisation choice might be more appropriate in such cases anyway.)

2
votes

I found a way to do this using ggpubr. First of all, I need to define the colors by hand. Then, use the ggboxplot and add a jitter plot, specify the fill color with the predefined colors. It seems that ggpubr created a separate layer that does not interfere with the main plot.

col=rainbow(length(levels(factor(mtcars$wt))))[factor(mtcars$wt)]

mtcars %>% ggboxplot(x="cyl", y="mpg", fill="cyl", add="jitter", 
        add.params=list(shape=21, color="black", fill=col, size=3))

enter image description here