Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add columns to a reactive data frame in Shiny and update them

Tags:

dataframe

r

shiny

I would like to be able to calculate a new column of data based on dividing one column by another, with both original columns selected by a user input. I would like to have this calculated data joined to the original table (or a copy of it).

I have managed to figure out how to make a dataframe that reacts to the column input selection, and I have managed to make a calculation that divides one column by the other, but I have not been able to make a final dataframe that includes all of the original columns as well as the new calculated one.

Here is a mock up I have made using the built in Iris data. It displays the data for the columns selected in the first table, and the calculation in the second table (you will need to scroll down quite far to see this).

How can I join this calculated data to the original source?

Many thanks

#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()
      })

    }
like image 656
RobinNN Avatar asked Apr 07 '17 12:04

RobinNN


2 Answers

You forget that iris is NOT a reactive element, so your code can't work. You have two options here:

  • creating a reactive value to store that data frame, using reactive().
  • creating a list of "global" reactive values in which you can store the updated data frame, using reactiveValues().

Using global reactive expressions with reactiveValues

Using reactiveValues you can make a list of reactive expressions much like input and output are. In the example below I use it to store the data frame iris as globals$mydf. Then you can use eg observe to change the value reactively, as in the following server function:

#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
  })
}

using reactive()

You can make two reactive expressions that depend on eachother:

  • one that selects the variables and calculates that ratio
  • one that combines this result with the selected variables

Your server would look like this :

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()
  })

}

Although you beliefe this is not what you're looking for, you can use newdf() in other code just like you would use globals$mydf in the previous example. reactiveValues() especially pays off if different parts of your code have to be able to change the data frame.

like image 65
Joris Meys Avatar answered Nov 16 '22 13:11

Joris Meys


You don't return anything in your reactive for selectedData2 you just do an incrementation <-, I think you should do this :

   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()
  })

}
like image 1
Smich7 Avatar answered Nov 16 '22 14:11

Smich7