rpurrrpmap

R dplyr purrr error when passing dataframe to pmap_dfr()


I'm preparing a function to graph trigonometric functions. I have written a function which successfully returns the correct value when given the parameters for single value of theta, but when I attempt to pass a data frame with a column for each parameter using purrr::pmap_dfr() in order to produce a set of values to graph, I get an error whose message doesn't appear to match the situation.

Here a reproducible example:

thetas <- seq(from = -3, to = 3, by = 0.05) 
amplitudes <- rep(1, times = length(thetas))
period_denoms<- rep(1, times = length(thetas))
horizontal_shifts <- rep(0, times = length(thetas))
vertical_shifts <- rep(0, times = length(thetas))

argList <- list(thetas,
                amplitudes,
                period_denoms,
                horizontal_shifts,
                vertical_shifts) %>%
    as_tibble(.name_repair = ~ c("theta",
                                "amplitude",
                                "period_denom",
                                "horizontal_shift",
                                "vertical_shift")
                )
xformed_sine <- function(theta, amplitude, period_denom, horizontal_shift, vertical_shift){
        period <- (2 * pi)/abs(period_denom)
        
        return(as.double(amplitude * sinpi(period(theta + horizontal_shift)) + vertical_shift))
}

pmap_dfr(argList, xformed_sine)

R returns this error:

"Error in dplyr::bind_rows(): ! Argument 1 must be a data frame or a named atomic vector."

As I read the error, R is complaining that the object argList is not a data frame, yet when I run this code: is.data.frame(argList) the returned value is TRUE.

The return from that last bit doesn't match the error message, which tells me that argList isn't a data frame. Both can't be true, and I suspect that either I misunderstand the error message, or there is a bug in the pmap_dfr() function.

Any thoughts?


Solution

  • The error is referring to what your xformed_sine() function returns. You can make it a tibble and your code will run:

    xformed_sine <- function(theta, amplitude, period_denom, horizontal_shift, vertical_shift){
      period <- (2 * pi)/abs(period_denom)
      
      return(
        tibble(result = amplitude * sinpi(period(theta + horizontal_shift)) + vertical_shift)
      )
    }
    
    pmap_dfr(argList, xformed_sine)
    # A tibble: 121 × 1
       result             
       <Period>           
     1 0S                 
     2 -0.15643446504023S 
     3 -0.309016994374948S
     4 -0.453990499739547S
     5 -0.587785252292474S
     6 -0.707106781186547S
     7 -0.809016994374947S
     8 -0.891006524188368S
     9 -0.951056516295154S
    10 -0.987688340595138S
    # … with 111 more rows
    # ℹ Use `print(n = ...)` to see more rows
    

    Alternately, just keep your xformed_sine() as is and use pmap_dbl().

    A little extra explanation: There's a hint that purrr is hitting an error after it completes the mapping function, as it fails when trying to bind rows on res (res = result of map operation) in rlang::last_error():

    rlang::last_error()
    <error/rlang_error>
    Error in `dplyr::bind_rows()`:
    ! Argument 1 must be a data frame or a named atomic vector.
    ---
    Backtrace:
     1. purrr::pmap_dfr(argList, xformed_sine)
     2. dplyr::bind_rows(res, .id = .id)
    

    It is kind of an ambiguous error message though, I can see how it is confusing without any additional context.