First things first, your likelihood of getting useful answers increases tremendously if you provide a Minimal Reproducible Example
Having said that, here's an example app which shows the idea:
- When loading the data, you load it into a
reactiveVal
(my_data
). This should hold the actual copy of your data and all data operations should update my_data
accordingly.
- When consuming some of the data, you do not reload the data, but instead use
my_data
.
- Likewise, when you store it, you use
my_data
.
In this way you keep stored and live data in sync.
Reprex
Play with the app to get the idea. You can modify the data in the corresponding tab and decide to store it permanently. If you do so and reload the app, you will see that the changes made are persistently stored. You cna also reste the data to its default.
library(shiny)
library(here)
library(glue)
data_dir <- here("datasets")
if (!dir.exists(data_dir)) {
dir.create(data_dir)
}
ui <- fluidPage(
titlePanel("Modify and Save Data"),
sidebarLayout(
sidebarPanel(
selectInput("data_src",
"Data:",
c("mtcars", "iris", "ChickWeight",
"ToothGrowth", "PlantGrowth")),
actionButton("save", "Save Dataset", icon("save"))
),
mainPanel(
tabsetPanel(
tabPanel("Modify Data",
p("Current Data:", textOutput("data_info", inline = TRUE)),
actionButton("add", "Add Random Column"),
actionButton("remove", "Remove Random Row"),
actionButton("reset", "Reset Data")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
server <- function(input, output, session) {
get_filename <- function(data_name) {
here(data_dir, paste0(data_name, ".Rdata"))
}
trigger_reload <- reactiveVal(0)
my_data <- reactiveVal(NULL)
observeEvent(list(input$data_src, trigger_reload()), {
fn <- get_filename(req(input$data_src))
if (!file.exists(fn)) {
my_data(get(input$data_src))
} else {
my_data(readRDS(fn))
}
})
observeEvent(input$save, {
fn <- get_filename(req(input$data_src))
saveRDS(req(my_data()),
fn)
})
observeEvent(input$reset, {
fn <- get_filename(req(input$data_src))
## unlink does not throw error for non existing file
unlink(fn)
trigger_reload(trigger_reload() + 1) ## retrigger-reload
})
observeEvent(input$add, {
dat <- my_data()
nm <- make.unique(c(names(dat), paste0("n", ncol(dat) + 1)))
dat <- cbind(dat, round(rnorm(nrow(dat)), 2))
names(dat) <- nm
my_data(dat)
})
observeEvent(input$remove, {
dat <- my_data()
if (nrow(dat)) {
my_data(dat[-sample(nrow(dat), 1), , drop = FALSE])
}
})
output$table <- renderTable(req(my_data()))
output$data_info <- renderText({
dat <- req(my_data())
dat_nm <- req(input$data_src)
glue("{dat_nm} ({ncol(dat)} cols / {nrow(dat)} rows)")
})
}
shinyApp(ui, server)