Skip to content

Commit

Permalink
export_as_txt refactoring (#124)
Browse files Browse the repository at this point in the history
paginate_listing hooked up to formatters machinery. pag_listing_indices defunct. Closes #96
---------

Co-authored-by: shajoezhu <[email protected]>
Co-authored-by: Gabriel Becker <[email protected]>
  • Loading branch information
3 people authored May 17, 2023
1 parent 2b765b6 commit 64710c5
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 399 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ License: Apache License 2.0
URL: https://github.com/insightsengineering/rlistings
BugReports: https://github.com/insightsengineering/rlistings/issues
Depends:
formatters (>= 0.4.0),
formatters (>= 0.4.1.9003),
methods,
tibble
Imports:
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ exportMethods(toString)
import(formatters)
import(methods)
import(tibble)
importFrom(formatters,export_as_txt)
importFrom(grDevices,dev.off)
importFrom(grDevices,pdf)
importFrom(grid,convertHeight)
Expand Down
148 changes: 2 additions & 146 deletions R/listing_export.R
Original file line number Diff line number Diff line change
@@ -1,46 +1,6 @@
#' Export as plain text with page break symbol
#'
#' @inheritParams paginate_listing
#' @param lst Listing object
#' @param file character(1). File to write.
#' @param page_type character(1). Name of a page type. See
#' `page_types`. Ignored when `pg_width` and `pg_height`
#' are set directly.
#' @param landscape logical(1). Should the dimensions of `page_type`
#' be inverted for landscape? Defaults to `FALSE`, ignored when
#' `pg_width` and `pg_height` are set directly.
#' @param font_family character(1). Name of a font family. An error
#' will be thrown if the family named is not monospaced. Defaults
#' to Courier.
#' @param font_size numeric(1). Font size, defaults to 8.
#' @param pg_width numeric(1). Page width in inches.
#' @param pg_height numeric(1). Page height in inches.
#' @param hsep character(1). Characters to repeat to create
#' header/body separator line.
#' @param indent_size numeric(1). Indent size in characters. Ignored
#' when `x` is already a MatrixPrintForm object in favor of information
#' there.
#' @param max_width integer(1), character(1) or NULL. Width that title
#' and footer (including footnotes) materials should be
#' word-wrapped to. If NULL, it is set to the current print width
#' of the session (`getOption("width")`). If set to `"auto"`,
#' the width of the table (plus any table inset) is used. Ignored
#' completely if `tf_wrap` is `FALSE`.
#' @param tf_wrap logical(1). Should the texts for title, subtitle,
#' and footnotes be wrapped?
#' @param paginate logical(1). Should \code{lst} be paginated before writing the file.
#' Defaults to `TRUE` if any sort of page dimension is specified.
#' @param \dots Passed directly to \code{\link{paginate_listing}}
#' @param page_break character(1). Page break symbol (defaults to outputting \code{"\\s"}).
#' @return \code{file} (this function is called for the side effect of writing the file.
#'
#' @note When specified, `font_size` is used *only* to determine pagination based
#' on page dimensions. The written file is populated in raw ASCII text, which
#' does not have the concept of font size.
#' @importFrom formatters export_as_txt
#'
#' @export
#'
#'
#' @examples
#'
#' dat <- ex_adae
Expand All @@ -52,108 +12,4 @@
#' main_footer(lsting) <- "this is some footer"
#' cat(export_as_txt(lsting, file = NULL, paginate = TRUE))
#'
export_as_txt <- function(lst, file = NULL,
page_type = NULL,
landscape = FALSE,
pg_width = page_dim(page_type)[if (landscape) 2 else 1],
pg_height = page_dim(page_type)[if (landscape) 1 else 2],
font_family = "Courier",
font_size = 8, # grid parameters
paginate = .need_pag(page_type, pg_width, pg_height, lpp, cpp),
cpp = NULL,
lpp = NULL,
..., page_break = "\\s\\n",
hsep = default_hsep(),
indent_size = 2,
tf_wrap = paginate,
max_width = cpp,
colwidths = propose_column_widths(matrix_form(lst, TRUE))) {

if (paginate) {
gp_plot <- gpar(fontsize = font_size, fontfamily = font_family)

pdf(file = tempfile(), width = pg_width, height = pg_height)
on.exit(dev.off())
grid.newpage()
pushViewport(plotViewport(margins = c(0, 0, 0, 0), gp = gp_plot))

cur_gpar <- get.gpar()
if (is.null(page_type) && is.null(pg_width) && is.null(pg_height) &&
(is.null(cpp) || is.null(lpp))) {
page_type <- "letter"
pg_width <- page_dim(page_type)[if (landscape) 2 else 1]
pg_height <- page_dim(page_type)[if (landscape) 1 else 2]
}

if (is.null(lpp)) {
lpp <- floor(convertHeight(unit(1, "npc"), "lines", valueOnly = TRUE) /
(cur_gpar$cex * cur_gpar$lineheight))
}
if (is.null(cpp)) {
cpp <- floor(convertWidth(unit(1, "npc"), "inches", valueOnly = TRUE) *
font_lcpi(font_family, font_size, cur_gpar$lineheight)$cpi)
}
if (tf_wrap && is.null(max_width)) {
max_width <- cpp
}

listings <- paginate_listing(lst,
page_type = page_type,
font_family = font_family,
font_size = font_size,
lineheight = cur_gpar$lineheight,
landscape = landscape,
pg_width = pg_width,
pg_height = pg_height,
lpp = lpp,
cpp = cpp,
colwidths = propose_column_widths(lst),
tf_wrap = tf_wrap,
max_width = max_width)
} else {
listings <- list(lst)
}

res <- paste(
mapply(
function(tb, ...) {
## 1 and +1 are because cwidths includes rowlabel 'column'
# cinds <- c(1, .figure_out_colinds(tb, lst) + 1L)
toString(tb, ...)
},
MoreArgs = list(hsep = hsep),
SIMPLIFY = FALSE,
tb = listings
),
collapse = page_break
)

if (!is.null(file)) {
cat(res, file = file)
} else {
res
}
}


.do_inset <- function(x, inset) {
if (inset == 0 || !any(nzchar(x))) {
return(x)
}
padding <- strrep(" ", inset)
if (is.character(x)) {
x <- paste0(padding, x)
} else if (is(x, "matrix")) {
x[, 1] <- .do_inset(x[, 1, drop = TRUE], inset)
}
x
}


.paste_no_na <- function(x, ...) {
paste(na.omit(x), ...)
}

.need_pag <- function(page_type, pg_width, pg_height, cpp, lpp) {
!(is.null(page_type) && is.null(pg_width) && is.null(pg_height) && is.null(cpp) && is.null(lpp))
}
formatters::export_as_txt
165 changes: 46 additions & 119 deletions R/paginate_listing.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@
paginate_listing <- function(lsting,
page_type = "letter",
font_family = "Courier",
font_size = 12,
font_size = 8,
lineheight = 1,
landscape = FALSE,
pg_width = NULL,
pg_height = NULL,
margins = c(top = .5, bottom = .5, left = .75, right = .75),
lpp,
cpp,
lpp = NA_integer_,
cpp = NA_integer_,
colwidths = propose_column_widths(lsting),
tf_wrap = FALSE,
tf_wrap = !is.null(max_width),
max_width = NULL,
verbose = FALSE) {
checkmate::assert_class(lsting, "listing_df")
Expand All @@ -62,133 +62,60 @@ paginate_listing <- function(lsting,
checkmate::assert_count(max_width, null.ok = TRUE)
checkmate::assert_flag(verbose)

if (missing(lpp) && missing(cpp) && !is.null(page_type) ||
(!is.null(pg_width) && !is.null(pg_height))) {
pg_lcpp <- page_lcpp(
page_type = page_type,
landscape = landscape,
font_family = font_family,
font_size = font_size,
lineheight = lineheight,
margins = margins,
pg_width = pg_width,
pg_height = pg_height
)
if (missing(lpp)) {
lpp <- pg_lcpp$lpp
}
if (missing(cpp)) {
cpp <- pg_lcpp$cpp
}
} else {
if (missing(cpp)) {
cpp <- NULL
}
if (missing(lpp)) {
lpp <- 70
}
}

if (is.null(colwidths)) {
colwidths <- propose_column_widths(matrix_form(lsting, indent_rownames = TRUE))
}

if (!tf_wrap) {
if (!is.null(max_width)) {
warning("tf_wrap is FALSE - ignoring non-null max_width value.")
}
max_width <- NULL
} else if (is.null(max_width)) {
max_width <- cpp
} else if (identical(max_width, "auto")) {
# this 3 is column separator width.
max_width <- sum(colwidths) + 3 * (length(colwidths) - 1)
}
if (!is.null(cpp) && !is.null(max_width) && max_width > cpp) {
warning("max_width specified is wider than characters per page width (cpp).")
}

# row-space pagination.
ret <- if (!is.null(lpp)) {
inds <- pag_listing_indices(
lsting = lsting,
lpp = lpp,
colwidths = colwidths,
verbose = verbose,
max_width = max_width
)
lapply(inds, function(i) lsting[i, ])
} else {
list(lsting)
}
indx <- paginate_indices(lsting,
page_type = page_type,
font_family = font_family,
font_size = font_size,
lineheight = lineheight,
landscape = landscape,
pg_width = pg_width,
pg_height = pg_height,
margins = margins,
lpp = lpp,
cpp = cpp,
colwidths = colwidths,
tf_wrap = tf_wrap,
max_width = max_width,
rep_cols = length(get_keycols(lsting)),
verbose = verbose)

# column-space pagination.
if (!is.null(cpp)) {
inds <- vert_pag_indices(
lsting,
cpp = cpp,
colwidths = colwidths,
verbose = verbose,
rep_cols = length(get_keycols(lsting))
)
dispcols <- listing_dispcols(lsting)
pag_cols <- lapply(inds, function(i) dispcols[i])
ret <- lapply(
ret,
function(oneres) {
lapply(
pag_cols,
function(cnames) {
ret <- oneres[, cnames, drop = FALSE]
listing_dispcols(ret) <- cnames
ret
}
)

vert_pags <- lapply(indx$pag_row_indices,
function(ii) lsting[ii, ])
dispnames <- listing_dispcols(lsting)
full_pag <- lapply(vert_pags,
function(onepag) {
if (!is.null(indx$pag_col_indices)) {
lapply(indx$pag_col_indices,
function(jj) {
res <- onepag[, dispnames[jj], drop = FALSE]
listing_dispcols(res) <- intersect(dispnames, names(res))
res
})
} else {
list(onepag)
}
)
ret <- unlist(ret, recursive = FALSE)
}
})

ret <- unlist(full_pag, recursive = FALSE)
ret
}

#' @rdname paginate
#' @title Defunct functions
#'
#' @description
#' These functions are defunct and their symbols will be removed entirely
#' in a future release.
#' @rdname defunct
#' @inheritParams paginate_listing
#' @export
pag_listing_indices <- function(lsting,
lpp = 15,
colwidths = NULL,
max_width = NULL,
verbose = FALSE) {
checkmate::assert_class(lsting, "listing_df")
checkmate::assert_numeric(colwidths, lower = 0, len = length(listing_dispcols(lsting)), null.ok = TRUE)
checkmate::assert_count(max_width, null.ok = TRUE)
checkmate::assert_flag(verbose)

dheight <- divider_height(lsting)
dcols <- listing_dispcols(lsting)
cinfo_lines <- max(
mapply(nlines, x = var_labels(lsting)[dcols], max_width = colwidths)
) + dheight
tlines <- if (any(nzchar(all_titles(lsting)))) {
length(all_titles(lsting)) + dheight + 1L
} else {
0
}
flines <- length(all_footers(lsting))
if (flines > 0) {
flines <- flines + dheight + 1L
}
rlpp <- lpp - cinfo_lines - tlines - flines
if (verbose) {
message("Adjusted Lines Per Page: ", rlpp, " (original lpp: ", lpp, ")")
}

pagdf <- make_row_df(lsting, colwidths)
pag_indices_inner(
pagdf = pagdf,
rlpp = rlpp,
min_siblings = 0,
verbose = verbose,
have_col_fnotes = FALSE,
div_height = dheight
)
.Defunct("paginate_indices", package = "formatters")
}
2 changes: 1 addition & 1 deletion R/rlistings.R
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ get_keycols <- function(df) {

#' @export
#' @inherit formatters::matrix_form
#' @seealso [formatters::matrix_form()]
#' @seealso [formatters::matrix_form()]
#' @param indent_rownames logical(1). Silently ignored, as listings do not have row names
#' nor indenting structure.
#'
Expand Down
Loading

0 comments on commit 64710c5

Please sign in to comment.