根据文件选择保存和加载用户选择 - R Shiny

Posted

技术标签:

【中文标题】根据文件选择保存和加载用户选择 - R Shiny【英文标题】:Save and Load user selections based on file selection - RShiny 【发布时间】:2019-04-01 15:53:59 【问题描述】:

我正在尝试创建一个简单的应用程序,它充当 GUI 来研究具有相同变量但具有不同版本和内容的不同文件。我无法提供一个应用程序,每次用户打开应用程序时,他们都不必在他们离开的地方再次输入参数。我希望他们能够保存他们的参数并在他们返回应用程序时再次显示它们。

我在这里给出了我的示例代码,但是在实际应用程序中输入和绘图的数量要多得多。我想知道是否有任何解决方案来保存这些依赖的输入和输出。

library(shiny)
library(pryr)

ui = shinyUI(fluidPage(

  # Application title
  titlePanel("Example Title"),

  # Sidebar structure
  sidebarLayout(
    sidebarPanel(
      textInput("save_file", "Save to file:", value="sample.RData"),
      actionButton("save", "Save input value to file"),
      uiOutput("load"),
      uiOutput("file"),
      uiOutput("mytype"),
      uiOutput("mysubtype")
    ),

    # Show a plot of the generated distribution
    mainPanel(
      tabsetPanel(id="tab",
                  tabPanel(
                    "Plot",
                    plotOutput("distPlot"),
                    checkboxInput(inputId = "density",
                                  label = strong("Show Adjustment Factors"),
                                  value = FALSE),
                    conditionalPanel(condition = "input.density == true",
                                     sliderInput(inputId = "bandwidth",
                                                 label = "Width adjustment: ",
                                                 min = 0.5, max = 4, value = 1, step = 0.1),
                                     radioButtons("mycolor", "Color Adjustment: ",
                                                  choices = c(Red = "red", Black = "black", Blue = "blue"),selected = "black", inline = TRUE)
                    )),
                  tabPanel("Summary",
                           h3(textOutput("label")),
                           verbatimTextOutput("summary")
                  )
      ))

  )
)
)

server = function(input, output, session) 
  # render a selectInput with all RData files in the specified folder
  output$load <- renderUI(
    choices <- list.files("/home/user/Documents/Shiny/", pattern="*.RData")
    selectInput("input_file", "Select input file", choices)
  )

  # render a selectInput with all csv files in the specified folder so that user can choose the version
  output$file <- renderUI(
    choices.1 <- list.files("/home/user/Documents/Shiny/", pattern="*.csv")
    selectInput("input_csv", "Select csv file", choices.1)
  )

  # Load a csv file and update input
  data = eventReactive(input$input_csv, 
    req(input$input_csv)
    read.csv(paste0("/home/user/Documents/Shiny/",input$input_csv),
             header = TRUE,
             sep = ",")
  )

  #Display Type - Types may differ based on file selection
  output$mytype <- renderUI(
    selectInput("var1", "Select a type of drink: ", choices = levels(data()$Type))
  )

  #Display SubType - This would be dependent on Type Selection
  output$mysubtype <- renderUI(
    selectInput("var2", "Select the SubType: ", choices = as.character(data()[data()$Type==input$var1,"Subtype"]))
  )

  # Save input when click the button
  observeEvent(input$save, 
    validate(
      need(input$save_file != "", message="Please enter a valid filename")
    )
    mycolor <- input$mycolor
    mytype = input$var1
    mysubtype = input$var2
    density <- input$density
    bandwidth <- input$bandwidth
    save(bandwidth, density,  mycolor, mytype, mysubtype,
         file=paste0("/home/user/Documents/Shiny/", input$save_file))
    choices <- list.files("/home/user/Documents/Shiny/", pattern="*.RData")
    updateSelectInput(session, "input_file", choices=choices)

    choices.1 <- list.files("/home/user/Documents/Shiny/", pattern="*.csv")
    updateSelectInput(session, "input_csv", choices=choices.1)
  )
  # Load an RData file and update input
  # input$var1, input$var2, input$density, input$bandwidth, input$mycolor),
  observeEvent(c(input$input_file), 
               
    load(paste0("/home/user/Documents/Shiny/",input$input_file))
    updateSelectInput(session, "var1", choices = levels(data()$Type), selected = mytype)
    updateSelectInput(session, "var2", choices = as.character(data()[data()$Type==mytype,"Subtype"]), selected = mysubtype)
    updateCheckboxInput(session, "density", value = density)
    updateSliderInput(session, inputId = "bandwidth", value=bandwidth)
    updateRadioButtons(session, "mycolor", choices = c(Red = "red", Black = "black", Blue = "blue"), selected = mycolor, inline = TRUE)
  )

  output$distPlot <- renderPlot(

    # generate plot
    x = data()[data()$Type == input$var1 & data()$Subtype == input$var2, c("Alcohol_Content","Price")]
    plot(x$Alcohol_Content, x$Price, type = "l", xlab = "Alcohol content", ylab = "Price",
         main = "Sample Plot",
         col="red",
         lwd=1.5)
    if (input$density)
      plot(x$Alcohol_Content, x$Price, type = "p", xlab = "Alcohol content", ylab = "Price",
           main = "Sample Plot",
           col=input$mycolor,
           lwd=input$bandwidth)


  )


  output$summary <- renderText(summary(data()))




