【发布时间】:2016-08-25 04:59:21
【问题描述】:
我正在基于令人敬畏的 R Shiny 包构建一个探索性的视觉应用程序。该应用程序要做的一件事是读取实值“测量”列并显示这些测量值的箱线图。此外,还有一个可选的selectInput 小部件,允许用户选择一个组 变量进行深入研究。 group 变量基本上包含具有分类值的列的名称,例如性别(女性与男性)、国家(美国、加利福尼亚州等)。因此,如果从 组 selectInput 中选择“性别”,应用程序将显示两个箱线图,一个用于女性,另一个用于男性。
为了让用户可以灵活地关注某些类别,比如只说女性,我想出了checkboxGroupInput,它仅在同时选择了choices 和selected 最初设置为 group 变量的所有类别。例如,当用户只想查看女性的箱线图时,他/她可以轻松取消选中男性的复选框,男性的箱线图被移除而女性的箱线图保留。
按照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 更新时,因为您会注意到错误消息“没有要绘制的数据!”当您从 组 下拉列表中选择“性别”时。所以我的问题是:有没有办法确保以下执行顺序:
-
input$group已更新 -> -
input$group_select得到更新 -> -
reactive得到(重新)执行,同时更新了input$group和input$group_select
我几乎花了一整天的时间寻找解决方案,但收效甚微。
- Roger Day 似乎在Using sendInputMessage and receiveMessage to make shiny input objects reactive 中解决了这个问题。但是他的方法涉及创建一个 jstree,这对我来说是一个完全陌生的领域,而且看起来他已经从他的 Github 中删除了解决方案。
- 另一个可能的结果是使用此处描述的
observeEvent(R shiny Observe running Before loading of UI and this causes Null parameters)。但是,当您取消选择input$group_select中的一个或多个类别时,observeEvent会忽略它。
正如 Roger Day 所指出的,它的困难在于输入更新函数通常不是反应式的,因此(根据我的实验和理解)比反应式语句执行得晚。或者,如果有办法使输入更新函数具有响应性,则可以应用优先级值来以所需的方式改变执行顺序。
非常感谢任何输入!抱歉描述太长了!
【问题讨论】:
-
你尝试过reactiveEvent函数吗?
-
您的意思是
observeEvent?是的,当“group_select”小部件出现observeEvent(input$group_select, {to_keep <- ...; data <- data[to_keep, ]})时,我尝试过滤数据。问题是observeEvent在您取消选择 input$group_select 中的一个或多个类别时似乎忽略了更改。例如,当从 groupselectInput中选择“gender”时,“group_select”显示时会同时选中“male”和“female”。但是,如果用户取消选中男性,数据不会删除所有男性行。 -
不,我的意思是一个非常相似的函数——eventReactive
-
从闪亮的帮助页面
eventReactive,在我看来eventReactive和observeEvent以类似的方式处理类似事件的表达式,除了eventReactive可以返回一个值。您能否详细说明如何使用它? -
这个想法是对响应事件中的箱线图的数据进行所有子集化。当用户做出选择时,他需要按一个按钮来创建一个情节。
标签: r shiny scheduling