diff --git a/R/group_bootstrap.R b/R/group_bootstrap.R index 18384f99..eac0aac0 100644 --- a/R/group_bootstrap.R +++ b/R/group_bootstrap.R @@ -61,6 +61,8 @@ group_bootstrap_row <- function(x, i, j, indent = 1, ...) { out <- bootstrap_setting(out, new = js, component = "cell") } + # add rows to attributes BEFORE style_tt + attr(out, "nrow") <- attr(out, "nrow") + length(label) # need unique function names in case there are # multiple tables in one Rmarkdown document diff --git a/R/group_tabularray.R b/R/group_tabularray.R index 5c8c1ab3..68039fb4 100644 --- a/R/group_tabularray.R +++ b/R/group_tabularray.R @@ -94,6 +94,9 @@ group_tabularray_row <- function(x, i, indent, ...) { attributes(tab) <- att class(tab) <- class(x) + # add rows to attributes BEFORE style_tt + attr(tab, "nrow") <- attr(tab, "nrow") + length(label) + cellspec <- sprintf("cell{%s}{%s}={%s}{%s},", idx$new[is.na(idx$old)] + attr(x, "nhead"), 1, diff --git a/R/group_tt.R b/R/group_tt.R index e750c145..25222df8 100644 --- a/R/group_tt.R +++ b/R/group_tt.R @@ -33,7 +33,6 @@ group_tt <- function(x, i, j, indent = 1, ...) { out <- group_bootstrap(out, i = i, j = j, indent = indent, ...) } - attr(out, "nrow") <- attr(out, "nrow") + length(i) if (is.list(j)) attr(out, "nhead") <- attr(out, "nhead") + 1 return(out) diff --git a/R/style_tt.R b/R/style_tt.R index 15a55a60..fc32ff65 100644 --- a/R/style_tt.R +++ b/R/style_tt.R @@ -53,25 +53,22 @@ style_tt <- function( bootstrap_css = NULL, bootstrap_css_rule = NULL) { - out <- x - - # no markdown styling - if (inherits(x, "tinytable_markdown")) return(x) - - if (!inherits(x, "tinytable_tabularray") && !inherits(x, "tinytable_bootstrap")) { + # supported formats + if (inherits(x, "tinytable_markdown")) { + return(x) + } else if (!inherits(x, "tinytable_tabularray") && !inherits(x, "tinytable_bootstrap")) { stop("`x` must be a table produced by `tt()`.", call. = FALSE) } - nhead <- attr(x, "nhead") + out <- x - assert_string(color, null.ok = TRUE) - assert_string(background, null.ok = TRUE) - assert_string(width, null.ok = TRUE) - assert_choice(align, c("c", "l", "r"), null.ok = TRUE) - assert_flag(bold) - assert_flag(italic) - assert_numeric(indent, len = 1, lower = 0) - assert_integerish(fontsize, len = 1, null.ok = TRUE) + if (!missing(i) && !missing(j)) { + component <- "cell" + } else if (missing(i) && !missing(j)) { + component <- "col" + } else { + component <- "row" + } # j is a regular expression if (!missing(j) && is.character(j) && length(j) == 1 && is.character(attr(x, "tt_colnames"))) { @@ -86,105 +83,118 @@ style_tt <- function( } assert_integerish(colspan, len = 1, lower = 1, upper = j + attr(x, "ncol")) } + # assert_string(color, null.ok = TRUE) + assert_string(background, null.ok = TRUE) + assert_string(width, null.ok = TRUE) + assert_choice(align, c("c", "l", "r"), null.ok = TRUE) + assert_flag(bold) + assert_flag(italic) + assert_numeric(indent, len = 1, lower = 0) + assert_integerish(fontsize, len = 1, null.ok = TRUE) - arguments <- list() - tabularray_cmd <- NULL - - if (isTRUE(bold)) { - tabularray_cmd <- c(tabularray_cmd, "\\bfseries") - arguments$bold <- list( - bootstrap = "font-weight: bold" - ) - } - if (isTRUE(italic)) { - tabularray_cmd <- c(tabularray_cmd, "\\textit") - arguments$italic <- list( - bootstrap = "font-style: italic" - ) - } - if (isTRUE(underline)) { - tabularray_cmd <- c(tabularray_cmd, "\\tinytableTabularrayUnderline") - arguments$italic <- list( - bootstrap = "text-decoration: underline" - ) - } - if (isTRUE(strikeout)) { - tabularray_cmd <- c(tabularray_cmd, "\\tinytableTabularrayStrikeout") - arguments$italic <- list( - bootstrap = "text-decoration: line-through" - ) - } - if (isTRUE(monospace)) { - tabularray_cmd <- c(tabularray_cmd, "\\texttt") - arguments$monospace <- list( - bootstrap = "font-family: monospace" - ) - } - if (is.numeric(fontsize)) { - arguments$monospace <- list( - tabularray = sprintf("font=\\fontsize{%s}{%s}\\selectfont", fontsize, fontsize + 2), - bootstrap = sprintf("font-size: %s;", paste0(1.33333 * fontsize, "px")) - ) - } - if (!is.null(align)) { - arguments$align <- list( - tabularray = sprintf("halign=%s", align), - bootstrap = paste("text-align:", switch(align, r = "right", l = "left", c = "center")) - ) + # fill missing indices + if (missing(i)) i <- seq_len(attr(x, "nrow")) + if (missing(j)) j <- seq_len(attr(x, "ncol")) + assert_integerish(i, lower = 0, upper = attr(x, "nrow")) + assert_integerish(j, lower = 1, upper = attr(x, "ncol")) + + + if (component == "cell") { + idx <- expand.grid(i = i, j = j) + } else if (component == "row") { + idx <- data.frame(i = i) + } else if (component == "col") { + idx <- data.frame(j = j) + } + + # do not style header by default. JS index starts at 0 + if (inherits(x, "tinytable_tabularray") && "i" %in% colnames(idx)) { + idx$i <- idx$i + attr(x, "nhead") + } + + bootstrap <- list( + if (isTRUE(bold)) "font-weight: bold" else NULL, + if (isTRUE(italic)) "font-style: italic" else NULL, + if (isTRUE(underline)) "text-decoration: underline" else NULL, + if (isTRUE(strikeout)) "text-decoration: line-through" else NULL, + if (isTRUE(monospace)) "font-family: monospace" else NULL, + if (is.numeric(fontsize)) sprintf("font-size: %s", paste0(1.33333 * fontsize, "px")) else NULL, + if (!is.null(align)) paste("text-align:", switch(align, r = "right", l = "left", c = "center")) else NULL, + if (!is.null(color)) paste0("color: ", color) else NULL, + if (!is.null(background)) paste0("background-color: ", background) else NULL, + if (!is.null(width)) paste("width:%s", width) else NULL + ) + bootstrap <- do.call("cbind", bootstrap) + if (!is.null(bootstrap)) { + bootstrap <- apply(bootstrap, 1, paste, collapse = "; ") + bootstrap <- paste0(bootstrap, ";") + } else { + bootstrap <- "" } - if (!is.null(colspan)) { - arguments$colspan <- list( - tabularray = paste0("c=", colspan), - bootstrap = "" - ) + + # apply style to bootstrap + for (k in seq_len(nrow(idx))) { + out <- style_bootstrap(out, i = idx$i[k], j = idx$j[k], css = bootstrap_css) + out <- style_bootstrap(out, i = idx$i[k], j = idx$j[k], css = bootstrap) } - if (!is.null(color)) { - if (inherits(x, "tinytable_tabularray") && isTRUE(grepl("^#", color))) { - color_latex <- sub("^#", "c", color) - out <- style_tabularray(out, - body = sprintf( - "\\tinytableDefineColor{%s}{HTML}{%s}", - color_latex, sub("^#", "", color)) - ) - } else { - color_latex <- color + + if (inherits(x, "tinytable_tabularray") && !is.null(color) && any(grepl("^#", color))) { + color_latex <- color + for (k in seq_along(color)) { + if (grepl("^#", color[k])) { + color_latex[k] <- gsub("^#", "c", color[k]) + out <- style_tabularray(out, + body = sprintf( + "\\tinytableDefineColor{%s}{HTML}{%s}", + color_latex[k], sub("^#", "", color[k])) + ) + } } - arguments$color <- list( - tabularray = paste0("fg=", color_latex), - bootstrap = paste0("color: ", color) - ) - } - if (!is.null(background)) { - arguments$background <- list( - tabularray = paste0("bg=", background), - bootstrap = paste0("background-color: ", background) - ) - } - if (!is.null(width)) { - arguments$width <- list( - tabularray = sprintf("wd={%s}", width), - bootstrap = paste("width:%s", width) - ) - } - if (indent > 0) { - arguments$indent <- list( - tabularray = sprintf("preto={\\hspace{%sem}}", indent), - bootstrap = sprintf("text-indent: %sem", indent) - ) - } - if (inherits(x, "tinytable_bootstrap")) { - css <- sapply(arguments, function(x) x[["bootstrap"]]) - css <- paste(css, collapse = "; ") - out <- style_bootstrap(out, i, j, css = css) + } else { + color_latex <- color + } + + tabularray <- list( + if (is.numeric(fontsize)) sprintf("font=\\fontsize{%s}{%s}\\selectfont", fontsize, fontsize + 2) else NULL, + if (!is.null(align)) sprintf("halign=%s", align) else NULL, + if (!is.null(background)) sprintf("bg=%s", background) else NULL, + if (!is.null(color)) sprintf("fg=%s", color_latex) else NULL, + if (!is.null(width)) sprintf("wd={%s}", width) else NULL, + if (indent > 0) sprintf("preto={\\hspace{%sem}}", indent) else NULL + ) + + tabularray <- do.call("cbind", tabularray) + if (!is.null(tabularray)) { + tabularray <- apply(tabularray, 1, paste, collapse = ", ") + tabularray <- paste0(tabularray, ",") + } else { + tabularray <- "" + } + + tabularray_cmd <- list( + if (isTRUE(bold)) "\\bfseries" else NULL, + if (isTRUE(italic)) "\\textit{}" else NULL, + if (isTRUE(underline)) "\\tinytableTabularrayUnderline" else NULL, + if (isTRUE(strikeout)) "\\tinytableTabularrayStrikeout" else NULL, + if (isTRUE(monospace)) "\\texttt{}" else NULL + ) + tabularray_cmd <- do.call("cbind", tabularray_cmd) + if (is.null(tabularray_cmd)) { + tabularray_cmd <- "" + } else { + tabularray_cmd <- apply(tabularray_cmd, 1, paste, collapse = "") } + if (tabularray_cmd != "") tabularray_cmd <- sprintf("cmd=%s,", tabularray_cmd) + tabularray <- paste(tabularray, tabularray_cmd) - tabularray <- sapply(arguments, function(x) x[["tabularray"]]) - # important for things like colspan - tabularray <- Filter(function(x) !is.null(x), tabularray) + # vectorized settings with a unique entry + if (length(tabularray) == 1) { + tabularray <- rep(tabularray, nrow(idx)) + } - + # Apply Tabularray command if (any(c("colspan", "rowspan") %in% names(tabularray))) { span <- tabularray[names(tabularray) %in% c("colspan", "rowspan")] span <- paste(span, collapse = ",") @@ -193,44 +203,30 @@ style_tt <- function( span <- "" } - tabularray <- paste0(paste(tabularray, collapse = ","), ",") - - if (length(tabularray_cmd) > 0) { - tabularray_cmd <- paste0("cmd=", paste(tabularray_cmd, collapse = "")) - tabularray <- paste(tabularray, tabularray_cmd, sep = ",") - } - - if (tabularray == ",") tabularray <- "" - - if (inherits(x, "tinytable_tabularray")) { - # specified columns or all cells - if (missing(i)) { - if (missing(j)) { - j <- seq_len(attr(x, "ncol")) + for (k in seq_len(nrow(idx))) { + if (component == "cell") { + # R is column-major + spec <- sprintf("cell{%s}{%s}={%s}{%s},", + # do not style header by default + idx$i[k], + idx$j[k], + span, + tabularray[k]) + } else if (component == "row") { + spec <- sprintf("row{%s}={%s},", + # do not style header by default + idx$i[k], + tabularray[k]) + } else if (component == "col") { + spec <- sprintf("column{%s}={%s},", + idx$j[k], + tabularray[k]) } - colspec <- sprintf("column{%s}={%s},", paste(j, collapse = ","), tabularray) - out <- style_tabularray(out, inner = colspec) - - # specified rows - } else if (missing(j)) { - # do not style header by default - rowspec <- sprintf("row{%s}={%s},", paste(i + nhead, collapse = ","), tabularray) - out <- style_tabularray(out, inner = rowspec) - - # specified cells - } else { - cellspec <- sprintf("cell{%s}{%s}={%s}{%s},", - # do not style header by default - paste(i + nhead, collapse = ","), - paste(j, collapse = ","), - span, - tabularray) - out <- style_tabularray(out, inner = cellspec) + out <- style_tabularray(out, inner = spec) } } - # Manual settings if (!is.null(tabularray_inner) || !is.null(tabularray_outer)) { out <- style_tabularray(out, inner = tabularray_inner, outer = tabularray_outer) @@ -239,6 +235,5 @@ style_tt <- function( out <- style_bootstrap(out, i = i, j = j, css = bootstrap_css, css_rule = bootstrap_css_rule) } - return(out) } diff --git a/R/tt_tabularray.R b/R/tt_tabularray.R index c77338ec..257efe28 100644 --- a/R/tt_tabularray.R +++ b/R/tt_tabularray.R @@ -17,7 +17,6 @@ tt_tabularray <- function(x, caption, theme, width, notes) { if (!is.null(colnames(x))) { header <- paste(colnames(x), collapse = " & ") header <- paste(header, "\\\\") - nrows <- nrows + 1 } else { header <- NULL } diff --git a/vignettes/tutorial.qmd b/vignettes/tutorial.qmd index a60f5389..d95bf07a 100644 --- a/vignettes/tutorial.qmd +++ b/vignettes/tutorial.qmd @@ -179,11 +179,11 @@ dat <- data.frame(Math = c("\\( x^2 + y^2 = z^2 \\)", "\\( \\frac{1}{2} \\)")) tt(dat, align = "c") ``` +```{r, eval = knitr::is_latex_output()} In LaTeX (PDF), you can also use the `mode` inner setting from `tabularray` to render math in tables without delimiters (see @sec-tabularray for details on `tabularray`): -```{r, eval = knitr::is_latex_output()} dat <- data.frame(Math = c("x^2 + y^2 = z^2", "\\frac{1}{2}")) -tt(dat) |> style_tt(tabularray_inner = "column{1}={mode=math},") +tt(dat, align = "c") |> style_tt(tabularray_inner = "column{1}={mode=math},") ``` # Style @@ -490,7 +490,7 @@ css_rule <- " } " -tt(x, align = "ccccc", theme = "table mytable") |> +tt(x, align = "ccccc", theme = "table mytable", width = 2/3) |> style_tt(bootstrap_css_rule = css_rule) ```