juliasilge / tidytext
1
#' Reorder an x or y axis within facets
2
#'
3
#' Reorder a column before plotting with faceting, such that the values are
4
#' ordered within each facet. This requires two functions: \code{reorder_within}
5
#' applied to the column, then either \code{scale_x_reordered} or
6
#' \code{scale_y_reordered} added to the plot.
7
#' This is implemented as a bit of a hack: it appends ___ and then the facet
8
#' at the end of each string.
9
#'
10
#' @param x Vector to reorder.
11
#' @param by Vector of the same length, to use for reordering.
12
#' @param within Vector or list of vectors of the same length that will later
13
#' be used for faceting. A list of vectors will be used to facet within multiple
14
#' variables.
15
#' @param fun Function to perform within each subset to determine the resulting
16
#' ordering. By default, mean.
17
#' @param sep Separator to distinguish the two. You may want to set this
18
#' manually if ___ can exist within one of your labels.
19
#' @param ... In \code{reorder_within} arguments passed on to
20
#' \code{\link{reorder}}. In the scale functions, extra arguments passed on to
21
#' \code{\link[ggplot2]{scale_x_discrete}} or \code{\link[ggplot2]{scale_y_discrete}}.
22
#'
23
#' @source "Ordering categories within ggplot2 Facets" by Tyler Rinker:
24
#' \url{https://trinkerrstuff.wordpress.com/2016/12/23/ordering-categories-within-ggplot2-facets/}
25
#'
26
#' @examples
27
#'
28
#' library(tidyr)
29
#' library(ggplot2)
30
#'
31
#' iris_gathered <- gather(iris, metric, value, -Species)
32
#'
33
#' # reordering doesn't work within each facet (see Sepal.Width):
34
#' ggplot(iris_gathered, aes(reorder(Species, value), value)) +
35
#'   geom_boxplot() +
36
#'   facet_wrap(~ metric)
37
#'
38
#' # reorder_within and scale_x_reordered work.
39
#' # (Note that you need to set scales = "free_x" in the facet)
40
#' ggplot(iris_gathered, aes(reorder_within(Species, value, metric), value)) +
41
#'   geom_boxplot() +
42
#'   scale_x_reordered() +
43
#'   facet_wrap(~ metric, scales = "free_x")
44
#'
45
#' # to reorder within multiple variables, set within to the list of
46
#' # facet variables.
47
#' ggplot(mtcars, aes(reorder_within(carb, mpg, list(vs, am)), mpg)) +
48
#'   geom_boxplot() +
49
#'   scale_x_reordered() +
50
#'   facet_wrap(vs ~ am, scales = "free_x")
51
#'
52
#' @export
53
reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
54 1
  if (!is.list(within)) {
55 1
    within <- list(within)
56
  }
57

58 1
  new_x <- do.call(paste, c(list(x, sep = sep), within))
59 1
  stats::reorder(new_x, by, FUN = fun)
60
}
61

62

63
#' @rdname reorder_within
64
#' @export
65
scale_x_reordered <- function(..., sep = "___") {
66 1
  reg <- paste0(sep, ".+$")
67 1
  ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
68
}
69

70

71
#' @rdname reorder_within
72
#' @export
73
scale_y_reordered <- function(..., sep = "___") {
74 0
  reg <- paste0(sep, ".+$")
75 0
  ggplot2::scale_y_discrete(labels = function(x) gsub(reg, "", x), ...)
76
}

Read our documentation on viewing source code .

Loading