Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Package: tinytable
Type: Package
Title: Simple and Configurable Tables in 'HTML', 'LaTeX', 'Markdown', 'Word', 'PNG', 'PDF', and 'Typst' Formats
Description: Create highly customized tables with this simple and dependency-free package. Data frames can be converted to 'HTML', 'LaTeX', 'Markdown', 'Word', 'PNG', 'PDF', or 'Typst' tables. The user interface is minimalist and easy to learn. The syntax is concise. 'HTML' tables can be customized using the flexible 'Bootstrap' framework, and 'LaTeX' code with the 'tabularray' package.
Version: 0.17.0.2
Version: 0.17.0.3
Imports:
methods
Depends:
Expand Down
13 changes: 11 additions & 2 deletions R/build_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,26 @@ build_tt <- function(x, output = NULL) {

x@style_other <- rect

# apply style_tt() and theme_*() after all group operations
# apply style_tt() and theme_*() after all group operations.
# style_tt_lazy() exposes only the current call's settings frame in @style;
# collect those frames here and rbind() them once. This replaces the previous
# pattern where every style_tt() call grew @style with an incremental rbind(),
# an O(N^2) cost that dominated on tables with many style_tt() calls.
lazy_style <- x@lazy_style
x@lazy_style <- list()

for (p in lazy_style) {
style_frames <- vector("list", length(lazy_style))
for (k in seq_along(lazy_style)) {
p <- lazy_style[[k]]
o <- attr(p, "output")
if (is.null(o) || x@output %in% o) {
p[["x"]] <- x
x <- eval(p)
if (nrow(x@style) > 0L) style_frames[[k]] <- x@style
}
}
style_frames <- style_frames[!vapply(style_frames, is.null, logical(1))]
x@style <- if (length(style_frames)) do.call(rbind, style_frames) else data.frame()

# Fix colspan that exceeds column count after lazy styles are evaluated
if (nrow(x@style) > 0) {
Expand Down
2 changes: 2 additions & 0 deletions R/expand_style.R
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ append_lines_to_rect <- function(style_lines, style_row, rect) {
#'
#' This is functionally equivalent to (and produces value-identical output as)
#' the per-row loop:
#' ```r
#' for (idx in seq_len(nrow(x@style))) {
#' style_other <- apply_style_to_rect(style_other, x@style[idx,])
#' style_lines <- append_lines_to_rect(style_lines, x@style[idx,], rect)
#' }
#' ```
#' but is O(N + cells) instead of O(N * cells * props) by avoiding the per-row
#' full-rect mask scan. The naive loop becomes the dominant bottleneck once a
#' table accumulates more than a few hundred style_tt() entries (which is
Expand Down
21 changes: 10 additions & 11 deletions R/style_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ style_tt_lazy <- function(
...) {

out <- x
# Each lazy call exposes only its own settings frame for build_tt() to
# collect. In particular, notes and caption styling return early below and
# must not expose the preceding call's frame again.
out@style <- data.frame()

# Set default line_color if NULL
if (is.null(line_color) && !is.null(line)) {
Expand Down Expand Up @@ -340,14 +344,12 @@ style_tt_lazy <- function(
cols <- unique(c("i", "j", sort(colnames(settings))))
settings <- settings[, cols, drop = FALSE]

# Only add settings if there are rows to add
if (nrow(settings) > 0) {
if (nrow(out@style) == 0) {
out@style <- settings
} else {
out@style <- rbind(out@style, settings)
}
}
# Expose this call's settings frame in @style. build_tt() collects the
# per-call frames and rbind()s them once at the end of the lazy loop, instead
# of growing @style with an incremental rbind() on every style_tt() call.
# That per-call rbind() was O(N^2) and dominated the lazy-style evaluation
# phase on tables with many style_tt() calls (e.g. per-cell heat-maps).
out@style <- settings

if (is.function(finalize)) {
out@lazy_finalize <- c(out@lazy_finalize, list(finalize))
Expand Down Expand Up @@ -549,7 +551,6 @@ assert_style_tt <- function(
#' @template limitations_word_markdown
#' @export
#' @examplesIf knitr::is_html_output()
#' @examples
#' if (knitr::is_html_output()) options(tinytable_print_output = "html")
#'
#' library(tinytable)
Expand Down Expand Up @@ -725,5 +726,3 @@ style_tt <- function(
return(x)
}



2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ tt(x,

## Tutorial

The `tinytable` 0.16.0.14 tutorial will take you much further. It is
The `tinytable` 0.17.0.2 tutorial will take you much further. It is
available in HTML and PDF formats at:
<https://vincentarelbundock.github.io/tinytable/>

Expand Down
21 changes: 21 additions & 0 deletions inst/tinytest/test-style.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ expect_snapshot_print(t[["typst"]], "style-smallcap.typ")
expect_snapshot_print(t[["markdown"]], "style-smallcap.md")


# Caption and notes styles must not duplicate the preceding cell style frame
tab <- tt(
data.frame(a = 1:2),
caption = "Caption",
notes = "Note") |>
style_tt(i = 1, line = "b", line_color = "red", line_width = 0.123) |>
style_tt(i = "caption", bold = TRUE) |>
style_tt(i = "notes", italic = TRUE)
tab <- tinytable:::build_tt(tab, output = "typst")
user_lines <- tab@style_lines[
tab@style_lines$line_color == "red" & tab@style_lines$line_width == 0.123,
,
drop = FALSE]
expect_equal(nrow(user_lines), 1L)
line_matches <- gregexpr(
'stroke: 0.123em + rgb("#FF0000")',
tab@table_string,
fixed = TRUE)[[1]]
expect_equal(sum(line_matches > 0L), 1L)


# partial align
tab <- tt(mtcars[1:5, 1:6]) |> style_tt(j = c(2, 4), align = "cr")
t <- expect_table(tab)
Expand Down
3 changes: 2 additions & 1 deletion man/style_tt.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading