【问题标题】:Rshiny download button that gathers multiple files from various locationsR Shiny 下载按钮,可从不同位置收集多个文件
【发布时间】:2020-10-28 04:31:28
【问题描述】:

我正在寻找有关在我的应用程序中有一个下载按钮的信息,该按钮将各种文件拉入一个 zip 存档。

我的应用程序显示时间线和数据表,并且将包含与数据表上的条目相关联的文件。这些文件将存储在应用程序的一个目录中,并且我将在数据表中有一列文件名。

我的想法是,当我单击下载按钮时,将创建一个 zip 存档,其中包含我指向的几个标准文件、数据表的 csv、时间线的 png 以及我拥有的任何文件与数据表的选定条目相关联。

我还没有开始处理与数据表相关的文件,但这是我的最终状态。

当前代码

library(shiny)
library(timevis)
library(lubridate)
library(dplyr)

starthour <- 8
today <- as.character(Sys.Date())
todayzero <- paste(today,"00:00:00")
todayAM <- paste(today,"07:00:00")
todayPM <- paste(today, "18:00:00")

items <- data.frame(
  category = c("Room","IceBreaker","Activity","Break"),
  group=c(1,2,3,4),
  className   = c ("red_point", "blue_point", "green_point","purple_point"),
  content = c("Big Room","Introductions","Red Rover","Lunch"),
  length = c(480,60,120,90)
)

groups <- data.frame(id= items$group, content = items$category)

data <- items %>% mutate(id = 1:4,
                         start = as.POSIXct(todayzero) + hours(starthour),
                         end   = as.POSIXct(todayzero) + hours(starthour) + minutes(items$length)
)

js <- "
$(document).ready(function(){
$('#download').on('click', function(){
domtoimage.toPng(document.getElementById('appts'), {bgcolor: 'white'})
.then(function (dataUrl) {
var link = document.createElement('a');
link.download = 'my-timeline.png';
link.href = dataUrl;
link.click();
});
});
});"

