首页 > 解决方案 > 在 Rshiny 的侧边栏面板中选择了未定义的列

问题描述

我是 Shiny 的新手,所以请原谅我问了一个如此基本的问题。

我正在尝试开发一个基本的数据分析应用程序,以处理大型数据库。我已经能够导入 DDBB 并将其可视化为表格。但是,当尝试对变量执行汇总统计时,我遇到以下错误:“选择了未定义的列”,我什么也看不到。如果我不在服务器中添加任何代码,我可以在应用程序中看到输出(箱线图、直方图和摘要),但我看不到变量名称(只有 1、2、3...)。我在下面显示我的代码。

我将非常感谢解决此问题的任何帮助。非常感谢。

shinyUI(fluidPage(

    main_page <- tabPanel(
        title = "Statistics",
        titlePanel("Statistical Analysis"),
        
        sidebarLayout(
            sidebarPanel(
                # Añado el archivo que quiero cargar
                fileInput('DDBB', 'Choose file to upload',
                          accept = c(
                              'text/csv',
                              'text/comma-separated-values',
                              '.csv'
                          )),
                #checkboxInput('header', 'Header', TRUE),
                #tags$hr(),
                selectInput('Variable', 'Select a variable', "",
                            choice=c((1:33)), multiple = FALSE,
                            selectize = TRUE
                            ),
                  sliderInput("bins",
                              "Number of bins:",
                              min = 1,
                              max = 200,
                              value = 30)
            ),
            
            mainPanel(
                tabsetPanel(
                    tabPanel(
                        title = "Data Visualization",
                       
                        DT::dataTableOutput("sample_table")
                    ),
                    tabPanel(
                        title = "Summary Statistics",
                        verbatimTextOutput("sum"),
                        fluidRow(splitLayout(cellWidths = c("50%", "50%"),
                                             plotOutput("box"),
                                             plotOutput('hist'))
                        )
                    )
                )
            )
        )
    )

  
))


# Define server logic required to draw a histogram
shinyServer(function(input, output, session) {

# Output a file input (cargar archivo).
    df_products_upload <- reactive({ 
        inFile <- input$DDBB 
        print(inFile)
        if (is.null(inFile))
            return(NULL)
        df <- read.csv(inFile$datapath, header = TRUE,sep = ';')
       # updateSelectInput(session, "Variable", choices = names(df))
        return(df)
    })

  
    output$sample_table<- DT::renderDataTable({ 
        df <- df_products_upload() 
        DT::datatable(df,
                      filter = 'top') %>%
            formatRound(columns= c(1:ncol(df)), digits = 2)
    })
    
    
    observeEvent(df_products_upload(), {
      updateSelectInput(session, "Variable", choices = colnames(df_products_upload()))
    })
    
    output$sum <- renderPrint({
      updateSelectInput(session, "Variable", choices = colnames(df)
        summary(df[,as.numeric(input$Variable)])
    })
    
    output$box <- renderPlot({
      updateSelectInput(session, "Variable", choices = colnames(df_products_upload))
        x<-summary(df[,as.numeric(input$Variable)])
        boxplot(x,col="sky blue",border="purple",main=names(df[as.numeric(input$Variable)]))

    })
    
    output$hist <- renderPlot({
      updateSelectInput(session, "Variable", choices = colnames(df_products_upload))
        # generate bins based on input$bins from ui.R
        x<-df[,as.numeric(input$Variable)]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)
        # draw the histogram with the specified number of bins
        hist(x, 
             main=names(df[as.numeric(input$Variable)]) ,
             breaks = bins, col = 'darkgray', border = 'black',
             xlab = 'samples')
        
    })
    
  
    
   
 
})

标签: rshiny

解决方案


欢迎来到 Stack-Overflow,Enrique :) 我添加了一行以将 iris 数据集保存为 ';' - 分隔的 csv 并将其用作可上传的数据示例。我必须说,您的代码有多个错误,既有闪亮的,也有一些基本的基本 R 数据帧操作。我已经更正了它们并添加了评论。万事开头难。我建议你回去做一些更闪亮的练习和教程。我认为这样你会进步得更快。

特别是重新审视反应式表达式: httpssum(my_reactive_numbers()) ://shiny.rstudio.com/tutorial/written-tutorial/lesson6/ 如果您将反应式或反应式自身 的值作为参数传递,这很重要sum(my_reactive_numbers)

还可以查看闪亮的反应上下文的范围规则。基本上就像函数一样,在一个反应​​上下文中定义的内容不会自动暴露给其他人,因此 df 问题。如果您想(可能不)使变量成为全局变量,这里有一个更深入的介绍: https ://shiny.rstudio.com/articles/scoping.html

library(DT)

write.table(iris,file = "./sample_upload_data_set.csv",sep = ";") #; because assmed in code

