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

format_tt initial #73

Merged
merged 7 commits into from
Jan 17, 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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ help: ## Display this help screen
check: ## check
Rscript -e "devtools::document();devtools::check()"

document: ## document
Rscript -e "devtools::document()"

test: ## test
Rscript -e "devtools::install();library(tinytable);tinytest::run_test_dir()"

Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Generated by roxygen2: do not edit by hand

S3method(print,tinytable)
export(format_tt)
export(group_tt)
export(knit_print.tinytable)
export(save_tt)
Expand Down
168 changes: 168 additions & 0 deletions R/format_tt.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# output is selected automatically if format_tt is called in tt()
# x is inserted automatically if format_tt is called in tt()


#' Format columns of a data frame
#'
#' This function formats the columns of a data frame based on the column type (logical, date, numeric).
#' It allows various formatting options like significant digits, decimal points, and scientific notation.
#' It also includes custom formatting for date and boolean values.
#'
#' @param x A data frame or a vector to be formatted.
#' @param digits Number of significant digits or decimal places.
#' @param num_fmt The format for numeric values; one of 'significant', 'decimal', or 'scientific'.
#' @param num_zero Logical; if TRUE, trailing zeros are kept in "decimal" format (but not in "significant" format).
#' @param num_mark_big Character to use as a thousands separator.
#' @param num_mark_dec Decimal mark character. Default is the global option 'OutDec'.
#' @param num_suffix Logical; if TRUE display short numbers with `digits` significant digits and K (thousands), M (millions), B (billions), or T (trillions) suffixes.
#' @param sprintf String passed to the `?sprintf` function to format numbers or interpolate strings with a user-defined pattern (similar to the `glue` package, but using Base R).
#' @param url Logical; if TRUE, treats the column as a URL.
#' @param date A string passed to the `format()` function, such as "%Y-%m-%d". See the "Details" section in `?strptime`
#' @param bool A function to format logical columns. Defaults to title case.
#' @param other A function to format columns of other types. Defaults to identity (no formatting).
#' @inheritParams tt
#' @inheritParams style_tt
#'
#' @return A data frame with formatted columns.
#' @export
format_tt <- function(x = NULL,
j = NULL,
output = NULL,
digits = getOption("digits"),
num_fmt = "significant",
num_zero = TRUE,
num_suffix = FALSE,
num_mark_big = "",
num_mark_dec = getOption("OutDec", default = "."),
sprintf = NULL,
url = FALSE,
date = "%Y-%m-%d",
bool = function(column) tools::toTitleCase(tolower(column)),
other = identity
) {

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

if (isTRUE(check_atomic_vector(x))) {
atomic_vector <- TRUE
x <- data.frame(tinytable = x)
j <- 1
} else {
atomic_vector <- FALSE
}

if (!inherits(x, "data.frame")) {
msg <- "`x` must be a data frame or an atomic vector."
stop(msg, call. = FALSE)
}

assert_data_frame(x)
assert_integerish(digits, len = 1)
assert_choice(num_fmt, c("significant", "decimal", "scientific"))
assert_flag(num_zero)
assert_string(num_mark_big)
assert_string(num_mark_dec)
assert_flag(url)
assert_string(date)
assert_function(bool)
assert_function(identity)
assert_string(sprintf, null.ok = TRUE)

output <- sanitize_output(output)

# column index NULL or regex or integer vector
if (is.null(j)) {
j <- seq_len(ncol(x))
} else if (is.character(j) && length(j) == 1 && !is.null(names(x))) {
j <- grep(j, colnames(x), perl = TRUE)
} else {
assert_integerish(j, lower = 1, upper = ncol(x))
}

# format each column
for (col in j) {

# sprintf() is self-contained
if (!is.null(sprintf)) {
x[[col]] <- base::sprintf(sprintf, x[[col]])

} else {

# logical
if (is.logical(x[[col]])) {
x[[col]] <- bool(x[[col]])

# date
} else if (inherits(x[[col]], "Date")) {
x[[col]] <- format(x[[col]], date)

# numeric
} else if (is.numeric(x[[col]]) && !is.null(digits)) {

# numeric suffix
if (isTRUE(num_suffix)) {
x[[col]] <- format_num_suffix(x[[col]], digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero)

# non-integer numeric
} else if (is.numeric(x[[col]]) && !isTRUE(check_integerish(x[[col]]))) {
if (num_fmt == "significant") {
x[[col]] <- format(x[[col]],
digits = digits, drop0trailing = !num_zero,
big.mark = num_mark_big, decimal.mark = num_mark_dec,
scientific = FALSE)

} else if (num_fmt == "decimal") {
x[[col]] <- formatC(x[[col]],
digits = digits, format = "f", drop0trailing = !num_zero,
big.mark = num_mark_big, decimal.mark = num_mark_dec)

if (num_fmt == "scientific") {
x[[col]] <- formatC(x[[col]],
digits = digits, format = "e", drop0trailing = !num_zero,
big.mark = num_mark_big, decimal.mark = num_mark_dec)
}
}

# integer
} else if (isTRUE(check_integerish(x[[col]]))) {
if (num_fmt == "scientific") {
x[[col]] <- formatC(x[[col]],
digits = digits, format = "e", drop0trailing = !num_zero,
big.mark = num_mark_big, decimal.mark = num_mark_dec)
}
}

} else {
x[[col]] <- other(x[[col]])
}

}

} # loop over columns

if (isTRUE(atomic_vector)) {
return(x[[1]])
} else {
return(x)
}

}



