使用DT导出表格时保持格式(DataTables按钮扩展)

Flo*_*nGD 5 javascript css r datatables shiny

我制作了一个闪亮的应用程序,其中有人上载文件,计算了一些比率,并且可以使用阈值滑块设置这些比率的格式。我用DT::formatStyle它,它真的很好。据我了解此功能,它创建一个回调来处理条件格式。

然后,我想使用中的按钮扩展名导出数据DT。我想在导出为pdf或打印时保留格式。事实证明这是行不通的:数据未经任何格式导出。我尝试设置exportOptions(list(stripHtml = FALSE)),但仍然无法正常工作。

同样令我惊讶的是,即使我直接从Firefox打印(如File / Print ...;我仅尝试使用Firefox,并且该应用程序将仅在Firefox中运行),颜色也会下降,但是字体粗细保持。我怀疑可能需要调整CSS,但是我不知道该怎么做。

我想有一种方法可以使pdf和/或打印文件“保持原样”,与我在浏览器中看到的最接近。下面是一个示例:

library(shiny)
library(DT)
library(dplyr)
data("starwars")

ui <- fluidPage(title = "Ratios",
  sidebarLayout(
    sidebarPanel(width = 2,
                 actionButton("button", "Go"), # Emulates data loading
                 sliderInput("seuil_j", "Threshold J",
                             min = 0,  max = 80, value = 35, step = 0.5)),
    mainPanel( 
      fluidRow(column(width = 12,
                      DT::dataTableOutput("ratios"))))
  )
)

server <- function(input, output, session) {
  donnees_ratios <- reactive({
    req(input$button)
    set.seed(14)
    starwars %>% 
      select(1:10) %>% # DataTables is not happy with list columns
      mutate(signe = sample(c(1, -1), replace = TRUE, size = nrow(.)),
             ratio_j = signe * mass / height) %>% 
      select(name, mass, height, signe, ratio_j, everything())
  })

  output$ratios <- DT::renderDataTable({
    donnees_ratios() %>% 
      creer_DT() %>% 
      formatter_DT(input)
  })
}

creer_DT <- function(donnees) {
  datatable(donnees, 
            rownames = FALSE, 
            class = 'cell-border stripe compact hover',
            extensions = c("Buttons"),
            options = list(
              dom = 'Blfrtip',
              buttons = list(
                list(extend = "pdf", 
                     exportOptions = list(stripHtml = FALSE,
                                                     columns = ':visible'),
                     orientation = 'landscape'),
                list(extend = "print", 
                     exportOptions = list(stripHtml = FALSE,
                                          columns = ':visible')),
               "excel", "csv", "colvis"),
              language = list(
                decimal = ",",
                thousands = "&#8239;"  # small unbreakable space
              )
            )
  )
}

formatter_DT <- function(table, input) {
  table %>% 
    formatPercentage(columns = c("ratio_j"),
                     digits = 1L, dec.mark = ",", mark = "&#8239;") %>%
    formatRound(columns = c("height", "mass"),
                digits = 1L, dec.mark = ",", mark = "&#8239;") %>%
    format_seuil("ratio_j", input$seuil_j)
}

format_seuil <- function(table, column, seuil) {
  # Threshold for the aboslute value, and different coloring if higher or lower
  formatStyle(table, column, 
              fontWeight = styleInterval(
                c(-seuil / 100, seuil / 100), c("bold", "normal", "bold")),
              color = styleInterval(
                c(-seuil / 100, seuil / 100), c("red", "black", "orange")
              ))
}

shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)

我可以导出为pdf或打印,但是显示已修改。我还可以使用rmarkdown和生成pdf knitr,但这是工作的两倍,感觉就像我错过了使用按钮扩展名的东西。

我希望这很清楚,并感谢您的帮助!

弗洛里安

RLe*_*sur 5

tl;dr 你不能继续格式化;你必须编写一个自定义的 JavaScript 函数。

PDFprint按钮有非常不同的行为。

print按钮的行为

当您单击该print按钮时,您将使用用户代理(在此用例中为浏览器)将HTML文档呈现为分页文档 (PDF)。有一个名为CSS Paged Media的 W3C 标准,它定义了如何将 CSS 规则应用于分页媒体。
这些 CSS 规则包含在 CSS @media printat-rule 中。
这里有一个关于 CSS Paged Media 的综合指南:print-css.rocks

