Sunday, 19 March 2017

R Shiny - Add new column to dataframe based on user selected input




Very new to R Shiny! I've looked through a good 20 questions but they don't necessarily address the problem I'm facing.



I have a few dataframes generated from API calls that look something like this:



Project.ID        Author.ID    Author.Name     Fav.Color
Test_Project1 1234 Bob Green
Test_Project1 2345 Jane Blue
Test_Project1 2687 Eric Blue
Test_Project1 8765 Tom Red



My goal is to allow users to select a column from the dataframe using a dropdown, select some values to compare from that column using some checkboxes, and add a new column to the same frame reflecting the comparisons that they wanted to make. It should look like this:



Project.ID      Author.ID    Author.Name     Fav.Color    RedvBlue   GreenvRed
Test_Project1 1234 Bob Green NA Green
Test_Project1 2345 Jane Blue Blue NA
Test_Project1 2687 Eric Blue Blue NA
Test_Project1 8765 Tom Red Red Red



ui.R



ui <- fluidPage(

sidebarPanel(
selectInput("viewType",
label = "Select to view:",
choices = c(' ', "Projects"), #will have other dataframes to select from
selected = ' '),
conditionalPanel(

condition = "input.viewType =='Projects'",
uiOutput("projectSelection"),
uiOutput("showMeta"),
uiOutput("showVal"),
textOutput("text")
)
),

mainPanel(
DT::dataTableOutput("mytable")

)
)


server.R



server <- function(input, output) {

viewSelection <- reactive({
if(input$viewType == "Projects"){

projectDT <- getJSON("an API url")

#replace spaces with dots in headers
names(projectDT) <- gsub(" ", ".", names(projectDT))

#show table
output$mytable <- DT::renderDataTable(DT::datatable(projectDT))


#Display columns from project to view

output$showMeta <- renderUI({
selectInput("metalab",
"Metadata Label:",
c(" ", unique(as.vector(colnames(projectDT))))
)
})

#Display unique column values to choose from in checkbox
#Gives Warning: Error in [.data.frame: undefined columns selected
output$showVal <- renderUI({

checkboxGroupInput("metaval",
"Metadata Value:",
choices = unique(as.vector(unlist(projectDT[input$metalab])))
)
})

}

})


output$mytable <- DT::renderDataTable({DT::datatable(viewSelection())})
}


I'm currently struggling to produce a new column in the dataframe based off the user's selections. So far, it displays what I would like it to in terms of the dropdown and checkboxes but I wasn't able to move any further with that. I'm not exactly sure where my problem lies - is my table rendering improperly, am I not adding a new column correctly?



I tried to access input$metalab and input$metaval but they return NULL outside a renderUI/renderText context. I've tried simply duplicating a column based on user choice but this doesn't work either:



projectDT['newCol'] = projectDT[input$metalab]



Any help is greatly appreciated! Sorry for the long blurb!


Answer



Hi is this something in the way of what you want to do?



server <- function(input, output, session) {
# update datatable
viewSelection <- reactive({
if(input$viewType == "Projects"){
projectDT <- read.table(header = TRUE,

text = "Project.ID,Author.ID,Author.Name,Fav.Color
Test_Project1,1234,Bob,Green
Test_Project1,2345,Jane,Blue
Test_Project1,2687,Eric,Blue
Test_Project1,8765,Tom,Red",
sep = ",")

#replace spaces with dots in headers
names(projectDT) <- gsub(" ", ".", names(projectDT))


projectDT



}

})
#show table
output$mytable <- DT::renderDataTable(DT::datatable(viewSelection()))
#Display columns from project to view

observeEvent({input$addCol},{
insertUI(
selector = "#addCol",
where = "beforeBegin",
ui = div(
uiOutput(paste0("showMeta",input$addCol)),
uiOutput(paste0("showVal",input$addCol))
)
)
})

lapply(1:5, function(idx){
output[[paste0("showMeta",idx)]] <- renderUI({
selectInput(inputId = paste0("metalab",idx),
label = "Metadata Label:",
choices = c(" ", unique(as.vector(colnames(viewSelection())))),
selected = input[[paste0("metalab",idx)]]
)
})
})
lapply(1:5,

function(idx){
output[[paste0("showVal",idx)]] <- renderUI({
req(input$addCol >= idx)
checkboxGroupInput(paste0("metaval",idx),
"Metadata Value:",
choices = unique(as.vector(unlist(viewSelection()[[input[[paste0("metalab",idx)]]]]))),
selected = input[[paste0("metaval",idx)]]
)
})
})


output$showMeta <- renderUI({
})
#Display unique column values to choose from in checkbox
#Gives Warning: Error in [.data.frame: undefined columns selected
output$showVal <- renderUI({
checkboxGroupInput("showVal",
"Metadata Value:",
choices = unique(as.vector(unlist(viewSelection()[[input$metalab]])))
)

})

output$mytable <- DT::renderDataTable({
req(input$viewType == "Projects")
projectDT <- viewSelection()
dta <- NULL
if(input$addCol > 0){
dta <- lapply(seq(input$addCol), function(idx){
if(!is.null(input[[paste0("metalab", idx)]]) &&
input[[paste0("metalab",idx)]] != " "){

ifelse(projectDT[[input[[paste0("metalab", idx)]]]] %in% input[[paste0("metaval", idx)]] ,as.character(projectDT[[input[[paste0("metalab", idx)]]]]),NA)
}
})
names(dta) <- sapply(seq(input$addCol),function(idx){
paste0("Compare",idx,"_",paste0(input[[paste0("metaval",idx)]],collapse = "vs"))
})
dta <- as_data_frame( dta[!sapply(dta,is.null)])
}
if(!is.null(dta) &&
!is.null(projectDT) &&

nrow(dta) == nrow(projectDT)){
projectDT <- cbind(projectDT,dta)
}
DT::datatable(projectDT)})

}


What I have done is that I have pulled all asignments of outputs out of the reactive statment. This is mainly I to make the code more stable.




Hope this helps!


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...