datatable filters update on the fly - shiny

In the basic example below I would like to have all filters updated every time user add a filter.
ui :
library(shiny)
library(DT)
fluidPage(
fluidRow(
column(4,
DT::dataTableOutput("dt")
)
)
)
Server :
library(shiny)
shinyServer(function(input, output) {
df <- data.frame(var1 = c(rep("A",3),rep("B",3)), var2 = c("x","y","x","z","x","s"), var3 = c(1:6))
output$dt <- renderDataTable({
DT::datatable(df, filter = 'top')
})
})
When no filter applied :
When I apply filter on var1 to "A", s and z still remain in the suggested label in var2 filter even if there are no value to s or z

This is how I would do if I use selectInput for the filters. May not be the best solution, but it has always worked for me.
Code for ui.r
library(shiny)
library(DT)
fluidPage(
fluidRow(
column(4,selectizeInput("var1", label = "Var 1", choices = NULL, multiple = TRUE)),
column(4,selectizeInput("var2", label = "Var 2", choices = NULL, multiple = TRUE)),
column(4,selectizeInput("var3", label = "Var 3", choices = NULL, multiple = TRUE)),
column(4,DT::dataTableOutput("dt")
)
)
)
Code for server.R
library(shiny)
shinyServer(function(input, output, session) {
df <- data.frame(var1 = c(rep("A",3),rep("B",3)), var2 = c("x","y","x","z","x","s"), var3 = c(1:6))
updateSelectizeInput(session, 'var1', choices = sort(unique(df$var1)), server = TRUE)
updateSelectizeInput(session, 'var2', choices = sort(unique(df$var2)), server = TRUE)
updateSelectizeInput(session, 'var3', choices = sort(unique(df$var3)), server = TRUE)
filterData <- function(dataset){
df <- dataset
if (!is.null(input$var1)){
df <- df[which(df$var1 == input$var1),]
}
if (!is.null(input$var2)){
df <- df[which(df$var2 == input$var2),]
}
if (!is.null(input$var3)){
df <- df[which(df$var3 == input$var3),]
}
df
}
output$dt <- renderDataTable({
DT::datatable(filterData(df))
})
getwhich<-function(){
whichs<-which(df$var3 == df$var3)
if(!is.null(input$var1)){
whichs<-intersect(whichs,which(df$var1 %in% input$var1))
}
if(!is.null(input$var2)){
whichs<-intersect(whichs,which(df$var2 %in% input$var2))
}
if(!is.null(input$var3)){
whichs<-intersect(whichs,which(df$var3 %in% input$var3))
}
return(whichs)
}
observe({
w<-getwhich()
if(is.null(input$var1)){
updateSelectizeInput(session,"var1",choices=sort(unique(df$var1[w])))
}
})
observe({
w<-getwhich()
if(is.null(input$var2)){
updateSelectizeInput(session,"var2",choices=sort(unique(df$var2[w])))
}
})
observe({
w<-getwhich()
if(is.null(input$var3)){
updateSelectizeInput(session,"var3",choices=sort(unique(df$var3[w])))
}
})
})
Hope this helps.

Related

How to visualise regression's predictions based on selected dataset and variables thereof

