My Shiny应用程序有几个输入,用于定义生成的绘图的几个参数。用户很可能会花费几分钟时间浏览所有可能的选项,直到他对输出感到满意为止。显然,可以以不同的格式导出绘图,但是用户可能希望稍后使用不同的数据重新创建相同的绘图,或者只是更改一个小细节。
因此,我需要为用户提供一种导出所有设置的方法,并保留该文件供以后使用。我已经开发了一种方法,但它运作良好。我使用reactiveValuesToList
获取所有输入元素的名称,并另存为格式为inputname=inputvalue
的简单文本文件。这是downloadHandler
上的server.R
:
output$bt_export <- downloadHandler(
filename = function() {
"export.txt"
},
content = function(file) {
inputsList <- names(reactiveValuesToList(input))
exportVars <- paste0(inputsList, "=", sapply(inputsList, function(inpt) input[[inpt]]))
write(exportVars, file)
})
这很好用,但加载并不顺利。由于我没有(并且无法弄清楚如何)保存输入类型,我必须盲目更新这些值。我就是这样做的:
importFile <- reactive({
inFile <- input$fileImport
if (is.null(inFile))
return(NULL)
lines <- readLines(inFile$datapath)
out <- lapply(lines, function(l) unlist(strsplit(l, "=")))
return(out)
})
observe({
imp <- importFile()
for (inpt in imp) {
if (substr(inpt[2], 0, 1) == "#") {
shinyjs::updateColourInput(session, inputId = inpt[1], value = inpt[2])
} else {
try({
updateTextInput(session, inputId = inpt[1], value = inpt[2])
updateNumericInput(session, inputId = inpt[1], value = inpt[2])
updateSelectInput(session, inputId = inpt[1], selected = inpt[2])
})
}
}
})
除了shinyjs::colorInput
开头可以识别的#
之外,我必须将try()
用于其他人。这部分工作,但有些输入没有更新。手动检查导出的文件会显示没有更新的输入,所以我认为一次更新100多个输入并不是一个好主意。此外try()
部分看起来并不好看,也许不是一个好主意。
该应用即将完成,但未来可能会更新,添加/更改了一些输入。如果这甚至可以使一些老的&#34;导出的输入无效,因为我会尝试保持向后兼容性。但是,我正在寻找一种不仅仅是编写数百行来逐步更新输入的方法。
我已考虑过使用save.image()
,但仅使用load()
无法恢复应用输入。我还考虑过以某种方式同时更新所有输入,而不是逐个更新,但没有提出任何建议。有没有更好的方法将所有用户输入导出到文件然后加载它们?如果它对这个更好或完全不同的方法进行调整并不重要。
答案 0 :(得分:9)
如果查看闪亮输入更新函数的代码,它们将以session$sendInputMessage(inputId, message)
结尾。 message
是需要在输入中更改的属性列表,例如,对于复选框输入:message <- dropNulls(list(label = label, value = value))
由于大多数输入都具有value
属性,因此您可以直接在所有输入上使用session$sendInputMessage
函数而不使用try
。
这是一个例子,当我点击按钮时,我创建了dummy_data
来更新所有输入,结构应该类似于你导出的内容:
<强> ui.R 强>
library(shiny)
shinyUI(fluidPage(
textInput("control_label",
"This controls some of the labels:",
"LABEL TEXT"),
numericInput("inNumber", "Number input:",
min = 1, max = 20, value = 5, step = 0.5),
radioButtons("inRadio", "Radio buttons:",
c("label 1" = "option1",
"label 2" = "option2",
"label 3" = "option3")),
actionButton("update_data", "Update")
))
<强> server.R 强>
library(shiny)
dummy_data <- c("inRadio=option2","inNumber=10","control_label=Updated TEXT" )
shinyServer(function(input, output,session) {
observeEvent(input$update_data,{
out <- lapply(dummy_data, function(l) unlist(strsplit(l, "=")))
for (inpt in out) {
session$sendInputMessage(inpt[1], list(value=inpt[2]))
}
})
})
在调用update
之前,所有session$sendInputMessage
函数都会预先格式化值。我还没有尝试过所有可能的输入,但至少对于这三个你可以将一个字符串传递给函数来更改numericInput
,它仍然可以正常工作。
如果这是某些输入的问题,您可能希望使用reactiveValuesToList(input)
保存save
,当您想要更新输入时,请使用load
并运行列表在for
循环中(您必须将其调整为命名列表)。
答案 1 :(得分:3)
这有点旧,但我认为发布一个完整的示例,保存和加载用户输入是有用的。
library(shiny)
ui <- shinyUI(fluidPage(
textInput("control_label",
"This controls some of the labels:",
"LABEL TEXT"),
numericInput("inNumber", "Number input:",
min = 1, max = 20, value = 5, step = 0.5),
radioButtons("inRadio", "Radio buttons:",
c("label 1" = "option1",
"label 2" = "option2",
"label 3" = "option3")),
actionButton("load_inputs", "Load inputs"),
actionButton('save_inputs', 'Save inputs')
))
server <- shinyServer(function(input, output,session) {
observeEvent(input$load_inputs,{
if(!file.exists('inputs.RDS')) {return(NULL)}
savedInputs <- readRDS('inputs.RDS')
inputIDs <- names(savedInputs)
inputvalues <- unlist(savedInputs)
for (i in 1:length(savedInputs)) {
session$sendInputMessage(inputIDs[i], list(value=inputvalues[[i]]) )
}
})
observeEvent(input$save_inputs,{
saveRDS( reactiveValuesToList(input) , file = 'inputs.RDS')
})
})
答案 2 :(得分:1)
除非您正在进行大量高度灵活的类型输入(renderUI
块可以是任何类型的输入),否则您可以创建一个存储所有当前值的列表,使用dput
来保存它们到具有相应dget
的文件中以读取它。
在我拥有的一个应用程序中,我允许用户下载存储所有上传数据及其所有选项的文件。
output$saveData <- downloadHandler(
filename = function() {
paste0('Export_',Sys.Date(),'.sprout')
},
content = function(file) {
dataToExport = list()
#User specified options
dataToExport$sproutData$transformations=sproutData$transformations #user specified transformations
dataToExport$sproutData$processing=sproutData$processing #user specified text processing rules
dataToExport$sproutData$sc=sproutData$sc #user specified option to spell check
dataToExport$sproutData$scOptions=sproutData$scOptions #user specified spell check options (only used if spell check is turned on)
dataToExport$sproutData$scLength=sproutData$scLength #user specified min word lenght for spell check (only used if spell check is turned on)
dataToExport$sproutData$stopwords=sproutData$stopwords #user specified stopwords
dataToExport$sproutData$stopwordsLastChoice=sproutData$stopwordsLastChoice #last pre-built list selected
dput(dataToExport,file=file)
}
)
在这里我创建一个空列表,然后我坚持使用我在我的应用程序中使用的值。 dTE$sD$name
结构的原因是我有一个名为reactiveValues
的{{1}},它存储了所有用户选择的选项和数据。所以,我在输出中保留了结构。
然后,我有一个加载数据页面,它执行以下操作:
sproutData
实际输出是一个表格,详细说明了它找到了什么以及它设置了什么。但是,因为我知道所有输入并且它们没有改变,所以我可以显式地存储它们(默认值或更改的值),然后在上载保存文件时显式更新它们。