Dynamic AND OR filter in R Shiny

时间:2016-07-11 22:35:45

标签: r shiny

I am struggling to make a set of dynamic data filters on multiple fields with selectable AND/OR join between fields which should look like following:

enter image description here

Here is my example code. I am just not sure how to make the filter joins (AND/OR) work properly.

library(shiny)
library(dplyr)
library(DT)

data("baseball")

Year = unique(baseball$year)
Team = unique(baseball$team)
Stint = unique(baseball$stint)

runApp(list(ui = fluidPage(
  titlePanel("Summary"),

  sidebarLayout(
    sidebarPanel(

      selectInput("year", label = "Year", choices = Year, selected = NULL, multiple = TRUE),
      selectInput("filter_join1", label = "", choices = c("OR","AND")),
      selectInput("team", label = "Team", choices = Team, selected = NULL, multiple = TRUE),
      selectInput("filter_join2", label = "", choices = c("OR","AND")),
      selectInput("stint", label = "Stint", choices = Stint, selected = NULL, multiple = TRUE)
    ),

    mainPanel(
      DT::dataTableOutput("table")
    )
  )
),

server = function(input, output, session) {
  WorkingDataset   <- reactive({ 
    df_temp <- baseball %>%
      filter(
        is.null(input$year)  | year %in% input$year,
        is.null(input$team)  | team %in% input$team,
        is.null(input$stint) | stint %in% input$stint
      )
    }) 

  output$table <- DT::renderDataTable({ WorkingDataset() })

})

)

1 个答案:

答案 0 :(得分:4)

,我们有iris数据集,我们想对其进行一些子集化。

iris$Species

# We can also use `with` for that
with(iris, Species) 

# We are interested in more complicated subsetting though. Want to have all rows
# with 'setosa'
with(iris, Species %in% 'setosa')
iris[with(iris, Species %in% 'setosa'), ]

# Now 'setosa' with some more condition
iris[with(iris, Species %in% 'setosa' & Sepal.Length > 5.3), ]


# That works perfectly. There is, however, an another way doing the exact thing in r.
# We can input the subsetting condition as a character string, then change it to 
# the `expression` and `eval`uate it.

cond_str <- paste0("with(iris, Species %in% 'setosa' & Sepal.Length > 5.3)")
cond_str
# which is the same as
cond_str <- paste0("with(iris, ", "Species %in% ", "'", "setosa", "'", " & ", 
                   "Sepal.Length > ", "5.3", ")")
cond_str

# This second approach will prove very powerful since we will replace "setosa"
# with, say, `input$species` later on.


cond <- parse(text = cond_str)
cond
eval(cond)
iris[eval(cond), ] # √

由于input$species可能是一个向量,因此会稍微复杂一些 因此我们可以获得多个字符串作为输出。 例如:

Spec <- c("setosa", "virginica") # ~ input$species
paste0("with(iris, Species %in% ", Spec, ")")

# We want only one character string! So, we'll have to collapse the vector Spec
paste0("with(iris, Species %in% ", 
       paste0(Spec, collapse = " "), ")")

# This is still not what we wanted. We have to wrap the entries into "c()"
# and add quote marks. So, it's going to be pretty technical:
paste0("with(iris, Species %in% ", 
       "c(", paste0("'", Spec, collapse = "',"), "'))")

# Now, this is what we wanted :) Let's check it 
check <- eval(parse(text = paste0("with(iris, Species %in% ", 
       "c(", paste0("'", Spec, collapse = "',"), "'))")))
iris[check, ] # √

现在,让我们转到闪亮的应用程序。由于我不知道在哪里可以找到与您的变量匹配的数据集baseball,因此我将使用包diamonds中的ggplot2数据集而不会使用{ {1}}。

我稍微修改了你的应用程序 - 更改了变量名称,然后使用上面描述的技巧进行子集化。您应该很容易将我的示例与您的问题相符合。

dplyr