在Shiny中向反应式数据框添加列并更新

8
我希望能够根据用户输入选择的原始列来计算一列新数据,该新数据是将一个列除以另一个列所得到的结果。我希望可以将这个计算出的数据加入到原表格(或其副本)中。
我已经找到了如何创建一个数据框来响应列输入选择,并且也已经成功做出了将一个列除以另一个列的计算,但我无法创建一个最终的数据框,它包括所有原始列以及新计算出的列。
以下是我使用内置的鸢尾花数据制作的模拟。它显示了在第一个表格中选择的列的数据以及在第二个表格中的计算结果(您需要向下滚动相当远才能看到此处)。
我该如何将这些计算出的数据连接到原始来源?
非常感谢。
#Ui        
pageWithSidebar(
      headerPanel('Calculate Column'),
      sidebarPanel(

        #select variables from iris dataset
        selectInput('xcol', 'X Variable', names(iris)),
        selectInput('ycol', 'Y Variable', names(iris),
                    selected=names(iris)[[2]])
      ),
      mainPanel(
        #display the selected variables
            tableOutput("view"),
         #display the calculated variable
            tableOutput("view2")
      )
    )


#Server
        function(input, output, session) {

      # Combine the selected input variables into a new data frame
      selectedData <- reactive({
        iris[, c(input$xcol, input$ycol),]
      })


      # divide one variable selection by the other
      selectedData2 <- reactive({
                iris$new<-iris[, c(input$xcol)]/iris[, c(input$ycol)]

        })

      # create data output for selected variables
      output$view <- renderTable({selectedData()
      })

      # create data output for calculated variable
      output$view2 <- renderTable({selectedData2()
      })

    }

我有些修改了一下你的标题,以更好地描述实际问题。在标题中没有必要提到 R 和 Shiny,因为它们已经在标签中了。 - Joris Meys
2个回答

12

您忘记了iris不是一个响应式元素,所以您的代码无法运行。在这里您有两个选择:

  • 使用reactive()创建一个响应式值来存储该数据框。
  • 使用reactiveValues()创建一个“全局”响应式值列表,其中可以存储更新后的数据框。

使用具有reactiveValues的全局响应式表达式

使用reactiveValues,您可以创建一个类似于inputoutput的响应式表达式列表。在下面的示例中,我将其用于将数据框iris存储为globals$mydf。然后,您可以使用例如observe来以反应方式更改该值,如以下服务器函数所示:

#Server
server <- function(input, output, session) {

  globals <- reactiveValues(
    mydf = iris
  )

  observe({
    thedf <- globals$mydf
    newvar <- thedf[[input$xcol]] / thedf[[input$ycol]]
    globals$mydf$ratio <- newvar
  })


  # create data output for selected variables
  output$view <- renderTable({
    globals$mydf
  })
}

使用reactive()

您可以创建两个相互依赖的响应式表达式:

  • 一个选择变量并计算比率
  • 另一个将该结果与所选变量组合

您的服务器代码如下:

server <- function(input, output, session) {

  newdf <- reactive({
    cbind(
      iris[c(input$xcol, input$ycol)],
      Ratio = newvar()
    )
  })

  newvar <- reactive({
    iris[[input$xcol]] / iris[[input$ycol]]
  })

  # create data output for selected variables
  output$view <- renderTable({
    newdf()
  })

}
尽管你认为这不是你想要的,但你可以像在前面的示例中使用 globals $ mydf 一样在其他代码中使用 newdf()。 如果代码的不同部分必须能够更改数据帧,则尤其可以使用 reactiveValues()

太好了,感谢您抽出时间解决并解释这个问题。 - RobinNN
这两种方法都给我这个错误:$ 中的错误:类型为“closure”的对象不可进行子集操作。 - Navid
@Navid: 这个错误的常见原因是忘记在名称或响应式数据后面加上括号(例如,使用newdf而不是newdf())。 - Rumpl

1
你的reactive中的selectedData2没有返回任何内容,你只是进行了一个递增操作<-,我认为你应该这样做:
   function(input, output, session) {

  # Combine the selected input variables into a new data frame
  selectedData <- reactive({
    return(iris[, c(input$xcol, input$ycol),])
  })


  # divide one variable selection by the other
  selectedData2 <- reactive({
            new<-iris[, c(input$xcol)]/iris[, c(input$ycol)]
            return(new)

    })

  # create data output for selected variables
  output$view <- renderTable({selectedData()
  })

  # create data output for calculated variable
  output$view2 <- renderTable({selectedData2()
  })

}

谢谢,我已经尝试使用这段代码,但它似乎仍然表现出相同的行为。我需要改变什么才能得到包含所有原始鸢尾花变量和新计算结果的数据集? - RobinNN
1
@RobinNN 你可以像我更新的答案中所示使用全局变量。 - Joris Meys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接