I have a package with custom summary()
, print()
methods for objects that have a particular class. This package also uses the wonderful dplyr
package for data manipulation - and I expect my users to write scripts that use both my package and dplyr.
One roadblock, which has been noted by others here and here is that dplyr verbs doesn't preserve custom classes - meaning that an ungroup
command can strip my data.frames of their custom classes, and thus screw up method dispatch for summary
, etc.
Hadley says "doing this correctly is up to you - you need to define a method for your class for each dplyr method that correctly restores all the classes and attributes" and I'm trying to take the advice - but I can't figure out how to correctly wrap the dplyr verbs.
Here's a simple toy example. Let's say I've defined a cars
class, and I have a custom summary
for it.
this works
library(tidyverse)
class(mtcars) <- c('cars', class(mtcars))
summary.cars <- function(x, ...) {
#gather some summary stats
df_dim <- dim(x)
quantile_sum <- map(mtcars, quantile)
cat("A cars object with:\n")
cat(df_dim[[1]], 'rows and ', df_dim[[2]], 'columns.\n')
print(quantile_sum)
}
summary(mtcars)
here's the problem
small_cars <- mtcars %>% filter(cyl < 6)
summary(small_cars)
class(small_cars)
that summary
call for small_cars
just gives me the generic summary, not my custom method, because small_cars
no longer retains the cars
class after dplyr filtering.
what I tried
First I tried writing a custom method around filter
(filter.cars
). That didn't work, because filter
actually a wrapper around filter_
that allows for non-standard evaluation.
So I wrote a custom filter_
method for cars
objects, attempting to implement @jwdink 's advice
filter_.cars <- function(df, ...) {
old_classes <- class(df)
out <- dplyr::filter_(df, ...)
new_classes <- class(out)
class(out) <- c(new_classes, old_classes) %>% unique()
out
}
That doesn't work - I get an infinite recursion error:
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
All I want to do is grab the classes on the incoming df, hand off to dplyr, then return the object with the same classnames as it had before the dplyr call. How do I change my filter_
wrapper to accomplish that? Thanks!