Блестящие реактивные выходы не обновляются, как ожидалось - PullRequest
0 голосов
/ 23 января 2019

Я создал блестящее приложение, которое вытягивает программные компоненты и их версии из списка узлов.Цель здесь состоит в том, чтобы сделать все наши узлы согласованными, когда это возможно, и это приложение помогает нам увидеть, какие узлы несовместимы.

В настоящее время вы можете изменить версию в базовой станции 'baseline', и она будет оперативно обновлять сводную таблицуниже с изменением, а также столбец BaselineStats в handsontable.Это работает как ожидалось.Меня попросили добавить возможность загружать CSV-файл, который будет перезаписывать базовую таблицу, чтобы пользователю не приходилось изменять эти «базовые» версии каждый раз, когда они загружают приложение.

Кроме того, некоторые компоненты соответствуют на 100%.В настоящее время они не отображаются в базовой таблице «baseline» (поскольку это инструмент для отображения несоответствий), но я добавил флажок, чтобы пользователь мог по-прежнему сообщать о тех компонентах, которые на 100% согласованы.

По какой-то причине ни fileUpload, ни checkboxInput не обновляются, и независимо от того, сколько я ткну и подталкиваю к своему коду, я не могу понять, почему.

server.R

library(shiny)
library(rhandsontable)
library(rpivotTable)
library(dplyr)
library(stringr)
library(lubridate)

shinyServer(function(input, output) {

  # Create dataframe
df.consistency <- structure(list(Node = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 
                                    2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L), .Label = c("A", "B", "C", 
                                                                                    "D"), class = "factor"), Component = structure(c(3L, 4L, 1L, 2L, 3L, 
                                                                                                                                     4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L), .Label = c("docker.version", 
                                                                                                                                                                                             "kernel.version", "os.name", "os.version"), class = "factor"), 
                 Version = structure(c(10L, 3L, 1L, 6L, 10L, 3L, 1L, 7L, 10L, 
                                     5L, 1L, 8L, 10L, 4L, 2L, 9L), .Label = c("1.12.1", "1.13.1", 
                                                                              "16.04", "17.04", "18.04", "3.10.0", "3.11.0", "3.12.0", 
                                                                              "3.13.0", "RedHat"), class = "factor")), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                     -16L))

# Get Date Time
Report.Date <- Sys.Date()

df.baseline <- reactive({

  inputFile <- input$uploadBaselineData

  if(!is.null(inputFile)){

    read.csv(inputFile$datapath, header = input$header)

  } else{
    if(input$showConsistent == FALSE){

      # Count the number of occurrences for Version and Component, then remove the Components that are consistent (not duplicated => nn == 1) and then remove nn column
      df.clusterCons.countComponent <- df.consistency %>%
        add_count(Version, Component) %>%
        add_count(Component) %>%
        filter(nn > 1) %>%
        select(-nn)

      # Change back to dataframe after grouping
      df.clusterCons.countComponent <- as.data.frame(df.clusterCons.countComponent)

      # Components and Versions are shown for every node/cluster. 
      # Reduce this df to get only a unique Component:Version combinations
      df.clusterCons.dist_tbl <- df.clusterCons.countComponent %>%
        distinct(Component, Version, .keep_all = TRUE)

      #Create a df that contains only duplicated rows (rows that are unique i.e. versions are consistent, are removed)
      df.clusterCons.dist_tbl.dup <- df.clusterCons.dist_tbl %>%
        filter(Component %in% unique(.[["Component"]][duplicated(.[["Component"]])]))

      #Create a baseline df to be used to filter larger dataset later 
      #(baseline = max(n) for Version -- but must retain Component since that is the parameter we will use to filter on later)
      df.clusterCons.baseline <- df.clusterCons.dist_tbl.dup[order(df.clusterCons.dist_tbl.dup$Component, df.clusterCons.dist_tbl.dup$n, decreasing = TRUE),]
      df.clusterCons.baseline <- df.clusterCons.baseline[!duplicated(df.clusterCons.baseline$Component), ]
      df.clusterCons.baseline <- df.clusterCons.baseline %>% 
        select(Component, Version)



    }
    else{
      # Count the number of occurrences for Version and Component, then remove the Components that are consistent (not duplicated => nn == 1) and then remove nn column
      df.clusterCons.countComponent <- df.consistency %>%
        add_count(Version, Component) %>%
        add_count(Component) %>%
        select(-nn)

      # Change back to dataframe after grouping
      df.clusterCons.countComponent <- as.data.frame(df.clusterCons.countComponent)

      # Components and Versions are shown for every node/cluster. 
      # Reduce this df to get only a unique Component:Version combinations
      df.clusterCons.dist_tbl <- df.clusterCons.countComponent %>%
        distinct(Component, Version, .keep_all = TRUE)

      df.clusterCons.baseline <- df.clusterCons.dist_tbl[order(df.clusterCons.dist_tbl$Component, df.clusterCons.dist_tbl$n, decreasing = TRUE),]
      df.clusterCons.baseline <- df.clusterCons.baseline[!duplicated(df.clusterCons.baseline$Component), ]
      df.clusterCons.baseline <- df.clusterCons.baseline %>% 
        select(Component, Version)
    }
  }
})


