Reputation: 81
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?
Upvotes: 8
Views: 1219
Reputation: 19716
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()
Upvotes: 7