2

In the following example (using the iris dataset), I am creating a factor class variable in which one of the species does not contain values of level C. When I make the plot, I cannot find a way to make ggplot not drop the empty level (virginica-C). In a previous post (from 10 years ago), it indicates to use the argument drop = FALSE, but it is not working for me. any suggestions?

require(dplyr)
require(ggplot2)

iris %>% 
  
  mutate(fct_x = factor(x = sample(x = c("A", "B", "C"), size = nrow(.), replace = TRUE), 
                        levels = c("A", "B", "C"))) %>% 
  
  filter(!(Species == "virginica" & fct_x == "C")) %>% 
  
  ggplot(aes(x = Species, y = Sepal.Length, fill = fct_x)) +
  
  geom_boxplot() +
  
  scale_fill_discrete(drop = FALSE)

In other words, the code shown above generates the following graphic. As you can see, the virginica group does NOT show an empty space for group C (because there are no elements of type virginica-C) and that is exactly what I want to achieve: to show that empty space in the figure.

enter image description here

PS: There is also another similar post (from 6 years ago) in which they suggest placing values outside the limits. It is not a bad idea when you have to make a point plot, but in my case I am making a script that generates automatic plots from incoming information and, therefore, I cannot limit the y-axis since the script itself defines the ylim according to the values that appear.

2 Answers2

0

You can specify the position function in the geom_boxplot call. In dodge2 (the default position parameter) you can set preserve="single" so the width of all the single columns is the same.

iris %>%

mutate(fct_x = factor(x = sample(x = c("A", "B", "C"), size = nrow(.), replace = TRUE),
                    levels = c("A", "B", "C"))) %>%

filter(!(Species == "virginica" & fct_x == "C")) %>%

mutate(fct_x = factor(fct_x, levels = c("A", "B", "C"))) %>%

ggplot(aes(x = Species, y = Sepal.Length, fill = fct_x)) +

geom_boxplot(position=position_dodge2(preserve="single"))

enter image description here See the definition of position_dodge2(): https://ggplot2.tidyverse.org/reference/position_dodge.html

asafpr
  • 347
  • 1
  • 5
  • Well, as you can see, it just modifies the width, but does not leave a real empty space. The (reproducible) example with `iris` is very simple, but in my real problem, I have groups with more than 5 levels, so I do need that the script leaves an empty space instead of avoiding and smashing together. – Wencheng Lau-Medrano Jun 16 '22 at 07:44
  • I see. In that case you can use `position_dodge` instead of `dodge2`, you'll need to define the `width=` parameter manually though – asafpr Jun 16 '22 at 07:57
0

You could get the empty slot by faceting with scales = "free_x" and using scale_x_discrete(drop = FALSE):

(The strip labels could be moved to the bottom, and the fct_x labels & gaps between facets removed, if preferred per the second example.)

require(dplyr)
require(ggplot2)

iris %>%
  mutate(fct_x = factor(
    x = sample(x = c("A", "B", "C"), size = nrow(.), replace = TRUE),
    levels = c("A", "B", "C")
  )) %>%
  filter(!(Species == "virginica" & fct_x == "C")) %>%
  ggplot(aes(x = fct_x, y = Sepal.Length, fill = fct_x)) +
  geom_boxplot() +
  facet_wrap(~ Species, scales = "free_x") +
  scale_x_discrete(drop = FALSE)

Created on 2022-06-16 by the reprex package (v2.0.1)

# Mimicing the original plot
require(dplyr)
require(ggplot2)

iris %>%
  mutate(fct_x = factor(
    x = sample(x = c("A", "B", "C"), size = nrow(.), replace = TRUE),
    levels = c("A", "B", "C")
  )) %>%
  filter(!(Species == "virginica" & fct_x == "C")) %>%
  ggplot(aes(x = fct_x, y = Sepal.Length, fill = fct_x)) +
  geom_boxplot() +
  facet_wrap(~ Species, scales = "free_x", strip.position = "bottom") +
  scale_x_discrete(drop = FALSE) +
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        strip.background = element_blank(),
        panel.spacing = unit(0, "lines")) +
  labs(x = "Species")

Created on 2022-06-16 by the reprex package (v2.0.1)

Carl
  • 4,232
  • 2
  • 12
  • 24