#' Reorder an x or y axis within facets #' #' Reorder a column before plotting with faceting, such that the values are ordered #' within each facet. This requires two functions: \code{reorder_within} applied to #' the column, then either \code{scale_x_reordered} or \code{scale_y_reordered} added #' to the plot. #' This is implemented as a bit of a hack: it appends ___ and then the facet #' at the end of each string. #' #' @param x Vector to reorder. #' @param by Vector of the same length, to use for reordering. #' @param within Vector of the same length that will later be used for faceting #' @param fun Function to perform within each subset to determine the resulting #' ordering. By default, mean. #' @param sep Separator to distinguish the two. You may want to set this manually #' if ___ can exist within one of your labels. #' @param ... In \code{reorder_within} arguments passed on to \code{\link{reorder}}. #' In the scale functions, extra arguments passed on to #' \code{\link[ggplot2]{scale_x_discrete}} or \code{\link[ggplot2]{scale_y_discrete}}. #' #' @source "Ordering categories within ggplot2 Facets" by Tyler Rinker: #' \url{https://trinkerrstuff.wordpress.com/2016/12/23/ordering-categories-within-ggplot2-facets/} #' #' @examples #' #' library(tidyr) #' library(ggplot2) #' #' iris_gathered <- gather(iris, metric, value, -Species) #' #' # reordering doesn't work within each facet (see Sepal.Width): #' ggplot(iris_gathered, aes(reorder(Species, value), value)) + #' geom_boxplot() + #' facet_wrap(~ metric) #' #' # reorder_within and scale_x_reordered work. #' # (Note that you need to set scales = "free_x" in the facet) #' ggplot(iris_gathered, aes(reorder_within(Species, value, metric), value)) + #' geom_boxplot() + #' scale_x_reordered() + #' facet_wrap(~ metric, scales = "free_x") #' #' @export reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) { new_x <- paste(x, within, sep = sep) stats::reorder(new_x, by, FUN = fun) } #' @rdname reorder_within #' @export scale_x_reordered <- function(..., sep = "___") { reg <- paste0(sep, ".+$") ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...) } #' @rdname reorder_within #' @export scale_y_reordered <- function(..., sep = "___") { reg <- paste0(sep, ".+$") ggplot2::scale_y_discrete(labels = function(x) gsub(reg, "", x), ...) }