1
votes

I am trying to produce a grouped violin chart with ggplot2 similar to this one in the R gallery. Without the grouping, I was able to make a violin plot with separate columns as my categories by stacking the data. I've copied the sample data and working code as well as the graph output below.

The problem is that stacking only seems to given me two columns, which means I can't add the third column for grouping (in this case, gender), so I can't follow the R gallery example.

Basically, I want to be able to produce the same graph as below, but splitting each violin plot into two, one for males and one for females. So for example, instead of the comfort.trustmainstreammedia plot in yellow, there will be one comfort.trustmainstreammedia plot above another comfort.trustmainstreammedia plot, with the colours corresponding to male and female, and there will be six violin plots in total.

Here's some sample data:

structure(list(comfort.trustmainstreammedia = c(100, 96, 100, 
40, 80, 100, 100, 100, 100, 100), comfort.democracybest = c(100, 
94, 100, 92, 80, 100, 45, 70, 100, 100), comfort.capitalismbest = c(100, 
90, 100, 86, 80, 100, 30, 100, 100, 100), gender = c("Male", 
"Female", "Male", "Female", "Male", "Female", "Male", "Male", 
"Male", "Male")), row.names = c(NA, -10L), class = c("tbl_df", 
"tbl", "data.frame"), .Names = c("comfort.trustmainstreammedia", 
"comfort.democracybest", "comfort.capitalismbest", "gender"))

And here is my code to produce the graph:

p <- stack(select(mwe, starts_with("comfort.")))
names(p)[names(p) == "values"] <- "value"
names(p)[names(p) == "ind"] <- "text"
p$text = with(p, reorder(text, value, mean))
p <- p %>%
  ggplot( aes(x=text, y=value, fill=text, color=text)) +
  geom_violin(width=1.4, size=0.2, trim=TRUE) +
  scale_fill_viridis(discrete=TRUE) +
  scale_color_viridis(discrete=TRUE) +
  theme(
    legend.position="none"
  ) +
  coord_flip() + # This switch X and Y axis and allows to get the horizontal version
  xlab("Question") +
  ylab("%") +
  title("Comfort")
p + stat_summary(fun=mean, geom="point", shape = 23, size=1, color="black")

...which produces this graph: enter image description here

1

1 Answers

2
votes

Instead of using stack you can use pivot_longer for the data preparation. This will keep the gender column which can then be mapped on color and fill. Try this:

library(ggplot2)
library(dplyr)
library(tidyr)
library(viridis)

d <- mwe %>% 
  tidyr::pivot_longer(-gender, names_to = "text") %>% 
  mutate(text = reorder(text, value, mean))

p <- ggplot(d, aes(x=text, y=value, fill=gender, color=gender)) +
  geom_violin(width=1.4, size=0.2, trim=TRUE) +
  scale_fill_viridis(discrete=TRUE) +
  scale_color_viridis(discrete=TRUE) +
  theme(legend.position="none") +
  coord_flip() + # This switch X and Y axis and allows to get the horizontal version
  xlab("Question") +
  ylab("%") +
  ggtitle("Comfort")

p + stat_summary(fun=mean, geom="point", shape = 23, size=1, color="black")
#> Warning: position_dodge requires non-overlapping x intervals