df.componentVersionCounts <- df.consistency %>%
  add_count(Component) %>%
  rename("CountComponents" = n) %>%
  add_count(Component, Version) %>%
  rename("CountComponentVersions" = n) %>%
  mutate("BaselineStats" = paste0("Baseline: ", round(CountComponentVersions / CountComponents * 100, 2), "% of Total: ", CountComponents)) %>%
  select(Component, Version, BaselineStats) %>%
  distinct(.keep_all = TRUE)

df.componentVersions_tbl <- reactive({
  df.componentVersions_tbl <- df.baseline() %>%
    distinct(Component, .keep_all = TRUE) %>%
    select(Component, Version) %>%
    left_join(df.componentVersionCounts, by = c("Component" = "Component", "Version" = "Version"))

})

# Report Date Output
output$reportDate <- renderText({
  return(paste0("Report last run: ", Report.Date))
})

# handsontable showing baseline and allowing for an updated baseline
output$baseline_table <- rhandsontable::renderRHandsontable({

  rhandsontable(df.componentVersions_tbl(), rowHeaders = NULL) %>%
    hot_col("Component", readOnly = TRUE) %>%
    hot_col("BaselineStats", readOnly = TRUE) %>%
    hot_cols(columnSorting = TRUE) %>%
    hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE, filters = TRUE)

})

observe({
  hot = isolate(input$baseline_table)
  if(!is.null(input$baseline_table)){
    handsontable <- hot_to_r(input$baseline_table)

    df.clusterCons.baseline2 <- handsontable %>%
      select(-BaselineStats)

    df.componentVersions_tbl <- df.clusterCons.baseline2  %>%
      left_join(df.componentVersionCounts, by = c("Component" = "Component", "Version" = "Version"))

    output$baseline_table <- rhandsontable::renderRHandsontable({

      rhandsontable(df.componentVersions_tbl, rowHeaders = NULL) %>%
        hot_col("Component", readOnly = TRUE) %>%
        hot_col("BaselineStats", readOnly = TRUE) %>%
        hot_cols(columnSorting = TRUE) %>%
        hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE, filters = TRUE)

    })

    df.clusterIncons <- anti_join(df.consistency, handsontable, by = c("Component" = "Component", "Version" = "Version"))
    df.clusterIncons <- df.clusterIncons

    # Pivot Table showing data with inconsistencies 
    output$pivotTable <- rpivotTable::renderRpivotTable({
      rpivotTable::rpivotTable(df.clusterIncons, rows = c("Cluster", "Node"), cols = "Component", aggregatorName = "List Unique Values", vals = "Version", 
                               rendererName = "Table", 
                               inclusions = list(Component = list("os.version", "os.name", "kernel.version", "docker.version")))


    })

    output$downloadBaselineData <- downloadHandler(
      filename = function() {
        paste('baselineData-', Sys.Date(), '.csv', sep='')
      },
      content = function(file) {
        baseline_handsontable <- handsontable %>%
          select(-BaselineStats)
        write.csv(baseline_handsontable, file, row.names = FALSE)
      }
    )


    output$downloadPivotData <- downloadHandler(
      filename = function() {
        paste('pivotData-', Sys.Date(), '.csv', sep='')
      },
      content = function(file) {
        write.csv(df.clusterIncons, file, row.names = FALSE)
      }
    )

  }
})

})

