Shiny R: Как сохранить список входов флажков из данных?

1

Я пытаюсь сохранить ввод из таблицы флажков (см. Здесь), адаптированный из [здесь] [2], после нажатия кнопки actionButton. В идеале, мне нужен список выбранных ящиков в одном столбце данных и имя пользователя в виде имени строки.

Я попробовал это с синтаксисом ниже, сохраняя ответы в списке, а затем добавляя их в существующий файл csv.file. Все, что я получаю: Warning in write.table(listed_responses, file = "responses.csv", append = TRUE, :appending column names to file, кроме предупреждения, ничего не сохраняется в CSV файле, и я не уверен что именно мне не хватает.

Как вы правильно сохраняете список отмеченных ячеек из datatable?

Любая помощь будет действительно оценена!

library(shiny)
library(DT)

answer_options<- c("reading", "swimming",
     "cooking", "hiking","binge- watching series",
     "other") 

question2<- "What hobbies do you have?"

shinyApp(
  ui = fluidPage(
    h2("Questions"),
    p("Below are a number of statements, please indicate your level of agreement"),
    
    
    DT::dataTableOutput('checkbox_matrix'),
    verbatimTextOutput('checkbox_list'),
    
    textInput(inputId = "username", label= "Please enter your username"),
    actionButton(inputId= "submit", label= "submit")
  ),
  
  
  server = function(input, output, session) {
    
      checkbox_m = matrix(
        as.character(answer_options), nrow = length(answer_options), ncol = length(question2), byrow = TRUE,
        dimnames = list(answer_options, question2)
      )
      
      for (i in seq_len(nrow(checkbox_m))) {
        checkbox_m[i, ] = sprintf(
          '<input type="checkbox" name="%s" value="%s"/>',
          answer_options[i], checkbox_m[i, ]
        )
      }
      checkbox_m
  output$checkbox_matrix= DT::renderDataTable(
    checkbox_m, escape = FALSE, selection = 'none', server = FALSE, 
    options = list(dom = 't', paging = FALSE, ordering = FALSE),
    callback = JS("table.rows().every(function(i, tab, row) {
                  var $this = $(this.node());
                  $this.attr('id', this.data()[0]);
                  $this.addClass('shiny-input-checkbox');
});
                  Shiny.unbindAll(table.table().node());
                  Shiny.bindAll(table.table().node());")
  )
  
  
    
    observeEvent(input$submit,{
      # unlist values from json table
      listed_responses <- sapply(answer_options, function(i) input[[i]])

      write.table(listed_responses,
                  file = "responses.csv",
                  append= TRUE, sep= ',',
                  col.names = TRUE)
    })
    }
    )
Теги:
shiny

1 ответ

2
Лучший ответ

Сообщение об ошибке

Ошибка возникает из-за использования col.names = TRUE и append = TRUE в том же вызове write.table. Например:

write.table(mtcars, "test.csv", append = TRUE, sep = ",", col.names = TRUE)
# Warning message:
# In write.table(mtcars, "test.csv", append = TRUE, sep = ",", col.names = TRUE) :
#  appending column names to file

write.table хочет, чтобы вы знали, что он добавляет строку имен столбцов в ваш csv. Поскольку вы, вероятно, не хотите, чтобы между именами наборов ответов была col.names = FALSE строка с именами столбцов, вероятно, более чистым было бы использовать append = TRUE когда col.names = FALSE. Вы можете использовать if...else чтобы написать две разные формы для сохранения вашего csv: один для создания файла и один для добавления последующих ответов:

if(!file.exists("responses.csv")) {
    write.table(responses, 
                "responses.csv", 
                col.names = TRUE, 
                append = FALSE,
                sep = ",")
} else {
    write.table(responses, 
                "responses.csv", 
                col.names = FALSE, 
                append = TRUE, 
                sep = ",")
}

Пустой csv

Ваш csv пуст, потому что ваши флажки не получают должным образом привязки в качестве входных данных. Мы можем это увидеть, добавив эти строки в ваше приложение:

server = function(input, output, session) {
   ...
   output$print <- renderPrint({
        reactiveValuesToList(input)
   })
}
ui = fluidPage(
    ...
    verbatimTextOutput("print")
)

В котором перечислены все входы в вашем приложении:

Изображение 174551

Флажки не указаны во input. Таким образом, listed_responses будет содержать список значений NULL, а write.table сохранит csv с пустыми строками.