shinyApp(ui, server)
    输入 csv 文件将始终存储在 "/home/user/Documents/Shiny/" 用户只需点击“保存到 文件:”,它应该将用户选择保存在“sample.RData”中 位于相同的“/home/user/Documents/Shiny/”中。因此,我想提供一个 selectinput,用户也可以在其中选择 .RData 文件。 用户还应该能够将输入保存在主面板上,用于修改图表

问题:-

    上面给出的大部分代码都可以正常工作,但是如何保存#Display Subtype。 如果我再添加一个依赖列表(如类型和子类型)会怎样? 如果我能就解决方案是否适用于多个选择输入获得一些帮助?

非常感谢您对代码的任何帮助。

虚拟数据:-

x = data.frame(Type=rep(c("WINE"), 9), Subtype=rep(c("TABLE WINE RED", "TABLE WINE WHITE", "MONTILLA"), each=3), Alcohol_content= c(14, 11.5, 12, 11, 13.5, 11, 12.5, 12, 11.5), Price = c(30.99, 32.99, 29.99, 33.99, 36.99, 34.99, 119, 32.99, 13.99))
y = data.frame(Type=rep(c("REFRESHMENT"), 9), Subtype=rep(c("CIDER ALL", "SPIRIT", "BEER"), each=3), Alcohol_content= c(5, 5.2, 7, 5.3, 6.9, 5, 5, 6, 5), Price = c(9.99, 9.99, 8.99, 9.95, 3.49, 9.99, 12.99, 13.49, 21.99))
bcl_data1 = rbind(x, y)
write.csv(bcl_data1, "bcl_data1.csv")

每种类型(葡萄酒、茶点)下还有更多子类型。我无法通过上面的代码检索 Subtype 值,但是当我加载 Sample.RData 时,我可以看到 var2 = my selected value。

我想知道如何保存这些值。

【问题讨论】:

您考虑过使用书签吗?见shiny.rstudio.com/articles/bookmarking-state.html 你好@ismirsehregal - 是的,它与书签功能配合得很好。但是,这将是一个本地桌面应用程序,用户无法从服务器许可证访问 RStudio。此外,书签在本地也可以正常工作,但是 URL IP 地址的一部分,例如如果我们关闭 RStudio 并重新启动它,(127.XX.XX.XX)会发生变化。因此,习惯上从本地 .RData 文件中保存和检索数据。 如果书签工作正常,您应该使用它们。可以自行保存设置,但需要做更多工作。 IP 地址由您的操作系统提供,不应仅通过重新启动 RStudio 来更改。调整后的 URL 是该概念的一部分:每个用户都可以创建自己的设置,为它们添加书签,然后返回到具有该唯一 URL 的相同状态。对于单个文件应用程序,您可以使用app &lt;- shinyApp(ui, server) 并将runApp(app, host="0.0.0.0", port=80) 添加到您的脚本中,这样该网页将在本地网络中可用。 我了解@ismirsehregal。我更新了昨天的代码。我是如此接近,但它并没有给出我正在寻找的东西。它保存了第一个依赖列表“var1”,但不知何故它没有保留“var”子类型。如果我给你虚拟数据会有帮助吗?我不知道如何上传它。请帮忙。 是的,显示您的结构的虚拟数据框会很有帮助。 【参考方案1】:

这是您的代码的工作版本。您的问题是同时使用 renderUI 和 updateSelectInput。每次您尝试更新您的 selectInput 时,它都会立即重新渲染,因此更改不可见。 我建议在 UI 中呈现 selectInput(我为“var2”所做的)并仅使用 updateSelectInput。 (如果你真的想继续建立自己的书签。)

最好的问候

library(shiny)
library(pryr)

if(!file.exists("bcl_data1.csv"))
  x = data.frame(Type=rep(c("WINE"), 9), Subtype=rep(c("TABLE WINE RED", "TABLE WINE WHITE", "MONTILLA"), each=3), Alcohol_content= c(14, 11.5, 12, 11, 13.5, 11, 12.5, 12, 11.5), Price = c(30.99, 32.99, 29.99, 33.99, 36.99, 34.99, 119, 32.99, 13.99))
  y = data.frame(Type=rep(c("REFRESHMENT"), 9), Subtype=rep(c("CIDER ALL", "SPIRIT", "BEER"), each=3), Alcohol_content= c(5, 5.2, 7, 5.3, 6.9, 5, 5, 6, 5), Price = c(9.99, 9.99, 8.99, 9.95, 3.49, 9.99, 12.99, 13.49, 21.99))
  bcl_data1 = rbind(x, y)
  write.csv(bcl_data1, "bcl_data1.csv")



settings_path <- getwd()
# settings_path <- "/home/user/Documents/Shiny/"

ui = shinyUI(fluidPage(

  # Application title
  titlePanel("Example Title"),

  # Sidebar structure
  sidebarLayout(
    sidebarPanel(
      textInput("save_file", "Save to file:", value="sample.RData"),
      actionButton("save", "Save input value to file"),
      p(),
      p(),
      uiOutput("load"),
      uiOutput("file"),
      uiOutput("mytype"),
      selectInput("var2", "Select the SubType: ", choices = NULL)
    ),

    # Show a plot of the generated distribution
    mainPanel(
      tabsetPanel(id="tab",
                  tabPanel(
                    "Plot",
                    plotOutput("distPlot"),
                    checkboxInput(inputId = "density",
                                  label = strong("Show Adjustment Factors"),
                                  value = FALSE),
                    conditionalPanel(condition = "input.density == true",
                                     sliderInput(inputId = "bandwidth",
                                                 label = "Width adjustment: ",
                                                 min = 0.5, max = 4, value = 1, step = 0.1),
                                     radioButtons("mycolor", "Color Adjustment: ",
                                                  choices = c(Red = "red", Black = "black", Blue = "blue"),selected = "black", inline = TRUE)
                    )),
                  tabPanel("Summary",
                           h3(textOutput("label")),
                           verbatimTextOutput("summary")
                  )
      ))

  )
)
)

