From c543570acba7120761815e23fc8b6e78560010d1 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 8 Oct 2025 13:19:51 +0200 Subject: [PATCH 1/3] early returns for empty data --- R/geom_edge_bundle_force.R | 6 ++++++ R/geom_edge_bundle_minimal.R | 6 ++++++ R/geom_edge_bundle_path.R | 6 ++++++ R/geom_edge_elbow.R | 17 ++++++++++------- R/geom_edge_link.R | 6 ++++++ R/geom_edge_parallel.R | 6 ++++++ R/geom_node_circle.R | 6 ++++++ R/utils.R | 4 ++++ 8 files changed, 50 insertions(+), 7 deletions(-) diff --git a/R/geom_edge_bundle_force.R b/R/geom_edge_bundle_force.R index 845b7be..72c8b2c 100644 --- a/R/geom_edge_bundle_force.R +++ b/R/geom_edge_bundle_force.R @@ -243,6 +243,9 @@ StatEdgeBundleForce2 <- ggproto( threshold = 0.6, eps = 1e-8 ) { + if (empty(data)) { + return(data_frame0()) + } data <- data[order(data$group), ] edges <- cbind( data$x[c(TRUE, FALSE)], @@ -382,6 +385,9 @@ StatEdgeBundleForce0 <- ggproto( threshold = 0.6, eps = 1e-8 ) { + if (empty(data)) { + return(data_frame0()) + } edges <- cbind(data$x, data$y, data$xend, data$yend) edges <- force_bundle_mem( edges, diff --git a/R/geom_edge_bundle_minimal.R b/R/geom_edge_bundle_minimal.R index 2e77a71..80b94ae 100644 --- a/R/geom_edge_bundle_minimal.R +++ b/R/geom_edge_bundle_minimal.R @@ -203,6 +203,9 @@ StatEdgeBundleMinimal2 <- ggproto( weight_fac = 2, tension = 1 ) { + if (empty(data)) { + return(data_frame0()) + } graph <- .G() nodes <- data_frame0(x = .N()$.ggraph_layout_x, y = .N()$.ggraph_layout_y) data <- data[order(data$group), ] @@ -321,6 +324,9 @@ StatEdgeBundleMinimal0 <- ggproto( weight_fac = 2, tension = 1 ) { + if (empty(data)) { + return(data_frame0()) + } graph <- .G() nodes <- data_frame0(x = .N()$.ggraph_layout_x, y = .N()$.ggraph_layout_y) edges <- minimal_bundle_mem( diff --git a/R/geom_edge_bundle_path.R b/R/geom_edge_bundle_path.R index c12ecb1..1baddde 100644 --- a/R/geom_edge_bundle_path.R +++ b/R/geom_edge_bundle_path.R @@ -228,6 +228,9 @@ StatEdgeBundlePath2 <- ggproto( weight_fac = 2, tension = 1 ) { + if (empty(data)) { + return(data_frame0()) + } graph <- .G() nodes <- data_frame0(x = .N()$.ggraph_layout_x, y = .N()$.ggraph_layout_y) data <- data[order(data$group), ] @@ -350,6 +353,9 @@ StatEdgeBundlePath0 <- ggproto( weight_fac = 2, tension = 1 ) { + if (empty(data)) { + return(data_frame0()) + } graph <- .G() nodes <- data_frame0(x = .N()$.ggraph_layout_x, y = .N()$.ggraph_layout_y) from <- .E()$from[data$edge_id] diff --git a/R/geom_edge_elbow.R b/R/geom_edge_elbow.R index 2ba94d5..8cbf43c 100644 --- a/R/geom_edge_elbow.R +++ b/R/geom_edge_elbow.R @@ -108,6 +108,10 @@ StatEdgeElbow <- ggproto( n = 100, strength = 1 ) { + if (empty(data)) { + return(data_frame0()) + } + data$group <- make_unique(data$group) if (data$circular[1] && n %% 2 == 1) { n <- n + 1 @@ -234,10 +238,6 @@ StatEdgeElbow <- ggproto( setup_data = function(data, params) { data <- StatFilter$setup_data(data, params) data <- remove_loop(data) - if (nrow(data) == 0) { - return(data) - } - data }, default_aes = aes(filter = TRUE), required_aes = c('x', 'y', 'xend', 'yend', 'circular', 'direction') @@ -325,6 +325,9 @@ StatEdgeElbow2 <- ggproto( n = 100, strength = 1 ) { + if (empty(data)) { + return(data_frame0()) + } pos_cols <- c('x', 'y', 'group', 'circular', 'direction', 'PANEL') data <- data[order(data$group), ] pos_data <- cbind( @@ -359,9 +362,6 @@ StatEdgeElbow2 <- ggproto( setup_data = function(data, params) { data <- StatFilter$setup_data(data, params) data <- remove_loop2(data) - if (nrow(data) == 0) { - return(data) - } data }, default_aes = aes(filter = TRUE), @@ -442,6 +442,9 @@ StatEdgeElbow0 <- ggproto( 'StatEdgeElbow0', Stat, compute_panel = function(data, scales, flipped = FALSE, strength = 1) { + if (empty(data)) { + return(data_frame0()) + } data$group <- make_unique(data$group) if (any(data$circular)) { if (strength != 1) { diff --git a/R/geom_edge_link.R b/R/geom_edge_link.R index b4a0399..9b3a5a4 100644 --- a/R/geom_edge_link.R +++ b/R/geom_edge_link.R @@ -186,6 +186,12 @@ StatEdgeLink2 <- ggproto( } StatLink2$setup_data(data, params) }, + compute_layer = function(data, params, layout) { + if (empty(data)) { + return(data) + } + StatEdgeLink2$compute_layer(data, params, layout) + }, default_aes = aes(filter = TRUE) ) #' @rdname geom_edge_link diff --git a/R/geom_edge_parallel.R b/R/geom_edge_parallel.R index b506278..4f2794e 100644 --- a/R/geom_edge_parallel.R +++ b/R/geom_edge_parallel.R @@ -207,6 +207,12 @@ StatEdgeParallel2 <- ggproto( data$.position <- rep(edge_positions(data1, data2), each = 2) StatLink2$setup_data(data, params) }, + compute_layer = function(data, params, layout) { + if (empty(data)) { + return(data) + } + StatEdgeLink2$compute_layer(data, params, layout) + }, required_aes = c('x', 'y', 'group', 'from', 'to'), default_aes = aes(filter = TRUE), extra_params = c('na.rm', 'n') diff --git a/R/geom_node_circle.R b/R/geom_node_circle.R index 5e9f40d..19534e6 100644 --- a/R/geom_node_circle.R +++ b/R/geom_node_circle.R @@ -71,5 +71,11 @@ StatNodeCircle <- ggproto( setup_data = function(data, params) { StatFilter$setup_data(data, params) }, + compute_layer = function(data, params, layout) { + if (empty(data)) { + return(data) + } + StatCircle$compute_layer(data, params, layout) + }, default_aes = aes(filter = TRUE) ) diff --git a/R/utils.R b/R/utils.R index 133e099..b509eba 100644 --- a/R/utils.R +++ b/R/utils.R @@ -206,3 +206,7 @@ snakeize <- function(x) { snake_class <- function(x) { snakeize(class(x)[1]) } + +empty <- function(df) { + is.null(df) || nrow(df) == 0 || ncol(df) == 0 || inherits(df, "waiver") +} From 2f3dc4bb800b172800e18899e013d4c61f8864d4 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 8 Oct 2025 13:23:37 +0200 Subject: [PATCH 2/3] explicit return value --- R/geom_edge_elbow.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/geom_edge_elbow.R b/R/geom_edge_elbow.R index 8cbf43c..132f5f1 100644 --- a/R/geom_edge_elbow.R +++ b/R/geom_edge_elbow.R @@ -238,6 +238,7 @@ StatEdgeElbow <- ggproto( setup_data = function(data, params) { data <- StatFilter$setup_data(data, params) data <- remove_loop(data) + data }, default_aes = aes(filter = TRUE), required_aes = c('x', 'y', 'xend', 'yend', 'circular', 'direction') From dbf5c43398d2d52e26507df56bf8759b4c89db02 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 8 Oct 2025 13:46:17 +0200 Subject: [PATCH 3/3] fix using wrong stat --- R/geom_edge_link.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/geom_edge_link.R b/R/geom_edge_link.R index 9b3a5a4..74a2378 100644 --- a/R/geom_edge_link.R +++ b/R/geom_edge_link.R @@ -190,7 +190,7 @@ StatEdgeLink2 <- ggproto( if (empty(data)) { return(data) } - StatEdgeLink2$compute_layer(data, params, layout) + StatLink2$compute_layer(data, params, layout) }, default_aes = aes(filter = TRUE) )