Я не смотрел, почему ваши js не работают, но метод yihui для создания данных с флажками, похоже, хорошо работает:

# taken from https://github.com/rstudio/DT/issues/93/#issuecomment-111001538
# a) function to create inputs
shinyInput <- function(FUN, ids, ...) {
      inputs <- NULL
      inputs <- sapply(ids, function(x) {
      inputs[x] <- as.character(FUN(inputId = x, label = NULL, ...))
            })
      inputs
 }
 # b) create dataframe with the checkboxes
 df <- data.frame(
            Activity = answer_options,
            Enjoy = shinyInput(checkboxInput, answer_options),
            stringsAsFactors = FALSE
 )
 # c) create the datatable
 output$checkbox_table <- DT::renderDataTable(
            df,
            server = FALSE, escape = FALSE, selection = 'none',
            rownames = FALSE,
            options = list(
                dom = 't', paging = FALSE, ordering = FALSE,
                preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
       )
 )

Полный пример

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

library(shiny)
library(DT)

shinyApp(
    ui =
        fluidPage(
            # style modals
            tags$style(
                HTML(
                    ".error {
                    background-color: red;
                    color: white;
                    }
                    .success {
                    background-color: green;
                    color: white;
                    }"
                    )),
            h2("Questions"),
            p("Please check if you enjoy the activity"),
            DT::dataTableOutput('checkbox_table'),
            br(),
            textInput(inputId = "username", label= "Please enter your username"),
            actionButton(inputId = "submit", label= "Submit Form")
        ),

    server = function(input, output, session) {

        # create vector of activities
        answer_options <- c("reading",
                            "swimming",
                            "cooking",
                            "hiking",
                            "binge-watching series",
                            "other")

        ### 1. create a datatable with checkboxes ###
        # taken from https://github.com/rstudio/DT/issues/93/#issuecomment-111001538
        # a) function to create inputs
        shinyInput <- function(FUN, ids, ...) {
            inputs <- NULL
            inputs <- sapply(ids, function(x) {
                inputs[x] <- as.character(FUN(inputId = x, label = NULL, ...))
            })
            inputs
        }
        # b) create dataframe with the checkboxes
        df <- data.frame(
            Activity = answer_options,
            Enjoy = shinyInput(checkboxInput, answer_options),
            stringsAsFactors = FALSE
        )
        # c) create the datatable
        output$checkbox_table <- DT::renderDataTable(
            df,
            server = FALSE, escape = FALSE, selection = 'none',
            rownames = FALSE,
            options = list(
                dom = 't', paging = FALSE, ordering = FALSE,
                preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
            )
        )

        ### 2. save rows when user hits submit -- either to new or existing csv ###
        observeEvent(input$submit, {
            # if user has not put in a username, don't add rows and show modal instead
            if(input$username == "") {
                showModal(modalDialog(
                    "Please enter your username first", 
                    easyClose = TRUE,
                    footer = NULL,
                    class = "error"
                ))
            } else {
                responses <- data.frame(user = input$username,
                                        activity = answer_options,
                                        enjoy = sapply(answer_options, function(i) input[[i]], USE.NAMES = FALSE))

                # if file doesn't exist in current wd, col.names = TRUE + append = FALSE
                # if file does exist in current wd, col.names = FALSE + append = TRUE
                if(!file.exists("responses.csv")) {
                    write.table(responses, "responses.csv", 
                                col.names = TRUE, 
                                row.names = FALSE,
                                append = FALSE,
                                sep = ",")
                } else {
                    write.table(responses, "responses.csv", 
                                col.names = FALSE, 
                                row.names = FALSE,
                                append = TRUE, 
                                sep = ",")
                }
                # tell user form was successfully submitted
                showModal(modalDialog("Successfully submitted",
                                      easyClose = TRUE,
                                      footer = NULL,
                                      class = "success")) 
                # reset all checkboxes and username
                sapply(answer_options, function(x) updateCheckboxInput(session, x, value = FALSE))
                updateTextInput(session, "username", value = "")
            }
        })
    }
)
  • 0
    Большое спасибо за ваше время ответить. Это именно то, что я хотел бы сделать!
  • 0
    @jkhuc Рад помочь и добро пожаловать в Stack Overflow! Если этот ответ решил вашу проблему, пометьте его как принятый

Ещё вопросы

Сообщество Overcoder
Наверх
Меню