I have the following code that basically uploads the data and once you have clicked on the row of the dataset you have uploaded, it reads the file. If you go to the second page in the navbar called regression you can choose variables from the dataset and run linear model. That works with the summary table. I want to achieve is something like here: https://towardsdatascience.com/build-an-interactive-machine-learning-model-with-shiny-and-flexdashboard-6d76f59a37f9
I want the prediction table and plot visualisation based on what has been selected. Appreciate your understanding and helpfulness.
library(shiny)
library(magrittr)
library(shiny)
library(readxl)
library(tidyverse)
library(DT)
library(reactable)
ui <- navbarPage("Demo",
tabPanel("Data Manipulation",
sidebarLayout(
sidebarPanel(
fileInput("upload", "Upload your file", multiple = TRUE, accept = c(".csv", ".xlsx") ),
selectInput('mydropdown', label = 'Select', choices = 'No choices here yet'),
h2("Modify variable type"),
selectInput("var_name", "Select variable", choices = c()),
radioButtons("action", NULL,
choiceNames = c("Make factor", "Make numeric"),
choiceValues = c("factor", "numeric")),
actionButton("modify", "Do it!"),
verbatimTextOutput("str")
),
mainPanel(
DT::DTOutput("files"),
reactable::reactableOutput("uploaded_files")
)
)
),
tabPanel("Regression",
sidebarLayout(
sidebarPanel(
selectInput("dep_var", "Select dependent variable", choices = c()),
selectInput("ind_var", "Select independent variables", choices = c(), multiple = TRUE),
actionButton("submit_reg", "Do it!")),
mainPanel(
verbatimTextOutput(outputId = "regsum")
)
)
),
)
server <- function(input, output, session) {
output$files <- DT::renderDT({
DT::datatable(input$upload, selection = c("single"))
})
selected_file <- reactiveVal()
observe({
## when developing, use a sample file you have on your computer so that you
## can load it immediately instead of going through button clicks
# demofile <- "/path/to/your/file.csv"
# selected_file( read.csv(demofile) )
# return()
req(input$upload, input$files_rows_selected)
idx <- input$files_rows_selected
file_info <- input$upload[idx, ]
if (tools::file_ext(file_info$datapath) == "csv") {
selected_file(read.csv(file_info$datapath))
} else if (tools::file_ext(file_info$datapath) == "xlsx") {
selected_file(readxl::read_xlsx(file_info$datapath))
} else {
stop("Invalid file type")
}
})
output$uploaded_files <- reactable::renderReactable({
req(selected_file())
reactable::reactable(
selected_file(),
searchable = TRUE
)
})
observe({
req(input$upload)
file_names <- input$upload$name
updateSelectInput(
session,
"mydropdown",
choices = file_names
)
})
observe({
req(selected_file())
updateSelectInput(session, "var_name", choices = names(selected_file()))
})
output$str <- renderPrint({
req(selected_file())
str(selected_file())
})
observeEvent(input$modify, {
df <- selected_file()
if (input$action == "factor") {
df[[input$var_name]] <- as.factor(df[[input$var_name]])
} else if (input$action == "numeric") {
df[[input$var_name]] <- as.numeric(df[[input$var_name]])
} else {
stop("Invalid action")
}
selected_file(df)
})
# Second Page
observe({
req(selected_file())
Dependent <- updateSelectInput(session, "dep_var", choices = names(selected_file()))
})
observe({
req(selected_file())
Independent <- updateSelectInput(session, "ind_var", choices = names(selected_file()))
})
observeEvent(input$submit_reg, {
lm1 <- reactive({
req(selected_file())
Model1 <- lm(reformulate(input$ind_var, input$dep_var), data = selected_file())})
options(scipen=999)
output$regsum <- renderPrint({summary(lm1())})
DT::renderDataTable({
df <- req(selected_file())
DT::datatable(df %>% select(input$dep_var, input$ind_var) %>% mutate(predicted = predict(lm1()), residuals = residuals(lm1())) %>% select(input$dep_var, predicted, residuals),
rownames = FALSE, colnames = c('actual value', 'predicted value', 'residuals'), extensions = c('Buttons', 'Responsive'),
options = list(columnDefs = list(list(className = 'dt-center', targets = "_all")), dom = 'Blfrt',
buttons = c('copy', 'csv', 'excel', 'print'), searching = FALSE, lengthMenu = c(20, 100, 1000, nrow(housing)), scrollY = 300, scrollCollapse = TRUE))
})
})
}
shinyApp(ui, server)

Update dataframe to change leaflet output based on users choice in shiny

