From 9641a92f01b9ed6b4cb94bb0fbb1dd595cf2d1ab Mon Sep 17 00:00:00 2001 From: Vincent Arel-Bundock Date: Mon, 15 Jan 2024 19:15:05 -0500 Subject: [PATCH] save_tt png and pdf --- DESCRIPTION | 3 +- R/save_tt.R | 96 ++++++++++++++++++++++++++++++------ man-roxygen/latex_preamble.R | 4 +- vignettes/tutorial.qmd | 17 +++++++ 4 files changed, 103 insertions(+), 17 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b56e575e..c73e1998 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -12,7 +12,8 @@ Suggests: rmarkdown, rstudioapi, tinysnapshot, - tinytest + tinytest, + webshot2 URL: https://vincentarelbundock.github.io/tinytable, https://github.com/vincentarelbundock/tinytable Authors@R: c( person("Vincent", "Arel-Bundock", diff --git a/R/save_tt.R b/R/save_tt.R index 9cf97f20..32dbbe8f 100644 --- a/R/save_tt.R +++ b/R/save_tt.R @@ -1,9 +1,9 @@ #' Save a Tiny Table to File #' -#' This function saves an object of class tinytable to a specified file, with an option to overwrite existing files. +#' This function saves an object of class tinytable to a specified file and format, with an option to overwrite existing files. #' #' @param x The tinytable object to be saved. -#' @param filename A string representing the path to the file where the object should be saved. +#' @param filename A string representing the path to the file where the object should be saved. The supported file formats are: .html, .png, .md, .pdf, and .tex. #' @param overwrite A logical value indicating whether to overwrite an existing file. #' @return invisible(TRUE) #' @export @@ -17,22 +17,90 @@ #' } #' save_tt <- function(x, filename, overwrite = FALSE) { - m <- meta(x) +m <- meta(x) - assert_string(filename) - assert_flag(overwrite) - if (file.exists(filename) && !overwrite) { - stop("File already exists and overwrite is set to FALSE.", call. = FALSE) - } - if (is.null(m)) { - stop("`x` must be an object produced by the `tinytable::tt()` function.", call. = FALSE) - } +assert_string(filename) +assert_flag(overwrite) +if (file.exists(filename) && !overwrite) { + stop("File already exists and overwrite is set to FALSE.", call. = FALSE) +} +if (is.null(m)) { + stop("`x` must be an object produced by the `tinytable::tt()` function.", call. = FALSE) +} - # evaluate styles at the very end of the pipeline - x <- eval_style(x) +file_ext <- tools::file_ext(filename) +sanity_file_extension(x, file_ext) + +# evaluate styles at the very end of the pipeline, just before writing +x <- eval_style(x) + +if (file_ext %in% c("html", "tex", "md", "Rmd", "qmd", "txt")) { write(x, file = filename) - return(invisible(TRUE)) +} else if (file_ext == "png") { + assert_dependency("webshot2") + d <- tempdir() + f <- file.path(d, "index.html") + write(x, file = f) + webshot2::webshot( + f, + file = filename, + selector = "body > div > table", + zoom = 4) + +} else if (file_ext == "pdf") { + assert_dependency("tinytex") + # \documentclass{standalone} does not support \begin{table} + tmp <- strsplit(x, "\\n")[[1]] + tmp <- tmp[!grepl("\\begin{table}", tmp, fixed = TRUE)] + tmp <- tmp[!grepl("\\end{table}", tmp, fixed = TRUE)] + tmp <- paste(tmp, collapse = "\n") + tmp <- sprintf(" +\\documentclass{standalone} +\\usepackage{tabularray} +\\usepackage{float} +\\usepackage{codehigh} +\\usepackage[normalem]{ulem} +\\UseTblrLibrary{booktabs} +\\newcommand{\\tinytableTabularrayUnderline}[1]{\\underline{#1}} +\\newcommand{\\tinytableTabularrayStrikeout}[1]{\\sout{#1}} +\\NewTableCommand{\\tinytableDefineColor}[3]{\\definecolor{#1}{#2}{#3}} +\\begin{document} +%s +\\end{document}", + tmp) + d <- tempdir() + f <- file.path(d, "index.tex") + write(tmp, f) + tinytex::xelatex(f, pdf_file = filename) +} + +return(invisible(TRUE)) +} + + +sanity_file_extension <- function(x, file_ext) { + m <- meta(x) + + # Define the expected output for each extension + expected_output <- switch(file_ext, + "png" = "html", + "html" = "html", + "pdf" = "latex", + "tex" = "latex", + "md" = "markdown", + "Rmd" = "markdown", + "qmd" = "markdown", + "txt" = "markdown", + stop("Unsupported file extension", call. = FALSE)) + + # Check if the actual output matches the expected output + if (!is.null(m) && !is.null(m$output) && m$output != expected_output) { + stop(paste("For", file_ext, "files, the `output` argument should be:", expected_output), call. = FALSE) + } + + # If everything is fine, return a success message or perform other actions + return(paste("File extension and output format are compatible.")) } diff --git a/man-roxygen/latex_preamble.R b/man-roxygen/latex_preamble.R index baad823f..1644a9bc 100644 --- a/man-roxygen/latex_preamble.R +++ b/man-roxygen/latex_preamble.R @@ -10,8 +10,8 @@ #' \usepackage{codehigh} #' \usepackage[normalem]{ulem} #' \UseTblrLibrary{booktabs} -#' \newcommand{\tinytableTabularrayUnderline}[1]{\underline{#1}}", -#' \newcommand{\tinytableTabularrayStrikeout}[1]{\sout{#1}}", +#' \newcommand{\tinytableTabularrayUnderline}[1]{\underline{#1}} +#' \newcommand{\tinytableTabularrayStrikeout}[1]{\sout{#1}} #' \NewTableCommand{\tinytableDefineColor}[3]{\definecolor{#1}{#2}{#3}} #' ``` #' diff --git a/vignettes/tutorial.qmd b/vignettes/tutorial.qmd index afff1792..f28701ca 100644 --- a/vignettes/tutorial.qmd +++ b/vignettes/tutorial.qmd @@ -52,6 +52,23 @@ tt(x, output = "markdown") When calling `tinytable` from a Quarto or Rmarkdown document, `tinytable` detects the output format automatically and generates an HTML or LaTeX table as appropriate. This means that we do not need to explicitly specify the `output` format. +With the `save_tt()` function, users can also save tables directly to PNG images or PDF documents, or any of the basic formats. All we need to do is supply a valid file name with the appropriate extension (ex: `.png`, `.html`, `.pdf`, etc.): + +```r +# PNG +tt(x, output = "html") |> save_tt("path/to/file.png") + +# PDF +tt(x, output = "html") |> save_tt("path/to/file.html") + +# PDF +tt(x, output = "latex") |> save_tt("path/to/file.pdf") + +# Text +tt(x, output = "markdown") |> save_tt("path/to/file.txt") +``` + + ## Themes `tinytable` offers a few basic themes out of the box: "default", "striped", "grid", "void." Those themes can be applied with the `theme` argument of the `tt()` function. As we will see below, it is easy to go much beyond those basic settings to customize your own tables. Here we only illustrate a few of the simplest settings: