Dynamic group-based filtering in R Shiny - search by tag replication

232 Views Asked by At

I want to create a filter in Shiny that would work like the details below.

I currently do not have anything close to working with the functionality described. The closest I have achieved is using selectizeGroupUI/Server. But this module from shinywidgets does have the desired output of searching by group.

  1. A table is displayed with two columns, an ID_Col and a Tag col and a dropdown filter box.

  2. Users click into the filter box and all of the tags are available (as nothing is filtered). They can scroll or search to find their first tag selection.

  3. The user selects their first tag. The table is filtered to show all IDs that meet that criteria, as well as every other row that belongs to that ID. AND the filter updates its Choices to only include relevant tags. ex: filtering for value "a" will return all 3 rows of ID_2 AND all 3 rows of ID_3. AND the search bar will update so that the second tag that can be selected will only be between the values "x", "y", and "n" As ID_2 and ID_3 have a row with a value of "a" and the tags related to ID_2 and ID_3 are "x", "y", and "n".

ex:

ID_Col | value
ID_1   | x
ID_1   | y
ID_1   | z
ID_2   | a
ID_2   | x
ID_2   | y
ID_3   | a
ID_3   | n
ID_3   | x

The user selects a 2nd tag from the updated list and the above actions repeat.

  1. The second tag is selected, the table is updated for only IDs that are related to tag_1 AND tag_2. The filter updates with only the relevant tags for IDs that are related to tag_1 AND tag_2.

ex: if the user selects "y" as the second tag then the filter is searching for IDs where the ID is associated to both "a" AND "y". So the only ID to return from the above example is ID_2. So it should work like the below in practice.

df <- 
  data.frame(ID_Col= c(rep("ID1", 3), rep("ID2", 3), rep("ID3", 3)),
       value= c("X", "Y", "Z", "X", "Y", "A", "A", "N", "X"))
# first filter returns both ID1 and ID2 because both ID have one row where value == "X"
df %>% 
  group_by(ID_Col) %>% 
  filter(any(value== "A"))
# this second filter will return only ID2 because only ID2 has a row where value == "X" AND a row where value == "A"
df %>% 
  group_by(ID_Col) %>% 
  filter(any(value== "A") & any(value== "Y"))

The more complex version of this question is that I have many types of tags with 1:1 and 1:many for example if we were talking recipes. In my 1:1 table I'd have recipe_ID, style (french OR japanese OR etc..), cook_duration etc. But then I'd have a 1:many table recipe_ID, ingredients.

The full question is how can I do the above, retain the choice updating, split out the types of tags into separate filters, AND have the search bars look for IDs where ALL of the tag conditions are met.

ex: I have a lot of a chicken to cook, select chicken as the first tag in ingredients. All recipes that use chicken show up. I also have a lot of onions. tag2 == onions. the table updates to only recipes with Chicken AND onions. I'm out of asian ingredients so I'll pick italian as my genre. the table updates to recipes that are Italian AND use chicken AND use onions.

To add another layer of complexity, it would be nice to choose between OR and AND when searching.

ex: I just got back from the Asian food store, now my search is recipes that are for Japanese OR Chinese where recipes have chicken AND onions.

Thank you in advance.


This is my starting point that I cannot get past. I am unsure if I can get what I want using selectizeGroup or not.

df <- data.frame(ID_Col= c(rep("ID1", 3), rep("ID2", 3), rep("ID3", 3)),
       value= c("X", "Y", "Z", "X", "Y", "A", "A", "N", "X"))

ui <- 
  fluidPage(
    fluidRow(
      column(
        width = 10, offset = 1,
        tags$h3("example"),
        panel(
          selectizeGroupUI(
            id = "my-filters",
            inline = TRUE,
            params = list(
              value_filter = list(
                inputId = "value",
                title = "value filter"
                # placeholder = 'select'
              )
            )
          ),
          status = "primary"
        ),
        DTOutput("table")
      )
    )    
  )

server <- function(input, output, session) {
  
  ##### Filters
  res_mod <- callModule(
    module = selectizeGroupServer,
    id = "my-filters",
    data = df,
    vars = c("value")
  )
  output$table <- renderDT({
    res_mod()
  })

}
shinyApp(ui = ui, server = server)
0

There are 0 best solutions below