2016-10-28 2 views
1

Ich habe eine Shiny-App, bei der die Änderung in einer selectInput eine Änderung der verfügbaren Optionen für den Benutzer in einer radioButtons Gruppe bewirkt. Nach dem documentation on updateRadioButtons,Shiny updateRadioButtons kann das ausgewählte Element nicht löschen

das ausgewählte Element kann mithilfe selected=character(0) gelöscht werden.

Aber wie im folgenden Beispiel gezeigt, scheint dies nicht zu funktionieren. Wenn Sie während des Änderns der Eingaben die Meldungen in der Konsole betrachten, wird die aktuelle Farbe nie auf Null zurückgesetzt. Wenn Sie "rot" wählen und dann von "a" zu "b" wechseln, ändert sich der Wert von "1" zu "4", als ob Sie wieder "rot" gewählt hätten. Dies ist nicht das gewünschte Verhalten in der realen Anwendung - "Wert" sollte sich nur ändern, nachdem der Benutzer eine Auswahl getroffen hat.

Irgendwelche Vorschläge zur Korrektur?

library(shiny) 

df <- data.frame(letter = c('a', 'a', 'a', 'b', 'b', 'b'), 
       color = c('red', 'blue', 'green', 'red', 'purple', 'orange'), 
       value = 1:6) 

ui <- shinyUI(fluidPage(
    tableOutput('show_df'), 
    selectInput('letter', 'Pick a letter', choices = c('a', 'b')), 
    radioButtons('color', 'Pick a color', choices = NULL, selected = character(0)) 
)) 

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

    output$show_df <- renderTable(df) 

    observe({ 
    current_letter <- input$letter 
    message(paste('Current letter is:', current_letter)) 
    updateRadioButtons(session, 
         'color', 
         choices = df$color[df$letter == current_letter], 
         selected = character(0)) 
    }) 

    observe({ 
    current_color <- input$color 
    message(paste('Current color is:', current_color)) 
    }) 

    observe({ 
    current_value <- df$value[df$letter == input$letter & df$color == input$color] 
    message(paste('Current value is:', current_value)) 
    }) 

}) 

shinyApp(ui = ui, server = server) 
+0

Es ist wahrscheinlich besser, 'renderUI' zu verwenden, um die RadioButtons jedes Mal neu zu rendern, wenn Sie die Auswahl ändern. Auf diese Weise können Sie sicherstellen, dass RadioButtons zurückgesetzt werden. –

+0

Es scheint, dass das Problem damit verbunden ist, 'df $ color' als Faktoren zu haben. Ich fügte der 'df' Definition' stringsAsFactors = FALSE' hinzu und es funktionierte. – Geovany

+0

Bitte sehen Sie mir die Antwort unten. – Geovany

Antwort

0

fand ich das Problem. Es scheint, dass updateRadioButtons das Widget ändern, aber es aktualisiert nicht den Wert in input$color, also selbst wenn alle Radio-Schaltflächen deaktiviert sind, ist der letzte Wert immer noch dort. Da Ihr letzter Beobachter den Wert color und letter verwendet, wird der Beobachter, wenn der Benutzer den Wert letter ändert, auch den Wert color (der letzte) verwenden. Das Problem bleibt bestehen, auch wenn Sie eine renderUI verwenden.

Below Ihr Code geändert, 1) es wird ein Datenrahmen mit stringsAsFactors = FALSE, 2) sie isoliert input$letter (Sie können auch obsereEvent statt) verwenden können, und 3) sie fügt eine Taste, um den Wert der Farbe zu jeder Zeit zu zeigen, , so können Sie bestätigen, dass selbst beim Aktualisieren der Optionsfelder der input$color immer noch den zuletzt verwendeten Wert hat.

library(shiny) 

df <- data.frame(letter = c('a', 'a', 'a', 'b', 'b', 'b'), 
       color = c('red', 'blue', 'green', 'red', 'purple', 'orange'), 
       value = 1:6, stringsAsFactors = FALSE) 

ui <- shinyUI(fluidPage(
    tableOutput('show_df'), 
    selectInput('letter', 'Pick a letter', choices = c('a', 'b')), 
    radioButtons('color', 'Pick a color', choices = NULL, selected = character(0)), 
    actionButton("test", "showColor") 
)) 

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

    output$show_df <- renderTable(df) 

    observe({ 
    current_letter <- input$letter 
    message(paste('Current letter is:', current_letter)) 
    updateRadioButtons(session, 
         'color', 
         choices = df$color[df$letter == current_letter], 
         selected = character(0)) 
    }) 

    observe({ 
    current_color <- input$color 
    message(paste('Current color is:', current_color)) 
    }) 

    observe({ 
    current_value <- df$value[df$letter == isolate(input$letter) & df$color == input$color] 
    message(paste('Current value is:', current_value)) 
    }) 

    observeEvent(input$test, { 
    message(">>>color:", input$color) 
    }) 

}) 

shinyApp(ui = ui, server = server) 
+0

Dies funktioniert nicht - zuerst, stringsAsFactors = FALSE einzustellen scheint keinen Effekt zu haben, und zweitens, wenn Sie 'rot' wählen, wechseln Sie von 'a' nach 'b', dann drücken Sie die showColor Taste, dies zeigt an Rot ist immer noch ausgewählt. Dies stellt das Problem nur noch einmal vor, was tatsächlich die Tatsache ist, dass die Eingabe $ color nicht zurückgesetzt wird. –

0

Wie die vorherige Antwort erklärt, input$color wird nicht aktualisiert, auch wenn die Radio-Buttons zurückgesetzt.

Eine Lösung besteht darin, eine dritte reaktive Variable für die Farbe zu verwenden, die von zwei verschiedenen Beobachtern geändert werden kann. Unten sind: 1) eine Grafik, die das ursprüngliche Problem zeigt, 2) die reactiveValues + observeEvent, und 3) eine Grafik, die die Lösung zeigt.

Hinweis 1: Dem Code wurde ein Fehlerbehebungs-Text hinzugefügt, um die Ausgaben auf der glänzenden Oberfläche anzuzeigen. Hinweis 2: Grafiken wurden mit einer früheren Lösung erstellt. Der ursprüngliche Beitrag hatte eine zusätzliche bedingte Wenn/Dann-Anweisung.

original result

library(shiny) 

df <- data.frame(letter = c('a', 'a', 'a', 'b', 'b', 'b'), 
       color = c('red', 'blue', 'green', 'red', 'purple', 'orange'), 
       value = 1:6) 

ui <- shinyUI(fluidPage(
    tableOutput('show_df'), 
    selectInput('letter', 'Pick a letter', choices = c('a', 'b')), 
    radioButtons('color', label = 'Pick a color', 
       choices = NULL, selected = character(0)), 
    HTML("Troubleshooting:"), br(), 
    verbatimTextOutput("troubleshooting") 
)) 

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

    output$show_df <- renderTable(df) 

    observe({ 
    current_letter <- input$letter 
    message(paste('Current letter is:', current_letter)) 
    updateRadioButtons(session, 
         'color', 
         choices = as.character(df$color[df$letter == current_letter]), 
         selected = character(0)) 
    }) 

    myColor <- reactiveValues(current = NULL) #Create a reactiveValue 
    #Define two observers that each can change the reactiveValue 
    observeEvent(input$letter, { 
    myColor$current <- NULL 
    }) 
    observeEvent(input$color, { 
    myColor$current <- input$color 
    }) 
    myValue <- reactive(df$value[df$letter == input$letter & df$color == myColor$current]) 

    observe({ 
    current_color <- input$color 
    message(paste('Current color is:', current_color)) 
    }) 

    observe({ 
    current_value <- myValue() 
    message(paste('Current value is:', current_value)) 
    }) 

    output$troubleshooting <- renderPrint({ list(
           paste("current letter:", input$letter), 
           paste("current color:", input$color), 
           #Reactive color not originally included in pics. 
           paste("current reactive color:", myColor$current), 
           paste("current value:", myValue()) 
               ) 
             }) 

}) 

shinyApp(ui = ui, server = server) 

Ergebnis: Die erste observeEvent gibt NULL zurück, wenn der Brief geändert wird, effektiv den Endwert zurückzusetzen. input$color wird immer noch nicht zurückgesetzt. Die zweite observeEvent gibt die Farbe zurück, wenn input$color geändert wird.

correct output

+0

Während dies scheint zu funktionieren, ist es einfach zu verschachtelt - es sollte nicht notwendig sein, Zähler und if-Anweisungen zu verwenden, um einen reaktiven Ausdruck zu erhalten, um richtig zu funktionieren, und in der tatsächlichen Anwendung könnte es ziemlich kompliziert werden. Ich schätze Ihre Bemühungen, aber ich muss glauben, dass es einen besseren Weg gibt. –

+0

