从闪亮的应用程序采用用户输入生成 R 脚本
Generate R script adopting user input from shiny app
我想将 r 代码(在激活操作按钮时评估)与相应的用户输入一起导出为 r 脚本。
很抱歉,如果我不够精确或者这个问题已经在其他地方被问过,但我不熟悉要搜索的正确术语和关键字。
我有以下 UI (similar to this app) 并添加了一个操作按钮:
library(shiny)
library(dplyr)
ui <- fluidPage(
fluidRow(
column(4,
selectInput(
"var",
"Variables:",
c("All", colnames(iris)),
selected = c("Sepal.Length","Petal.Length"),
multiple = T)
),
column(4,
textInput("filter",
"Filter Data",
value = "Sepal.Length < 5"))
),
DT::dataTableOutput("table"),
actionButton("script",
"Save script")
)
想法是让用户 select
来自数据集的列 (iris
) 和 filter
使用标准 r / dplyr 语法和准引用 ()
server <- function(input, output){
dat <- reactive({
data <- iris
if(!input$var %in% "All"){
data <- data %>% select(input$var)
}
if(input$filter != ""){
data <- data %>% filter(!!rlang::parse_expr(input$filter))
}
data
})
output$table <- DT::renderDataTable(DT::datatable(dat()))
# insert code below here
}
shinyApp(ui, server)
这按预期工作。但是,我想导出 r 代码,它提供所需的输出并将其保存在新的 r 文件中。也就是说,按下操作按钮后,代码将被打印 (cat
) 并且用户输入 (input
) 将填充空白:
observeEvent(input$script, {
cat('#this is an automatically generated r script
data <- iris
if(!',paste0("c(",paste(paste0('"',input$var, '"'), collapse = ","), ")"), '%in% "All"){
data <- data %>% select(',paste(input$var, collapse = ","),')
}
if(',paste0("c(",paste(paste0('"',input$filter, '"'), collapse = ","), ")"),' != ""){
data <- data %>% filter(',input$filter,')
}', file = "r_script.r")
})
这种令人厌恶的代码确实有效,生成的 r_script.r
文件包含以下代码:
#this is an automatically generated r script
data <- iris
if(! c("Sepal.Length","Petal.Length") %in% "All"){
data <- data %>% select( Sepal.Length,Petal.Length )
}
if( c("Sepal.Length < 5") != ""){
data <- data %>% filter( Sepal.Length < 5 )
}
我的问题是: 是否有更简单的方法来访问服务器上 运行 的底层代码并将其导出为 r 脚本,最好使用if
个语句已评估:
#this is an automatically generated r script
data <- iris
data <- data %>% select( Sepal.Length,Petal.Length )
data <- data %>% filter( Sepal.Length < 5 )
非常感谢任何帮助!
您需要使用 rlang
包将代码转换为可以打印为文本或计算的表达式。示例代码:
server <- function(input,output,session){
user_script <- reactiveVal()
observe({
req(input$var)
req(input$filter)
# you need to sanitize user input to prevent error, now I just wrote a tryCatch()
dplyr_expr <- tryCatch({
# check user input
if(any(input$var == "All")){
columns <- colnames(iris)
} else {
columns <- input$var
}
dplyr_expr <- expr({
data <- iris
data <- data %>% select( !!!syms(columns))
data <- data %>% filter( !!parse_expr(input$filter) )
})
# save script
expression_string <- capture.output(dplyr_expr)
script_text <- paste0(
expression_string[2:(length(expression_string)-1)],collapse = "<br>"
)
user_script(script_text)
# evaluate expression
eval(dplyr_expr)
user_script(script_text)
output$table <- renderDataTable(data)
},error = function(e){
print("user input caused an error")
})
})
observeEvent(input$script,{
req(user_script())
showModal(
modalDialog(
HTML(
paste(
"# this is an automatically generated r script<br>",
user_script()
)
)
)
)
})
}
为了帮助您更好地理解,让我们先在 shiny 之外进行。
让我们首先模拟来自 UI:
的用户输入
input1 <- c("Species","Sepal.Length")
input2 <- c("Sepal.Length < 5")
user_data <- iris
服务器处理
# read user input and convert it to expression
dplyr_expr <- expr({
data <- !!expr(user_data)
data <- data %>% select( !!!syms(input1))
data <- data %>% filter( !!!parse_expr(input2) )
})
到 return 作为字符串的值:
expression_string <- capture.output(dplyr_expr)
writeLines(paste0(expression_string[2:(length(expression_string)-1)],collapse = "\n"))
returns
data <- user_data
data <- data %>% select(Species, Sepal.Length)
data <- data %>% filter(Sepal.Length < 5)
评价
eval(dplyr_expr)
str(data)
returns
'data.frame': 22 obs. of 2 variables:
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Sepal.Length: num 4.9 4.7 4.6 4.6 4.4 4.9 4.8 4.8 4.3 4.6 ...
我想将 r 代码(在激活操作按钮时评估)与相应的用户输入一起导出为 r 脚本。
很抱歉,如果我不够精确或者这个问题已经在其他地方被问过,但我不熟悉要搜索的正确术语和关键字。
我有以下 UI (similar to this app) 并添加了一个操作按钮:
library(shiny)
library(dplyr)
ui <- fluidPage(
fluidRow(
column(4,
selectInput(
"var",
"Variables:",
c("All", colnames(iris)),
selected = c("Sepal.Length","Petal.Length"),
multiple = T)
),
column(4,
textInput("filter",
"Filter Data",
value = "Sepal.Length < 5"))
),
DT::dataTableOutput("table"),
actionButton("script",
"Save script")
)
想法是让用户 select
来自数据集的列 (iris
) 和 filter
使用标准 r / dplyr 语法和准引用 (
server <- function(input, output){
dat <- reactive({
data <- iris
if(!input$var %in% "All"){
data <- data %>% select(input$var)
}
if(input$filter != ""){
data <- data %>% filter(!!rlang::parse_expr(input$filter))
}
data
})
output$table <- DT::renderDataTable(DT::datatable(dat()))
# insert code below here
}
shinyApp(ui, server)
这按预期工作。但是,我想导出 r 代码,它提供所需的输出并将其保存在新的 r 文件中。也就是说,按下操作按钮后,代码将被打印 (cat
) 并且用户输入 (input
) 将填充空白:
observeEvent(input$script, {
cat('#this is an automatically generated r script
data <- iris
if(!',paste0("c(",paste(paste0('"',input$var, '"'), collapse = ","), ")"), '%in% "All"){
data <- data %>% select(',paste(input$var, collapse = ","),')
}
if(',paste0("c(",paste(paste0('"',input$filter, '"'), collapse = ","), ")"),' != ""){
data <- data %>% filter(',input$filter,')
}', file = "r_script.r")
})
这种令人厌恶的代码确实有效,生成的 r_script.r
文件包含以下代码:
#this is an automatically generated r script
data <- iris
if(! c("Sepal.Length","Petal.Length") %in% "All"){
data <- data %>% select( Sepal.Length,Petal.Length )
}
if( c("Sepal.Length < 5") != ""){
data <- data %>% filter( Sepal.Length < 5 )
}
我的问题是: 是否有更简单的方法来访问服务器上 运行 的底层代码并将其导出为 r 脚本,最好使用if
个语句已评估:
#this is an automatically generated r script
data <- iris
data <- data %>% select( Sepal.Length,Petal.Length )
data <- data %>% filter( Sepal.Length < 5 )
非常感谢任何帮助!
您需要使用 rlang
包将代码转换为可以打印为文本或计算的表达式。示例代码:
server <- function(input,output,session){
user_script <- reactiveVal()
observe({
req(input$var)
req(input$filter)
# you need to sanitize user input to prevent error, now I just wrote a tryCatch()
dplyr_expr <- tryCatch({
# check user input
if(any(input$var == "All")){
columns <- colnames(iris)
} else {
columns <- input$var
}
dplyr_expr <- expr({
data <- iris
data <- data %>% select( !!!syms(columns))
data <- data %>% filter( !!parse_expr(input$filter) )
})
# save script
expression_string <- capture.output(dplyr_expr)
script_text <- paste0(
expression_string[2:(length(expression_string)-1)],collapse = "<br>"
)
user_script(script_text)
# evaluate expression
eval(dplyr_expr)
user_script(script_text)
output$table <- renderDataTable(data)
},error = function(e){
print("user input caused an error")
})
})
observeEvent(input$script,{
req(user_script())
showModal(
modalDialog(
HTML(
paste(
"# this is an automatically generated r script<br>",
user_script()
)
)
)
)
})
}
为了帮助您更好地理解,让我们先在 shiny 之外进行。
让我们首先模拟来自 UI:
的用户输入input1 <- c("Species","Sepal.Length")
input2 <- c("Sepal.Length < 5")
user_data <- iris
服务器处理
# read user input and convert it to expression
dplyr_expr <- expr({
data <- !!expr(user_data)
data <- data %>% select( !!!syms(input1))
data <- data %>% filter( !!!parse_expr(input2) )
})
到 return 作为字符串的值:
expression_string <- capture.output(dplyr_expr)
writeLines(paste0(expression_string[2:(length(expression_string)-1)],collapse = "\n"))
returns
data <- user_data
data <- data %>% select(Species, Sepal.Length)
data <- data %>% filter(Sepal.Length < 5)
评价
eval(dplyr_expr)
str(data)
returns
'data.frame': 22 obs. of 2 variables:
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Sepal.Length: num 4.9 4.7 4.6 4.6 4.4 4.9 4.8 4.8 4.3 4.6 ...