1#' Scales for area or radius
2#'
3#' `scale_size()` scales area, `scale_radius()` scales radius. The size
4#' aesthetic is most commonly used for points and text, and humans perceive
5#' the area of points (not their radius), so this provides for optimal
6#' perception. `scale_size_area()` ensures that a value of 0 is mapped
7#' to a size of 0. `scale_size_binned()` is a binned version of `scale_size()` that
8#' scales by area (but does not ensure 0 equals an area of zero). For a binned
9#' equivalent of `scale_size_area()` use `scale_size_binned_area()`.
10#'
11#' @name scale_size
12#' @inheritParams continuous_scale
13#' @inheritParams binned_scale
14#' @param range a numeric vector of length 2 that specifies the minimum and
15#'   maximum size of the plotting symbol after transformation.
16#' @seealso [scale_size_area()] if you want 0 values to be mapped
17#'   to points with size 0.
18#' @examples
19#' p <- ggplot(mpg, aes(displ, hwy, size = hwy)) +
20#'    geom_point()
21#' p
22#' p + scale_size("Highway mpg")
23#' p + scale_size(range = c(0, 10))
24#'
25#' # If you want zero value to have zero size, use scale_size_area:
26#' p + scale_size_area()
27#'
28#' # Binning can sometimes make it easier to match the scaled data to the legend
29#' p + scale_size_binned()
30#'
31#' # This is most useful when size is a count
32#' ggplot(mpg, aes(class, cyl)) +
33#'   geom_count() +
34#'   scale_size_area()
35#'
36#' # If you want to map size to radius (usually bad idea), use scale_radius
37#' p + scale_radius()
38NULL
39
40#' @rdname scale_size
41#' @export
42#' @usage NULL
43scale_size_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(),
44                                  limits = NULL, range = c(1, 6),
45                                  trans = "identity", guide = "legend") {
46  continuous_scale("size", "area", area_pal(range), name = name,
47    breaks = breaks, labels = labels, limits = limits, trans = trans,
48    guide = guide)
49}
50
51#' @rdname scale_size
52#' @export
53scale_size <- scale_size_continuous
54
55#' @rdname scale_size
56#' @export
57scale_radius <- function(name = waiver(), breaks = waiver(), labels = waiver(),
58                         limits = NULL, range = c(1, 6),
59                         trans = "identity", guide = "legend") {
60  continuous_scale("size", "radius", rescale_pal(range), name = name,
61    breaks = breaks, labels = labels, limits = limits, trans = trans,
62    guide = guide)
63}
64
65#' @rdname scale_size
66#' @export
67scale_size_binned <- function(name = waiver(), breaks = waiver(), labels = waiver(),
68                              limits = NULL, range = c(1, 6), n.breaks = NULL,
69                              nice.breaks = TRUE, trans = "identity", guide = "bins") {
70  binned_scale("size", "area_b", area_pal(range), name = name,
71               breaks = breaks, labels = labels, limits = limits, trans = trans,
72               n.breaks = n.breaks, nice.breaks = nice.breaks, guide = guide)
73}
74
75#' @rdname scale_size
76#' @export
77#' @usage NULL
78scale_size_discrete <- function(...) {
79  warn("Using size for a discrete variable is not advised.")
80  scale_size_ordinal(...)
81}
82
83#' @rdname scale_size
84#' @export
85#' @usage NULL
86scale_size_ordinal <- function(..., range = c(2, 6)) {
87  force(range)
88
89  discrete_scale(
90    "size",
91    "size_d",
92    function(n) {
93      area <- seq(range[1] ^ 2, range[2] ^ 2, length.out = n)
94      sqrt(area)
95    },
96    ...
97  )
98}
99
100#' @inheritDotParams continuous_scale -aesthetics -scale_name -palette -rescaler
101#' @param max_size Size of largest points.
102#' @export
103#' @rdname scale_size
104scale_size_area <- function(..., max_size = 6) {
105  continuous_scale("size", "area",
106    palette = abs_area(max_size),
107    rescaler = rescale_max, ...)
108}
109
110#' @export
111#' @rdname scale_size
112scale_size_binned_area <- function(..., max_size = 6) {
113  binned_scale("size", "area_b",
114               palette = abs_area(max_size),
115               rescaler = rescale_max, ...)
116}
117
118#' @rdname scale_size
119#' @export
120#' @usage NULL
121scale_size_datetime <- function(..., range = c(1, 6)) {
122  datetime_scale("size", "time", palette = area_pal(range), ...)
123}
124
125#' @rdname scale_size
126#' @export
127#' @usage NULL
128scale_size_date <- function(..., range = c(1, 6)) {
129  datetime_scale("size", "date", palette = area_pal(range), ...)
130}
131