Ich stimme zu, und hoffentlich postet jemand eine prägnantere Methode. Das große Problem ist, dass "input $ color" nicht zurückgesetzt wird. Wenn Sie den obigen Code verdichten wollen, setzen Sie den reactiveValue im Beobachter 'input $ letter' auf NULL und im Beobachter 'input $ color' auf' color'. Dann können Sie loswerden, wenn die if/then-Anweisung und den reactiveValue anstelle von "input $ color" verwenden. Momentan glaube ich nicht, dass Sie eine dritte Variable setzen können. – oshun

+0

Ich werde nur die Antwort bearbeiten, um zu zeigen, wie es prägnanter sein kann. – oshun

0

Ich bin damit einverstanden, scheint das Problem, dass Sie nicht die Eingangsgröße $ Farbe zurücksetzen. Z.B. Im folgenden Beispielprogramm können Sie die gleiche Aktion nicht zweimal ausführen.

 ui <- fluidPage (
     sidebarLayout(
      sidebarPanel (uiOutput('uiRadioButtons')), 
      mainPanel (uiOutput('action')) 
     )) 
    server <- function(input, output) { 
     output$uiRadioButtons <- renderUI({ radioButtons (inputId='actionId', label='action:', choices = c ('a', 'b', 'c'), selected=character(0)) }) 
     n <- 0 
     observe({ 
      actionId <- input$actionId 
      n <<- n+1 
      if (!is.null(actionId)) { 
       if (actionId=='a') output$action <- renderText (paste (n, "action A")) 
       if (actionId=='b') output$action <- renderText (paste (n, "action B")) 
       if (actionId=='c') output$action <- renderText (paste (n, "action C")) 
       output$uiRadioButtons <- renderUI({ radioButtons (inputId='actionId', label='action:', choices = c ('a', 'b', 'c'), selected=character(0)) }) 
      } else     output$action <- renderText ("actionId equals NULL") 
     }) 
} 
shinyApp (ui = ui, server = server) 

Als Alternative, wenn Sie nicht die Eingangsgröße zurücksetzen können auf NULL, Sie Dummy-Wert entscheiden können, die und mit den regulären Optionen direkt verarbeitet und ersetzt gezeigt. Dies wird in dem modifizierten Beispiel unten gezeigt.

ui <- fluidPage (
    sidebarLayout(
     sidebarPanel (
      # radioButtons (inputId='objectId', label='selct object:', choices = c ('o1', 'o2', 'o3'), inline = TRUE), 
      uiOutput('uiRadioButtons') 
     ), 
     mainPanel (uiOutput('action')) 
    ) 
) 
server <- function(input, output) { 
    showActions <- function() { 
     output$uiRadioButtons <- renderUI ({ radioButtons (inputId='actionId', label='action:', choices = c ('a', 'b', 'c'), selected=character(0)) }) 
    } 
    showActions() 
    n <- 0 
    observe({ 
     actionId <- input$actionId 
     n <<- n+1 
     if (!is.null(actionId)) { 
      if (actionId=='dummy') showActions() 
      else { 
       if (actionId=='a') output$action <- renderText (paste (n, "action A")) 
       if (actionId=='b') output$action <- renderText (paste (n, "action B")) 
       if (actionId=='c') output$action <- renderText (paste (n, "action C")) 
       output$uiRadioButtons <- renderUI({ radioButtons (inputId='actionId', label='action:', choices = 'dummy') }) 
      } 
     } else     output$action <- renderText ("actionId equals NULL") 

    }) 
} 
shinyApp (ui = ui, server = server) 

Diese Lösung ist jedoch möglicherweise zu langsam für Remote-Anwendungen. Verwenden Sie in diesem Fall eine zusätzliche Option "none" (siehe Radiobuttons-Hilfe) oder einen zusätzlichen actionButton und beobachten Sie stattdessen diese Schaltfläche. Wir hoffen, dass RStudio die Option implementiert, anwendbare Eingabevariablen zurückzusetzen.

+0

Ich denke, was wir hier haben, ist das UI-Design-Prinzip, dass es so etwas wie Radio-Tasten mit nichts ausgewählt werden sollte. Um diesen Status darzustellen, müssen Sie eine Option namens "Keine ausgewählt" als eine der Schaltflächen hinzufügen. Wenn wir das akzeptieren können, dann sind die einzigen wirklichen Probleme hier, dass es tatsächlich möglich ist, Optionsfelder ohne Auswahl zu initialisieren, und dass die Dokumentation behauptet, dass es möglich ist, zu diesem Zustand zurückzukehren, wenn es nicht wirklich funktioniert. (Leider stimmen unsere Kunden nicht immer mit den UI-Designprinzipien überein, aber das ist ein anderes Problem.) –

Verwandte Themen