/
lollipop_chart.R
148 lines (141 loc) · 5.34 KB
/
lollipop_chart.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#' Lollipop Chart
#'
#' Easily create a lollipop chart
#'
#' @param data Dataset to use for the bar chart
#' @param x \code{character} or \code{factor} column of \code{data}
#' @param y \code{numeric} column of \code{data} representing the lollipop length.
#' If missing, the lollipop length will be proportional to the count of
#' each value in \code{x}.
#' @param facet \code{character} or \code{factor} column of \code{data} defining
#' the faceting groups
#' @param ... Additional arguments passed to \code{aes()}
#' @param line_size \code{numeric}. Size of the lollipop 'stick'
#' @param line_color \code{character}. Color of the lollipop 'stick'
#' @param point_size \code{numeric}. Size of the lollipop 'head'
#' @param point_color \code{character}. Color of the lollipop 'head'
#' @param highlight \code{character}. One or more value(s) of \code{x} that
#' should be highlighted in the plot
#' @param sort \code{logical}. Should the data be sorted before plotting?
#' @param horizontal \code{logical}. Should the plot be oriented horizontally?
#' @param top_n \code{numeric}. If a value for \code{top_n} is provided only the
#' top \code{top_n} records will be displayed
#' @param threshold \code{numeric}. If a value for threshold is provided only
#' records with \code{y > threshold} will be displayed
#' @param other \code{logical}. Should all \code{x} with \code{y < threshold} be
#' summarized in a group called 'other' and be displayed at the bottom of
#' the chart?
#' @param limit Deprecated. use \code{top_n} instead.
#'
#' @details
#' Both \code{top_n} and \code{threshold} only work when \code{sort = TRUE}.
#' Attempting to use them when \code{sort = FALSE} will result in an error.
#' Furthermore, only \code{top_n} or \code{threshold} can be used at a time.
#' Providing a value for both \code{top_n} and \code{threshold} will result in
#' an error as well.
#'
#' @return An object of class \code{ggplot}
#'
#' @author Thomas Neitmann
#'
#' @seealso
#' For more details have a look at these vignettes:
#' \code{vignette("highlight", package = "ggcharts")}
#' \code{vignette("customize", package = "ggcharts")}
#'
#' @examples
#' data(biomedicalrevenue)
#' revenue2016 <- biomedicalrevenue[biomedicalrevenue$year == 2016, ]
#' revenue_bayer <- biomedicalrevenue[biomedicalrevenue$company == "Bayer", ]
#'
#' ## By default lollipop_chart() creates a horizontal and sorted plot
#' lollipop_chart(revenue2016, company, revenue)
#'
#' ## If the `y` argument is missing the count of each value in `x` is displayed
#' lollipop_chart(mtcars, cyl)
#'
#' ## Create a vertical, non-sorted lollipop chart
#' lollipop_chart(revenue_bayer, year, revenue, horizontal = FALSE, sort = FALSE)
#'
#' ## Limit the number of lollipops to the top 15
#' lollipop_chart(revenue2016, company, revenue, top_n = 15)
#'
#' ## Display only companies with revenue > 50B.
#' lollipop_chart(revenue2016, company, revenue, threshold = 50)
#'
#' ## Change the color of the whole lollipop
#' lollipop_chart(revenue2016, company, revenue, line_color = "purple")
#'
#' ## Change the color of the lollipop stick and head individually
#' lollipop_chart(revenue2016, company, revenue, point_color = "darkgreen", line_color = "gray")
#'
#' ## Decrease the lollipop head size
#' lollipop_chart(revenue2016, company, revenue, point_size = 2.5)
#'
#' ## Highlight a single lollipop
#' lollipop_chart(revenue2016, company, revenue, top_n = 15, highlight = "Roche")
#'
#' ## Use facets to show the top 10 companies over the years
#' lollipop_chart(biomedicalrevenue, company, revenue, facet = year, top_n = 10)
#' @import ggplot2
#' @importFrom magrittr %>%
#' @export
lollipop_chart <- function(data, x, y, facet = NULL, ..., line_size = 0.75,
line_color = "auto", point_size = 4,
point_color = line_color, highlight = NULL,
sort = TRUE, horizontal = TRUE, top_n = NULL,
threshold = NULL, other = FALSE, limit = NULL) {
x <- rlang::enquo(x)
y <- rlang::enquo(y)
facet <- rlang::enquo(facet)
dot_names <- names(rlang::enquos(...))
if (length(line_color) == 1 && line_color == "auto") {
line_color <- auto_color()
if (length(point_color) == 1 && point_color == "auto") {
point_color <- line_color
}
}
data <- pre_process_data(
data = data, x = !!x, y = !!y,
facet = !!facet,
highlight = highlight,
highlight_color = line_color,
sort = sort,
top_n = top_n,
threshold = threshold,
other = other,
limit = limit
)
if (rlang::quo_is_missing(y)) {
y <- sym("n")
}
gp_args <- list()
gs_args <- list(
mapping = aes(y = 0, xend = !!x, yend = !!y),
size = line_size
)
if (!"size" %in% dot_names) {
gp_args$size <- point_size
}
if (!is.null(highlight)) {
gs_args$mapping <- aes(y = 0, xend = !!x, yend = !!y, color = .data$.color)
gp_args$mapping <- aes(color = .data$.color)
} else if (!"color" %in% dot_names) {
gs_args$color <- line_color
gp_args$color <- point_color
}
p <- ggplot(data, aes(!!x, !!y, ...)) +
do.call(geom_segment, gs_args) +
do.call(geom_point, gp_args)
post_process_plot(
plot = p,
is_sorted = TRUE,
horizontal = horizontal,
facet = !!facet,
fill = FALSE,
highlight = highlight,
color = line_color,
other = other,
threshold = threshold
)
}