处理 CSS Paged Media 并不简单:

  • 浏览器严重执行 CSS Paged Media 标准;无头用户代理 ( wkhtmltopdf, weasyprint, XML Prince...) 用于生成带有 CSS Paged Media 的 PDF。使用这些用户代理之一非常容易,因为pandoc 2.0:它们可以替换LaTeX引擎。
  • 当您打开HTML文件时,浏览器@media print默认不应用(它们@media screen按规则应用)。因此,很难找出@media print规则。我知道跟踪这些规则的唯一方法是使用 Chrome 开发人员工具(打开菜单,选择More toolsRendering。在Rendering面板中,您可以模拟分页媒体选择print)。

由于您想使用浏览器生成样式化的PDF,我认为 CSS 分页媒体规则是一种不切实际的方式。此外,使用带有动态 HTML 文档的无头用户代理作为 Shiny 应用程序非常复杂。所以,我的建议是忘记print按钮。

PDF按钮的行为

DataTableslibrary 依赖于pdfmakeJavaScript 库来生成 PDF 文件。您可以将传递 JavaScript 函数的自定义样式应用到按钮customize选项pdfHtml5。此函数自定义发送到pdfmakeAPI的文档对象。

为了了解JSON传递DataTables给 to的文档对象的结构pdfmake,可以将其输出到浏览器控制台:

library(shiny)
library(DT)
library(dplyr)
data("starwars")

ui <- fluidPage(title = "Ratios",
                sidebarLayout(
                  sidebarPanel(width = 2,
                               actionButton("button", "Go"), # Emulates data loading
                               sliderInput("seuil_j", "Threshold J",
                                           min = 0,  max = 80, value = 35, step = 0.5)),
                  mainPanel( 
                    fluidRow(column(width = 12,
                                    DT::dataTableOutput("ratios"))))
                )
)

server <- function(input, output, session) {
  donnees_ratios <- reactive({
    req(input$button)
    set.seed(14)
    starwars %>% 
      select(1:10) %>% # DataTables is not happy with list columns
      mutate(signe = sample(c(1, -1), replace = TRUE, size = nrow(.)),
             ratio_j = signe * mass / height) %>% 
      select(name, mass, height, signe, ratio_j, everything())
  })

  output$ratios <- DT::renderDataTable({
    donnees_ratios() %>% 
      creer_DT() %>% 
      formatter_DT(input)
  })
}

creer_DT <- function(donnees) {
  datatable(donnees, 
            rownames = FALSE, 
            class = 'cell-border stripe compact hover',
            extensions = c("Buttons"),
            options = list(
              dom = 'Blfrtip',
              buttons = list(
                list(extend = "pdf", 
                     exportOptions = list(stripHtml = FALSE,
                                          columns = ':visible'),
                     orientation = 'landscape',
                     customize = JS("function(doc){console.dir(doc);}")),
                list(extend = "print", 
                     exportOptions = list(stripHtml = FALSE,
                                          columns = ':visible')),
                "excel", "csv", "colvis"),
              language = list(
                decimal = ",",
                thousands = "&#8239;"  # small unbreakable space
              )
            )
  )
}

formatter_DT <- function(table, input) {
  table %>% 
    formatPercentage(columns = c("ratio_j"),
                     digits = 1L, dec.mark = ",", mark = "&#8239;") %>%
    formatRound(columns = c("height", "mass"),
                digits = 1L, dec.mark = ",", mark = "&#8239;") %>%
    format_seuil("ratio_j", input$seuil_j)
}

format_seuil <- function(table, column, seuil) {
  # Threshold for the aboslute value, and different coloring if higher or lower
  formatStyle(table, column, 
              fontWeight = styleInterval(
                c(-seuil / 100, seuil / 100), c("bold", "normal", "bold")),
              color = styleInterval(
                c(-seuil / 100, seuil / 100), c("red", "black", "orange")
              ))
}

shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)

您可以修改默认样式。这是更改tableHeader样式字体颜色的一个示例:

customize = JS("function(doc){doc.styles.tableHeader.color='yellow';}"))
Run Code Online (Sandbox Code Playgroud)

为了进一步定制,您必须编写自己的 JavaScript 函数。这是使用百分比格式化第五列的示例:

customize = JS("function(doc){doc.content[1].table.body.forEach(function(el,idx){if(idx>0){el[4].text=String((parseFloat(el[4].text)*100).toFixed(1))+'%'}})}"))
Run Code Online (Sandbox Code Playgroud)