I'm new to shiny and I have tried multiple ways to update the leaflet output based on two selectinput, the first chooses the data frame to use and the second what to filter on. this bit is working but I don't seem to be able to pass this to the leaflet proxy, any thoughts would be appreciated
poldat <- vroom::vroom("F:/ming1/data/poldat.csv")
meddat <- vroom::vroom("F:/ming1/data/meddat.csv")
medlist <- vroom::vroom("F:/ming1/data/ddl1.csv")
pollist <- vroom::vroom("F:/ming1/data/ddl2.csv")
library(shiny)
library(leaflet)
library(RColorBrewer)
library(vroom)
ui <- bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "50%", height = "100%"),
absolutePanel(top = 10, right = 10,
selectInput('var1', 'Select the area you wish to view', choices = c("choose" = "","police","Medical")),
selectInput('var2', 'Select the area you would like to view' ,choices =c("choose" = "")),
))
server <- function(input, output, session){
output$map <- renderLeaflet({
leaflet(map1) %>% addTiles() %>%
fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
})
observe({
a_option <- input$var1
if (a_option == "police") {
updateSelectInput(session, "var2", choices = c("choose" = "",pollist$row1))
}else{
updateSelectInput(session, "var2", choices = c("choose" = "",medlist$row1))
}
})
observe({
catreq <- input$var1
#mapfilt <- input$var2
mydf<- input$var1
if (mydf == "police") {
mydf = poldat
}else{
mydf = meddat
}
mycol <- input$var1
if (mycol == "police") {
mycol = "fallswithin"
}else{
mycol = "healtharea"
}
map1 <- subset(mydf, mycol == input$var2)
leafletProxy("map", data = map1[2:3]) %>% addTiles()# %>%
addMarkers(clusterOptions = markerClusterOptions(),label = paste("test"))
})
}
shinyApp(ui, server)

In shiny How to create a DT table, where i can add rows and delete the rows simultaneously

I have tried this in different ways and achieved one task, either add or delete., but i couldn't get complete solution in one, i might be missing some small concept somewhere.. I am adding the code , please help me complete my basic app.
library(shiny)
library(DT)
x<- data.frame(v1 = NA,
v2 = NA
),
ui = shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
textInput("v1","v1","a"),
numericInput("V2","V2","1"),
# Row selection
numericInput(inputId = "row.selection", label = "Select row to be
deleted", min = 1, max = 100, value = "")
# Add button
actionButton(inputId = "add.button", label = "Add", icon =
icon("plus")),
# Delete button
actionButton(inputId = "delete.button", label = "Delete", icon =
icon("minus")),
),
mainPanel(
dataTableOutput('table')
)
)
)
),
Server side code
server = function(input, output, session) {
values <- reactiveValues()
values$df <- x
newEntry <- observe({
cat("newEntry\n")
if(input$add.button > 0) {
newRow <- data.frame(input$v1, input$v2)
isolate(values$df <- rbind(values$df,newRow))
}
})
deleteEntry <- observe({
cat("deleteEntry\n")
if(input$delete.button > 0) {
if(is.na(isolate(input$row.selection))){
values$df <- isolate(values$df[-nrow(values$df), ])
} else {
values$df <- isolate(values$df[-input$row.selection, ])
}
}
})
output$table = renderDataTable({
values$df
})
}
Try to use observeEvent rather than obser with actionbutton
and also, you have uppercase and lowercase issue with input$v2 (should be input$V2)
Try this modified code:
library(shiny)
library(DT)
x<- data.frame(v1 = NA,
v2 = NA
)
ui = shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
textInput("v1","v1","a"),
numericInput("V2","V2","1"),
# Row selection
numericInput(inputId = "row.selection", label = "Select row to be
deleted", min = 1, max = 100, value = ""),
# Add button
actionButton(inputId = "add.button", label = "Add", icon =
icon("plus")),
# Delete button
actionButton(inputId = "delete.button", label = "Delete", icon =
icon("minus"))
),
mainPanel(
dataTableOutput('table')
)
)
)
)
server = function(input, output, session) {
values <- reactiveValues()
values$df <- x
observeEvent(input$add.button,{
cat("addEntry\n")
print(input$v1)
print(input$V2)
newRow <- data.frame(input$v1, input$V2)
colnames(newRow)<-colnames(values$df)
values$df <- rbind(values$df,newRow)
print(nrow(values$df))
})
observeEvent(input$delete.button,{
cat("deleteEntry\n")
if(is.na(input$row.selection)){
values$df <- values$df[-nrow(values$df), ]
} else {
values$df <- values$df[-input$row.selection, ]
}
})
output$table = renderDataTable({
values$df
})
}
shinyApp(ui,server)
Just run all the code above, and it should work properly.

