如何在 R Shiny 中构建动态过滤器?
How to build a dynamic filter in R Shiny?
我正在构建一个具有上传功能和类别变量过滤功能的应用程序。这样,用户就可以通过指定列和值来进行一些数据操作。但是,过滤功能不起作用。代码简化如下:
#ui.R
library(shiny)
fluidPage(
titlePanel("Test Dynamic Column Selection"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
hr(),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',
c(Comma=',',
Semicolon=';',
Tab='\t'),
','),
hr(),
uiOutput("choose_columns"),
hr(),
uiOutput("choose_column"),
textInput('column_value', label = 'Value'),
actionButton('filter', label = 'Filter')
),
mainPanel(
tableOutput('contents')
)
)
)
#server.R
library(shiny)
function(input, output) {
uploaded_data <- reactive({
inFile <- input$file1
read.table(inFile$datapath, header=input$header, sep=input$sep, quote=input$quote)
})
react_vals <- reactiveValues(data = NULL)
output$choose_columns <- renderUI({
if(is.null(input$file1))
return()
colnames <- names(react_vals$data)
checkboxGroupInput("choose_columns", "Choose columns",
choices = colnames,
selected = colnames)
})
output$choose_column <- renderUI({
if(is.null(input$file1))
return()
is_factor <- sapply(react_vals$data, is.factor)
colnames <- names(react_vals$data[, is_factor])
selectInput("choose_column", "Choose column", choices = colnames)
})
observeEvent(input$file1, react_vals$data <- uploaded_data())
observeEvent(input$choose_columns, react_vals$data <- react_vals$data[, input$choose_columns])
# This line of code does not work :(
observeEvent(input$filter, react_vals$data <- subset(react_vals$data, input$choose_column != input$column_value))
output$contents <- renderTable(react_vals$data)
}
我认为您的应用存在多个问题,我尝试逐步解释:
input$choose_columns
取决于 react_vals$data
反应值,因此当取消选中复选框时,Shiny 会为 react_vals$data
分配一个新值,少一列,然后重新呈现 input$choose_columns
UI,这样就少了一个checkbox。 (与 input$choose_column
selectInput
相同)
您的代码:
colnames <- names(react_vals$data)
替换代码:
colnames <- names(uploaded_data())
- 在检查文件是否已上传、UI 是否已呈现等时使用
req()
。这是最佳做法。
您的代码:
if(is.null(input$file1)) return()
替换代码:
req(input$file1)
- 过滤无效。基本上它不起作用的原因是它尝试基于比较来自
input$choose_column
和 input$column_value
. 的两个字符串来进行子集化
即:"Column name A" != "Value: something"
returns TRUE
通常是每一行,结果根本没有过滤。
我想出了2个解决方案,它们有点难看,所以如果有人想出更好的解决方案,请随时comment/edit。
#server.R
library(shiny)
function(input, output) {
uploaded_data <- reactive({
inFile <- input$file1
read.table(inFile$datapath, header=input$header, sep=input$sep, quote=input$quote)
})
react_vals <- reactiveValues(data = NULL)
output$choose_columns <- renderUI({
req(input$file1)
colnames <- names(uploaded_data())
checkboxGroupInput("choose_columns", "Choose columns",
choices = colnames,
selected = colnames)
})
output$choose_column <- renderUI({
req(input$file1)
is_factor <- sapply(uploaded_data(), is.factor)
colnames <- colnames(uploaded_data()[is_factor])
selectInput("choose_column", "Choose column", choices = colnames)
})
observeEvent(input$file1, react_vals$data <- uploaded_data())
observeEvent(input$choose_columns, react_vals$data <- uploaded_data()[, input$choose_columns])
observeEvent(input$filter, {
react_vals$data <-
#Option A
eval(parse(text = sprintf("subset(uploaded_data(), %s != '%s')", input$choose_column, input$column_value)))
#Option B
#subset(uploaded_data(), uploaded_data()[, which(names(uploaded_data()) == input$choose_column)] != input$column_value)
})
output$contents <- renderTable(react_vals$data)
}
shinyApp(ui, server)
我正在构建一个具有上传功能和类别变量过滤功能的应用程序。这样,用户就可以通过指定列和值来进行一些数据操作。但是,过滤功能不起作用。代码简化如下:
#ui.R
library(shiny)
fluidPage(
titlePanel("Test Dynamic Column Selection"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
hr(),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',
c(Comma=',',
Semicolon=';',
Tab='\t'),
','),
hr(),
uiOutput("choose_columns"),
hr(),
uiOutput("choose_column"),
textInput('column_value', label = 'Value'),
actionButton('filter', label = 'Filter')
),
mainPanel(
tableOutput('contents')
)
)
)
#server.R
library(shiny)
function(input, output) {
uploaded_data <- reactive({
inFile <- input$file1
read.table(inFile$datapath, header=input$header, sep=input$sep, quote=input$quote)
})
react_vals <- reactiveValues(data = NULL)
output$choose_columns <- renderUI({
if(is.null(input$file1))
return()
colnames <- names(react_vals$data)
checkboxGroupInput("choose_columns", "Choose columns",
choices = colnames,
selected = colnames)
})
output$choose_column <- renderUI({
if(is.null(input$file1))
return()
is_factor <- sapply(react_vals$data, is.factor)
colnames <- names(react_vals$data[, is_factor])
selectInput("choose_column", "Choose column", choices = colnames)
})
observeEvent(input$file1, react_vals$data <- uploaded_data())
observeEvent(input$choose_columns, react_vals$data <- react_vals$data[, input$choose_columns])
# This line of code does not work :(
observeEvent(input$filter, react_vals$data <- subset(react_vals$data, input$choose_column != input$column_value))
output$contents <- renderTable(react_vals$data)
}
我认为您的应用存在多个问题,我尝试逐步解释:
input$choose_columns
取决于react_vals$data
反应值,因此当取消选中复选框时,Shiny 会为react_vals$data
分配一个新值,少一列,然后重新呈现input$choose_columns
UI,这样就少了一个checkbox。 (与input$choose_column
selectInput
相同)
您的代码:
colnames <- names(react_vals$data)
替换代码:
colnames <- names(uploaded_data())
- 在检查文件是否已上传、UI 是否已呈现等时使用
req()
。这是最佳做法。
您的代码:
if(is.null(input$file1)) return()
替换代码:
req(input$file1)
- 过滤无效。基本上它不起作用的原因是它尝试基于比较来自
input$choose_column
和input$column_value
. 的两个字符串来进行子集化
即:"Column name A" != "Value: something"
returns TRUE
通常是每一行,结果根本没有过滤。
我想出了2个解决方案,它们有点难看,所以如果有人想出更好的解决方案,请随时comment/edit。
#server.R
library(shiny)
function(input, output) {
uploaded_data <- reactive({
inFile <- input$file1
read.table(inFile$datapath, header=input$header, sep=input$sep, quote=input$quote)
})
react_vals <- reactiveValues(data = NULL)
output$choose_columns <- renderUI({
req(input$file1)
colnames <- names(uploaded_data())
checkboxGroupInput("choose_columns", "Choose columns",
choices = colnames,
selected = colnames)
})
output$choose_column <- renderUI({
req(input$file1)
is_factor <- sapply(uploaded_data(), is.factor)
colnames <- colnames(uploaded_data()[is_factor])
selectInput("choose_column", "Choose column", choices = colnames)
})
observeEvent(input$file1, react_vals$data <- uploaded_data())
observeEvent(input$choose_columns, react_vals$data <- uploaded_data()[, input$choose_columns])
observeEvent(input$filter, {
react_vals$data <-
#Option A
eval(parse(text = sprintf("subset(uploaded_data(), %s != '%s')", input$choose_column, input$column_value)))
#Option B
#subset(uploaded_data(), uploaded_data()[, which(names(uploaded_data()) == input$choose_column)] != input$column_value)
})
output$contents <- renderTable(react_vals$data)
}
shinyApp(ui, server)