R/Shiny - 如何反应性地编写包含 actionButton 的 .csv?

R/Shiny - How to write a .csv reactively including a actionButton?

我正在尝试弄清楚如何根据最终用户所做的选择编写 .csv。所做的选择将 "geodata.csv" 子集并在应用程序文件夹中写入一个单独的 "solution.csv" 文件。

N.B. - 我创建了一个 github repo 来简化问题的解决。它包含 geodata.csv、ui.R 和 server.R,但还没有 solution.csv!

geodata.csv

Postcode,HC,BSL,Position Location
10,1,A,C
10,1,A,D
10,1,A,D
11,1,B,C
11,1,B,C

ui.R

shinyUI(
 pageWithSidebar(
  headerPanel('Min. working example - write a csv based on user input'),

  sidebarPanel(
   selectInput("filter1", "First selection:" 
              , choices = c(Choose='', "A", "B")
              #, multiple=T
              ),

   selectInput("filter2", "Second selection:", 
              choices = c(Choose='', "C", "D")
              ),
   br(),
   p("Include actionButton to prevent write occuring before user finalises selection"),  
   actionButton("generateButton","Write Data")    
  ),
  mainPanel()
 )
)

server.R

# Load data
setwd("/Users/lukesingham/SOtestApp")
geodata <- read.csv("geodata.csv", na.string = "#N/A", row.names=NULL)

# Reactivity to subset data ####
shinyServer(function(input, output) {
  geodatasetInput <- reactive({

    # BSL switch
    selection <-switch(input$BSL
                       , A = "A"
                       , B = "B"
                       ) 
    # Location switch    
    selection2 <-switch(input$Location
                       , C = "C"
                       , D = "D"
                       )

    # subset based on selection
    Subgeodata <- subset(geodata, BSL == selection & Position.Location == selection2)

    # Execute selections on data upon button-press
    input$generateButton

    # aggregate by postcode
    Subgeodata <- Subgeodata[1:2] #no longer need other columns
    AggSubGdata <- aggregate(. ~ Postcode, data=Subgeodata, FUN=sum)
    isolate(write.csv(AggSubGdata
              , file = "/Users/lukesingham/SOtestApp/solution.csv"
              , row.names=F
    ))
  })
})

solution.csv

例如,根据用户选择 AD,解决方案文件应如下所示:

Postcode,HC
10,2

你需要渲染你的 table 你正在子集化,也许其他人可以解释为什么你需要这种相互依赖。下面是我去解决它的方式的工作示例。它将 solution.csv 保存在工作目录中。

rm(list = ls())
library(shiny)
# You can change this directory
setwd("/Users/lukesingham/SOtestApp")
geodata <- read.csv("geodata.csv", header = TRUE, sep = ",",stringsAsFactors =FALSE)

ui = pageWithSidebar(
  headerPanel('Min. working example - write a csv based on user input'),
  sidebarPanel(
    selectInput("filter1", "First selection:", choices = c("A", "B"),selected = "A"),    
    selectInput("filter2", "Second selection:", choices = c("C", "D"),selected = "C"),
    br(),
    p("Include actionButton to prevent write occuring before user finalises selection"),  
    actionButton("generateButton","Write Data")),mainPanel(tableOutput("test1"))
)

server = function(input, output) {

  geodatasetInput <- reactive({
    if(input$generateButton == 0){return()}

    isolate({ 
      input$generateButton
      test_data <- geodata[geodata$BSL %in% as.character(input$filter1),]
      test_data <- geodata[geodata$Position.Location %in% as.character(input$filter2),]
      test_data <- test_data[,1:2]
      test_data <- aggregate(. ~ Postcode, data=test_data, FUN=sum)
      test_data
    })
    write.csv(test_data,"solution.csv",row.names=F)
  })
  output$test1 <- renderTable({geodatasetInput()})
}

runApp(list(ui = ui, server = server)) 

这是工作示例:

# Load data
setwd("/Users/lukesingham/SOtestApp")
geodata <- read.csv("geodata.csv", na.string = "#N/A", row.names=NULL)

# Reactivity to subset data ####
shinyServer(function(input, output) {
  geodatasetInput <- observe({

    # Execute selections on data upon button-press
    if(input$generateButton == 0) return()

    inp.BSL <- isolate(input$filter1)
    inp.loc <- isolate(input$filter2)
    if (inp.BSL=='' | inp.loc=='') return()

    # BSL switch
    selection <-switch(inp.BSL
                       , A = "A"
                       , B = "B"
                       ) 
    # Location switch    
    selection2 <-switch(inp.loc
                       , C = "C"
                       , D = "D"
                       )

    # subset based on selection
    Subgeodata <- subset(geodata, BSL == selection & Position.Location == selection2)

    # browser()
    # aggregate by postcode
    Subgeodata <- Subgeodata[1:2] #no longer need other columns
    AggSubGdata <- aggregate(. ~ Postcode, data=Subgeodata, FUN=sum)
    write.csv(AggSubGdata
              , file = "solution.csv"
              , row.names=F
    )
  })
})

并对您的代码进行简短分析:

  1. geodatasetInput根本没有启动的主要原因是因为它是一个reactive()表达式。 reactive() 只有在被@pops 的回答中的 renderTable() 之类的其他东西调用时才会被评估。如果想让它自己执行,应该是observe().

  2. 在 observe() 表达式的开头添加 input$generateButton 可能是个好主意。

  3. ui.R中,你调用了一个数字输入字段filter1,但你试图从server.R获取它的值为input$BSLfilter2.

  4. 也是如此
  5. 因为您希望 geodataSetInput 仅在 generateButton 上触发,所有其他 input$ 和包含 geodataSetInput 的反应式表达式应与 isolate()。另一方面,不需要隔离 write.csv 因为这个特定的函数调用不涉及任何 'dynamic' 参数。