Allow User to change input selection in selectizeInput

This app is creating a vector of standardised names which I create given some user input (number of channels and replicates). An example of the standard names given the number of channels = 4 and and replicates = 1 is as follows:
c("rep1_C0","rep1_C1","rep1_C2","rep1_C3")
I would like to allow the user to replace the value of the selection with their own custom value. For example to change the input "rep1_C0" to "Control_rep1". And then for it to then update the reactive vector in question. Here is my code:
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(column(5, numericInput("chans","# Channels",value = 4, min = 1)),
column(5, numericInput("reps","# Replicates",value = 1,min = 1))
),
uiOutput("selectnames")
),
mainPanel(
tableOutput("testcols")
)
)
))
server <- shinyServer(function(input, output) {
standardNames <- reactive({
paste("rep",rep(1:input$reps,each = input$chans),"_",
rep(paste("C",0:(input$chans - 1), sep = ""),input$reps),sep = "")
})
output$selectnames <- renderUI({
selectizeInput("selectnames", "Change Names", choices = standardNames(),
options = list(maxOptions = input$reps * input$chans))
})
## output
output$testcols <- renderTable({
standardNames()
})
})
shinyApp(ui = ui, server = server)
Is there some kind of option I can pass in the options sections that will allow this?
With selectizeInput you can set options = list(create = TRUE) to allow the user to add levels to the selection list, but I don't think that is what you want.
Instead, here is code that generates a text input box for each of the standard names, and allows the user to enter a label for them. It uses lapply and sapply to loop over each value and generate/read the inputs.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(column(5, numericInput("chans","# Channels",value = 4, min = 1)),
column(5, numericInput("reps","# Replicates",value = 1,min = 1))
),
uiOutput("setNames")
),
mainPanel(
tableOutput("testcols")
)
)
))
server <- shinyServer(function(input, output) {
standardNames <- reactive({
paste("rep",rep(1:input$reps,each = input$chans),"_",
rep(paste("C",0:(input$chans - 1), sep = ""),input$reps),sep = "")
})
output$setNames <- renderUI({
lapply(standardNames(), function(thisName){
textInput(paste0("stdName_", thisName)
, thisName
, thisName)
})
})
labelNames <- reactive({
sapply(standardNames()
, function(thisName){
input[[paste0("stdName_", thisName)]]
})
})
## output
output$testcols <- renderTable({
data.frame(
stdName = standardNames()
, label = labelNames()
)
})
})
shinyApp(ui = ui, server = server)
If you want to hide the list unless the user wants to add labels, you can use a simple checkbox, like this, which hides the label making list until the use checks the box to show it.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(column(5, numericInput("chans","# Channels",value = 4, min = 1)),
column(5, numericInput("reps","# Replicates",value = 1,min = 1))
)
, checkboxInput("customNames", "Customize names?")
, uiOutput("setNames")
),
mainPanel(
tableOutput("testcols")
)
)
))
server <- shinyServer(function(input, output) {
standardNames <- reactive({
paste("rep",rep(1:input$reps,each = input$chans),"_",
rep(paste("C",0:(input$chans - 1), sep = ""),input$reps),sep = "")
})
output$setNames <- renderUI({
if(!input$customNames){
return(NULL)
}
lapply(standardNames(), function(thisName){
textInput(paste0("stdName_", thisName)
, thisName
, thisName)
})
})
labelNames <- reactive({
if(!input$customNames){
return(standardNames())
}
sapply(standardNames()
, function(thisName){
input[[paste0("stdName_", thisName)]]
})
})
## output
output$testcols <- renderTable({
data.frame(
stdName = standardNames()
, label = labelNames()
)
})
})
shinyApp(ui = ui, server = server)
Alternatively, if you think the user may want to only change one or a small number of labels, here is a way to allow them to choose which standard name they are applying a label to:
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(column(5, numericInput("chans","# Channels",value = 4, min = 1)),
column(5, numericInput("reps","# Replicates",value = 1,min = 1))
)
, uiOutput("setNames")
),
mainPanel(
tableOutput("testcols")
)
)
))
server <- shinyServer(function(input, output) {
vals <- reactiveValues(
labelNames = character()
)
standardNames <- reactive({
out <- paste("rep",rep(1:input$reps,each = input$chans),"_",
rep(paste("C",0:(input$chans - 1), sep = ""),input$reps),sep = "")
vals$labelNames = setNames(out, out)
return(out)
})
output$setNames <- renderUI({
list(
h4("Add labels")
, selectInput("nameToChange", "Standard name to label"
, names(vals$labelNames))
, textInput("labelToAdd", "Label to apply")
, actionButton("makeLabel", "Set label")
)
})
observeEvent(input$makeLabel, {
vals$labelNames[input$nameToChange] <- input$labelToAdd
})
## output
output$testcols <- renderTable({
data.frame(
stdName = standardNames()
, label = vals$labelNames
)
})
})
shinyApp(ui = ui, server = server)

