La mia app Shiny ha diversi input che vengono utilizzati per definire diversi parametri di un grafico generato. È molto probabile che l'utente trascorrerà alcuni minuti attraverso tutte le opzioni possibili finché non sarà soddisfatto dell'output. Ovviamente la trama può essere esportata in diversi formati, ma è possibile che l'utente vorrà ricreare la stessa trama con dati diversi in seguito, o forse semplicemente cambiare un piccolo dettaglio.Esporta tutti gli input utente in un'app Shiny per caricarli e caricarli in un secondo momento
Per questo motivo, ho bisogno di offrire all'utente un modo per esportare tutte le sue impostazioni e conservare quel file per un uso successivo. Ho sviluppato un approccio, ma non sta funzionando bene. Sto usando reactiveValuesToList
per ottenere i nomi di tutti gli elementi di input e salvarli come un semplice file di testo con il formato inputname=inputvalue
. Questo è il downloadHandler
su 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)
})
Questo funziona bene, ma il caricamento non sta andando molto bene. Dal momento che non riesco (e non riesco a capire come) salvare il tipo di input, devo aggiornare i valori alla cieca. Questo è come lo faccio:
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])
})
}
}
})
A parte il shinyjs::colorInput
, che può essere riconosciuto dal inizio #
, devo usare try()
per gli altri. Questo funziona, parzialmente, ma alcuni input non vengono aggiornati. Ispezionare manualmente il file esportato mostra che gli input che non sono stati aggiornati sono lì, quindi suppongo che l'aggiornamento di 100+ input contemporaneamente non sia una buona idea. Anche la parte try()
non sembra buona e probabilmente non è una buona idea.
L'app è quasi terminata, ma probabilmente verrà aggiornata in futuro, con alcuni input aggiunti/modificati. È accettabile se questo rende invalidi alcuni "vecchi" input esportati, poiché proverò a mantenere la compatibilità con le versioni precedenti. Ma sto cercando un approccio che non stia solo scrivendo centinaia di righe per aggiornare gli input uno per uno.
Ho pensato di utilizzare save.image()
ma semplicemente utilizzando load()
non ripristinare gli input dell'app. Ho anche considerato un modo per aggiornare in qualche modo tutti gli input contemporaneamente, invece che uno alla volta, ma non ho trovato nulla. Esiste un modo migliore per esportare tutti gli input dell'utente in un file e quindi caricarli tutti? Non importa se si tratta di un tweak per questo che funziona meglio o un approccio completamente diverso.
La tua app presenta input altamente dipendenti? Sono molti i blocchi 'renderUI' o ci sono molti input' numericInput'? – Mark
@Mark Sono tutti input "statici", nessuno dei quali è stato creato usando 'renderUI'. – Molx
@Molx Se non trovi una soluzione di cui sei soddisfatto, ti prego di contattarmi. Se una delle soluzioni qui funziona, allora ottimo :) (bello vedere il mio coloreInput utilizzato!) –