【问题标题】:Problems with reactive dataframe and update input in shin Rshin R 中反应性数据框和更新输入的问题
【发布时间】:2021-03-09 19:36:00
【问题描述】:

我仍然是使用闪亮的初学者(下面的代码将清楚地证明这一事实)。在我正在做的工作的这个例子中,我必须生成两个条形图。这两个图都来自一组数据框,每个数据框都与不同的年份相关联。在每个数据框中都有一些行(示例中为 8 行),每一行都与一个值相关联(例如.、“值 1”、“值 2”等)。用户选择年份范围(start_yearend_year),服务器计算两年之间每个值的差值(例如。,2018 年的“值 1”减去“值 1” " 2015 年)。但是,在第一个条形图中只显示了有限数量的值,在本例中为 4。到目前为止,我还没有遇到任何问题。但是,我必须显示另一个条形图,链接到示例中的输入 val_select。我必须只添加第一个条形图中显示的前四个值作为此输入的选择。此外,用户可以在这个值的短列表中进行选择,并且在第二个条形图中,它将显示所选年份期间每年所选值的趋势。例如,如果在 2005-2018 年期间显示的四个值是“值 2”、“值 4”、“值 6”、“值 7”,则可以在第三个输入中选择这些值四个值,选定的一个将显示在第二个条形图中,其值介于 2005 年和 2018 年之间。 我在脚本中有两个主要问题:

  1. 尝试将第三个输入 val_select 中的选项列表更新为 updateSelectInput 会导致应用崩溃;
  2. 第二个条形图未生成并返回以下错误:
Problem with `mutate()` input `x`.
[31mx[39m Input `x` can't be recycled to size 2.
[34mi[39m Input `x` is `plot_data$years`.
[34mi[39m Input `x` must be size 2 or 1, not 4.

下面是我在线程结束时编写的示例,尝试了所需的输出。

library(shiny)
library(shinydashboard)
library(highcharter)
library(dplyr)

# Generate data
years = c(2009:2019)

list_db = vector("list")
var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")

for (i in 1:length(years)){
    x = runif(8, min = 0, max = 100)
    df = data.frame(var, x)
    list_db[[i]] = df
}
names(list_db) = years

# UI
ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(
        sidebarMenu(
            menuItem("Page 1", tabName = 'tab_page_1'),
            selectInput(inputId = "start_year",
                        label = "Select starting year:",
                        choices = min(years):max(years)),
            selectInput(inputId = "end_year",
                        label = "Select ending year:",
                        choices = min(years):max(years)),
            selectInput(inputId = "val_select",
                        label = "Select Value (within the selected range) to show:",
                        choices = var)
        )
    ),
    dashboardBody(
        tabItem(tabName = 'tab_page_1'),
        fluidPage(
            titlePanel("Example Page 1")
        ),
        fluidPage(
            fluidRow(
                box(title = "Barplot n.1",
                    solidHeader = TRUE, 
                    status = 'primary',
                    highchartOutput("tab_1", height = 500)
                ),
                box(title = "Barplot n.2 (Value focus)",
                    solidHeader = TRUE, 
                    status = 'primary',
                    highchartOutput("tab_2", height = 500)
                ),
                
            )
        )
    )
)

# Server
server <- function(input, output, session) {
    
    # Update 'end_year' based on 'start_year' input
    
    observeEvent(input$start_year, {
        updateSelectInput(session, 'end_year',
                          choices = (as.integer(input$start_year)+1):max(years)
        )
    })
    
    # Reactive data frame
    
    react_data = reactive({
        
        # Generate starting and ending data frame
        assign("data_start", list_db[[as.character(input$start_year)]])
        assign("data_end", list_db[[as.character(input$end_year)]])
        
        # Add the selected year to variables' names
        data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
        data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
        
        # Join starting and ending data frame
        dt = full_join(data_start, data_end, by = "var")
        
        # Calculate vars' differences between the selected years
        dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)] 
        
        # Select only first 4 Values
        dt = head(dt[order(dt$x_diff),],4)
        
    })

    # Update 'val_select' b <--- Problematic
    
    observeEvent({
        val_select_data = react_data()
        mylist = val_select_data$var
        updateSelectInput(session, 'val_select',
                          choices = mylist
        )
    })
    
    # Output 'tab_1' <--- This works
    
    output$tab_1 = renderHighchart({ 
        
        # Select data frame
        mydata1 = react_data()
        
        # Plot
        highchart() %>% 
            hc_chart(type = "bar") %>%
            hc_xAxis(categories = mydata1$var)  %>%
            hc_series(list(name = "Variables", 
                           pointWidth = 50, 
                           data = mydata1$x_diff, 
                           color = "rgba(162, 52, 52, 0.5)")) %>%
            hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
            hc_chart(plotBackgroundColor = "#EEEEEE") %>%
            hc_legend(enabled = FALSE)
    })
    
    # Output 'tab_2' <--- Problematic
    
    output$tab_2 = renderHighchart({ 
        
        # Select data frame
        mydata2 = react_data()
        
        # List of first 4 Value in the selected year range
        first_values = mydata2$var
        
        # List of years in the selected year range
        years = sort(c(min(input$start_year):max(input$end_year)))
        
        # Create a list to contain data frame for each year (inside the selected range)
        data_year = vector("list", length(years))
        
        for (i in as.character(years)){
            
            assign("df", list_db[[i]])
            
            # Consider only Value in 'first_values'
            df = df[df$var %in% first_values,]
            
            # Insert into the list
            data_year[[i]] = df
            
        }
        # Remove empty elements from the list
        data_year = data_year[!sapply(data_year,is.null)]
        
        # Generate a yearly data frame for each Value
        data_values = vector("list", length(first_values))
        years_lead = years[-1]
        
        for (row in 1:length(data_values)){
            
            df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
            
            for (i in years_lead){
                df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
            }
            
            df = cbind(years, df)
            data_values[[row]] = df
            
        }
        
        # Assign names to the list
        names(data_values) = paste(first_values)
        
        # Select the dataframe based on the selected profession
        assign("plot_data", data_values[[as.character(input$val_select)]])
        
        # Plot
        highchart() %>% 
            hc_title(text = input$val_select) %>%
            hc_subtitle(text = "Trend in the considerd period") %>%
            hc_chart(type = "column") %>%
            hc_add_series(name = "Amount",
                          data = plot_data,
                          type = "column",
                          hcaes(x = plot_data$years, y =  plot_data$x),
                          color = "rgba(0, 102, 102, 0.6)",
                          yAxis = 0) %>%
            hc_xAxis(labels = list(style = list(fontSize = "12")),
                     opposite = FALSE) %>%
            hc_chart(plotBackgroundColor = "#EEEEEE") %>%
            hc_legend(enabled = FALSE)
    })
    
}

# UI
shinyApp(ui = ui, server = server)

提前感谢任何可以给我一些建议的人,我提前为我可能“笨拙”的代码道歉。

【问题讨论】:

    标签: r shiny bar-chart reactive r-highcharter


    【解决方案1】:

    第二个observeEvent 不起作用,因为您没有考虑空值。此外,最初的开始和结束年份是相同的,这应该在反应数据中加以说明。一旦你修复了这部分,左边的图表很好,第二张图表的数据也很好。但是,我不确定这是否是您要在右侧绘制的数据。一旦你确定了,你需要调整output$tab_2中第二个highchart的语法。试试这个代码:

    library(DT)
    
    # Generate data
    years = c(2009:2019)
    
    list_db = vector("list")
    var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")
    
    for (i in 1:length(years)){
      x = runif(8, min = 0, max = 100)
      df = data.frame(var, x)
      list_db[[i]] = df
    }
    names(list_db) = years
    
    # UI
    ui <- dashboardPage(
      dashboardHeader(),
      dashboardSidebar(
        sidebarMenu(
          menuItem("Page 1", tabName = 'tab_page_1'),
          selectInput(inputId = "start_year",
                      label = "Select starting year:",
                      choices = min(years):max(years)),
          selectInput(inputId = "end_year",
                      label = "Select ending year:",
                      choices = min(years):max(years)),
          selectInput(inputId = "val_select",
                      label = "Select Value (within the selected range) to show:",
                      choices = var)
        )
      ),
      dashboardBody(
        tabItem(tabName = 'tab_page_1'),
        fluidPage(
          titlePanel("Example Page 1")
        ),
        fluidPage(
          useShinyjs(),
          fluidRow(
            box(title = "Barplot n.1",
                solidHeader = TRUE, 
                status = 'primary', 
                highchartOutput("tab_1", height = 500)
            ),
            box(title = "Barplot n.2 (Value focus)",
                solidHeader = TRUE, 
                status = 'primary',  DTOutput("tb2")
                #highchartOutput("tab_2", height = 500)
            ),
            
          )
        )
      )
    )
    
    # Server
    server <- function(input, output, session) {
      plotme <- reactiveValues(data=NULL)
      # Update 'end_year' based on 'start_year' input
      
      observeEvent(input$start_year, {
        updateSelectInput(session, 'end_year',
                          choices = (as.integer(input$start_year)+1):max(years)
        )
      })
      
      # Reactive data frame
      
      react_data <- reactive({
        req(input$start_year,input$end_year)
        
        if (input$start_year == input$end_year){
          dt <- NULL
        }else {
          # Generate starting and ending data frame
          assign("data_start", list_db[[as.character(input$start_year)]])
          assign("data_end", list_db[[as.character(input$end_year)]])
          
          # Add the selected year to variables' names
          data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
          data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
          
          # Join starting and ending data frame
          dt = full_join(data_start, data_end, by = "var")
          
          # Calculate vars' differences between the selected years
          dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)] 
          
          # Select only first 4 Values
          dt = head(dt[order(dt$x_diff),],4)
        }
        dt
        
      })
      
      output$tb1 <- renderDT(react_data())
      
      # Update 'val_select' b <--- Problem fixed when you account for react_data() not being NULL
      
      observeEvent(list(input$start_year,input$end_year), {
        if (!is.null(react_data())) {
          mylist <- as.character(react_data()[,1])
          updateSelectInput(session, 'val_select', choices = mylist )
        }
      })
      
      # Output 'tab_1' <--- This works
      
      output$tab_1 = renderHighchart({ 
        if (is.null(react_data())) return(NULL)
        # Select data frame
        mydata1 = react_data()
        
        # Plot
        highchart() %>% 
          hc_chart(type = "bar") %>%
          hc_xAxis(categories = mydata1$var)  %>%
          hc_series(list(name = "Variables", 
                         pointWidth = 50, 
                         data = mydata1$x_diff, 
                         color = "rgba(162, 52, 52, 0.5)")) %>%
          hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
          hc_chart(plotBackgroundColor = "#EEEEEE") %>%
          hc_legend(enabled = FALSE)
      })
      
      observe({
        req(input$start_year,input$end_year,input$val_select)
        if (is.null(react_data())) return(NULL)
        # Select data frame
        mydata2 = react_data()
        
        # List of first 4 Value in the selected year range
        first_values = mydata2$var
        
        # List of years in the selected year range
        years = sort(c(min(as.numeric(input$start_year)):max(as.numeric(input$end_year))))
        
        # Create a list to contain data frame for each year (inside the selected range)
        data_year = vector("list", length(years))
        
        for (i in as.character(years)){
          
          assign("df", list_db[[i]])
          
          # Consider only Value in 'first_values'
          df = df[df$var %in% first_values,]
          
          # Insert into the list
          data_year[[i]] = df
          
        }
        # Remove empty elements from the list
        data_year = data_year[!sapply(data_year,is.null)]
        
        # Generate a yearly data frame for each Value
        data_values = vector("list", length(first_values))
        years_lead = years[-1]
        
        for (row in 1:length(data_values)){
          
          df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
          
          for (i in years_lead){
            df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
          }
          
          df = cbind(years, df)
          data_values[[row]] = df
          
        }
        
        # Assign names to the list
        names(data_values) = paste(first_values)
        
        # Select the dataframe based on the selected profession
        assign("plot_data", data_values[[as.character(input$val_select)]])
        plotme$data <- plot_data
        
        output$tb2 <- renderDT(plotme$data)
        
        # Output 'tab_2' <--- Problematic  - needs some work to fix the highchart
        
        output$tab_2 = renderHighchart({
          plot_data <- plotme$data
          if (is.null(plot_data)) return(NULL)
          # Plot
          plot_data %>% 
          highchart() %>% 
            hc_title(text = unique(plot_data$var)) %>%
            hc_subtitle(text = "Trend in the considerd period") %>%
            hc_chart(type = "column") %>%
            hc_add_series(name = "Amount",
                          #data = plot_data,
                          type = "column",
                          hcaes(x = plot_data$years, y =  plot_data$x),
                          color = "rgba(0, 102, 102, 0.6)",
                          yAxis = 0) %>%
            hc_xAxis(labels = list(style = list(fontSize = "12")),
                     opposite = FALSE) %>%
            hc_chart(plotBackgroundColor = "#EEEEEE") %>%
            hc_legend(enabled = FALSE)
        })
      })
      
    }
    
    # UI
    shinyApp(ui = ui, server = server)
    

    【讨论】:

      【解决方案2】:

      非常感谢@YBS 的友好回答。经过一些调整,它奏效了。 我必须对mylistfirst_values 进行排序,以使输入“选择值(在选定范围内)显示:”中的选定选项与显示的表格/条形图之间存在对应关系。此外,第二个条形图的问题与我给垂直轴的名称有关......'x',我为这样的选择感到羞耻。事实上,我对ggplot2 感到厌烦,而且它奏效了。然后,通过重命名变量,脚本就可以正常工作了。再次感谢你。在我根据您的建议修改的编辑脚本下方。

      library(shiny)
      library(shinydashboard)
      library(highcharter)
      library(dplyr)
      library(DT)
      
      # Generate data
      years = c(2009:2019)
      
      list_db = vector("list")
      var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")
      
      for (i in 1:length(years)){
          x = runif(8, min = 0, max = 100)
          df = data.frame(var, x)
          list_db[[i]] = df
      }
      names(list_db) = years
      
      # UI
      ui <- dashboardPage(
          dashboardHeader(),
          dashboardSidebar(
              sidebarMenu(
                  menuItem("Page 1", tabName = 'tab_page_1'),
                  selectInput(inputId = "start_year",
                              label = "Select starting year:",
                              choices = min(years):max(years)),
                  selectInput(inputId = "end_year",
                              label = "Select ending year:",
                              choices = min(years):max(years)),
                  selectInput(inputId = "val_select",
                              label = "Select Value (within the selected range) to show:",
                              choices = var)
              )
          ),
          dashboardBody(
              tabItem(tabName = 'tab_page_1'),
              fluidPage(
                  titlePanel("Example Page 1")
              ),
              fluidPage(
                  fluidRow(
                      box(title = "Barplot n.1",
                          solidHeader = TRUE, 
                          status = 'primary',
                          highchartOutput("tab_1", height = 500)
                      ),
                      box(title = "Table n.1 (Value focus)",
                          solidHeader = TRUE, 
                          status = 'primary',
                          DTOutput("tab_2")
                      ),
                      box(title = "Barplot n.2 (Value focus)",
                          solidHeader = TRUE, 
                          status = 'primary',
                          highchartOutput("tab_3", height = 500)
                      )
                  )
              )
          )
      )
      
      # Server
      server <- function(input, output, session) {
          
          plotme = reactiveValues(data = NULL)
          
          # Update 'end_year' based on 'start_year' input
          
          observeEvent(input$start_year, {
              updateSelectInput(session, 'end_year',
                                choices = (as.integer(input$start_year)+1):max(years)
              )
          })
          
          # Reactive data frame
          
          react_data = reactive({
              
              req(input$start_year, input$end_year)
              
              if (input$start_year == input$end_year){
                  dt = NULL
              } else {
              
              # Generate starting and ending data frame
              assign("data_start", list_db[[as.character(input$start_year)]])
              assign("data_end", list_db[[as.character(input$end_year)]])
              
              # Add the selected year to variables' names
              data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
              data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
              
              # Join starting and ending data frame
              dt = full_join(data_start, data_end, by = "var")
              
              # Calculate vars' differences between the selected years
              dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)] 
              
              # Select only first 4 Values
              dt = head(dt[order(dt$x_diff),],4)
              
              }
              
              dt
              
          })
      
          # Update 'val_select' 
          
          observeEvent(list(input$start_year,input$end_year), {
              if (!is.null(react_data())) {
                  mylist = as.character(react_data()[,1])
                  updateSelectInput(session, 'val_select', choices = sort(mylist))
              }
          })
          
          # Output 'tab_1' 
          
          output$tab_1 = renderHighchart({ 
              
              # Select data frame
              mydata1 = react_data()
              
              # Plot
              highchart() %>% 
                  hc_chart(type = "bar") %>%
                  hc_xAxis(categories = mydata1$var)  %>%
                  hc_series(list(name = "Variables", 
                                 pointWidth = 50, 
                                 data = mydata1$x_diff, 
                                 color = "rgba(162, 52, 52, 0.5)")) %>%
                  hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
                  hc_chart(plotBackgroundColor = "#EEEEEE") %>%
                  hc_legend(enabled = FALSE)
          })
          
          # Output 'tab_2' and 'tab_3'
          
          observe({
              req(input$start_year,input$end_year,input$val_select)
              if (is.null(react_data())) return(NULL)
              
              # Select data frame
              mydata2 = react_data()
              
              # List of first 4 Value in the selected year range
              first_values = mydata2$var
              first_values = sort(first_values)
              
              # List of years in the selected year range
              years = sort(c(min(as.numeric(input$start_year)):max(as.numeric(input$end_year))))
              
              # Create a list to contain data frame for each year (inside the selected range)
              data_year = vector("list", length(years))
              
              for (i in as.character(years)){
                  
                  assign("df", list_db[[i]])
                  
                  # Consider only Value in 'first_values'
                  df = df[df$var %in% first_values,]
                  
                  # Insert into the list
                  data_year[[i]] = df
                  
              }
              # Remove empty elements from the list
              data_year = data_year[!sapply(data_year,is.null)]
              
              # Generate a yearly data frame for each Value
              data_values = vector("list", length(first_values))
              years_lead = years[-1]
              
              for (row in 1:length(data_values)){
                  
                  df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
                  
                  for (i in years_lead){
                      df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
                  }
                  
                  df = cbind(years, df)
                  data_values[[row]] = df
                  
              }
              
              # Assign names to the list
              names(data_values) = paste(first_values)
              
              # Select the dataframe based on the selected value
              assign("plot_data", data_values[[as.character(input$val_select)]])
              
              plotme$data = plot_data
              
              # Plot table 'tab_2'
              
              output$tab_2 = renderDT(plotme$data)
              
              # Plot table 'tab_3'
              
              output$tab_3 = renderHighchart({
                  
                  #plot_data = plotme$data
                  if (is.null(plot_data)) return(NULL)
                  
                  names(plot_data)[names(plot_data) == 'x'] = 'variable'
      
                  highchart() %>% 
                      hc_title(text = unique(plot_data$var)) %>%
                      hc_subtitle(text = "Trend in the considerd period") %>%
                      hc_chart(type = "column") %>%
                      hc_add_series(name = "Amount",
                                    data = plot_data,
                                    type = "column",
                                    hcaes(x = years, y = variable),
                                    color = "rgba(0, 102, 102, 0.6)",
                                    yAxis = 0) %>%
                      hc_xAxis(labels = list(style = list(fontSize = "12")),
                               opposite = FALSE) %>%
                      hc_chart(plotBackgroundColor = "#EEEEEE") %>%
                      hc_legend(enabled = FALSE)
                  
                  })
              
          })
          
      }
      
      # UI
      shinyApp(ui = ui, server = server)
      

      【讨论】:

        猜你喜欢
        • 2015-10-29
        • 1970-01-01
        • 2021-10-20
        • 1970-01-01
        • 2019-11-20
        • 2014-06-16
        • 2017-11-19
        • 2020-09-18
        • 1970-01-01
        相关资源
        最近更新 更多