4

How can I split a beeswarm plot by group, similar to this: Split violin plot with ggplot2

But instead of density plots, I would like to get points...

The "calculating the density approach" as suggested by @axeman in the linked question does obviously not work, because beeswarm doesn't use densities.

#Desired output:
require(ggplot2)
require(ggbeeswarm)
my_dat <- data.frame(x = 'x', m = rep(c('a','b'),100), y = rnorm(200))
ggplot(my_dat, aes(x,y))+ geom_quasirandom(method = 'smiley')

Desired output something like:

enter image description here

  • The resulting plot was edited with Adobe illustrator, in order to show what I want to get...
  • The points in the central axis should rather be dodged to the left/right too, depending on the group.

Edit
a better way to achieve what I want is to use method = 'pseudorandom' instead of 'smiley'. see
Split beeswarm 2.

tjebo
  • 21,977
  • 7
  • 58
  • 94

1 Answers1

5

You can try following hardcoded solution

library(tidyverse)
# the plot
p <- ggplot(my_dat, aes(x,y,color=m))+ 
  geom_quasirandom(method = 'smiley')
# get the layer_data(p, i = 1L)
p <- ggplot_build(p)
# update the layer data
p$data[[1]] <-   p$data[[1]] %>%
  mutate(x=case_when(
    colour=="#00BFC4" ~ PANEL + abs(PANEL - x),
    TRUE ~ PANEL - abs(PANEL - x))
  )
# plot the update
plot(ggplot_gtable(p))

enter image description here

Doing it in a more generalized way, you can create a function for switching x-adjustment per group

foo <- function(plot){
 p <- ggplot_build(plot)
 p$data[[1]] <-   p$data[[1]] %>%
   mutate(diff = abs(x-round(x)),  # calculating the difference to the x axis position
          # update the new position depending if group is even (+diff) or odd (-diff)
          x = case_when(group %% 2 == 0 ~ round(x) + diff,
                        TRUE ~ round(x) - diff)) %>%
   select(-diff)
 plot(ggplot_gtable(p))
}

Some other data

set.seed(121)
p <- diamonds %>% 
  mutate(col=gl(2,n()/2)) %>% 
  sample_n(1000) %>% 
  ggplot(aes(cut,y,color= factor(col)))+ 
  geom_beeswarm()
p

enter image description here

and the updated plot

foo(p)

enter image description here

Roman
  • 17,008
  • 3
  • 36
  • 49
  • Unfortunately, it seems not yet quite over... there seems to be a problem with saving the separated beeswarm plot. Using ggsave mixes the dots up again, and opening device via `pdf()` does not draw anything. Do you have an explanation why? (I guess it must have to do with the use of the function, but I am somewhat overwhelmed here). I am very happy to ask this as a separate question if you think it's worth it. – tjebo Apr 12 '18 at 00:16
  • 1
    @Tjebo no problem here using `ggsave(foo(p), filename = "test.pdf")`. Info `ggplot2_2.2.1` and `R version 3.4.1` – Roman Apr 16 '18 at 08:07
  • Thanks again for this great hint towards `ggplot_build`. I have tweaked your function a bit in order to generalise it for more than one plot - using `for(i in 1:length(p$data)) { p$data[[i]] <- p$data[[i]] %>% etc...`. If anyone else should read this comment, in the case of more than one plot you need to specify the groups in each plot with `group` parameter in `aes` – tjebo Apr 20 '18 at 08:25