Input 2nd file in R Shiny only if results from 1st Input file satisfies requirement

I am relatively new on using R Shiny, I am trying to build Shiny app for predictive modeling.
I have R code ready with me and have loaded them in R Shiny.
Please refer to below ui.r and server.r which I have prepared.
shinyUI(
fluidPage(
titlePanel("Prediction"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose Past CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
conditionalPanel(
condition = "output.fileUploaded",
fileInput('file2', 'Choose Future CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
downloadButton("downloadData", "Download Prediction")
)
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel('Results', (DT::dataTableOutput('table'))),
tabPanel("Model Summary",
verbatimTextOutput("summary"))
)
)
)
)
)
shinyServer(function(input, output) {
# hide the output
output$fileUploaded <- reactive({
return(!is.null(input$file1))
})
outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
data <- reactive({
File <- input$file1
if (is.null(File))
return(NULL)
complete <- read.csv(File$datapath,header=T,na.strings=c(""))
File1 <- input$file2
if (is.null(File1))
return(NULL)
raw.data <- read.csv(File1$datapath,header=T,na.strings=c(""))
#Change all variable to factor
complete[] <- lapply(complete, factor)
complete$Target <- recode(complete$Target," 'YES' = 1; 'Yes' = 1; 'NO' = 0 " )
set.seed(33)
splitIndex <- createDataPartition(complete$Target, p = .75, list = FALSE, times = 1)
trainData <- complete[ splitIndex,]
testData <- complete[-splitIndex,]
fitControl <- trainControl(method = "repeatedcv", number = 4, repeats = 4)
set.seed(33)
gbmFit1 <- train(as.factor(Target) ~ ., data = trainData, method = "gbm", trControl = fitControl,verbose = FALSE)
pred <- predict(gbmFit1, testData,type= "prob")[,2]
perf = prediction(pred, testData$Target)
pred1 = performance(perf, "tpr","fpr")
acc.perf <- performance(perf, "acc")
ind = which.max( slot(acc.perf, "y.values")[[1]])
acc = slot(acc.perf, "y.values")[[1]][ind]
output$summary <- renderPrint({
print(c(Accuracy=acc))
})
raw.data[] <- lapply(raw.data, factor)
testpred <- predict(gbmFit1, raw.data,type= "prob")[,2]
final = cbind(raw.data, testpred)
final
})
output$table = DT::renderDataTable({
final <- data()
DT::datatable(
data(), options = list(
pageLength = 5)
)
})
output$downloadData <- downloadHandler(
filename = function() { paste('SLA Prediction', '.csv', sep='') },
content = function(file) {
write.csv(data(),file)
}
)
return(output)
})
Model is created using first Input file, my requirement is user should asked to upload 2nd input file (for which they want to predict results) only if model Accuracy which calculated using first input file stored in variable acc should be more than 0.9, I am not able to get solution for this, can anyone help me in this.
Now the second file input depends on the variable acc and shows up only when it is bigger than 0.9. I additionally did some changes, mainly because your code didn't work on my laptop :). Instead of return(NULL) you can use the function req to ensure that the values are available.
library(shiny)
library(shinysky)
library(shinythemes)
library(caret)
library(gbm)
library(ROCR)
library(car)
ui <- shinyUI(
fluidPage(
theme = shinytheme("united"), # added new theme from the package 'shinythemes'
titlePanel("Prediction"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose Past CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
uiOutput("dynamic")
),
mainPanel(
# added busyIndicator
busyIndicator(text = "Calculation in progress..",
img = "shinysky/busyIndicator/ajaxloaderq.gif", wait = 500),
tabsetPanel(type = "tabs",
tabPanel('Results',
(DT::dataTableOutput('table'))),
tabPanel("Model Summary",
verbatimTextOutput("summary")),
tabPanel("Predictions",
DT::dataTableOutput('tablePred'))
)
)
)
)
)
server <- shinyServer(function(input, output) {
# hide the output
output$fileUploaded <- reactive({
return(!is.null(input$file1))
})
outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
data <- reactive({
File <- input$file1
req(File)
complete <- read.csv(File$datapath,header=T,na.strings=c(""))
complete
})
model <- reactive({
complete <- lapply(data(), factor)
complete$Target <- recode(data()$Target," 'YES' = 1; 'Yes' = 1; 'NO' = 0 " )
set.seed(33)
splitIndex <- createDataPartition(data()$Target, p = .75, list = FALSE, times = 1)
trainData <- data()[ splitIndex,]
testData <- data()[-splitIndex,]
fitControl <- trainControl(method = "repeatedcv", number = 4, repeats = 4)
set.seed(33)
gbmFit1 <- train(as.factor(Target) ~ ., data = trainData, method = "gbm", trControl = fitControl,verbose = FALSE)
pred <- predict(gbmFit1, testData, type= "prob")[,2]
perf = prediction(pred, testData$Target)
pred1 = performance(perf, "tpr","fpr")
acc.perf <- performance(perf, "acc")
ind = which.max( slot(acc.perf, "y.values")[[1]])
acc = slot(acc.perf, "y.values")[[1]][ind]
retval <- list(model = gbmFit1, accuracy = acc)
return(retval)
})
output$summary <- renderPrint({
req(model())
print(model())
})
output$dynamic <- renderUI({
req(model())
if (model()$accuracy >= 0.9)
list(
fileInput('file2', 'Choose Future CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
downloadButton("downloadData", "Download Prediction")
)
})
data2 <- reactive({
req(input$file2)
File1 <- input$file2
raw.data <- read.csv(File1$datapath,header=T,na.strings=c(""))
raw.data
})
preds <- reactive({
raw.data <- data2()
testpred <- predict(model()$model, raw.data,type= "prob")[,2]
print(testpred)
final = cbind(raw.data, testpred)
final
})
output$table = DT::renderDataTable({
DT::datatable(data(), options = list(pageLength = 15))
})
output$tablePred = DT::renderDataTable({
req(input$file2)
DT::datatable(preds(), options = list(pageLength = 15))
})
output$downloadData <- downloadHandler(
filename = function() { paste('SLA Prediction', '.csv', sep='') },
content = function(file) {
write.csv(preds(),file)
}
)
return(output)
})
shinyApp(ui, server)