Skip to content

Allow selection of vectors and filters upon initialization#20

Merged
Jeff-Thompson12 merged 25 commits into
develfrom
jt-13-preselection
Aug 9, 2023
Merged

Allow selection of vectors and filters upon initialization#20
Jeff-Thompson12 merged 25 commits into
develfrom
jt-13-preselection

Conversation

@Jeff-Thompson12
Copy link
Copy Markdown
Collaborator

Addresses #13

@Jeff-Thompson12
Copy link
Copy Markdown
Collaborator Author

@AARON-CLARK what do you think of the approach outlined in this PR?

Things I like about it:

  • I'm utilizing how the {tidyverse} creates function mappers, so I think it will be intuitive for users (i.e. a user can specify function(x) x <= 100 or ~.x <= 100)
  • It's fairly uniform across the different methods. We don't have method specific workarounds

Things I don't like:

  • I have inserted a new argument before verbose which makes the functions not as backwards compatible as I would like. This issue feels fairly unavoidable though.
  • The filtering is happening on the vector itself instead of the input (e.g. ~ .x <= 100 might result with x <= 90 if 90 is the largest number less than or equal to 100)
  • Bad inputs for the preselection mostly fail silently

Here's a snippet to see the preselection in action:

ui <- fluidPage(
  titlePanel("Filter Data Example"),
  fluidRow(
    column(8,
      verbatimTextOutput("data_summary"),
      verbatimTextOutput("data_filter_code")),
    column(4, IDEAFilter::shiny_data_filter_ui("data_filter"))))

srv <- function(input, output, session) {
  filtered_data <- callModule(
    IDEAFilter::shiny_data_filter,
    "data_filter",
    data = airquality,
    preselection = list(Ozone = list(filter_na = TRUE, filter_fn = ~.x <= 100),
                        Solar.R = list()),
    verbose = FALSE)

  output$data_filter_code <- renderPrint({
    cat(gsub("%>%", "%>% \n ",
      gsub("\\s{2,}", " ",
        paste0(
          capture.output(attr(filtered_data(), "code")),
          collapse = " "))
    ))
  })

  output$data_summary <- renderPrint({
    if (nrow(filtered_data())) show(filtered_data())
    else "No data available"
  })
}

shinyApp(ui, srv)

Copy link
Copy Markdown
Collaborator

@AARON-CLARK AARON-CLARK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is cool. I love the pre-selection feature and how easy / intuitive it is to add in.

I have inserted a new argument before verbose which makes the functions not as backwards compatible as I would like. This issue feels fairly unavoidable though.

Why can't it be last? so it doesn't introduce breaking changes to users who may not be specifying the arg name with the module call?

The filtering is happening on the vector itself instead of the input (e.g. ~ .x <= 100 might result with x <= 90 if 90 is the largest number less than or equal to 100)

I don't think that's a big deal. Yes, it is slightly confusing if your a developer and you think your filtering to < 100. It's a shame the generated code doesn't reflect the filter_fn. Do you think it could some how?

image

The filtering is happening on the vector itself instead of the input (e.g. ~ .x <= 100 might result with x <= 90 if 90 is the largest number less than or equal to 100)

I think it's fine that variables not found in the data are "ignored" or "fail silently" as long as that message is sent to the console. Nice work!

I was playing around with the starwars example app in our inst/ folder by adding the following code:

filtered_data <- callModule(
   shiny_data_filter, 
   "data_filter", 
   data = starwars2,
   preselection = list(name = list(filter_na = TRUE, filter_fn = ~stringr::str_detect(.x, '[0-9]')),
                       eye_color = list(filter_na = TRUE, filter_fn = ~ c("yellow","red") %in% .x),
                       Solar.R = list()),
   verbose = FALSE)

I did notice that my filter on eye_color didn't really work. For some reason, it's still including "black" eye colors.

image

@Jeff-Thompson12
Copy link
Copy Markdown
Collaborator Author

Why can't it be last? so it doesn't introduce breaking changes to users who may not be specifying the arg name with the module call?

It can be last. In my mind the verbose argument makes sense as the last value, but at this point new arguments should be added to the end of functions already being exported.

@Jeff-Thompson12
Copy link
Copy Markdown
Collaborator Author

I was playing around with the starwars example app in our inst/ folder by adding the following code:

filtered_data <- callModule(
   shiny_data_filter, 
   "data_filter", 
   data = starwars2,
   preselection = list(name = list(filter_na = TRUE, filter_fn = ~stringr::str_detect(.x, '[0-9]')),
                       eye_color = list(filter_na = TRUE, filter_fn = ~ c("yellow","red") %in% .x),
                       Solar.R = list()),
   verbose = FALSE)

I did notice that my filter on eye_color didn't really work. For some reason, it's still including "black" eye colors.

image

So I noticed that your filter is backwards (i.e. you have c("yellow", "red") %in% .x instead of .x %in% c("yellow", "red")). This is causing Filter() to apply a logical vector of length 12 instead of 6 giving the bizarre results. I can't decide if this is a problem for the PR thought because R is behaving in the expected way.

@Jeff-Thompson12
Copy link
Copy Markdown
Collaborator Author

Yes, it is slightly confusing if your a developer and you think your filtering to < 100. It's a shame the generated code doesn't reflect the filter_fn. Do you think it could some how?

image

Not really. I was going down that route at the start, but then you have to account for the different methods. We could allow for other arguments (e.g. if a user provides a max or range value it supersedes filter_fn), but that type of processing is not very intuitive.

Plus since the filter has a waterfall type affect, you couldn't force the values anyways. I think the main thing is that the filtering code is meant to be reproducible on the same dataset, not across datasets.

@Jeff-Thompson12 Jeff-Thompson12 marked this pull request as ready for review August 9, 2023 18:18
@Jeff-Thompson12 Jeff-Thompson12 merged commit 5c2bb92 into devel Aug 9, 2023
@Jeff-Thompson12 Jeff-Thompson12 deleted the jt-13-preselection branch August 9, 2023 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants