argument of length is zero. Program does not recognize option from SelectInput - r

SelectInput function in ui is supposed to give me an option to choose "YES" or "NO". When "NO" is selected, it will choose the " if(("NO" %in% input$qualify_pit))" block in renderDataTable function in server and execute that perfectly. However, when I choose "YES" option, its block does not run, not displaying any table. I tried everything to get it to run its block (if(("YES" %in% input$qualify_pit))) but to no avail.
library(shiny)
library(shinythemes)
library(DT)
pit <- read.csv("PIT_STAT.csv")
pit_stat <- c("MLB_name","MLBId","LastName","FirstName","LW","W","L","Sv","BS","HLD","G","GS","CG","GF","QS","SHO","IP","BFP","H","X1B","X2B","X3B",
"HR","R","ER","SH","SF","HBP","BB","IBB","BB_noIBB","K","WP","BLK","GB","FB","LD","POPU","SB",
"CS","PKO","SVO","OUTS","K9","BB9","AVG","BABIP","HR9","GB_percent","HRperFB","ERA","KperBB",
"K_percent","BB_percent","K_minus_BB","WHIP","LD_percent","FB_percent","GBperFB")
pit_def <- c("MLB_name","MLBId","LastName","FirstName","LW","W","L","ERA","IP","H","HR","R","ER","BB","K","K9","BB9","HR9","WHIP",
"GB_percent","FB_percent","LD_percent","K_percent","BB_percent","KperBB","K_minus_BB")
ui <- shinyUI(fluidPage(
shinythemes::themeSelector(),
theme = shinytheme("paper"),
titlePanel("WSFB Stats Lab"),
fluidRow(
uiOutput("uis")
),
fluidRow(
tabsetPanel(id = "tabs",
tabPanel("Pitch Table",dataTableOutput("pitch_table"))
)
)
)
)
server <- shinyServer(function(input, output, session){
output$uis <- renderUI({
if(input$tabs == "Pitch Table")
{
pit <- read.csv("PIT_STAT.csv")
pit_stat <- c("MLB_name","MLBId","LastName","FirstName","LW","W","L","Sv","BS","HLD","G","GS","CG","GF","QS","SHO","IP","BFP","H","X1B","X2B","X3B",
"HR","R","ER","SH","SF","HBP","BB","IBB","BB_noIBB","K","WP","BLK","GB","FB","LD","POPU","SB",
"CS","PKO","SVO","OUTS","K9","BB9","AVG","BABIP","HR9","GB_percent","HRperFB","ERA","KperBB",
"K_percent","BB_percent","K_minus_BB","WHIP","LD_percent","FB_percent","GBperFB")
pit_def <- c("MLB_name","MLBId","LastName","FirstName","LW","W","L","ERA","IP","H","HR","R","ER","BB","K","K9","BB9","HR9","WHIP",
"GB_percent","FB_percent","LD_percent","K_percent","BB_percent","KperBB","K_minus_BB")
wellPanel(
checkboxGroupInput('show_vars', 'Variables to display', pit_stat, inline = TRUE, selected = pit_def),
selectInput("qualify_pit","MIN IP:",choices = c("YES","NO"))
)
}
})
output$pitch_table <- renderDataTable({
if(("YES" %in% input$qualify_pit))
{
pit <- read.csv("PIT_STAT.csv")
pit2 <- pit[pit$IP >= 162,]
DT::datatable(pit2[,input$show_vars, drop = FALSE])
}
if(("NO" %in% input$qualify_pit))
{
pit <- read.csv("PIT_STAT.csv")
DT::datatable(pit[,input$show_vars, drop = FALSE])
}
})
})
shinyApp(ui = ui, server = server)

It works with NO because the DT:datatable is the last expression of the function, therefore it is the implicit return value.
But for the YES, which is not the last evaluation (the if("NO" %in%... is), you have to explicitly use return:
return(DT::datatable(pit2[,input$show_vars, drop = FALSE]))
Otherwise you can simply use else
output$pitch_table <- renderDataTable({
if(("YES" %in% input$qualify_pit))
{
DT::datatable(pit[pit$IP >= 162,input$show_vars, drop = FALSE])
}
else
{
DT::datatable(pit[,input$show_vars, drop = FALSE])
}
})
For more details about using return you can read this thread

Related

How to fix editable DT::datatable throwing: "Error in split.default: first argument must be a vector"

I am trying to make a module that accepts a data frame and produces an editable datatable out of it. This worked until I made the module able to accept multiple edits by making the following change:
editTable <- reactive({
datatable(
reactives$input,
#editable = T #PREVIOUS (working fine)
editable = list(target = "all"), #NEW (problem-causing)
rownames = F
)
})
Once the code labelled #NEW is included, clicking labelDo (in this case "Edit") causes the app to crash with this error message:
Warning: Error in split.default: first argument must be a vector
The closest problem I could find to this one is here . This user's problem is the same but mine is not solved (as theirs allegedly is) by putting rownames = FALSE into their datatable() equivalent of the snippet above.
Please go ahead and run the following module and app together and attempt to edit one of the numbers in the table. Click 'edit' and you will get the same result.
Module:
editrUI <- function(id, labelDo, labelUndo) {
ns <- NS(id)
tagList(
dataTableOutput(ns("out")),
actionButton(
inputId = ns("do"),
label = labelDo
),
actionButton(
inputId = ns("undo"),
label = labelUndo
)
)
}
editrServer <- function(id, dataFrame) {
moduleServer(
id,
function(input, output, session){
reactives <- reactiveValues()
reactives$input <- NULL
observe({
reactives$input <- dataFrame
})
editTable <- reactive({
datatable(
reactives$input,
#editable = T #old
editable = list(target = "all"), #new
rownames = F
)
})
output$out <- renderDataTable(
editTable()
)
observeEvent(input$do , {
reactives$input <<- editData(reactives$input, input$out_cell_edit, rownames = F)
})
observeEvent(input$undo , {
reactives$input <- dataFrame
})
return(reactive({reactives$input}))
}
)
}
App:
library(shiny)
source(
#source of module
)
a <- 1:5
df <- tibble(a, a*2)
ui <- fluidPage(
editrUI(id = "id", labelDo = "Edit", labelUndo = "Undo")
)
server <- function(input, output) {
editrServer(id = "id", dataFrame = df)
}
# Run the application
shinyApp(ui = ui, server = server)
It seems this error is caused when input$out_cell_edit is NULL (no cell has been edited).
You can fix it with req(input$out_cell_edit) that will cancel the event in case input$out_cell_edit is NULL.
Also you don't need to use <<- to assign to the reactiveValues.
observeEvent(input$do , {
req(input$out_cell_edit)
reactives$input <- editData(reactives$input, input$out_cell_edit, rownames = F)
})

How do we duplicate existed attribute values with different attribute name in shinyapp?

It would be great some one could help on below requirement.
url <- "https://bbolker.github.io/mpha_2019/gapminder_index.csv"
dt <- fread(url)
# UI
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("newcolumnname", "Custom Attribute Name"),
selectInput("formula", "Enter Custom Formula", choices = unique(names(dt)), multiple = TRUE),
actionButton("addnewcolumn", "Add new column")
),
mainPanel(
DT::DTOutput("data_tbl")
)
)
)
#SERVER
server <- function(input, output, session) {
reactive_dt <- eventReactive(input$addnewcolumn, {
if (input$newcolumnname != "" &&
!is.null(input$newcolumnname) && input$addnewcolumn > 0) {
#newcolval <- dt$input$formula
newcolval <- dt[,input$formula]
newcol <- data.table(newcolval)
names(newcol) <- input$newcolumnname
dt <<- cbind(dt, newcol)
}
dt
})
output$data_tbl <- DT::renderDT({ head(reactive_dt(),5) })
}
#Run the Shiny App to Display Webpage
shinyApp(ui = ui, server = server)
Requirement details:-
would like to concatenate the values of "Category/Provider" attribute values under new column called "Category_provider", unfortunately instead of values it's showing attribute names in UI table. what would be the correction in my code to achieve the requirement.
Try this,
url <- "https://bbolker.github.io/mpha_2019/gapminder_index.csv"
dt <- as.data.frame(fread(url))
# UI
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("newcolumnname", "Custom Attribute Name"),
selectInput("formula", "Enter Custom Formula", choices = unique(names(dt)), multiple = TRUE),
actionButton("addnewcolumn", "Add new column")
),
mainPanel(
DT::DTOutput("data_tbl")
)
)
)
#SERVER
server <- function(input, output, session) {
reactive_dt <- eventReactive(input$addnewcolumn, {
if (input$newcolumnname != "" &&
!is.null(input$newcolumnname) && input$addnewcolumn > 0) {
newcol <- apply(dt[,input$formula] , 1, function(x) paste(x, collapse = "_"))
cn <-colnames(dt)
dt <<- data.frame(dt, newcol)
colnames(dt) <- c(cn,input$newcolumnname)
}
dt
})
output$data_tbl <- DT::renderDT({ head(reactive_dt(),5) })
}
#Run the Shiny App to Display Webpage
shinyApp(ui = ui, server = server)

R Shiny : dynamic number of tables within a tab

first I know there is a lot of threads covering my problem, I read them all, but I did not manage to do it. I got a list of 10 data.frame which I built through the following code :
list_of_df=list()
for (i in seq(1,10)){
number_row=sample(seq(5,10),size = 1)
num=seq(1,number_row)
val=sample(x = letters,size = number_row,replace = TRUE )
df=data.frame(num=num,
val=val)
rownames(df)=NULL
list_of_df[[i]]=df
}
I want the user to enter n, the number of tables he wants to see. And then display n random tables from the list_of_df. I want to display those tables inside tabs. Here is what I did, I grabbed some ideas here and there, but obviously it does not work and I do not know why.
library(shiny)
# ui function
ui = pageWithSidebar(
headerPanel('Dynamic Tabs'),
sidebarPanel(
numericInput(inputId = "numput",label = "number of tables",value = 1,min = 1,max = 5)
),
mainPanel(
uiOutput('mytabs')
)
)
# server function
server = function(input, output, session){
random_tables<- reactive({
index=sample(seq(1,10),size = input$numput,replace=FALSE)
list_of_df[[index]]
})
size<-reactive({
length(random_tables())
})
for (i in 1:size()) {
local({
my_i <- i
tablename <- paste("table_", my_i, sep="")
output[[tablename]] <- renderTable({
random_tables()[[i]]
})
})
}
output$mytabs = renderUI({
nTabs = size()
myTabs = lapply(paste0('table_', 1: nTabs), function(x){
tabPanel(x, tableOutput(x))
})
do.call(tabsetPanel, myTabs)
})
}
shinyApp(ui, server)
So, if you see what I should do ...
Here is a working version:
library(shiny)
# ui function
ui = pageWithSidebar(
headerPanel('Dynamic Tabs'),
sidebarPanel(
numericInput(inputId = 'numput',label = "number of tables",value = 1,min = 1,max = 5)
),
mainPanel(
uiOutput('mytabs')
)
)
# server function
server = function(input, output, session){
list_of_df=list()
for (i in seq(1,10)){
number_row=sample(seq(5,10),size = 1)
num=seq(1,number_row)
val=sample(x = letters,size = number_row,replace = TRUE )
df=data.frame(num=num,
val=val)
rownames(df)=NULL
list_of_df[[i]]=df
}
random_tables<- reactive({
index=sample(seq(1,10),size = input$numput,replace=FALSE)
list_of_df[index]
})
size<-reactive({
input$numput
})
observe({
lapply(seq_len(size()), function(i) {
local({
my_i <- i
tablename <- paste("table_", my_i, sep="")
output[[tablename]] <- renderTable({
random_tables()[[i]]
})
})
})
})
output$mytabs = renderUI({
nTabs = size()
myTabs = lapply(paste0('table_', seq_len(nTabs)), function(x){
tabPanel(x, tableOutput(x))
})
do.call(tabsetPanel, myTabs)
})
}
shinyApp(ui=ui,server=server)
A couple issues, you subset the list with double brackets, but it isn't working like you think it is, you need single brackets. Next when you select a single table random_table() is a data.frame so when you call length you get 2, the number of columns. So just use the input$numput for size() since they are the same anyways. Also, I put the dynamic output in an observe so that it can access the reactive size(). A small thing, but I used seq_len instead of 1:aNumber since it is more robust.
Hope this helps

shiny R can't display a text from vector

How can I display value only on the browser?
Below is my code.
ui <- shinyUI(bootstrapPage(
absolutePanel(
textOutput("renderText1")
)
)
)
server <- function(input,output,session)
{
observeEvent(input$dropdown, {
query <- sprintf("select ....",input$dropdown)
cabinet_info <- dbGetQuery(con,query)
output$renderText1 <- renderText({
paste(cabinet_info)
})
})
}
Below are the outputs:
c('a','w','r','t')
While Geovany's answer may work, it is not a good practice to use observeEvent with the global assignment operator (<<-).
If you would like to execute a side effect (e.g. writing a file, plotting, printing), then you can use observe or observeEvent, but if you want to use a return value, use eventReactive instead.
ui <- shinyUI(bootstrapPage(
absolutePanel(
selectInput("dropdown", label = 'SelectInput', choices = c('A', 'B')),
textOutput("renderText1")
)
)
)
server <- function(input,output,session)
{
cab <- eventReactive(input$dropdown, {
query <- sprintf("select ....",input$dropdown)
#cabinet_info <- dbGetQuery(con,query) #Replaced by a constant
cabinet_info <- paste(c(input$dropdown, 'a','w','r','t'), sep=",")
})
output$renderText1 <- renderText({
cab()
})
}
shinyApp(ui, server)
Call eventReactive from the server side just like a function: cab()
This could help you
runApp(list(
ui = shinyUI(bootstrapPage(
absolutePanel(
actionButton("dropdown", "dropdown"),
textOutput("renderText1")
)
)
),
server = shinyServer(function(input, output) {
cabinet_info <- NULL
observeEvent(input$dropdown, {
cabinet_info <<- c('a','w','r','t')
})
output$renderText1 <- renderText({
input$dropdown
paste(cabinet_info, collapse = ',')
})
})
))

Shiny R renderPrint in loop usinf RenderUI only update the output

I am trying to dynamically render multiple text output from multiple text input. I tried to use this very helpfull example and this one too.
This conversation is also helpfull.
But when I try to adapt this examples on the following script, I have a problem of output update. Apparently, only the last element was read and updated. It's probably a reactivity problem but it seems to be difficult to associate reactive{()} and renderUI{()}functions.
rm(list = ls())
library(shiny)
creatDataElem <- function(ne, input) {
x1 <- lapply(1:ne, function(i) {
textInput(paste0("elemName", i),
label = h4(strong("Name of dataset element")),
value = "")
})
return(x1)
}
ui = (fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("elemNb",
"Number of elements", value = 1, min = 1,
max = 3)
,
conditionalPanel(
condition = "input.elemNb == 1",
creatDataElem(1)
),
conditionalPanel(
condition = "input.elemNb == 2",
creatDataElem(2)
),
conditionalPanel(
condition = "input.elemNb == 3",
creatDataElem(3)
)
),
mainPanel(
uiOutput("nameElem")
)
)
)
)
server = function(input, output, session) {
max_elem <- 3
# Name
output$nameElem <-renderUI({
nameElem_output_list <- lapply(1:input$elemNb, function(i) {
elemName <- paste0("elemName", i)
tags$div(class = "group-output",
verbatimTextOutput(elemName)
)
})
do.call(tagList, nameElem_output_list)
})
for (i in 1:max_elem) {
local({
force(i)
my_i <- i
elemName <- paste0("elemName", my_i)
output[[elemName]] <- renderPrint(input[[elemName]])
})
}
}
runApp(list(ui = ui, server = server))
The idea with a reactive({}) function is to add an independant object (a function in this case) like:
nameElem <- reactive({
if (input$goElem == 0) {
return()
} else {
isolate({
if (is.null(input$elemName)) {
return()
} else if (test(input$elemName)) {
return("TEST RESULT")
} else {
return(input$elemName)
}
})
}
})
and to use renderUI on this object (with an ActionButton).
So, if someone knows why the output does not return the good object...
I think one of your problems is that your creatDataElem function is such that when it is called with argument ne=3, the first and second textInput elements are created again (and their value "lost").
Anyway, I think one solution would be to create those textInput elements as an "uiOutput".
You'll find a possible solution below which (I think) does what you want.
Lise
rm(list = ls())
library(shiny)
ui = (fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("elemNb",
"Number of elements", value = 1, min = 1,
max = 3),
uiOutput("myUI")
),
mainPanel(
uiOutput("nameElem")
)
)
)
)
server = function(input, output, session) {
output$myUI=renderUI({
w=""
for (i in 1:input$elemNb){
w=paste0(w,
textInput(paste0("elemName",i),label='Name of dataset element'))
}
HTML(w)
})
output$nameElem <-renderUI({
elems=c("<div>")
for(i in 1:input$elemNb){
elems=paste(elems,"</div><div>",input[[paste0("elemName",i)]])
}
elems=paste0(elems,"</div>")
HTML(elems)
})
}
runApp(list(ui = ui, server = server))
Found a solution:
library(readr)
library(dplyr)
library(shiny)
df <- data.frame(symbol = 1:10)
uiOutput("myUI")
createUI <- function(dfID, symbol) {
div(class="flex-box",paste0(symbol, " - 10"))
}
output$myUI <- renderUI({
w <- lapply(seq_len(nrow(df)), function(i) {
createUI(i, df[i,"symbol"])
})
do.call(fluidPage,w)
})

Resources