在操作按钮后隔离用于显示选择和过滤器的反应功能
isolate reactive function for displaying selections and filters after action button
我正在尝试使用 isolate
命令从 ui.R
文件中的以下代码创建一个 reactive
函数到 server.R
文件,其中数据 table 仅在用户输入他们的选择和过滤器后才会填充。
现在,数据 table 仅在 运行 过滤器和选择后自行填充,无需单击 Run Query
按钮。
如有任何帮助,我们将不胜感激!
actionButton("runit", "RUN QUERY")
非常感谢!
代码如下:
ui.R
library(DT)
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
dashboardHeader(title = "CL Pivot"),
dashboardSidebar(
actionButton("runit", "RUN QUERY"),
h4(HTML(" "), "Select Table Rows"),
uiOutput("rowSelect"),
hr(),
h4(HTML(" "), "Select Table Columns"),
uiOutput("colSelect"),
hr(),
h4(HTML(" "), "Select Table Cell Fill"),
selectizeInput(
inputId = "funChoices",
label = NULL,
multiple = FALSE,
choices = c("Count", "Average", "Median", "Sum", "Maximum", "Minimum"),
selected = c()
),
hr(),
h4(HTML(" "), "Filter Data Set"),
uiOutput("hairColorFilter"),
uiOutput("skinColorFilter")
),
dashboardBody(dataTableOutput("data"))
)
}
server.R
library(DT)
library(shiny)
library(shinydashboard)
library(dplyr)
library(dbplyr)
library(tidyverse)
library(DBI)
data <- starwars
# Convenience Function to Make Upcoming Chain Less Messy
fun_across <- function(cols, fun, fun_name) {
fun_list <- list(fun)
names(fun_list) <- fun_name
across(all_of(cols), fun_list, .names = "{fn}_{col}")
}
shinyServer(function(input, output, session) {
# Identify Measures and Dimensions -------------
dimensions <- colnames(data)[!sapply(data, is.numeric)]
measures <- colnames(data)[sapply(data, is.numeric)]
# Identify Filter Choices -----------------------------------------------
hairColorChoices <- sort(unique(data$hair_color))
skinColorChoices <- sort(unique(data$skin_color))
# Define User Inputs ----------------------------------------------------
output$rowSelect <- renderUI({
selectizeInput(
inputId = "rowChoices",
label = NULL,
multiple = TRUE,
choices = dimensions,
selected = c()
)
})
output$colSelect <- renderUI({
selectizeInput(
inputId = "colChoices",
label = NULL,
multiple = TRUE,
choices = measures,
selected = c()
)
})
output$hairColorFilter <- renderUI({
sidebarMenu(
menuItem(
text = "Hair Color",
icon = icon("briefcase"),
checkboxGroupInput(
inputId = "hairColorChoices",
label = NULL,
choices = hairColorChoices,
selected = hairColorChoices
)
)
)
})
output$skinColorFilter <- renderUI({
sidebarMenu(
menuItem(
text = "Skin Color",
icon = icon("thermometer-half"),
checkboxGroupInput(
inputId = "skinColorChoices",
label = NULL,
choices = skinColorChoices,
selected = skinColorChoices
)
)
)
})
# Define Reactive Functions ---------------------------------------------
pairColFuns <- reactive({
colChoices <- input$colChoices
names(colChoices) <- input$funChoices
return(colChoices)
})
# Construct DataFrame Based on User Inputs
output$data <- renderDataTable({
colChoices <- pairColFuns()
rowChoices <- input$rowChoices
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% input$hairColorChoices,
skin_color %in% input$skinColorChoices
) %>%
group_by(across(all_of(rowChoices))) %>%
summarize(
# Once again we've sacrificed a bit of elegance for clarity. This chunk will
# apply the specified function to whichever columns are included in the
# specified variable. If the variable is empty, no operation is performed.
fun_across({{countCols}}, length, "count"),
fun_across({{averageCols}}, ~mean(.x, na.rm = TRUE), "average"),
fun_across({{medianCols}}, ~median(.x, na.rm = TRUE), "median"),
fun_across({{sumCols}}, ~sum(.x, na.rm = TRUE), "total"),
fun_across({{maxCols}}, ~max(.x, na.rm = TRUE), "max"),
fun_across({{minCols}}, ~min(.x, na.rm = TRUE), "min"),
.groups = "drop"
)
return(displayTable)
})
})
您需要 isolate()
所有不应触发事件的输入,您可以使用 req()
启用提交按钮:
pairColFuns <- reactive({
colChoices <- isolate(input$colChoices) #isolated
names(colChoices) <- isolate(input$funChoices) #isolated
return(colChoices)
})
# Construct DataFrame Based on User Inputs
output$data <- renderDataTable({
req(input$runit) # submit button should trigger
colChoices <- pairColFuns()
rowChoices <- isolate(input$rowChoices) #isolated
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% isolate(input$hairColorChoices), #isolated
skin_color %in% isolate(input$skinColorChoices) #isolated
...
我会拆分 table 渲染和数据处理,然后您可以使用 eventReactive
方法。这样可以节省您将每个输入包装到 isolate
.
首先制作一个 eventReactive
来计算您的数据。它仅在第一个 reactive
/input 更改时更新。然后你可以用它来渲染你的 table:
table_data <- eventReactive(input$runit, {
colChoices <- pairColFuns()
rowChoices <- input$rowChoices
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% input$hairColorChoices,
skin_color %in% input$skinColorChoices
) %>%
group_by(across(all_of(rowChoices))) %>%
summarize(
# Once again we've sacrificed a bit of elegance for clarity. This chunk will
# apply the specified function to whichever columns are included in the
# specified variable. If the variable is empty, no operation is performed.
fun_across({{countCols}}, length, "count"),
fun_across({{averageCols}}, ~mean(.x, na.rm = TRUE), "average"),
fun_across({{medianCols}}, ~median(.x, na.rm = TRUE), "median"),
fun_across({{sumCols}}, ~sum(.x, na.rm = TRUE), "total"),
fun_across({{maxCols}}, ~max(.x, na.rm = TRUE), "max"),
fun_across({{minCols}}, ~min(.x, na.rm = TRUE), "min"),
.groups = "drop"
)
displayTable
})
output$data <- renderDataTable({
table_data()
})
我正在尝试使用 isolate
命令从 ui.R
文件中的以下代码创建一个 reactive
函数到 server.R
文件,其中数据 table 仅在用户输入他们的选择和过滤器后才会填充。
现在,数据 table 仅在 运行 过滤器和选择后自行填充,无需单击 Run Query
按钮。
如有任何帮助,我们将不胜感激!
actionButton("runit", "RUN QUERY")
非常感谢!
代码如下:
ui.R
library(DT)
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
dashboardHeader(title = "CL Pivot"),
dashboardSidebar(
actionButton("runit", "RUN QUERY"),
h4(HTML(" "), "Select Table Rows"),
uiOutput("rowSelect"),
hr(),
h4(HTML(" "), "Select Table Columns"),
uiOutput("colSelect"),
hr(),
h4(HTML(" "), "Select Table Cell Fill"),
selectizeInput(
inputId = "funChoices",
label = NULL,
multiple = FALSE,
choices = c("Count", "Average", "Median", "Sum", "Maximum", "Minimum"),
selected = c()
),
hr(),
h4(HTML(" "), "Filter Data Set"),
uiOutput("hairColorFilter"),
uiOutput("skinColorFilter")
),
dashboardBody(dataTableOutput("data"))
)
}
server.R
library(DT)
library(shiny)
library(shinydashboard)
library(dplyr)
library(dbplyr)
library(tidyverse)
library(DBI)
data <- starwars
# Convenience Function to Make Upcoming Chain Less Messy
fun_across <- function(cols, fun, fun_name) {
fun_list <- list(fun)
names(fun_list) <- fun_name
across(all_of(cols), fun_list, .names = "{fn}_{col}")
}
shinyServer(function(input, output, session) {
# Identify Measures and Dimensions -------------
dimensions <- colnames(data)[!sapply(data, is.numeric)]
measures <- colnames(data)[sapply(data, is.numeric)]
# Identify Filter Choices -----------------------------------------------
hairColorChoices <- sort(unique(data$hair_color))
skinColorChoices <- sort(unique(data$skin_color))
# Define User Inputs ----------------------------------------------------
output$rowSelect <- renderUI({
selectizeInput(
inputId = "rowChoices",
label = NULL,
multiple = TRUE,
choices = dimensions,
selected = c()
)
})
output$colSelect <- renderUI({
selectizeInput(
inputId = "colChoices",
label = NULL,
multiple = TRUE,
choices = measures,
selected = c()
)
})
output$hairColorFilter <- renderUI({
sidebarMenu(
menuItem(
text = "Hair Color",
icon = icon("briefcase"),
checkboxGroupInput(
inputId = "hairColorChoices",
label = NULL,
choices = hairColorChoices,
selected = hairColorChoices
)
)
)
})
output$skinColorFilter <- renderUI({
sidebarMenu(
menuItem(
text = "Skin Color",
icon = icon("thermometer-half"),
checkboxGroupInput(
inputId = "skinColorChoices",
label = NULL,
choices = skinColorChoices,
selected = skinColorChoices
)
)
)
})
# Define Reactive Functions ---------------------------------------------
pairColFuns <- reactive({
colChoices <- input$colChoices
names(colChoices) <- input$funChoices
return(colChoices)
})
# Construct DataFrame Based on User Inputs
output$data <- renderDataTable({
colChoices <- pairColFuns()
rowChoices <- input$rowChoices
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% input$hairColorChoices,
skin_color %in% input$skinColorChoices
) %>%
group_by(across(all_of(rowChoices))) %>%
summarize(
# Once again we've sacrificed a bit of elegance for clarity. This chunk will
# apply the specified function to whichever columns are included in the
# specified variable. If the variable is empty, no operation is performed.
fun_across({{countCols}}, length, "count"),
fun_across({{averageCols}}, ~mean(.x, na.rm = TRUE), "average"),
fun_across({{medianCols}}, ~median(.x, na.rm = TRUE), "median"),
fun_across({{sumCols}}, ~sum(.x, na.rm = TRUE), "total"),
fun_across({{maxCols}}, ~max(.x, na.rm = TRUE), "max"),
fun_across({{minCols}}, ~min(.x, na.rm = TRUE), "min"),
.groups = "drop"
)
return(displayTable)
})
})
您需要 isolate()
所有不应触发事件的输入,您可以使用 req()
启用提交按钮:
pairColFuns <- reactive({
colChoices <- isolate(input$colChoices) #isolated
names(colChoices) <- isolate(input$funChoices) #isolated
return(colChoices)
})
# Construct DataFrame Based on User Inputs
output$data <- renderDataTable({
req(input$runit) # submit button should trigger
colChoices <- pairColFuns()
rowChoices <- isolate(input$rowChoices) #isolated
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% isolate(input$hairColorChoices), #isolated
skin_color %in% isolate(input$skinColorChoices) #isolated
...
我会拆分 table 渲染和数据处理,然后您可以使用 eventReactive
方法。这样可以节省您将每个输入包装到 isolate
.
首先制作一个 eventReactive
来计算您的数据。它仅在第一个 reactive
/input 更改时更新。然后你可以用它来渲染你的 table:
table_data <- eventReactive(input$runit, {
colChoices <- pairColFuns()
rowChoices <- input$rowChoices
countCols <- unname(colChoices[names(colChoices) == "Count"])
averageCols <- unname(colChoices[names(colChoices) == "Average"])
medianCols <- unname(colChoices[names(colChoices) == "Median"])
sumCols <- unname(colChoices[names(colChoices) == "Sum"])
maxCols <- unname(colChoices[names(colChoices) == "Maximum"])
minCols <- unname(colChoices[names(colChoices) == "Minimum"])
displayTable <- as_tibble(data) %>%
filter(
hair_color %in% input$hairColorChoices,
skin_color %in% input$skinColorChoices
) %>%
group_by(across(all_of(rowChoices))) %>%
summarize(
# Once again we've sacrificed a bit of elegance for clarity. This chunk will
# apply the specified function to whichever columns are included in the
# specified variable. If the variable is empty, no operation is performed.
fun_across({{countCols}}, length, "count"),
fun_across({{averageCols}}, ~mean(.x, na.rm = TRUE), "average"),
fun_across({{medianCols}}, ~median(.x, na.rm = TRUE), "median"),
fun_across({{sumCols}}, ~sum(.x, na.rm = TRUE), "total"),
fun_across({{maxCols}}, ~max(.x, na.rm = TRUE), "max"),
fun_across({{minCols}}, ~min(.x, na.rm = TRUE), "min"),
.groups = "drop"
)
displayTable
})
output$data <- renderDataTable({
table_data()
})