server = function(input, output, session) 
  # render a selectInput with all RData files in the specified folder
  last_save_path <- file.path(settings_path, "last_input.backup")
  if(file.exists(last_save_path))
    load(last_save_path)
    if(!exists("last_save_file"))
      last_save_file <- NULL
    
   else 
    last_save_file <- NULL
  

  if(!is.null(last_save_file))
   updateTextInput(session, "save_file", "Save to file:", value=last_save_file)
  

  output$load <- renderUI(
    choices <- list.files(settings_path, pattern="*.RData")
    selectInput("input_file", "Select input file", choices, selected = last_save_file)
  )

  # render a selectInput with all csv files in the specified folder so that user can choose the version
  output$file <- renderUI(
    choices.1 <- list.files(settings_path, pattern="*.csv")
    selectInput("input_csv", "Select csv file", choices.1)
  )

  # Load a csv file and update input
  csv_data = eventReactive(input$input_csv, 
    req(input$input_csv)
    read.csv(file.path(settings_path,input$input_csv),
             header = TRUE,
             sep = ",")
  )

  #Display Type - Types may differ based on file selection
  output$mytype <- renderUI(
    req(csv_data())
    selectInput("var1", "Select a type of drink: ", choices = unique(csv_data()$Type))
  )

  #Display SubType - This would be dependent on Type Selection
  observeEvent(input$var1, 
    req(csv_data())
    req(input$var1)
    updateSelectInput(session, "var2", "Select the SubType: ", choices = as.character(csv_data()[csv_data()$Type==input$var1,"Subtype"]), selected = isolate(input$var2))
  )

  # Save input when click the button
  observeEvent(input$save, 
    validate(
      need(input$save_file != "", message="Please enter a valid filename")
    )

    last_save_file <- input$save_file
    save(last_save_file,  file=last_save_path)

    mycolor <- input$mycolor
    mytype = input$var1
    mysubtype = input$var2
    density <- input$density
    bandwidth <- input$bandwidth
    save(bandwidth, density,  mycolor, mytype, mysubtype,
         file=file.path(settings_path, input$save_file))
  )

  # Load an RData file and update input
  observeEvent(input$input_file, 
    req(input$input_file)
    load(file.path(settings_path, input$input_file))
    updateSelectInput(session, "var1", choices =  unique(csv_data()$Type), selected = mytype)
    updateSelectInput(session, "var2", choices = mysubtype, selected = mysubtype)
    updateCheckboxInput(session, "density", value = density)
    updateSliderInput(session, "bandwidth", value = bandwidth)
    updateRadioButtons(session, "mycolor", choices = c(Red = "red", Black = "black", Blue = "blue"), selected = input$mycolor)
  )

  output$distPlot <- renderPlot(
    req(csv_data())
    req(input$var1)
    req(input$var2)

    # generate plot
    x = csv_data()[csv_data()$Type == input$var1 & csv_data()$Subtype == input$var2, c("Alcohol_content",  "Price")]
    if(nrow(x) > 0)
      x <- x[order(x$Alcohol_content), ]
      plot(x$Alcohol_content, x$Price, type = "l", xlab = "Alcohol content", ylab = "Price",
           main = "Sample Plot",
           col="red",
           lwd=1.5)
      if (input$density)
        plot(x$Alcohol_content, x$Price, type = "p", xlab = "Alcohol content", ylab = "Price",
             main = "Sample Plot",
             col=input$mycolor,
             lwd=input$bandwidth)
    

  )


  output$summary <- renderText(summary(csv_data()))



shinyApp(ui, server)

【讨论】:

嗨@ismirsehregal - 此代码有效,但是当我单击“保存”然后重新启动它时,我仍然无法看到“var2”的选定值。重新启动后它仍然不记得我的“var2”。调用所有其他输入值。 编辑了我的答案以恢复上次保存的 .RData 文件。请检查一切是否按预期工作。 非常感谢。这正是我想要的。

以上是关于根据文件选择保存和加载用户选择 - R Shiny的主要内容,如果未能解决你的问题,请参考以下文章

R Shiny 请求用户选择目录

R Shiny 如何在根据用户选择从 mysqlDB 检索数据时使用 renderPlot 构建条形图

如何从 Shiny 中的下拉框中根据变量选择动态创建直方图

Shiny App中的文件夹选择(本地和服务器上)以读取文件并保存结果

根据用户的输入创建列联表 - R Shiny

根据 R Shiny 中的其他选择动态更新两个 selectInput 框