@@ -188,6 +188,9 @@ GeomPath <- ggproto("GeomPath", Geom,
188
188
end <- c(group_diff , TRUE )
189
189
190
190
if (! constant ) {
191
+
192
+ arrow <- repair_segment_arrow(arrow , munched $ group )
193
+
191
194
segmentsGrob(
192
195
munched $ x [! end ], munched $ y [! end ], munched $ x [! start ], munched $ y [! start ],
193
196
default.units = " native" , arrow = arrow ,
@@ -363,3 +366,40 @@ stairstep <- function(data, direction = "hv") {
363
366
364
367
data_frame0(x = x , y = y , data_attr )
365
368
}
369
+
370
+ repair_segment_arrow <- function (arrow , group ) {
371
+ # Early exit if there is no arrow
372
+ if (is.null(arrow )) {
373
+ return (arrow )
374
+ }
375
+
376
+ # Get group parameters
377
+ rle <- vec_group_rle(group ) # handles NAs better than base::rle()
378
+ n_groups <- length(rle )
379
+ rle_len <- field(rle , " length" ) - 1 # segments have 1 member less than lines
380
+ rle_end <- cumsum(rle_len )
381
+ rle_start <- rle_end - rle_len + 1
382
+
383
+ # Recycle ends and lengths
384
+ ends <- rep(rep(arrow $ ends , length.out = n_groups ), rle_len )
385
+ len <- rep(rep(arrow $ length , length.out = n_groups ), rle_len )
386
+
387
+ # Repair ends
388
+ # Convert 'both' ends to first/last in multi-member groups
389
+ is_both <- which(ends == 3 )
390
+ ends [setdiff(intersect(rle_start , is_both ), rle_end )] <- 1L
391
+ ends [setdiff(intersect(rle_end , is_both ), rle_start )] <- 2L
392
+ arrow $ ends <- ends
393
+
394
+ # Repair lengths
395
+ zero <- unit(0 , " mm" )
396
+ # Set length of first segment to zero when ends is 'last'
397
+ len [intersect(setdiff(rle_start , rle_end ), which(ends == 2 ))] <- zero
398
+ # Set length of last segment to zero when ends is 'first'
399
+ len [intersect(setdiff(rle_end , rle_start ), which(ends == 1 ))] <- zero
400
+ # Set length of middle pieces to zero
401
+ len [setdiff(seq_along(len ), c(rle_start , rle_end ))] <- zero
402
+ arrow $ length <- len
403
+
404
+ return (arrow )
405
+ }
0 commit comments