Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy format #81

Merged
merged 5 commits into from
Jan 18, 2024
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
39 changes: 39 additions & 0 deletions R/build_tt.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# internal function
# style_tt() stores style calls and we only want to evaluate them at the end because
# some rows may be added, which changes how the style is applied
build_tt <- function(x) {
m <- meta(x)

out <- x

# format data before drawing the table
for (l in m$lazy_format) {
tmp <- out
class(tmp) <- "data.frame"
l[["x"]] <- tmp
out <- eval(l)
}

# draw the table
lazy_tt <- meta(x, "lazy_tt")
lazy_tt[["x"]] <- out
out <- eval(lazy_tt)

# group the table (before style)
for (l in m$lazy_group) {
l[["x"]] <- out
out <- eval(l)
}

# style the table
for (l in m$lazy_style) {
l[["x"]] <- out
out <- eval(l)
}

m <- meta(x)
m$lazy_style <- list()
attr(out, "tinytable_meta") <- m

return(out)
}
57 changes: 53 additions & 4 deletions R/format_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#' num_mark_big = " ")
#' tt(tab)
#'
format_tt <- function(x = NULL,
format_tt <- function(x,
j = NULL,
output = NULL,
digits = getOption("digits"),
Expand All @@ -51,9 +51,59 @@ format_tt <- function(x = NULL,
other = identity
) {

if (inherits(x, "tinytable")) {
msg <- "`format_tt()` must be called *before* `tt()`. You must format your dataset before drawing a table."
out <- x

if (inherits(out, "tinytable")) {
cal <- call("format_tt_lazy",
j = j,
output = output,
digits = digits,
num_fmt = num_fmt,
num_zero = num_zero,
num_suffix = num_suffix,
num_mark_big = num_mark_big,
num_mark_dec = num_mark_dec,
sprintf = sprintf,
url = url,
date = date,
bool = bool,
other = other)
out <- meta(out, "lazy_format", c(meta(out)$lazy_format, list(cal)))
} else {

out <- format_tt_lazy(out,
j = j,
output = output,
digits = digits,
num_fmt = num_fmt,
num_zero = num_zero,
num_suffix = num_suffix,
num_mark_big = num_mark_big,
num_mark_dec = num_mark_dec,
sprintf = sprintf,
url = url,
date = date,
bool = bool,
other = other)
}
return(out)
}

format_tt_lazy <- function(x,
j = NULL,
output = NULL ,
digits,
num_fmt = "significant",
num_zero = FALSE,
num_suffix = FALSE,
num_mark_big = "",
num_mark_dec = NULL,
sprintf = NULL,
url = FALSE,
date = "%Y-%m-%d",
bool = identity,
other = identity
) {

if (isTRUE(check_atomic_vector(x))) {
atomic_vector <- TRUE
Expand Down Expand Up @@ -93,7 +143,6 @@ format_tt <- function(x = NULL,

# format each column
for (col in j) {

# sprintf() is self-contained
if (!is.null(sprintf)) {
x[[col]] <- base::sprintf(sprintf, x[[col]])
Expand Down
33 changes: 12 additions & 21 deletions R/group_tabularray.R
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
group_tabularray <- function(x, i, j, indent, ...) {
group_tabularray <- function(x, i, j, indent) {
out <- x
# columns first to count headers properly
if (!is.null(j)) {
out <- group_tabularray_col(out, j, ...)
out <- group_tabularray_col(out, j)
}
if (!is.null(i)) {
out <- group_tabularray_row(out, i, indent, ...)
out <- group_tabularray_row(out, i, indent)
}
return(out)
}


group_tabularray_col <- function(x, j, ...) {
group_tabularray_col <- function(x, j) {

m <- meta(x)

dots <- list(...)

out <- strsplit(x, split = "\\n")[[1]]

header <- rep("", m$ncols)
Expand Down Expand Up @@ -46,16 +44,14 @@ group_tabularray_col <- function(x, j, ...) {

for (k in seq_along(j)) {
z <- min(j[[k]])
args <- list(x = out,
args <- list(tt_build_now = TRUE,
x = out,
# the new header is always first row and
# style_tt always adds nhead to index
i = 1 - meta(out)$nhead,
j = z,
align = "c",
colspan = max(j[[k]]) - min(j[[k]]) + 1)
if (!"halign" %in% names(dots)) {
args["align"] <- "c"
}
args <- c(args, dots)
out <- do.call(style_tt, args)
}

Expand All @@ -64,7 +60,7 @@ group_tabularray_col <- function(x, j, ...) {
}


group_tabularray_row <- function(x, i, indent, ...) {
group_tabularray_row <- function(x, i, indent) {

m <- meta(x)

Expand All @@ -73,12 +69,13 @@ group_tabularray_row <- function(x, i, indent, ...) {
}
label <- names(i)

m$nrows <- m$nrows + length(label)
tab <- strsplit(x, "\\n")[[1]]

# store the original body lines when creating the table, and use those to guess the boundaries.
# a hack, but probably safer than most regex approaches I can think of.
body <- which(tab %in% m$body)
body_min <- max(grep("TinyTableHeader|toprule|inner close", tab)) + 1
body_max <- min(grep("bottomrule|end.tblr", tab))
body <- body_min:body_max
top <- tab[1:(min(body) - 1)]
mid <- tab[min(body):max(body)]
bot <- tab[(max(body) + 1):length(tab)]
Expand Down Expand Up @@ -107,16 +104,10 @@ group_tabularray_row <- function(x, i, indent, ...) {
# we also want to indent the header
i <- idx$new[!is.na(idx$old)] + m$nhead
if (m$nhead > 0) i <- c(1:m$nhead, i)
cellspec <- sprintf("cell{%s}{%s}={%s},", i, 1, sprintf("preto={\\hspace{%sem}}", indent))
cellspec <- sprintf("cell{%s}{%s}={%s},\n", i, 1, sprintf("preto={\\hspace{%sem}}", indent))
cellspec <- paste(cellspec, collapse = "")
tab <- tabularray_insert(tab, content = cellspec, type = "inner")

dots <- list(...)
if (length(dots) > 0) {
args <- c(list(x = tab, i = idx$new[is.na(idx$old)]), dots)
tab <- do.call(style_tt, args)
}

return(tab)
}

Expand Down
9 changes: 5 additions & 4 deletions R/group_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
#' @inheritParams tt
#' @inheritParams style_tt
#' @param indent integer number of `pt` to use when indenting the non-labelled rows.
#' @param ... All additional arguments (ex: `italic`, `bold`, `color`) are automatically passed to the `style_tt()` function and applied to the labels.
group_tt <- function(x, i = NULL, j = NULL, indent = 1, ...) {
group_tt <- function(x, i = NULL, j = NULL, indent = 1) {

if (is.null(meta(x))) stop("`x` must be generated by `tinytable::tt()`.", call. = FALSE)
if (!isTRUE(meta(x, "output") %in% c("html", "latex"))) return(x)
Expand All @@ -24,11 +23,13 @@ group_tt <- function(x, i = NULL, j = NULL, indent = 1, ...) {
i <- unlist(i)

if (meta(out)$output == "latex") {
out <- group_tabularray(out, i = i, j = j, indent = indent, ...)
cal <- call("group_tabularray", i = i, j = j, indent = indent)
} else if (meta(out)$output == "html") {
out <- group_bootstrap(out, i = i, j = j, indent = indent, ...)
cal <- call("group_bootstrap", i = i, j = j, indent = indent)
}

out <- meta(out, "lazy_group", c(meta(out)$lazy_group, list(cal)))

return(out)
}

Expand Down
4 changes: 2 additions & 2 deletions R/print.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#' @export
knit_print.tinytable <- function(x, ...) {
# lazy styles get evaluated here, at the very end
out <- eval_style(x)
out <- build_tt(x)

if (meta(out)$output == "html") {
# from htmltools:::html_preserve
Expand All @@ -25,7 +25,7 @@ knit_print.tinytable <- function(x, ...) {
#' @export
print.tinytable <- function(x, ...) {
# lazy styles get evaluated here, at the very end
out <- eval_style(x)
out <- build_tt(x)

if (meta(out, "output") == "latex") {
class(out) <- "character"
Expand Down
2 changes: 1 addition & 1 deletion R/save_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ 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)
x <- build_tt(x)

if (file_ext %in% c("html", "tex", "md", "Rmd", "qmd", "txt")) {
write(x, file = filename)
Expand Down
11 changes: 9 additions & 2 deletions R/style_tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#' @param bootstrap_css_rule A string with complete CSS rules that apply to the table class specified using the `theme` argument of the `tt()` function.
#' @param tabularray_inner A string that specifies the "inner" settings of a tabularray LaTeX table.
#' @param tabularray_outer A string that specifies the "outer" settings of a tabularray LaTeX table.
#' @param ... extra arguments are ignored
#' @return Returns a modified `tinytable` object with the applied styles.
#' @template latex_preamble
#' @export
Expand Down Expand Up @@ -59,7 +60,9 @@ style_tt <- function (x,
tabularray_inner = NULL,
tabularray_outer = NULL,
bootstrap_css = NULL,
bootstrap_css_rule = NULL) {
bootstrap_css_rule = NULL,
...) {

out <- x
cal <- call("style_tt_lazy",
# out <- style_tt_lazy(
Expand All @@ -83,7 +86,11 @@ style_tt <- function (x,
bootstrap_css = bootstrap_css,
bootstrap_css_rule = bootstrap_css_rule)

out <- meta(out, "lazy_style", c(meta(out)$lazy_style, list(cal)))
if (isTRUE(list(...)[["tt_build_now"]])) {
out <- eval(cal)
} else {
out <- meta(out, "lazy_style", c(meta(out)$lazy_style, list(cal)))
}

return(out)
}
Expand Down
44 changes: 21 additions & 23 deletions R/tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#' @export
tt <- function(x,
output = NULL,
digits = getOption("digits"),
digits = NULL,
caption = NULL,
width = NULL,
notes = NULL,
Expand All @@ -49,45 +49,43 @@ tt <- function(x,
assert_numeric(width, len = 1, lower = 0, upper = 1, null.ok = TRUE)
assert_integerish(digits, len = 1, null.ok = TRUE)

# formatting options are limited here
if (!is.null(digits)) {
x <- format_tt(x, digits = digits)
}

# notes can be a single string or a (named) list of strings
if (is.character(notes) && length(notes)) {
notes <- list(notes)
}
assert_list(notes, null.ok = TRUE)

out <- x
# before style_tt() call for align
out <- x
out <- meta(out, "x_character", data.frame(lapply(x, as.character)))
out <- meta(out, "output", output)
out <- meta(out, "colnames", names(x))
out <- meta(out, "xdim", dim(x))
out <- meta(out, "output", output)
out <- meta(out, "id", get_id("tinytable_"))
out <- meta(out, "nhead", if (is.null(colnames(x))) 0 else 1)
out <- meta(out, "nrows", nrow(x))
out <- meta(out, "ncols", ncol(x))
class(out) <- c("tinytable", class(out))

# build table
if (output == "latex") {
out <- tt_tabularray(out, caption = caption, theme = theme, width = width, notes = notes)
cal <- call("tt_tabularray", x = out, caption = caption, theme = theme, width = width, notes = notes, placement = placement)

} else if (output == "html"){
out <- tt_bootstrap(out, caption = caption, theme = theme, width = width, notes = notes)
cal <- call("tt_bootstrap", x = out, caption = caption, theme = theme, width = width, notes = notes)

} else {
out <- tt_markdown(out, caption = caption)
cal <- call("tt_markdown", x = out, caption = caption)
}

# before style_tt() call for align
out <- meta(out, "colnames", names(x))
out <- meta(out, "xdim", dim(x))
out <- meta(out, "output", output)
out <- meta(out, "id", get_id("tinytable_"))
out <- meta(out, "nhead", if (is.null(colnames(x))) 0 else 1)
out <- meta(out, "nrows", nrow(x))
out <- meta(out, "ncols", ncol(x))
out <- meta(out, "lazy_style", list())
out <- meta(out, "lazy_tt", cal)

# placement
assert_string(placement, null.ok = TRUE)
if (!is.null(placement)) {
# dollar sign to avoid [H][H] when we style multiple times
out <- sub("\\\\begin\\{table\\}", sprintf("\\\\begin{table}[%s]\n", placement), out)
# formatting options are limited here
# after creating the table since the new lazy system
if (!is.null(digits)) {
out <- format_tt(out, digits = digits)
}

return(out)
Expand Down
2 changes: 2 additions & 0 deletions R/tt_bootstrap.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
tt_bootstrap <- function(x, caption, theme, width, notes) {

template <- template_bootstrap(theme)
m <- meta(x)


# caption
Expand Down Expand Up @@ -98,6 +99,7 @@ tt_bootstrap <- function(x, caption, theme, width, notes) {
out <- paste(template, collapse = "\n")

class(out) <- c("tinytable", "knit_asis", class(out))
attr(out, "tinytable_meta") <- m
return(out)
}

Expand Down
Loading