10
10
# ' @eval rd_aesthetics("geom", "violin")
11
11
# ' @inheritParams layer
12
12
# ' @inheritParams geom_bar
13
- # ' @param draw_quantiles If `not(NULL)` (default), draw horizontal lines
14
- # ' at the given quantiles of the density estimate.
15
13
# ' @param trim If `TRUE` (default), trim the tails of the violins
16
14
# ' to the range of the data. If `FALSE`, don't trim the tails.
17
15
# ' @param geom,stat Use to override the default connection between
23
21
# ' finite, boundary effect of default density estimation will be corrected by
24
22
# ' reflecting tails outside `bounds` around their closest edge. Data points
25
23
# ' outside of bounds are removed with a warning.
24
+ # ' @param quantile.colour,quantile.color,quantile.linewidth,quantile.linetype
25
+ # ' Default aesthetics for the quantile lines. Set to `NULL` to inherit from
26
+ # ' the data's aesthetics. By default, quantile lines are hidden and can be
27
+ # ' turned on by changing `quantile.linetype`.
28
+ # ' @param draw_quantiles `r lifecycle::badge("deprecated")` Previous
29
+ # ' specification of drawing quantiles.
26
30
# ' @export
27
31
# ' @references Hintze, J. L., Nelson, R. D. (1998) Violin Plots: A Box
28
32
# ' Plot-Density Trace Synergism. The American Statistician 52, 181-184.
91
95
geom_violin <- function (mapping = NULL , data = NULL ,
92
96
stat = " ydensity" , position = " dodge" ,
93
97
... ,
94
- draw_quantiles = NULL ,
95
98
trim = TRUE ,
96
99
bounds = c(- Inf , Inf ),
100
+ quantile.colour = NULL ,
101
+ quantile.color = NULL ,
102
+ quantile.linetype = 0L ,
103
+ quantile.linewidth = NULL ,
104
+ draw_quantiles = deprecated(),
97
105
scale = " area" ,
98
106
na.rm = FALSE ,
99
107
orientation = NA ,
100
108
show.legend = NA ,
101
109
inherit.aes = TRUE ) {
110
+
111
+ extra <- list ()
112
+ if (lifecycle :: is_present(draw_quantiles )) {
113
+ deprecate_soft0(
114
+ " 3.6.0" ,
115
+ what = " geom_violin(draw_quantiles)" ,
116
+ with = " geom_violin(quantiles.linetype)"
117
+ )
118
+ check_numeric(draw_quantiles )
119
+
120
+ # Pass on to stat when stat accepts 'quantiles'
121
+ stat <- check_subclass(stat , " Stat" , current_call(), caller_env())
122
+ if (" quantiles" %in% stat $ parameters()) {
123
+ extra $ quantiles <- draw_quantiles
124
+ }
125
+
126
+ # Turn on quantile lines
127
+ if (! is.null(quantile.linetype )) {
128
+ quantile.linetype <- max(quantile.linetype , 1 )
129
+ }
130
+ }
131
+
132
+ quantile_gp <- list (
133
+ colour = quantile.color %|| % quantile.colour ,
134
+ linetype = quantile.linetype ,
135
+ linewidth = quantile.linewidth
136
+ )
137
+
102
138
layer(
103
139
data = data ,
104
140
mapping = mapping ,
@@ -110,10 +146,11 @@ geom_violin <- function(mapping = NULL, data = NULL,
110
146
params = list2(
111
147
trim = trim ,
112
148
scale = scale ,
113
- draw_quantiles = draw_quantiles ,
114
149
na.rm = na.rm ,
115
150
orientation = orientation ,
116
151
bounds = bounds ,
152
+ quantile_gp = quantile_gp ,
153
+ !!! extra ,
117
154
...
118
155
)
119
156
)
@@ -146,7 +183,7 @@ GeomViolin <- ggproto("GeomViolin", Geom,
146
183
flip_data(data , params $ flipped_aes )
147
184
},
148
185
149
- draw_group = function (self , data , ... , draw_quantiles = NULL , flipped_aes = FALSE ) {
186
+ draw_group = function (self , data , ... , quantile_gp = list ( linetype = 0 ) , flipped_aes = FALSE ) {
150
187
data <- flip_data(data , flipped_aes )
151
188
# Find the points for the line to go all the way around
152
189
data <- transform(data ,
@@ -165,36 +202,28 @@ GeomViolin <- ggproto("GeomViolin", Geom,
165
202
newdata <- vec_rbind0(newdata , newdata [1 ,])
166
203
newdata <- flip_data(newdata , flipped_aes )
167
204
205
+ violin_grob <- GeomPolygon $ draw_panel(newdata , ... )
206
+
207
+ if (! " quantile" %in% names(newdata ) ||
208
+ all(quantile_gp $ linetype == 0 ) ||
209
+ all(quantile_gp $ linetype == " blank" )) {
210
+ return (ggname(" geom_violin" , violin_grob ))
211
+ }
212
+
168
213
# Draw quantiles if requested, so long as there is non-zero y range
169
- if (length(draw_quantiles ) > 0 & ! scales :: zero_range(range(data $ y ))) {
170
- if (! (all(draw_quantiles > = 0 ) && all(draw_quantiles < = 1 ))) {
171
- cli :: cli_abort(" {.arg draw_quantiles} must be between 0 and 1." )
172
- }
173
-
174
- # Compute the quantile segments and combine with existing aesthetics
175
- quantiles <- create_quantile_segment_frame(data , draw_quantiles )
176
- aesthetics <- data [
177
- rep(1 , nrow(quantiles )),
178
- setdiff(names(data ), c(" x" , " y" , " group" )),
179
- drop = FALSE
180
- ]
181
- aesthetics $ alpha <- rep(1 , nrow(quantiles ))
182
- both <- vec_cbind(quantiles , aesthetics )
183
- both <- both [! is.na(both $ group ), , drop = FALSE ]
184
- both <- flip_data(both , flipped_aes )
185
- quantile_grob <- if (nrow(both ) == 0 ) {
186
- zeroGrob()
187
- } else {
188
- GeomPath $ draw_panel(both , ... )
189
- }
190
-
191
- ggname(" geom_violin" , grobTree(
192
- GeomPolygon $ draw_panel(newdata , ... ),
193
- quantile_grob )
194
- )
214
+ quantiles <- newdata [! is.na(newdata $ quantile ),]
215
+ quantiles $ group <- match(quantiles $ quantile , unique(quantiles $ quantile ))
216
+ quantiles $ linetype <- quantile_gp $ linetype %|| % quantiles $ linetype
217
+ quantiles $ linewidth <- quantile_gp $ linewidth %|| % quantiles $ linewidth
218
+ quantiles $ colour <- quantile_gp $ colour %|| % quantiles $ colour
219
+
220
+ quantile_grob <- if (nrow(quantiles ) == 0 ) {
221
+ zeroGrob()
195
222
} else {
196
- ggname( " geom_violin " , GeomPolygon $ draw_panel(newdata , ... ) )
223
+ GeomPath $ draw_panel(quantiles , ... )
197
224
}
225
+
226
+ ggname(" geom_violin" , grobTree(violin_grob , quantile_grob ))
198
227
},
199
228
200
229
draw_key = draw_key_polygon ,
0 commit comments