Skip to content
Draft
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
6 changes: 3 additions & 3 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ jobs:

- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
- {os: ubuntu-latest, r: 'oldrel-2'}
# - {os: ubuntu-latest, r: 'oldrel-1'}
# - {os: ubuntu-latest, r: 'oldrel-2'}
- {os: ubuntu-latest, r: 'oldrel-3'}
# - {os: ubuntu-latest, r: 'oldrel-4'}

Expand All @@ -57,4 +57,4 @@ jobs:
- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ URL: https://pharmaverse.github.io/gridify/
BugReports: https://github.com/pharmaverse/gridify/issues
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
Imports:
grDevices,
grid,
methods
Suggests:
flextable (>= 0.8.0),
jsonlite,
ggplot2,
gridGraphics,
gt (>= 0.11.0),
Expand All @@ -41,7 +41,7 @@ Suggests:
spelling,
testthat (>= 3.0.0)
Collate:
grid_utils.R
gridify-utils.R
gridify-classes.R
gridify-methods.R
ansi_colour.R
Expand All @@ -54,3 +54,4 @@ Collate:
VignetteBuilder: knitr
Config/testthat/edition: 3
Language: en-GB
Config/roxygen2/version: 8.0.0
13 changes: 12 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@

## New features

* `export_to()` gains a `metadata` argument that records effective cell text
values, including layout defaults and values supplied via `set_cell()`,
alongside the exported output. The default is `metadata = "none"`; pass
`"sidecar"` to write a JSON sidecar `<file>.json` next to the output.
The sidecar identifies itself as `gridify.sidecar.metadata` and uses a
schema-versioned `pages` structure for both single-page and multi-page exports.
Re-exporting the same output without metadata, or with no effective cell text,
removes any stale sidecar for that output.
The default can be changed project-wide by setting
`options(gridify.export.metadata = "sidecar")`.
* Added support for `fill_empty = NA` in the `paginate_table()` function.

## Bug fixes