ui <- fluidPage(
  tags$head(
    tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"),
    tags$script(src = "myJS.js"),
    tags$style(HTML("
                    .red_point  { border-color: red; border-width: 2px;   }
                    .blue_point { border-color: blue; border-width: 2px;  }
                    .green_point  { border-color: green; border-width: 2px;   }
                    .purple_point { border-color: purple; border-width: 2px;  }
                    "))),
  timevisOutput("appts"),
  div("Selected items:", textOutput("selected", inline = TRUE)),
  div("Visible window:", textOutput("window", inline = TRUE)),
  tableOutput("table"),
  actionButton("download", "Download timeline", class = "btn-success")
    )

server <- function(input, output) {
  output$appts <- renderTimevis(
    timevis(
      data = data,
      groups = groups,
      fit = TRUE,
      options = list(editable = TRUE, multiselect = TRUE, align = "center", stack = TRUE,start = todayAM,
                     end = todayPM,showCurrentTime = FALSE,showMajorLabels=FALSE)
    )
  )
  
  output$selected <- renderText(
    paste(input$appts_selected, collapse = " ")
  )
  
  output$window <- renderText(
    paste(input$appts_window[1], "to", input$appts_window[2])
  )
  
  output$table <- renderTable(
    input$appts_data
  )
  
}
shinyApp(ui, server)

编辑

这是我当前如何从我的生产应用程序的数据表中下载选定的行。

output$downloadData2 <- downloadHandler(
      filename = function() {paste('Selected Retreat Options', Sys.Date(), '.csv', sep = '')},
      content = function(file){ write.csv(thedata()[input[["tbl1_rows_selected"]], ],file)})

【问题讨论】:

    标签: javascript r shiny


    【解决方案1】:

    这是一种使用 JavaScript 库的方法

    • dom-to-image 将时间线导出为 PNG 图像;

    • table2CSV 将表格转换为 CSV 字符串;

    • JSZip 压缩。


    library(shiny)
    library(timevis)
    library(lubridate)
    library(dplyr)
    
    starthour <- 8
    today <- as.character(Sys.Date())
    todayzero <- paste(today,"00:00:00")
    todayAM <- paste(today,"07:00:00")
    todayPM <- paste(today, "18:00:00")
    
    items <- data.frame(
      category = c("Room","IceBreaker","Activity","Break"),
      group=c(1,2,3,4),
      className   = c ("red_point", "blue_point", "green_point","purple_point"),
      content = c("Big Room","Introductions","Red Rover","Lunch"),
      length = c(480,60,120,90)
    )
    
    groups <- data.frame(id= items$group, content = items$category)
    
    data <- items %>% mutate(id = 1:4,
                             start = as.POSIXct(todayzero) + hours(starthour),
                             end   = as.POSIXct(todayzero) + hours(starthour) + minutes(items$length)
    )
    
    js <- "
    $(document).ready(function(){
      $('#download').on('click', function(){
        var csv = $('#table table').table2CSV({delivery:'value'});
        domtoimage.toPng(document.getElementById('appts'), {bgcolor: 'white'})
          .then(function (dataUrl) {
            var zip = new JSZip();
            var idx = dataUrl.indexOf('base64,') + 'base64,'.length; 
            var content = dataUrl.substring(idx);
            zip.file('timeline.png', content, {base64: true})
              .file('timeline.csv', btoa(csv), {base64: true});
            zip.generateAsync({type:'base64'}).then(function (b64) {
              var link = document.createElement('a');
              link.download = 'mytimeline.zip';
              link.href = 'data:application/zip;base64,' + b64;
              link.click();
            });
          });
      });
    });"
    
    ui <- fluidPage(
      tags$head(
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"),
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.5.0/jszip.min.js"),
        tags$script(src = "https://cdn.jsdelivr.net/gh/rubo77/table2CSV/table2CSV.js"),
        tags$script(HTML(js)),
        tags$style(HTML("
                        .red_point  { border-color: red; border-width: 2px;   }
                        .blue_point { border-color: blue; border-width: 2px;  }
                        .green_point  { border-color: green; border-width: 2px;   }
                        .purple_point { border-color: purple; border-width: 2px;  }
                        "))),
      timevisOutput("appts"),
      div("Selected items:", textOutput("selected", inline = TRUE)),
      div("Visible window:", textOutput("window", inline = TRUE)),
      tableOutput("table"),
      actionButton("download", "Download timeline", class = "btn-success")
    )
    
    server <- function(input, output) {
      output$appts <- renderTimevis(
        timevis(
          data = data,
          groups = groups,
          fit = TRUE,
          options = list(editable = TRUE, multiselect = TRUE, align = "center", stack = TRUE,start = todayAM,
                         end = todayPM,showCurrentTime = FALSE,showMajorLabels=FALSE)
        )
      )
      
      output$selected <- renderText(
        paste(input$appts_selected, collapse = " ")
      )
      
      output$window <- renderText(
        paste(input$appts_window[1], "to", input$appts_window[2])
      )
      
      output$table <- renderTable(
        input$appts_data
      )
      
    }
    
    shinyApp(ui, server)
    

    编辑

    为了使上述解决方案起作用,表格必须显示在页面中。下面是一个不需要的解决方案。它使用 JavaScript 库 PapaParse

    library(shiny)
    library(timevis)
    library(lubridate)
    library(dplyr)
    library(jsonlite)
    
    starthour <- 8
    today <- as.character(Sys.Date())
    todayzero <- paste(today,"00:00:00")
    todayAM <- paste(today,"07:00:00")
    todayPM <- paste(today, "18:00:00")
    
    items <- data.frame(
      category = c("Room","IceBreaker","Activity","Break"),
      group=c(1,2,3,4),
      className   = c ("red_point", "blue_point", "green_point","purple_point"),
      content = c("Big Room","Introductions","Red Rover","Lunch"),
      length = c(480,60,120,90)
    )
    
    groups <- data.frame(id= items$group, content = items$category)
    
    data <- items %>% mutate(id = 1:4,
                             start = as.POSIXct(todayzero) + hours(starthour),
                             end   = as.POSIXct(todayzero) + hours(starthour) + minutes(items$length)
    )
    
    js <- "
    function downloadZIP(jsontable){
      var csv = Papa.unparse(jsontable);
      domtoimage.toPng(document.getElementById('appts'), {bgcolor: 'white'})
        .then(function (dataUrl) {
          var zip = new JSZip();
          var idx = dataUrl.indexOf('base64,') + 'base64,'.length; 
          var content = dataUrl.substring(idx);
          zip.file('timeline.png', content, {base64: true})
            .file('timeline.csv', btoa(csv), {base64: true});
          zip.generateAsync({type:'base64'}).then(function (b64) {
            var link = document.createElement('a');
            link.download = 'mytimeline.zip';
            link.href = 'data:application/zip;base64,' + b64;
            link.click();
          });
        });
    }
    $(document).on('shiny:connected', function(){
      Shiny.addCustomMessageHandler('download', downloadZIP);
    });"
    
    ui <- fluidPage(
      tags$head(
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"),
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.5.0/jszip.min.js"),
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.2.0/papaparse.min.js"),
        tags$script(HTML(js)),
        tags$style(HTML("
                        .red_point  { border-color: red; border-width: 2px;   }
                        .blue_point { border-color: blue; border-width: 2px;  }
                        .green_point  { border-color: green; border-width: 2px;   }
                        .purple_point { border-color: purple; border-width: 2px;  }
                        "))),
      timevisOutput("appts"),
      div("Selected items:", textOutput("selected", inline = TRUE)),
      div("Visible window:", textOutput("window", inline = TRUE)),
      actionButton("download", "Download timeline", class = "btn-success")
    )
    
    server <- function(input, output, session) {
      output$appts <- renderTimevis(
        timevis(
          data = data,
          groups = groups,
          fit = TRUE,
          options = list(editable = TRUE, multiselect = TRUE, align = "center", stack = TRUE,start = todayAM,
                         end = todayPM,showCurrentTime = FALSE,showMajorLabels=FALSE)
        )
      )
      
      output$selected <- renderText(
        paste(input$appts_selected, collapse = " ")
      )
      
      output$window <- renderText(
        paste(input$appts_window[1], "to", input$appts_window[2])
      )
      
      observeEvent(input$download, {
        session$sendCustomMessage(
          "download", 
          fromJSON(toJSON(input$appts_data), simplifyDataFrame = FALSE)
        )
      })
      
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 我真的开始认为我应该在 jquery 中完成整个页面。哈哈。再次感谢!我喜欢你用 JS 绕过 Rshiny 限制的方式。
    • 有什么方法可以下载表格而不显示它?在我实际工作的应用程序中,显示了表格,用户选择项目并单击按钮以显示时间线。然后从那里下载数据包。我从来没有像上面的通用应用程序那样实际显示带有所选行的附加表。
    • 或者我可以隐藏表格,因为我认为必须生成它才能让您的脚本工作?
    • @Steve 如果您像这样隐藏表格,这将起作用:div(tableOutput("table"), style="visibility: hidden;")。但这会显示一个白色区域。您可以通过 div(tableOutput("table"), style="display: none;") 以没有白色区域的方式隐藏表格,但 CSV 文件为空。所以使用visibility: hidden并将表格放在页面底部。
    • 是的,我只是在玩它,还有用于隐藏表格的 shinyjs。这也会导致一个空的 csv。我可能只需要合并该表。我在我的问题中添加了一段代码,显示了我当前如何从我的数据表中下载选定的行。
    猜你喜欢
    • 1970-01-01
    • 2015-05-30
    • 2017-08-09
    • 1970-01-01
    • 2021-09-25
    • 2022-01-19
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    相关资源
    最近更新 更多