ui.R

library(shiny)
library(shinydashboard)
library(rhandsontable)
library(rpivotTable)

dashboardPage(

  dashboardHeader(title = "Test Dashboard", titleWidth = "97%"),

  dashboardSidebar(
    collapsed = TRUE,
    sidebarMenu(
      menuItem("App", tabName = "app", icon = icon("table"))
    )
  ),

  dashboardBody(

    tabItems(
      tabItem("app",
              fluidRow(
                box(width = 3, background = "light-blue",
                    "This box includes details to the user about how the application works", br(), br(), br(), 
                    verbatimTextOutput("reportDate")
                ),
                box(width = 7, status = "info", title = "Version baselines based on greatest occurance",
                    rHandsontableOutput("baseline_table", height = "350px")
                ),
                column(width = 2, 
                       fluidRow(
                         fileInput("uploadBaselineData", "Upload Other Baseline Data:", multiple = FALSE, 
                                   accept = ".csv")
                       ),
                       fluidRow(
                         downloadButton("downloadBaselineData", "Download Baseline Data")
                       ),
                       br(), 
                       fluidRow(
                         downloadButton("downloadPivotData", "Download Pivot Table Data")
                       ),
                       br(), 
                       fluidRow(
                         checkboxInput("showConsistent", "Show Consistent Components in baseline")
                       )
                )
              ),
              fluidRow(
                box(width = 12, status = "info", title = "Nodes with versions inconsistent with baseline",
                    div(style = 'overflow-x: scroll', rpivotTable::rpivotTableOutput("pivotTable", height = "500px"))
                )
              )
              )
    )
)
    )

Я довольно часто работал с реактивностью, но я не часто использую наблюдение или изоляцию, чтобыгде я сталкиваюсь с проблемой.Я также опробовал новый пакетactlog, но я все еще не уверен в пути вперед.

Вот изображение результатов реакции, прежде чем я установлю флажок или загрузлю новые базовые данные: Reactlog Output 1 И после: enter image description here

1 Ответ

0 голосов
/ 05 февраля 2019

На самом деле данная структура Shiny App очень запутана, и она не использует реактивность эффективно.Итак, сначала мы можем начать с более простого приложения, чтобы убедиться, что базовые компоненты работают, а затем добавить больше.

Некоторые проблемы

  • включенный фрейм данных df.consistency мешает реальным реактивным компонентам, которые вы хотите добавить.Например, поток if/else проблематичен, потому что он всегда переходит к первому else, поскольку csv не существует при запуске приложения и выражение для чтения не является точным, однако df.consistency всегда доступен.

  • есть дублирование одного и того же компонента, как output$baseline_table, который определяется дважды.

  • с read.csv, вы передали аргумент header = input$header, который не определен (если вы взяли это из примера здесь , это относится кфлажок, но он здесь недействителен) .

Минимальное приложение

Если вы хотите начать с минимального приложения,Вы можете начать со следующего кода.Это позволит вам:

  • использовать данные по умолчанию или загрузить csv для отмены значения по умолчанию.
  • просмотреть результаты в rhandsontable в середине.

Обратите внимание, что:

  • baseline_data является реактивным, поэтому другие выражения, которые его используют, также являются реактивными.

  • если вы хотите иметь различные вычисления df.componentVersionCounts в зависимости от флажка, вы можете добавить if/else внутри выражения, чтобы записать вычисления для обоих случаев.

library(shiny)
library(rpivotTable)
library(dplyr)
library(stringr)
library(lubridate)
library(shinydashboard)
library(rhandsontable)

