How to change the order of dodged bar plot with two factor levels in ggplot2?

53 views Asked by At

I have a bar plot in R using

ggplot2::geom_bar(data = data,
           mapping = ggplot2::aes(
             x = values_for_x,
             y = values_for_y,
             color = factor_levels_for_color,
             fill = factor_levels_for_color,
             alpha = factor_levels_for_alpha
           ),
           position = ggplot2::position_dodge2(
             preserve = "total"
           ),
           stat = "identity",
           linewidth = 0
         )

As you can see, I have 3 different columns defining color, fill and alpha. Currently, my dodged bars are first ordered/grouped by alpha and the by color. However, I would like to have them first ordered by the color and then by alpha.

I am currently stuck finding the right position to define this. Any help/hint is appreciated!

Thanks!

Update incl. code example.

The following code plots a ggplot. It does order all dodged bars first by the levels of the alpha value, then using the color_values factor levels. I would like to switch this, but fail so far to do this.

While this is a minimal example, my code defines the levels manually and also assigns specific color or alpha values to certain values that I do not want to change.

Thanks again!

data <- base::data.frame(
  x_values = rep(x = c("Treatment 1", "Treatment 2", "Treatment 3"), times = 3),
  y_values = c(5,8,7,3,7,8,3,1,5),
  alpha_values = c(1,2,3,1,2,3,1,2,3),
  group = "A",
  color_values = c("location1", "location1", "location1",
                   "location2", "location2", "location2",
                   "location3", "location3", "location3")
)

data2 <- base::data.frame(
  x_values = rep(x = c("Treatment 1", "Treatment 2", "Treatment 3"), times = 3),
  y_values = c(17,18,17,13,17,18,13,11,15),
  alpha_values = c(7,7,7,3,3,3,5,5,5),
  group = "B",
  color_values = c("location3", "location3", "location3",
                   "location1", "location1", "location1",
                   "location2", "location2", "location2")
)

data <- dplyr::bind_rows(base::list(data, data2))

data$alpha_values <- base::as.factor(data$alpha_values)
data$group <- base::as.factor(data$group)
data$color_values <- base::as.factor(data$color_values)

ggplot2::ggplot(data = data,
                mapping = ggplot2::aes(x = x_values,
                              y = y_values,
                              alpha = alpha_values,
                              fill = color_values)) +
  ggplot2::geom_bar(stat = "identity", position = ggplot2::position_dodge2())
1

There are 1 answers

5
Jon Spring On BEST ANSWER

One approach could be to make a factor that combines the color and alpha values, and order it the way you want. For instance you can order it using multiple variables using dplyr::arrange, and then make a new factor variable that respects that compound order using forcats::fct_inorder:

ggplot2::ggplot(data = data |>
                  dplyr::arrange(color_values, alpha_values) |>
                  dplyr::mutate(order = forcats::fct_inorder(paste(color_values, alpha_values))),
                mapping = ggplot2::aes(x = x_values,
                                       y = y_values,
                                       alpha = alpha_values,
                                       fill = color_values,
                                       group = order)) +
  ggplot2::geom_bar(stat = "identity", position = ggplot2::position_dodge2())

enter image description here

In very limited circumstances you could skip the "new combined factor" step and use group = interaction(alpha_values, color_values) in your aes() to get the same result -- provided your factors are alphanumerically ordered like in your example case. ?interaction says the result is unordered, but in your example the factors are alphanumerically ordered, so interaction(data$alpha_values, data$color_values) outputs [1] 1.location1 2.location1 3.location1 1.location2 ...), which happens to have the order you want. This won't work in most cases, though, e.g. if the numbers exceed 9, or if the factors don't happen to be alphabetically ordered.

In some circumstances, it might suffice to add group = color_values to tell ggplot2 that the dodging should be done (primarily) based on color_values, and not by alpha_values. Dodging behaviour is specified by the group aesthetic, and it appears that when it is not specified, but color and alpha are, the default is to group by the alpha mapping.