如何在闪亮的反应式数据表中添加注释

时间:2019-06-09 14:59:04

标签: r shiny

此问题是我发布的问题的扩展:this question

我创建了一个包含3列的数据框:num,id和val。我希望我的闪亮应用程序执行以下操作:

  1. 数据帧dat被num列过滤
  2. dat(selectInput)的id列中选择一个值。
  3. 在文本框中添加文本注释(textInput)
  4. 单击操作按钮
  5. 在数据表中创建一个新的列,即注释,将文本注释添加到id等于所选值的行的注释列中。

代码在下面。我不知道为什么它不起作用。

非常感谢!

    library(shiny)
    library(DT)
    dat = data.frame(num=rep(1:2, each=5), id=rep(LETTERS[1:5],2), val=rnorm(10)) 
    ui = fluidPage(
        fluidRow(
            column(12, selectInput('selectNum', label='Select Num', 
                                 choices=1:10, selected='')),
            column(2, selectInput(inputId = 'selectID',
                                  label = 'Select ID2',
                                  choices = LETTERS[1:10],
                                  selected='',
                                  multiple=TRUE)),
            column(6, textInput(inputId = 'comment', 
                                label ='Please add comment in the text box:', 
                                value = "", width = NULL,
                                placeholder = NULL)),
            column(2, actionButton(inputId = "button", 
                                   label = "Add Comment"))
        ),
        fluidRow (
            column(12, DT::dataTableOutput('data') ) 
        )           
    )

    server <- function(input, output, session) {

     ## make df reactive

     df = reactive ({ dat %>% filter(num %in% input$selectNum) })
     df_current <- reactiveVal(df())

     observeEvent(input$button, {

      req(df_current())

      ## update df by adding comments
      df_new <- df_current()
      df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment

      df_current(df_new)

      })

      output$data <- DT::renderDataTable({

      req(df_current())

      DT::datatable(df_current(), 
          options = list(orderClasses = TRUE,
              lengthMenu = c(5, 10, 20), pageLength = 5))
     })

    shinyApp(ui=ui, server=server)

2 个答案:

答案 0 :(得分:1)

与其对df使用react / eventReactive语句,使用Comment的reactVal对象跟踪df列中先前输入的注释可能更自然。另请参见对此问题的回答:R Shiny: reactiveValues vs reactive。如果您更喜欢对df使用反应式/ eventReactive语句,则最好使用单独的对象来存储以前的输入注释(而不是将其合并到df的反应式语句中)。

library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10)) 
ui = fluidPage(
    fluidRow(
        column(12, selectInput('selectNum', label='Select Num', 
                choices=1:10)),
        column(2, selectInput(inputId = 'selectID',
                label = 'Select ID2',
                choices = LETTERS[1:10],
                selected='',
                multiple=TRUE)),
        column(6, textInput(inputId = 'comment', 
                label ='Please add comment in the text box:', 
                value = "", width = NULL,
                placeholder = NULL)),
        column(2, actionButton(inputId = "button", 
                label = "Add Comment"))
    ),
    fluidRow (
        column(12, DT::dataTableOutput('data') ) 
    )            
)

server <- function(input, output, session) {

  ## make df reactive
  df_current <- reactiveVal(dat)

  observeEvent(input$button, {

        req(df_current(), input$selectID %in% dat$id)

        ## update df by adding comments
        df_new <- df_current()
        df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment

        df_current(df_new)

      })

  output$data <- DT::renderDataTable({

        req(df_current())

        ## filter df_current by 'selectNum'
        df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]

        ## show comments if non-empty
        showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))

        DT::datatable(df_filtered, 
            options = list(orderClasses = TRUE,
                lengthMenu = c(5, 10, 20), pageLength = 5,
                columnDefs = list(
                    list(targets = ncol(df_filtered), visible = showComments)
                )
            )
        )

      })
}

shinyApp(ui=ui, server=server)

编辑:在已编辑的server函数下方,该函数使用df_current <- reactive({...})而非df_current <- reactiveVal({...})并定义了一个单独的reactVal对象以跟踪注释。

server <- function(input, output, session) {

  ## initialize separate reactive object for comments
  df_comments <- reactiveVal({
        data.frame(
            id = character(0), 
            Comment = character(0),
            stringsAsFactors = FALSE
        )
      })

  ## reactive object df
  df_current <- reactive({

        ## reactivity that df depends on
        ## currently df = dat does not change
        df <- dat

        ## merge with current comments
        if(nrow(df_comments()) > 0)
        df <- merge(df, df_comments(), by = "id", all.x = TRUE)

        return(df)

      })

  observeEvent(input$button, {

        req(input$selectID)

        ## update df_comments by adding comments
        df_comments_new <- rbind(df_comments(), 
            data.frame(id = input$selectID, Comment = input$comment)
        )

        ## if duplicated id's keep only most recent rows 
        df_comments_new <- df_comments_new[!duplicated(df_comments_new$id, fromLast = TRUE), , drop = FALSE]

        df_comments(df_comments_new)

      })

  output$data <- DT::renderDataTable({

        req(df_current())

        ## filter df_current by 'selectNum'
        df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]

        ## show comments if non-empty
        showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))

        DT::datatable(df_filtered, 
            options = list(orderClasses = TRUE,
                lengthMenu = c(5, 10, 20), pageLength = 5,
                columnDefs = list(
                    list(targets = ncol(df_filtered), visible = showComments)
                )
            )
        )

      })
}

答案 1 :(得分:0)

您有一个可行的示例。

我认为事情是,您正在尝试通过observeEvent更新值,根据文档所述,这不是很好。 ?observeEvent

  

每当您要执行响应事件的操作时,请使用watchEvent。 (请注意,“重新计算值”通常不算是执行操作-有关该操作,请参见eventReactive。)

library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10)) 
ui = fluidPage(
  fluidRow(
    column(12, selectInput('selectNum', label='Select Num', 
                           choices=1:10, selected='')),
    column(2, selectInput(inputId = 'selectID',
                          label = 'Select ID2',
                          choices = LETTERS[1:10],
                          selected='',
                          multiple=TRUE)),
    column(6, textInput(inputId = 'comment', 
                        label ='Please add comment in the text box:', 
                        value = "", width = NULL,
                        placeholder = NULL)),
    column(2, actionButton(inputId = "button", 
                           label = "Add Comment"))
  ),
  fluidRow (
    column(12, DT::dataTableOutput('data') ) 
  )           
)

server <- function(input, output, session) {

  ## make df reactive

  df_current = reactive({ 
    df = dat %>% filter(num %in% input$selectNum) 

    if(input$button != 0) {
      input$button    
      df[df$id %in% input$selectID, "Comment"] <- isolate(input$comment)
    }

    return(df)
    })


  output$data <- DT::renderDataTable({

    req(df_current())
    DT::datatable(df_current(), 
                  options = list(orderClasses = TRUE,
                                 lengthMenu = c(5, 10, 20), pageLength = 5))
  })
}
  shinyApp(ui=ui, server=server)

因此,您可以使用反应性值,也可以使用文档中所述的eventReactive。