* When `fill_empty` in the `paginate_table()` function is a character value, the final paginated table now coerces columns to character before filling empty cells (#20).
* When `fill_empty` in the `paginate_table()` function is a character value,
the final paginated table now coerces columns to character before filling empty cells (#20).

## Miscellaneous

Expand Down
49 changes: 0 additions & 49 deletions R/grid_utils.R

This file was deleted.

81 changes: 66 additions & 15 deletions R/gridify-methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,25 @@ setMethod("show", "gridifyLayout", function(object) {
#' The extension determines the output format.
#' @param device a function for graphics device.
#' By default a file name extension is used to choose a graphics device function. Default `NULL`
#' @param metadata Controls writing of metadata derived from effective cell text
#' values, including layout defaults and values supplied via [set_cell()].
#' One of:
#' \itemize{
#' \item `"sidecar"` - write a JSON sidecar file next to the output named `<to>.json`
#' containing `schema`, `schema_version` and `pages`. The `schema` value is
#' `"gridify.sidecar.metadata"`. Each page contains a `cells` object mapping
#' cell names to their text values. Single-page and multi-page exports use the
#' same structure; multi-page PDFs contain one page entry per exported object.
#' Any stale sidecar is removed when no effective cell text exists.
#' \item `"none"` (default) - do not produce any metadata and remove any existing
#' sidecar for the same output file.
#' }
#' Validated with [match.arg()] so it can be abbreviated.
#' When `metadata = NULL` (the default), the value is taken from the
#' `gridify.export.metadata` global option (see [options()]), falling back to
#' `"none"` if unset. This makes it possible to enable the feature globally
#' for a project via
#' `options(gridify.export.metadata = "sidecar")`.
Comment on lines +957 to +962
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#' Validated with [match.arg()] so it can be abbreviated.
#' When `metadata = NULL` (the default), the value is taken from the
#' `gridify.export.metadata` global option (see [options()]), falling back to
#' `"none"` if unset. This makes it possible to enable the feature globally
#' for a project via
#' `options(gridify.export.metadata = "sidecar")`.
#' It is possible to enable the feature globally for a project via
#' `options(gridify.export.metadata = "sidecar")`.

#' @param ... Additional arguments passed to the graphics device functions
#' (`pdf()`, `png()`, `tiff()`, `jpeg()` or your custom one).
#' Default width and height for each export type, respectively:
Expand Down Expand Up @@ -1116,17 +1135,25 @@ setMethod("show", "gridifyLayout", function(object) {
#' )
#'
#' @export
setGeneric("export_to", function(x, to, device = NULL, ...) {
standardGeneric("export_to")
})
setGeneric(
"export_to",
function(x, to, device = NULL, metadata = NULL, ...) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation says this is "none" by default and to use "none" when you don't want to export the metadata

Suggested change
function(x, to, device = NULL, metadata = NULL, ...) {
function(x, to, device = NULL, metadata = "none", ...) {

Or it should be NULL by default and docs need updating

standardGeneric("export_to")
}
)

#' @rdname export_to
#' @export
setMethod("export_to", "gridifyClass", function(x, to, device = NULL, ...) {
setMethod(
"export_to",
"gridifyClass",
function(x, to, device = NULL, metadata = NULL, ...) {
if (!(length(to) == 1 && is.character(to))) {
stop("`to` must be a single string (file path) for single gridify object.")
}

metadata <- resolve_export_metadata(metadata)

dir_name <- dirname(to)
if (!(dir.exists(dir_name))) {
stop(sprintf(
Expand All @@ -1151,6 +1178,12 @@ setMethod("export_to", "gridifyClass", function(x, to, device = NULL, ...) {
}

user_args <- list(...)
payload <- if (metadata == "none") NULL else gridify_metadata(x)
sidecar_json <- if (metadata == "sidecar" && has_metadata_payload(payload)) {
gridify_to_json(metadata_sidecar_payload(payload))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions gridify_to_json and metadata_sidecar_payload are always used together and are quite small, it might be worth merging them together. I also think it would be easier to debug in the future as you wouldn't have to check both functions

} else {
NULL
}

if (ext %in% c("pdf")) {
default_args <- list(width = 11.69, height = 8.27)
Expand All @@ -1162,8 +1195,9 @@ setMethod("export_to", "gridifyClass", function(x, to, device = NULL, ...) {
}

do.call(device, dev_args)
on.exit(grDevices::dev.off(), add = TRUE)
print(x)
on.exit(grDevices::dev.off())
sync_metadata_sidecar(to, sidecar_json)
} else if (ext %in% c("png", "jpeg", "jpg", "tiff", "tif")) {
default_args <- list(width = 600, height = 400)
dev_args <- utils::modifyList(default_args, user_args)
Expand All @@ -1182,21 +1216,26 @@ setMethod("export_to", "gridifyClass", function(x, to, device = NULL, ...) {
device <- dev_func
}
do.call(device, dev_args)
on.exit(grDevices::dev.off(), add = TRUE)
grid::grid.newpage()
print(x)
on.exit(grDevices::dev.off())
sync_metadata_sidecar(to, sidecar_json)
}
})


#' @rdname export_to
#' @export
setMethod("export_to", "list", function(x, to, device = NULL, ...) {
setMethod(
"export_to",
"list",
function(x, to, device = NULL, metadata = NULL, ...) {
if (
!all(vapply(x, function(elem) inherits(elem, "gridifyClass"), logical(1)))
) {
stop("All elements of the list must be 'gridifyClass' objects.")
}
metadata <- resolve_export_metadata(metadata)

to_dirs <- dirname(to)
dir_exists <- dir.exists(to_dirs)
Expand Down Expand Up @@ -1231,18 +1270,30 @@ setMethod("export_to", "list", function(x, to, device = NULL, ...) {
device <- grDevices::pdf
}

do.call(
device,
utils::modifyList(
list(file = to, width = 11.69, height = 8.27, onefile = TRUE),
list(...)
)
payload <- if (metadata == "none") {
NULL
} else {
lapply(x, gridify_metadata)
}
sidecar_json <- if (metadata == "sidecar" && has_metadata_payload(payload)) {
gridify_to_json(metadata_sidecar_payload(payload))
} else {
NULL
}

user_args <- list(...)
dev_args <- utils::modifyList(
list(file = to, width = 11.69, height = 8.27, onefile = TRUE),
user_args
)
do.call(device, dev_args)
on.exit(grDevices::dev.off(), add = TRUE)

for (obj in x) {
print(obj)
}

sync_metadata_sidecar(to, sidecar_json)
} else {
stop(
"For a list of gridify objects and a single file path, the `to` extension has to be pdf."
Expand All @@ -1251,7 +1302,7 @@ setMethod("export_to", "list", function(x, to, device = NULL, ...) {
} else if (length(to) == length(x)) {
# Each plot goes to a separate file path in `to`
for (i in seq_along(x)) {
export_to(x[[i]], to[[i]], ...)
export_to(x[[i]], to[[i]], device = device, metadata = metadata, ...)
}
} else {
stop(
Expand All @@ -1263,7 +1314,7 @@ setMethod("export_to", "list", function(x, to, device = NULL, ...) {

#' @rdname export_to
#' @export
setMethod("export_to", "ANY", function(x, to, ...) {
setMethod("export_to", "ANY", function(x, to, device = NULL, metadata = NULL, ...) {
stop(
"export_to is supported for gridifyClass or list of gridifyClass objects."
)
Expand Down
Loading
Loading