如何在 R Shiny 中对使用反应式数据框呈现的数据 table 执行计算?
How to perform calculations on a data table rendered with a reactive data frame, in R Shiny?
下面的 MWE 代码按预期工作,用于对反应数据帧的列求和(代码中的 data()
和 summed_data()
)。如果您 运行 代码或查看底部的图像,您将看到根据两个用户输入分组标准之一对数据框列求和的位置,在 header“对 table 列的数据求和:”。该应用程序运行良好,通过“对数据 table 列求和:”。
但是,我现在正在尝试生成一个新数据 table,它从 summed_data()
中获取分组值,并执行图片中标题“计算”下描述的计算对汇总数据 table 列执行:"(基本上,[colA] 除以 [从一行移动到下一行时 colB 的平均值])。用户也可以通过 Period_1 或 Period_2 选择如何在计算中对数据进行分组。 “对数据 table 列求和”和“执行的计算...”用于分组选择的用户输入将彼此独立。
有没有有效的方法来完成这个?我试图坚持使用基础 R 和包 tidyverse
和 dplyr
。我想避免“包膨胀”。
请注意,在部署的更完整的应用程序中,需要计算的列比在这个简单的 MWE 中要多得多。
MWE 代码:
library(shiny)
library(tidyverse)
ui <-
fluidPage(
h3("Data table:"),
tableOutput("data"),
h3("Sum the data table columns:"),
radioButtons(
inputId = "grouping",
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("sums"),
h3("Calculations performed on summed data table columns:"),
radioButtons(
inputId = "grouping2",
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
)
)
server <- function(input, output, session) {
data <- reactive({
# example data. Might change dynamically
data.frame(
Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
Period_2 = c(1, 2, 3, 3, 1, 2),
ColA = c(10, 20, 30, 40, 50, 64),
ColB = c(15, 25, 35, 45, 55, 33)
)
})
summed_data <- reactive({
data() %>%
group_by(!!sym(input$grouping)) %>%
select(matches("^Col")) %>%
summarise(across(everything(), sum))
})
output$data <- renderTable(data())
output$sums <- renderTable(summed_data())
}
shinyApp(ui, server)
我想出了一个解决方案,创建一个新的反应对象 calculated_data()
并使用 dplyr group_by()
和 mutate()
函数来执行计算,如下修改后的代码所示:
ui <-
fluidPage(
h3("Data table:"),
tableOutput("data"),
h3("Sum the data table columns:"),
radioButtons(
inputId = "grouping1", # changed
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("sums"),
h3("Calculations performed on summed data table columns:"),
radioButtons(
inputId = "grouping2", # changed
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("calc") # added
)
server <- function(input, output, session) {
data <- reactive({
data.frame(
Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
Period_2 = c(1, 2, 3, 3, 1, 2),
ColA = c(10, 20, 30, 40, 50, 64),
ColB = c(15, 25, 35, 45, 55, 33)
)
})
summed_data <- reactive({
data() %>%
group_by(!!sym(input$grouping1)) %>%
select("ColA","ColB") %>%
summarise(across(everything(), sum))
})
calculated_data <- reactive({ # added this section
data() %>%
group_by(!!sym(input$grouping2)) %>%
select("ColA","ColB") %>%
summarise(across(everything(), sum)) %>%
mutate(avgColB=case_when(is.na(lag(ColB)) ~ ColB, TRUE ~ (lag(ColB) + ColB)/2)) %>%
mutate(ColAB = ColA / avgColB) %>%
select(-ColA,-ColB,-avgColB)
})
output$data <- renderTable(data())
output$sums <- renderTable(summed_data())
output$calc <- renderTable(calculated_data()) # added
}
shinyApp(ui, server)
下面的 MWE 代码按预期工作,用于对反应数据帧的列求和(代码中的 data()
和 summed_data()
)。如果您 运行 代码或查看底部的图像,您将看到根据两个用户输入分组标准之一对数据框列求和的位置,在 header“对 table 列的数据求和:”。该应用程序运行良好,通过“对数据 table 列求和:”。
但是,我现在正在尝试生成一个新数据 table,它从 summed_data()
中获取分组值,并执行图片中标题“计算”下描述的计算对汇总数据 table 列执行:"(基本上,[colA] 除以 [从一行移动到下一行时 colB 的平均值])。用户也可以通过 Period_1 或 Period_2 选择如何在计算中对数据进行分组。 “对数据 table 列求和”和“执行的计算...”用于分组选择的用户输入将彼此独立。
有没有有效的方法来完成这个?我试图坚持使用基础 R 和包 tidyverse
和 dplyr
。我想避免“包膨胀”。
请注意,在部署的更完整的应用程序中,需要计算的列比在这个简单的 MWE 中要多得多。
MWE 代码:
library(shiny)
library(tidyverse)
ui <-
fluidPage(
h3("Data table:"),
tableOutput("data"),
h3("Sum the data table columns:"),
radioButtons(
inputId = "grouping",
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("sums"),
h3("Calculations performed on summed data table columns:"),
radioButtons(
inputId = "grouping2",
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
)
)
server <- function(input, output, session) {
data <- reactive({
# example data. Might change dynamically
data.frame(
Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
Period_2 = c(1, 2, 3, 3, 1, 2),
ColA = c(10, 20, 30, 40, 50, 64),
ColB = c(15, 25, 35, 45, 55, 33)
)
})
summed_data <- reactive({
data() %>%
group_by(!!sym(input$grouping)) %>%
select(matches("^Col")) %>%
summarise(across(everything(), sum))
})
output$data <- renderTable(data())
output$sums <- renderTable(summed_data())
}
shinyApp(ui, server)
我想出了一个解决方案,创建一个新的反应对象 calculated_data()
并使用 dplyr group_by()
和 mutate()
函数来执行计算,如下修改后的代码所示:
ui <-
fluidPage(
h3("Data table:"),
tableOutput("data"),
h3("Sum the data table columns:"),
radioButtons(
inputId = "grouping1", # changed
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("sums"),
h3("Calculations performed on summed data table columns:"),
radioButtons(
inputId = "grouping2", # changed
label = NULL,
choiceNames = c("By period 1", "By period 2"),
choiceValues = c("Period_1", "Period_2"),
selected = "Period_1",
inline = TRUE
),
tableOutput("calc") # added
)
server <- function(input, output, session) {
data <- reactive({
data.frame(
Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
Period_2 = c(1, 2, 3, 3, 1, 2),
ColA = c(10, 20, 30, 40, 50, 64),
ColB = c(15, 25, 35, 45, 55, 33)
)
})
summed_data <- reactive({
data() %>%
group_by(!!sym(input$grouping1)) %>%
select("ColA","ColB") %>%
summarise(across(everything(), sum))
})
calculated_data <- reactive({ # added this section
data() %>%
group_by(!!sym(input$grouping2)) %>%
select("ColA","ColB") %>%
summarise(across(everything(), sum)) %>%
mutate(avgColB=case_when(is.na(lag(ColB)) ~ ColB, TRUE ~ (lag(ColB) + ColB)/2)) %>%
mutate(ColAB = ColA / avgColB) %>%
select(-ColA,-ColB,-avgColB)
})
output$data <- renderTable(data())
output$sums <- renderTable(summed_data())
output$calc <- renderTable(calculated_data()) # added
}
shinyApp(ui, server)