2016-04-29 71 views
0

我正在構建一個基於真棒R Shiny軟件包的探索性視覺應用程序。應用程序要做的一件事就是讀取實值「測量」列並顯示這些測量值的箱形圖。此外,還有一個可選的selectInput小部件,它允許用戶選擇一個變量來潛入。變量基本上包含具有分類值的列的名稱,例如,性別(女性vs男性),國家(美國,加拿大等)。因此,如果從羣組selectInput中選擇「性別」,該應用將顯示兩個箱圖,一個用於女性,另一個用於男性。R Shiny:如何在執行反應語句之前更新輸入對象

要向用戶提供集中於某些類別的靈活性,說只雌性,我想出了checkboxGroupInput當與既choicesselected被初始設置爲所有類別中選擇變量,其僅示出變量。例如,當用戶只想看到女性的箱形圖時,他/她可以容易地取消男性的複選框和男性的箱形圖,而女性的箱形圖則保留。

warmoverflow的建議,這裏是一個可重複的玩具例子

# global setup 
library(shiny) 
library(ggplot2) 
library(dplyr) 
set.seed(12345) 
dummy_data <- data.frame(
    Value = c(rnorm(50), 2 + rnorm(50)), 
    Gender = c(rep('Female', 50), rep('Male', 50)), 
    Country = c(rep('US', 50), rep('CA', 50)), 
    stringsAsFactors = FALSE 
) 

# ui function 
ui <- fluidPage(
    sidebarLayout(
     sidebarPanel(
      selectInput('group', 'Group', 
         c('Choose'='', setdiff(names(dummy_data), 'Value'))), 
      uiOutput('group_select') 
     ), 
     mainPanel(plotOutput('box_plot')) 
    ) 
) 

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

    # the group level select/unselect widget 
    output$group_select <- renderUI({ 
     req(input$group) 
     data <- dummy_data 
     group_levels <- unique(data[[input$group]]) 
     conditionalPanel(
      condition = "input.group != ''", 
      checkboxGroupInput('group_select', input$group, 
           choices = group_levels, selected = group_levels) 
     ) 
    }) 

    # filter the data if group variable is selected 
    data_to_plot <- reactive({ 
     data <- dummy_data 
     if(!(is.null(input$group) || input$group == '')) { 
      data <- data %>% 
       mutate_(group_ = input$group) %>% 
       filter(group_ %in% input$group_select) 
     } else { 
      data$group_ <- as.factor(rep.int(1, nrow(data))) 
     } 
     return(data) 
    }) 

    # show the boxplot 
    output$box_plot <- renderPlot({ 
     data <- data_to_plot() 
     validate(
      need(!(is.null(data) || nrow(data) == 0), 
       'There are no data to plot!') 
     ) 
     ggplot(data = data, aes(factor(group_), Value)) + geom_boxplot() 
    }) 
} 

shinyApp(ui = ui, server = server) 

嗯,代碼工作,但reactive語句運行不必要的兩次,一次是當input$group得到更新和另一個當input$group_select得到更新,你可以看到錯誤消息「沒有要繪製的數據!」當您從下拉列表中選擇「性別」時。所以我的問題是:有沒有辦法保證以下執行順序:

  1. input$group更新 - >
  2. input$group_select得到更新 - >
  3. reactive被(重新)既更新input$groupinput$group_select執行

我花了幾乎整整一天尋找解決方案,沒有多大用處。

Roger Day指出的難點在於輸入更新函數通常不會被反應,因此(根據我的實驗和理解)比被動語句晚執行。或者,如果有辦法使輸入更新功能無效,則可以應用優先級值以期望的方式更改執行順序。

任何輸入,非常感謝!對不起,很長的描述!

+0

替代input$group_select你嘗試reactiveEvent功能? –

+0

你是不是指'observeEvent'?是的,當「group_select」小部件出現時使用'observeEvent(輸入$ group_select,{to_keep < - ...; data < - data [to_keep,]})''時,我嘗試過濾數據。問題在於,當您取消選擇輸入$ group_select中的一個或多個類別時,observeEvent似乎忽略了更改。例如,當從**組**''selectInput'中選擇「性別」時,「group_select」顯示最初選中「男性」和「女性」。但是,如果用戶取消選中男性,數據不會刪除所有男性行。 – statechular

+0

不,我的意思是一個非常類似的功能 - eventReactive –

回答

1

我想我找到了解決方案。 UnnamedUserwarmoverflow中提到的方向是正確的。的總體思路是創建一個反應性值來表示,或更精確地說,以監視由用戶選擇,則類別和檢測兩個可變變量選擇的類別的任何變化(使用observe)和(使用observe),然後通過在server函數中添加以下代碼塊來相應地修改無功值。

# use a reactive value to represent group level selection 
group_selects <- reactiveValues(value = NULL) 
observe({ 
    input$group 
    if(is.null(input$group) || input$group == '') 
     group_selects$value <- NULL 
    else { 
     data <- dummy_data 
     group_selects$value <- unique(data[[input$group]]) 
    } 
}) 
observe({ 
    input$group_select 
    group_selects$value <- input$group_select 
}) 

然後用group_selects$value在數據處理塊

# filter the data if group variable is selected 
data_to_plot <- reactive({ 
    data <- dummy_data 
    if(!(is.null(input$group) || input$group == '')) { 
     req(group_selects$value)      # To prevent unnecessary re-run 
     data <- data %>% 
      mutate_(group_ = input$group) %>% 
      filter(group_ %in% group_selects$value)  # Replaced input$group_select 
    } else { 
     data$group_ <- as.factor(rep.int(1, nrow(data))) 
    } 
    return(data) 
}) 
相關問題