Reputation: 2166
I have template plot functions that check whether a data frame has > 0 rows before running:
library(tidyverse)
plot_fun <- function(df) {
if (nrow(df) > 0) {
df %>%
ggplot(., aes(Sepal.Length, Sepal.Width)) +
geom_point()
}
}
Then I use this within pipes and add bespoke layers:
iris %>% plot_fun() + ggtitle("Plot me")
However if the data framed piped in has 0 rows I get an error because I am trying to add layers to nothing:
iris %>%
filter(Sepal.Length > 1000) %>%
plot_fun() +
ggtitle("Plot me")
Error in iris %>% filter(Sepal.Length > 1000) %>% plot_fun() + ggtitle("Plot me") : non-numeric argument to binary operator
I can build a check mid pipe to avoid the error:
iris %>%
filter(Sepal.Length > 1000) %>%
plot_fun() %>%
{
if (!is.null(.)) {
. +
ggtitle("Plot me")
}
}
That works but that seems clunky. Is it possible to make a function check_df_pipe()
or something to stop the pipe if preceding filters remove all data? Or maybe to check if the pipe .
is NULL
at a point?
check_df_pipe <- function(x) {
if(nrow(x) > 0) {
x
} else{
stop("Dont return an error just to exit pipe")
}
}
iris %>%
filter(Sepal.Length > 1000) %>%
check_df_pipe() %>%
plot_fun() +
ggtitle("Plot me")
Error in check_df_pipe(.) : Dont return an error just to exit pipe
Or any other ideas on how to deal with this? I don't want to add ggtitle("Plot me")
into plot_fun
because I wan't plot_fun
to stay generic.
Upvotes: 2
Views: 2341
Reputation: 2816
This doesn't directly answer your question, but how about a different approach? When the dataframe has zero rows, use geom_blank()
to create an empty plot. Adding a title later doesn't return an error.
plot_fun <- function(df) {
if (nrow(df) > 0) {
df %>%
ggplot(., aes(Sepal.Length, Sepal.Width)) +
geom_point()
} else {
ggplot(data = data.frame()) +
geom_blank()
}
}
iris %>%
filter(Sepal.Length > 1000) %>%
plot_fun() +
ggtitle("Plot me")
You can pass layers as function arguments. Here's a function that checks whether the plot exists, and then adds the layers only if it does.
append_layers_maybe <- function(p, l) {
if(!is.null(p)) {
p + l
}
}
iris %>%
plot_fun() %>%
append_layers_maybe(facet_wrap(~ Species)) %>%
append_layers_maybe(ggtitle("Foo"))
iris %>%
filter(Sepal.Length > 1000) %>%
plot_fun() %>%
append_layers_maybe(facet_wrap(~ Species)) %>%
append_layers_maybe(ggtitle("Plot me"))
Upvotes: 2
Reputation: 1258
I would not recommend such piping. It can be confusing to decode such a code. But here is a solution:
cond_pipe <- function(x) {
if (nrow(x) > 0) {
x %>%
plot_fun() +
ggtitle("Plot me")
} else {
warning("Dont return an error just to exit pipe")
}
}
iris %>%
filter(Sepal.Length > 1000) %>%
cond_pipe()
Upvotes: 1