format_num_suffix <- function(x, digits, num_mark_big, num_mark_dec, num_zero) {
suffix <- number <- rep("", length(x))
suffix <- ifelse(x > 1e3, "K", suffix)
suffix <- ifelse(x > 1e6, "M", suffix)
suffix <- ifelse(x > 1e9, "B", suffix)
suffix <- ifelse(x > 1e12, "T", suffix)
number <- format_tt(x, num_fmt = "decimal", digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero)
number <- ifelse(x > 1e3, format_tt(x / 1e3, num_fmt = "decimal", digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero), number)
number <- ifelse(x > 1e6, format_tt(x / 1e6, num_fmt = "decimal", digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero), number)
number <- ifelse(x > 1e9, format_tt(x / 1e9, num_fmt = "decimal", digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero), number)
number <- ifelse(x > 1e12, format_tt(x / 1e12, num_fmt = "decimal", digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero), number)
number <- paste0(number, suffix)
return(number)
}
21 changes: 21 additions & 0 deletions R/sanity.R
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,24 @@ assert_list <- function(x, named = FALSE, null.ok = FALSE, name = as.character(s
}
}
}


assert_function <- function(x, null.ok = FALSE, name = as.character(substitute(x))) {
if (isTRUE(null.ok) && is.null(x)) return(invisible(TRUE))
if (!is.function(x)) {
msg <- sprintf("`%s` must be a function.", name)
stop(msg, call. = FALSE)
}
}

check_atomic_vector<- function(x, null.ok = FALSE, name = as.character(substitute(x))) {
if (isTRUE(null.ok) && is.null(x)) return(invisible(TRUE))
flag <- is.atomic(x) && is.vector(x) && !is.list(x)
if (flag) {
out <- TRUE
} else {
out <- sprintf("`%s` must be an atomic vector.", name)
}
return(out)
}

8 changes: 8 additions & 0 deletions R/tt.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#'
#' @param x A data frame or data table to be rendered as a table.
#' @param output The format of the output table. Can be "html", "latex", or "markdown". If NULL, the format is automatically detected in Quarto or Rmarkdown documents.
#' @param digits Number of significant digits to keep for numeric variables. When `digits` is an integer, `tt()` calls `format_tt(x, digits = digits)` before proceeding to draw the table. Users who need more control can proceed in two steps: (1) format the data with `format_tt()` or other functions, and (2) pass the formatted data to `tt()` for drawing. See `?format_tt` for more details on formating options (ex: decimal, scientific notation, dates, boolean variables, etc.).
#' @param align A string specifying the alignment of columns. Each character in the string corresponds to a column; 'l' for left, 'c' for center, and 'r' for right alignment. The length of the string must match the number of columns in `x`.
#' @param caption A string that will be used as the caption of the table.
#' @param width A numeric value between 0 and 1 indicating the proportion of the line width that the table should cover.
Expand Down Expand Up @@ -32,6 +33,7 @@
#' @export
tt <- function(x,
output = NULL,
digits = getOption("digits"),
align = NULL,
caption = NULL,
width = NULL,
Expand All @@ -45,7 +47,13 @@ tt <- function(x,
assert_string(caption, null.ok = TRUE)
assert_string(align, null.ok = TRUE)
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)
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


<p align="center">
<img src="man/figures/tinytable_logo.svg" height = "250" class = "center">
</p>
Expand Down
6 changes: 6 additions & 0 deletions README.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@









<p align="center">
<img src="man/figures/tinytable_logo.svg" height = "250" class = "center">
</p>
Expand Down
Binary file modified inst/tinytest/_tinysnapshot/html-heatmap.rds
Binary file not shown.
Binary file modified inst/tinytest/_tinysnapshot/html-issue58.rds
Binary file not shown.
Binary file modified inst/tinytest/_tinysnapshot/html-striped.rds
Binary file not shown.
Binary file modified inst/tinytest/_tinysnapshot/html-striped_orange.rds
Binary file not shown.
Binary file modified inst/tinytest/_tinysnapshot/html-vectorized_color_j.rds
Binary file not shown.
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-align.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ cell{1}{5}={}{halign=r,},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-cell_color.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ cell{3}{4}={}{,fg=orange,},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-col_color.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ column{4}={,fg=orange,},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ row{even}={bg=black!5!white},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-group_style_order.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ cell{1}{3}={c=2,}{halign=c,},
\toprule
blah & & bar & \\ \cmidrule[lr]{1-2}\cmidrule[lr]{3-4}
mpg & cyl & disp & hp \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 \\
21 & 6 & 160 & 110 \\
22.8 & 4 & 108 & 93 \\
21.0 & 6 & 160 & 110 \\
21.0 & 6 & 160 & 110 \\
22.8 & 4 & 108 & 93 \\
21.4 & 6 & 258 & 110 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-nohead.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
colspec={Q[]Q[]Q[]Q[]Q[]},
} %% tabularray inner close
\toprule
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-row_color.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ row{5}={,fg=orange,},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-theme_grid.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ colspec={Q[]Q[]Q[]Q[]Q[]},
hlines={},vlines={},
} %% tabularray inner close
mpg & cyl & disp & hp & drat \\
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\end{tblr}
\end{table}
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-theme_striped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ row{even}={bg=black!5!white},
} %% tabularray inner close
\toprule
mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\bottomrule
\end{tblr}
Expand Down
6 changes: 3 additions & 3 deletions inst/tinytest/_tinysnapshot/latex-theme_void.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
colspec={Q[]Q[]Q[]Q[]Q[]},
} %% tabularray inner close
mpg & cyl & disp & hp & drat \\
21 & 6 & 160 & 110 & 3.9 \\
21 & 6 & 160 & 110 & 3.9 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.0 & 6 & 160 & 110 & 3.90 \\
21.0 & 6 & 160 & 110 & 3.90 \\
22.8 & 4 & 108 & 93 & 3.85 \\
21.4 & 6 & 258 & 110 & 3.08 \\
\end{tblr}
\end{table}
Loading