I am trying to create several individual plots from the same data.frame with a different order of the factor levels on the y axis for each plot. Each plot is supposed to order the factor levels on y decreasingly.
I know that this can be done manually for each plot but I am looking for a more efficient and elegant way since I'll have quite a number of plots that I need to create. This doesn't have to include the use of of facet_wrap, if there is another way, maybe with loops etc.?
library(ggplot2)
library(dplyr)
data("diamonds")
Taking the data set and aggregating by two factor levels (clarity and cut):
means <- diamonds %>%
group_by(clarity, cut) %>%
summarise(carat = mean(carat))
Here I reorder by mean of one factor but eventually I would like to reorder separately for each plot (by decreasing mean of clarity).
means$clarity <- reorder(means$clarity, means$carat, FUN = mean)
Creating separate plots with face_wrap. Using coord_flip to compare plots more easily.
ggplot(means, aes(x = clarity, y = carat)) +
geom_col() +
facet_wrap(~cut, ncol = 1) +
coord_flip()
You'll see that this creates separate plots for each type of cut but the order of the factor levels on the y axis are not correct for each individual case. How can I order them correctly without having to do that manually for each type of cut?
One way to change the level order is to use factor() on the factor and specify the order directly. In this example, the function ordered() could be used instead of factor() . Another way to change the order is to use relevel() to make a particular level first in the list.
fct_reorder() is useful for 1d displays where the factor is mapped to position; fct_reorder2() for 2d displays where the factor is mapped to a non-position aesthetic. last2() and first2() are helpers for fct_reorder2() ; last2() finds the last value of y when sorted by x ; first2() finds the first value.
We can use the function fct_relevel() when we need to manually reorder our factor levels. In addition to the factor, you give it a character vector of level names, and specify where you want to move them.
This can be done in one plot by utilizing two functions:
reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
new_x <- paste(x, within, sep = sep)
stats::reorder(new_x, by, FUN = fun)
}
scale_x_reordered <- function(..., sep = "___") {
reg <- paste0(sep, ".+$")
ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
}
available on github dgrtwo/drlib
ggplot(means, aes(x = reorder_within(clarity, carat, cut, mean), y = carat)) +
geom_col() +
scale_x_reordered() +
facet_wrap(~cut, scales = "free_y", ncol = 1) +
coord_flip()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With