Scott Scott - 1 month ago 17
R Question

How to reactively define first column with dplyr in Shiny

Let's say I want to have a user-uploaded dataset similar to the CO2 one provided in R in my Shiny app. I'm looking for people to load any dataset of this type and then generate a new value from existing ones using dplyr's

mutate
. I've coded reactive values that check to see if "conc" and "uptake" are present in the data, and if so to use them to generate the new value.

I then want a new table rendered that shows the first column (that identifies the sample) and this new value. However, since the datasets will change depending on user input, I can't specify the column (for the CO2 dataset, it would be "Plants").

Here's my toy example:

library(shiny)
library(dplyr)

ui <- pageWithSidebar(
headerPanel("Test"),
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
tags$hr(),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',c(Comma=',',Semicolon=';',Tab='\t'),',')
),
mainPanel(
tableOutput("inputfile"),
tableOutput("do")
)
)

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

upData <- reactive({
if(is.null(input$file1)) return(CO2)
inFile <- input$file1
dat <- read.csv(inFile$datapath)
return(dat)
})

output$inputfile <- renderTable({
head(upData())
})

concvar <- reactive({
if("conc" %in% colnames(upData())==TRUE) {upData()$conc}
else{0}
})

uptakevar <- reactive({
if("uptake" %in% colnames(upData())==TRUE) {upData()$uptake}
else{0}
})

newvalue <- reactive({
upData() %>%
mutate(newvalue=concvar()/uptakevar()) %>%
select(newvalue)
})

output$do <- ({
renderTable(head(newvalue()))
})

}

shinyApp(ui = ui, server = server)


This does almost everything I want, but I can't figure out how to get this new column of values to also have a column that identifies the respective sample.

I've tried defining
upData()[,1]
and using
select_
in the "newvalue" dplyr chain but I keep getting errors. How can I reactively define the first column of various hypothetical datasets in a
select
call so my new values are contextualized with sample names?

Answer

The issue is that your concvar and uptakevar functions are returning the full vector of the values, but you are trying to treat them as column names. Either, use the vectors directly like this:

newvalue <- reactive({
  data.frame(
    newvalue = concvar() / uptakevar()
  )
})

Or, return the column names, then use mutate_ to construct the column of interest, like this. Note that I used select_ as well to allow you to select the first column in addition to the newvalue. It would probably be even better to define this as a character as well (like your conc and uptake variables) to allow the user to pick a reasonable ID column to include (instead of assuming the first column is an ID).

concvar <- reactive({
  if("conc" %in% colnames(upData())==TRUE) {"conc"} 
  else{0} 
})

uptakevar <- reactive({
  if("uptake" %in% colnames(upData())==TRUE) {"uptake"} 
  else{0} 
})

newvalue <- reactive({
  upData() %>%
    mutate_(newvalue = paste(concvar(), "/", uptakevar())) %>% 
    select_(names(upData())[1], "newvalue")
})

I would recommend the latter, as I assume you are planning on using a select box of some sort to let the user pick the column names to use (which will return a character vector with the column name).