Carrying names forward when assigning a reactive gives `Error in UseMethod: no applicable method for 'filter' applied to an object of class "c('reactiveExpr...`

Hi, I'm new to Shiny and noticed something that prevents my typical coding practice (which is maybe bad?).

Something like this will give an error:

years_server <- function(id, .data){
  moduleServer( id, function(input, output, session){

    .data <- reactive({
      .data |>
        dplyr::filter(year %in% input$year[1]:input$year[2]) 

      })

    output$table <- renderTable(.data())
})
})

But when writing a general R function, this is fine:

summarize_years <- function(.data){

  .data <- .data |>
    dplyr::arrange(year)

 .data

}

Why is that?

Reprex below:

library(shiny)

ui <- fluidPage(
  mainPanel(
    tableOutput("table")
  ),
  sliderInput(
    inputId = "mpg",
    label = "Choose mpg",
    step = 1,
    sep = "",
    min = 15,
    max = 20,
    value = c(15, 20)
  )
)

mpg_server <- function(id, .data){
  moduleServer( id, function(input, output, session){

    .data <- reactive({
      .data |>
        dplyr::filter(mpg %in% input$mpg)

    })

    output$table <- renderTable(.data())
  })
}

server <- function(input, output, session, .data) {
  .data <- mpg_server("test", .data = mpg)
  output$table <- renderTable(.data())
}

shinyApp(ui = ui, server)

I think its bad practice to reuse (a very generic name) for different purposes.
What is .data ? A parameter sent into your module ? Or a name of a reactive defined by your module.

In the definition you are necessarily referring to the param sent in, was that a reactive ? If it was you would need to acess the value via brackets in the standard way. .data()

.data is a parameter which will take a data.frame.

The error message clearly shows that R thinks you are trying to filter a reactive.. and not a data.frame. First step is to edit your names to disambiguate them, as i said previously

Hi Adam :wave:

As @nirgrahamuk points out, the issue stems from name collision.

Interestingly, even if you passed .data() (the content of the reactive expression) to dplyr::filter(), you would face infinite recursion (the reactive expression reacts to itself) and Shiny would throw an error.

To avoid this, disentangle the name of the reactive expression from the name of the dataframe (which would remain .data in the following example), by using a different name (e.g. filtered_data) :

years_server <- function(id, .data){
  moduleServer( id, function(input, output, session){

    filtered_data <- reactive({
      .data |>
        dplyr::filter(year %in% input$year[1]:input$year[2]) 

      })

    output$table <- renderTable(filtered_data())
})
})

Hope this helps :slight_smile:
Cheers!


This post was published by an Appsilon team member. Our company can help you get the most out of RShiny and Posit/RStudio products.

Check our open positions here.

Appsilon: Building impactful RShiny Dashboards and providing R coding services.
Appsilon_GIFsmall_whitebg

Thanks, I understand how to solve the error. I'm more trying to wrap my head around the why/philosophy behind the need to separate the names .data and filtered_data.

When I look at the simple function, I think of the process acting linearly, once through. Is the difference that a server is live? So that .data becomes a reactive, and cannot be filtered on? What exactly happens step by step in the server that causes the error?

summarize_years <- function(.data){

  .data <- .data |>
    dplyr::arrange(year)

 .data

}

Ah, I see :+1:

why/philosophy behind the need to separate the names .data and filtered_data

The short answer is because they are different things:.data is a dataframe, while filtered_data is a reactive. A reactive is a function. This function is called each time something reactive inside its definition gets invalidated (e.g. a change in input$year).

However, from your original post, it seems you are expecting .data to always be a dataframe, even when you defined the name of your reactive as .data as well.

R doesn't know your intentions and just looks for an object called .data which in your case is the reactive itself. However, as you are just using the expression and not its result (by accessing it with ()) it throws an error. Even if you used .data() this would cause infinite recursion.

When I look at the simple function, I think of the process acting linearly, once through. Is the difference that a server is live? So that .data becomes a reactive, and cannot be filtered on? What exactly happens step by step in the server that causes the error?

Maybe we can illustrate this without even refering to Shiny and reactivity.
Imagine this simplification of your case, and please take a look at the comments in the code I made:

# Your dataframe (i.e. original .data)
.data <- 1

# Your reactive expression (which you also named .data)
.data <- function() {
 # What do you think this `.data` object (right below this comment) will be when you run this function? A numeric or a function?
 .data + 1
}

# What do you think will happen when you run this?
.data()

Hope this helps :slight_smile:
Cheers!


This post was published by an Appsilon team member. Our company can help you get the most out of RShiny and Posit/RStudio products.

Check our open positions here.

Appsilon: Building impactful RShiny Dashboards and providing R coding services.
Appsilon_GIFsmall_whitebg

1 Like

That was very helpful, thanks agus! Thinking of reactive() as a function solved my confusion. Following your last example, I believe the server function in my original post is like the below

.data <- 1

server_fnc <- function(.data){
  .data <- function() {
    .data + 1
  }
  return(.data)
}

server_fnc(.data)
#> function() {
#>     .data + 1
#>   }
#> <environment: 0x000002001db24958>

Created on 2023-02-21 with reprex v2.0.2

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.