## UI ------------------------------------------------------------------------------
ui <- dashboardPage(

  dashboardHeader(title = "Test Dashboard", titleWidth = "97%"),

  dashboardSidebar(
    collapsed = TRUE,
    sidebarMenu(
      menuItem("App", tabName = "app", icon = icon("table"))
    )
  ),

  dashboardBody(

    tabItems(
      tabItem("app",
              fluidRow(
                box(width = 3, background = "light-blue",
                    "This box includes details to the user about how the application works", br(), br(), br(), 
                    verbatimTextOutput("reportDate")
                ),
                box(width = 7, status = "info", title = "Version baselines based on greatest occurance",
                    rHandsontableOutput("baseline_table", height = "350px")
                ),

                column(width = 2, 
                       fluidRow(
                         fileInput("uploadBaselineData", "Upload Other Baseline Data:", multiple = FALSE, 
                                   accept = ".csv")
                       ),

                       fluidRow(
                         checkboxInput("showConsistent", "Show Consistent Components in baseline")
                       )
                )
              )
      )
    )
  )
)


## define default baseline data
df.consistency <- structure(list(Node = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 
                                                    2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L),
                                                  .Label = c("A", "B", "C", 
                                                                                                    "D"), class = "factor"), Component = structure(c(3L, 4L, 1L, 2L, 3L, 
                                                                                                                                                     4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L), .Label = c("docker.version", 
                                                                                                                                                                                                             "kernel.version", "os.name", "os.version"), class = "factor"), 
                                 Version = structure(c(10L, 3L, 1L, 6L, 10L, 3L, 1L, 7L, 10L, 
                                                       5L, 1L, 8L, 10L, 4L, 2L, 9L),
                                                     .Label = c("1.12.1", "1.13.1", 
                                                                                                "16.04", "17.04", "18.04", "3.10.0", "3.11.0", "3.12.0", 
                                                                                                "3.13.0", "RedHat"), class = "factor")), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                             -16L))


## Server ------------------------------------------------------------------
server <- function(input, output) {

  ## Get Date Time
  Report.Date <- Sys.Date()

  baseline_data <- reactive({

    inputFile <- input$uploadBaselineData
    if(!is.null(inputFile)){
      ## WHEN A CSV IS UPLOADED
      read.csv(inputFile$datapath)
    }else{
      ## DEFAULT
      df.consistency #or write the any other expression to read from a certain path or query
    }
  })

  ## df.componentVersionCounts ---------------------------------------------------------------
  df.componentVersionCounts <- reactive({
    req(baseline_data())

    baseline_data() %>%
      add_count(Component) %>%
      rename("CountComponents" = n) %>%
      add_count(Component, Version) %>%
      rename("CountComponentVersions" = n) %>%
      mutate("BaselineStats" = paste0("Baseline: ", round(CountComponentVersions / CountComponents * 100, 2), "% of Total: ", CountComponents)) %>%
      select(Component, Version, BaselineStats) %>%
      distinct(.keep_all = TRUE)
  })

  ## df.componentVersions_tbl ------------------------------------------------------------ 
  df.componentVersions_tbl <- reactive({
    req(baseline_data())

    baseline_data() %>% ##df.baseline()
      distinct(Component, .keep_all = TRUE) %>%
      select(Component, Version) %>%
      left_join(df.componentVersionCounts(),
                by = c("Component" = "Component", "Version" = "Version"))

  })

  # handsontable showing baseline and allowing for an updated baseline ---------------------
  output$baseline_table <- rhandsontable::renderRHandsontable({

    rhandsontable(df.componentVersions_tbl(), rowHeaders = NULL) %>%
      hot_col("Component", readOnly = TRUE) %>%
      hot_col("BaselineStats", readOnly = TRUE) %>%
      hot_cols(columnSorting = TRUE) %>%
      hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE, filters = TRUE)

  })

  # Report Date Output -------------------------------------------------------
  output$reportDate <- renderText({
    return(paste0("Report last run: ", Report.Date))
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...