1010# ' @eval rd_aesthetics("geom", "violin")
1111# ' @inheritParams layer
1212# ' @inheritParams geom_bar
13- # ' @param draw_quantiles If `not(NULL)` (default), draw horizontal lines
14- # ' at the given quantiles of the density estimate.
1513# ' @param trim If `TRUE` (default), trim the tails of the violins
1614# ' to the range of the data. If `FALSE`, don't trim the tails.
1715# ' @param geom,stat Use to override the default connection between
2321# ' finite, boundary effect of default density estimation will be corrected by
2422# ' reflecting tails outside `bounds` around their closest edge. Data points
2523# ' 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.
2630# ' @export
2731# ' @references Hintze, J. L., Nelson, R. D. (1998) Violin Plots: A Box
2832# ' Plot-Density Trace Synergism. The American Statistician 52, 181-184.
9195geom_violin <- function (mapping = NULL , data = NULL ,
9296 stat = " ydensity" , position = " dodge" ,
9397 ... ,
94- draw_quantiles = NULL ,
9598 trim = TRUE ,
9699 bounds = c(- Inf , Inf ),
100+ quantile.colour = NULL ,
101+ quantile.color = NULL ,
102+ quantile.linetype = 0L ,
103+ quantile.linewidth = NULL ,
104+ draw_quantiles = deprecated(),
97105 scale = " area" ,
98106 na.rm = FALSE ,
99107 orientation = NA ,
100108 show.legend = NA ,
101109 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+
102138 layer(
103139 data = data ,
104140 mapping = mapping ,
@@ -110,10 +146,11 @@ geom_violin <- function(mapping = NULL, data = NULL,
110146 params = list2(
111147 trim = trim ,
112148 scale = scale ,
113- draw_quantiles = draw_quantiles ,
114149 na.rm = na.rm ,
115150 orientation = orientation ,
116151 bounds = bounds ,
152+ quantile_gp = quantile_gp ,
153+ !!! extra ,
117154 ...
118155 )
119156 )
@@ -146,7 +183,7 @@ GeomViolin <- ggproto("GeomViolin", Geom,
146183 flip_data(data , params $ flipped_aes )
147184 },
148185
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 ) {
150187 data <- flip_data(data , flipped_aes )
151188 # Find the points for the line to go all the way around
152189 data <- transform(data ,
@@ -165,36 +202,28 @@ GeomViolin <- ggproto("GeomViolin", Geom,
165202 newdata <- vec_rbind0(newdata , newdata [1 ,])
166203 newdata <- flip_data(newdata , flipped_aes )
167204
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+
168213 # 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()
195222 } else {
196- ggname( " geom_violin " , GeomPolygon $ draw_panel(newdata , ... ) )
223+ GeomPath $ draw_panel(quantiles , ... )
197224 }
225+
226+ ggname(" geom_violin" , grobTree(violin_grob , quantile_grob ))
198227 },
199228
200229 draw_key = draw_key_polygon ,
0 commit comments