ui <- shinyUI(fluidPage(
  
  main_page <- tabPanel(
    title = "Statistics",
    titlePanel("Statistical Analysis"),
    
    sidebarLayout(
      sidebarPanel(
        # Añado el archivo que quiero cargar
        fileInput('DDBB', 'Choose file to upload',
                  accept = c(
                    'text/csv',
                    'text/comma-separated-values',
                    '.csv'
                  )),
        #checkboxInput('header', 'Header', TRUE),
        #tags$hr(),
        selectInput('Variable', 'Select a variable', NULL,
                    choices = NULL,    #edits start with NULL as no data set yet
                    multiple = FALSE,
                    selectize = TRUE
        ),
        sliderInput("bins",
                    "Number of bins:",
                    min = 1,
                    max = 200,
                    value = 30)
      ),
      
      mainPanel(
        tabsetPanel(
          tabPanel(
            title = "Data Visualization",
            
            DT::dataTableOutput("sample_table")
          ),
          tabPanel(
            title = "Summary Statistics",
            verbatimTextOutput("sum"),
            fluidRow(splitLayout(cellWidths = c("50%", "50%"),
                                 plotOutput("box"),
                                 plotOutput('hist'))
            )
          )
        )
      )
    )
  )
  
  
))


# Define server logic required to draw a histogram
server <- function(input, output, session) {
  
  #expose an uplaoded csv file as a reactive data.frame
  df_products_upload <- reactive({  #todo consider a shorter name e.g. r_prod_up.df
    inFile <- input$DDBB  #
    print(inFile)
    #if (!is.null(inFile))
    #  return(NULL) do not use return in any shiny reactive context, it is not a function
    
    #req is practical replacement of if '(is.null(inFile)) return(NULL)'-pattern
    req(inFile$datapath) #must be not null, non_empty character, or reactive will not complete
    
    df <- read.csv(inFile$datapath, header = TRUE,sep = ';')
    # updateSelectInput(session, "Variable", choices = names(df))

    #return(df) ## EDIT do not use return
    df
  })
  
  #let data.frame column names be choices of an input 
  observe({ #edit observeEvent was redundant, just use observe here
    df <- df_products_upload()
    
    #the following code expects numeric columns
    the_numeric_columns <- colnames(df)[sapply(df,is.numeric)]
    
    updateSelectInput(session, "Variable", choices = the_numeric_columns)
  })
  
  
  


  #render the data.frme with data.table
  output$sample_table <- DT::renderDataTable({ 
    df <- df_products_upload() 
    DT::datatable(df, filter = 'top') %>%
      #formatRound will mask non numeric columns
      formatRound(
        columns = which(sapply(df,is.numeric)), #only format numeric columns
        digits = 2
      )
  })
  
  
  
  # but this render makes absolutely no sense, you should 
  output$sum <- renderPrint({
    
    #edit it is bad behavior to do side effects in render scopes
    # updateSelectInput(session, "Variable", choices = colnames(df_products_upload()) #edit df was not assign in scope
    #                   summary(df[,as.numeric(input$Variable)])
    # })
    
  }) # edit missing bracket
    
  output$box <- renderPlot({
    #browser()
    
    #edit bad behaviour, maybe you missunderstood the update functionSelectInput
    #updateSelectInput(session, "Variable", choices = colnames(df_products_upload())) #edit reactive must be read not passed directly to colnames
    
    #edit df is not assigened in this scope
    df <- df_products_upload()
    
    #x<-summary(df[,as.numeric(input$Variable)]) #edit this is no bueno, what if varaible names were ... names
    # edit since plucking only one column and dropping data.frame wrap
    # you may just use [[]] brackets to make it more explicit to the reader
    x<-df[[input$Variable]] #this can only return the vector of one column or NULL
    x<-summary(x) 
    
    
    boxplot(
      x,
      col="sky blue",
      border="purple",
      
      #comma was missing here, and why not just use Varaible 
      main = input$Variable
    
    )
    
  })
    
  output$hist <- renderPlot({
    #browser()
    #edit df is not assigened in this scope
    df <- df_products_upload()
    
    #update makes no sense here
    #updateSelectInput(session, "Variable", choices = colnames(df)) #edit if introducing df anyways just use that
    # generate bins based on input$bins from ui.R
    
    # edit since plucking only one column and dropping data.frame wrap
    # you may just use [[]] brackets to make it more explicit to the reader
    x<-df[[input$Variable]] #this can only return the vector of one column or NULL
    
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    # draw the histogram with the specified number of bins
    hist(x, 
         #main=names(df[as.numeric(input$Variable)]) , # you're assuming columns would be named by numbers...
         #...and it is quite like crossing the river to get water,
         main = input$Varible, 
         breaks = bins, col = 'darkgray', border = 'black',
         xlab = 'samples'
    )
    
    
  })
    
    
    
    
    
}


shiny::shinyApp(ui = ui, server = server)

推荐阅读