简体   繁体   English

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

[英]Keep formatting when exporting table with DT (DataTables buttons extension)

I made a shiny app where someone uploads a file, some ratios are computed, and those ratios can be formatted using sliders for thresholds. 我制作了一个闪亮的应用程序,其中有人上传文件,计算一些比率,并且可以使用滑块来设置阈值的格式。 I use DT::formatStyle for this and it is working really fine. 我为此使用DT::formatStyle ,它工作得非常好。 As far as I understand this function, it creates a callback to handle the conditional formatting. 据我了解这个函数,它创建一个回调来处理条件格式。

Then, I want to export the data, using the buttons extension in DT . 然后,我想使用DT的按钮扩展名导出数据。 I want to keep the formatting when exporting to pdf or printing. 我想在导出为pdf或打印时保留格式。 It turns out that this doesn't work: the data is exported without any formatting. 事实证明这不起作用:数据导出时没有任何格式。 I tried to set exportOptions(list(stripHtml = FALSE)) , but it still doesn't work. 我试图设置exportOptions(list(stripHtml = FALSE)) ,但它仍然不起作用。

What surprises me as well, is that even when I print directly from Firefox (as File/Print... ; I have tried with Firefox only, and the app will only be run in Firefox), the color is dropped, but font weight is kept. 让我感到惊讶的是,即使我直接从Firefox打印(如文件/打印......;我只尝试使用Firefox,而应用程序只能在Firefox中运行),颜色会被删除,但字体重量保持。 I suspect that I may have to tweak the CSS but I do not know how to do that. 我怀疑我可能不得不调整CSS,但我不知道该怎么做。

I would like to have a way to make the pdf and/or the print "as is", the closest to what I see in the browser. 我想有办法使pdf和/或打印“按原样”,最接近我在浏览器中看到的内容。 Below is an example: 以下是一个例子:

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)

I can export to pdf or print, but the display is modified. 我可以导出为pdf或打印,但显示被修改。 I could also generate a pdf with rmarkdown and knitr , but this would be twice the work, and it feels like I miss something using the buttons extension. 我也可以使用rmarkdownknitr生成一个pdf,但这将是工作的两倍,感觉就像我使用按钮扩展错过了一些东西。

I hope that is clear and thanks for helping! 我希望这很清楚,谢谢你的帮助!

Florian 弗洛里安

tl;dr You cannot keep formatting; tl; dr你不能保持格式化; you have to write a custom JavaScript function. 你必须编写一个自定义JavaScript函数。

PDF and print buttons have very different behaviors. PDFprint按钮具有非常不同的行为。

The print button behavior print按钮行为

When you click the print button, you use the user agent (in this use case, the browser) to render the HTML document as a paged document (PDF). 单击print按钮时,使用用户代理(在此用例中为浏览器)将HTML文档呈现为分页文档(PDF)。 There's a W3C standard named CSS Paged Media that defines how CSS rules are applied for paged media. 有一个名为CSS Paged Media的W3C标准,它定义了CSS规则如何应用于分页媒体。
Theses CSS rules are enclosed in CSS @media print at-rule. 这些CSS规则包含在CSS @media print at-rule中。
There's a comprehensive guide about CSS Paged Media here: print-css.rocks . 这里有一个关于CSS分页媒体的综合指南: print-css.rocks

Dealing with CSS Paged Media is not straightforward: 处理CSS分页媒体并不简单:

  • browsers badly implement CSS Paged Media standards; 浏览器严重执行CSS分页媒体标准; headless user agents ( wkhtmltopdf , weasyprint , XML Prince ...) are used to generate PDF with CSS Paged Media. 无头用户代理( wkhtmltopdfweasyprintXML Prince ...)用于使用CSS Paged Media生成PDF。 Using one of these user agents is quite easy since pandoc 2.0 : they can replace a LaTeX engine. 使用其中一个用户代理非常容易,因为pandoc 2.0 :它们可以取代LaTeX引擎。
  • when you open a HTML file, browsers do not apply @media print by default (they apply @media screen at-rule). 当您打开HTML文件时,浏览器默认不应用@media print (它们在@media screen上应用规则)。 So, it can be hard to figure out @media print rules. 因此,很难找出@media print规则。 The only mean I know to track theses rules is to use the Chrome Developer Tools (open the menu, select More tools and Rendering . In the Rendering panel, you can emulate a paged media selecting print ). 我知道跟踪这些规则的唯一方法是使用Chrome开发者工具(打开菜单,选择More toolsRendering 。在Rendering面板中,您可以模拟分页媒体选择print )。

Since you want to use a browser to generate a styled PDF , I think CSS paged media rules is an impracticable way. 由于您希望使用浏览器生成样式化PDF ,我认为CSS分页媒体规则是不切实际的方法。 Moreover, using a headless user agent with a dynamic HTML document as a Shiny App is extremely complex. 此外,将无头用户代理与动态HTML文档一起用作Shiny App非常复杂。 So, my advise is to forget the print button. 所以,我的建议是忘记print按钮。

The PDF button behavior PDF按钮行为

DataTables library relies on pdfmake JavaScript library to generate a PDF file. DataTables库依赖于pdfmake JavaScript库来生成PDF文件。 You can apply custom styles passing a JavaScript function to the customize option of the pdfHtml5 button . 您可以将传递JavaScript函数的customize定义样式应用于pdfHtml5按钮customize选项 This function customizes the document object sent to the pdfmake API . 此函数自定义发送到pdfmake API的文档对象。

In order to understand the structure of the JSON document object passed by DataTables to pdfmake , you can output it to the browser console: 为了理解DataTables传递给pdfmakeJSON文档对象的结构,您可以将其输出到浏览器控制台:

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)

You can modify a default style. 您可以修改默认样式。 Here's one example changing the font color of the tableHeader style: 这是更改tableHeader样式的字体颜色的一个示例:

customize = JS("function(doc){doc.styles.tableHeader.color='yellow';}"))

For further customization, you have to write your own JavaScript function. 要进一步定制,您必须编写自己的JavaScript函数。 Here's an example to format the fifth column with percent: 以下是使用百分比格式化第五列的示例:

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))+'%'}})}"))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 DataTables - 如何使用自己的按钮进行导出? - DataTables - How can I use my own buttons for exporting? 导出到 Excel 时更改数据表中的列标题 - Change Column titles in dataTables when exporting to excel 用colspan导出表并在angular js中格式化 - Exporting table with colspan and formatting in angular js 如何将 DataTables 按钮定位在表格包装器之外 - How to position DataTables buttons outside of table wrapper JQUERY DataTables-保留表格样式的打印 - JQUERY DataTables - Keep Table stying on print jquery 数据表按钮:[&#39;excel&#39;] 在 document.ready() 中构建表时不起作用,但在动态构建表时起作用 - jquery datatables buttons: ['excel'] does not work when table is built in document.ready() but does when the table is built dynamically 导出时,React.Component是默认扩展名吗? - Is React.Component the default extension when exporting? 如何格式化使用R DT(datatables)包生成的表的标题 - How do you format the header of a table produced using the R DT (datatables) package 从数据表导出excel文件时数据之间的空间 - Space between data when exporting excel file from datatables 导出到DataTables中的Excel文件时,如何不在span元素上显示工具提示? - How to not display the tooltip on a span element when exporting to an Excel file in DataTables?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM