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
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Authors@R: c(
person("Agota", "Bodoni", , "Agota.Bodoni@ucb.com", role = "ctb"),
person("Eilis", "Meldrum-Dolan", , "Eilis.Meldrum-Dolan@ucb.com", role = "ctb"),
person("Gary", "Cao", , "Gary.Cao@ucb.com", role = "ctb"),
person("Monika", "Beh", , "Monika.Beh@ucb.com", role = "ctb"),
person("UCB S.A., Belgium", role = c("cph", "fnd"))
)
Description: A simple and flexible tool designed to create enriched figures and tables by providing a way to add text
Expand All @@ -24,7 +25,6 @@ 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,
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
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

## New features

* Added vertical anchoring for the gridify object inside its cell via the new
`vjust` slot of `gridifyObject()` and the `object_vjust` argument of
`simple_layout()`, `complex_layout()`, `pharma_layout_base()`,
`pharma_layout_A4()` and `pharma_layout_letter()`.
`0` aligns the object to the bottom, `0.5` (default) centers it, and `1`
anchors it to the top of the cell. Most useful
for fixed-size grobs such as `gt` and `flextable` tables. When `vjust != 0.5`
is used with a fixed-size grob the viewport is sized to `grid::grobHeight()`
and the `height` slot of `gridifyObject()` is ignored. For fixed-size tables,
edge values (`0` or `1`) place the table directly against the object-row edge;
add spacer rows in custom layouts or use inset values such as `0.05` or `0.95`
if nearby text appears too close. Reported and proposed by Monika Beh.
* Added support for `fill_empty = NA` in the `paginate_table()` function.

## Bug fixes
Expand Down
20 changes: 4 additions & 16 deletions R/complex_layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,7 @@
#' notes and footnotes around the output.
#'
#' @name complex_layout
#' @param margin A unit object specifying the margins around the output. Default is 10% of the output area on all sides.
#' @param global_gpar A gpar object specifying the global graphical parameters.
#' Must be the result of a call to `grid::gpar()`.
#' @param background A string specifying the background fill colour.
#' Default `grid::get.gpar()$fill` for a white background.
#' @param scales A string, either `"free"` or `"fixed"`.
#' By default, `"fixed"` ensures that text elements (titles, footers, etc.)
#' retain a static height, preventing text overlap while maintaining a
#' structured layout. However, this may result in different height proportions
#' between the text elements and the output.
#'
#' The `"free"` option makes the row heights proportional,
#' allowing them to scale dynamically based on the overall output size.
#' This ensures that the text elements and the output maintain relative proportions.
#' @inheritParams simple_layout
#'
#' @details The layout consists of six rows for headers, titles, object (figure or table), notes, and footnotes.
#' The object is placed in the fourth row.\cr
Expand Down Expand Up @@ -81,7 +68,8 @@ complex_layout <- function(
margin = grid::unit(c(t = 0.1, r = 0.1, b = 0.1, l = 0.1), units = "npc"),
global_gpar = grid::gpar(),
background = grid::get.gpar()$fill,
scales = c("fixed", "free")
scales = c("fixed", "free"),
object_vjust = 0.5
) {
scales <- match.arg(scales, c("fixed", "free"))

Expand All @@ -103,7 +91,7 @@ complex_layout <- function(
background = background,
margin = margin,
adjust_height = TRUE,
object = gridifyObject(row = 4, col = c(1, 3)),
object = gridifyObject(row = 4, col = c(1, 3), vjust = object_vjust),
cells = gridifyCells(
header_left = gridifyCell(row = 1, col = 1),
header_middle = gridifyCell(row = 1, col = 2),
Expand Down
49 changes: 0 additions & 49 deletions R/grid_utils.R

This file was deleted.

73 changes: 64 additions & 9 deletions R/gridify-classes.R
Original file line number Diff line number Diff line change
Expand Up @@ -439,28 +439,59 @@ gridifyCells <- function(...) {
#'
#' @slot row A numeric value, span or sequence specifying the row position of the object.
#' @slot col A numeric value, span or sequence specifying the column position of the object.
#' @slot height A numeric value specifying the height of the object.
#' @slot height A numeric value specifying the height of the object as a fraction of the row
#' (interpreted in `npc`). Ignored when `vjust != 0.5` and the grob is fixed-size: in that
#' case the viewport is sized to `grid::grobHeight()` so the object can be anchored within
#' a taller row. The 1-inch floor in applies in both cases.
#' @slot width A numeric value specifying the width of the object.
#' @slot vjust A numeric value in `[0, 1]` specifying the vertical anchoring of the object
#' within its cell. `0` aligns to the bottom, `0.5` (default) centers it, and
#' `1` aligns to the top.
#' Anchoring only takes effect for fixed-size grobs (e.g. `gt::as_gtable()`,
#' `flextable::gen_grob()`, plain `grid::rectGrob()`). Flexible grobs whose natural height is
#' meant to fill the container (e.g. `ggplot2::ggplotGrob()`, recorded gTrees from
#' `grid::grid.grabExpr()`) always span the full row regardless of `vjust`.
#' For fixed-size table grobs, edge values (`0` or `1`) place the table directly
#' against the object-row edge; add spacer rows in a custom layout or use an
#' inset value such as `0.05` or `0.95` if nearby text appears too close.
#' @exportClass gridifyObject
setClass(
"gridifyObject",
representation(
row = "numeric",
col = "numeric",
height = "numeric",
width = "numeric"
)
width = "numeric",
vjust = "numeric"
),
prototype = list(vjust = 0.5)
)

setValidity("gridifyObject", function(object) {
errs <- character()
if (min(object@row) < 1 || !all(object@row %% 1 == 0)) {
stop("cell row has to be positive integer.")
errs <- c(errs, "cell row has to be positive integer.")
}
if (min(object@col) < 1 || !all(object@col %% 1 == 0)) {
stop("cell col has to be positive integer.")
errs <- c(errs, "cell col has to be positive integer.")
}
if (
length(object@vjust) != 1L ||
anyNA(object@vjust) ||
!is.finite(object@vjust) ||
object@vjust < 0 ||
object@vjust > 1
) {
errs <- c(
errs,
"vjust has to be a single finite numeric value in [0, 1]."
)
}
if (object@height > 1 ) {
errs <- c(errs, "height must be less than or equal to 1.")
}

TRUE
if (length(errs)) errs else TRUE
})

#' Create a gridifyObject
Expand All @@ -469,17 +500,36 @@ setValidity("gridifyObject", function(object) {
#'
#' @param row A numeric value, span or sequence specifying the row position of the object.
#' @param col A numeric value, span or sequence specifying the row position of the object.
#' @param height A numeric value specifying the height of the object. Default is 1.
#' @param height A numeric value specifying the height of the object as a fraction of the row
#' (interpreted in `npc`). Default is 1. Ignored when `vjust != 0.5` and the grob is
#' fixed-size: in that case the viewport is sized to `grid::grobHeight()` so the object
#' can be anchored within a taller row.
#' @param width A numeric value specifying the width of the object. Default is 1.
#' @param vjust A numeric value in `[0, 1]` specifying the vertical anchoring of the object
#' within its cell. `0` aligns to the bottom, `0.5` (default) centers it, and
#' `1` aligns to the top.
#' Anchoring only takes effect for fixed-size grobs (e.g. `gt::as_gtable()`,
#' `flextable::gen_grob()`). Flexible grobs (e.g. `ggplot2::ggplotGrob()`) always fill the
#' full row regardless of `vjust`.
#' For fixed-size table grobs, edge values (`0` or `1`) place the table directly
#' against the object-row edge; add spacer rows in a custom layout or use an
#' inset value such as `0.05` or `0.95` if nearby text appears too close.
#'
#' @return An instance of the gridifyObject class.
#'
#' @seealso [gridifyLayout()]
#' @export
#' @examples
#' object <- gridifyObject(row = 1, col = 1, height = 1, width = 1)
gridifyObject <- function(row, col, height = 1, width = 1) {
new("gridifyObject", row = row, col = col, height = height, width = width)
gridifyObject <- function(row, col, height = 1, width = 1, vjust = 0.5) {
new(
"gridifyObject",
row = row,
col = col,
height = height,
width = width,
vjust = vjust
)
}

#' gridifyClass class
Expand Down Expand Up @@ -644,6 +694,11 @@ gridify <- function(
object <- grid::grid.grabExpr(
gridGraphics::grid.echo(function() eval(object_expr))
)
# Mark the recorded gTree as flexible: its `grobHeight()` is meaningful
# only inside the recording viewport (collapses to 0 elsewhere), so the
# viewport must span the full row regardless of `vjust`.
# See is_flexible_grob() / object_viewport_height_expr().
attr(object, "gridify.flexible") <- TRUE
} else {
stop("Please install gridGraphics to use it in gridify.")
}
Expand Down
20 changes: 14 additions & 6 deletions R/gridify-methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -254,16 +254,22 @@ setMethod(
setMethod("print", "gridifyClass", function(x, ...) {
grid::grid.newpage()

# See object_viewport_height_expr() for the rationale behind this choice.
height_expr <- object_viewport_height_expr(
grob = x@object,
vjust = x@layout@object@vjust,
height = x@layout@object@height
)

pp_list <- list(
substitute(
grid::grobTree(
grid::editGrob(
OBJECT,
vp = grid::viewport(
height = grid::unit.pmax(
grid::unit(height_value, "npc"),
grid::unit(1, "inch")
),
y = grid::unit(vjust_value, "npc"),
just = c(0.5, vjust_value),
height = HEIGHT_EXPR,
width = grid::unit.pmax(
grid::unit(width_value, "npc"),
grid::unit(1, "inch")
Expand All @@ -276,10 +282,11 @@ setMethod("print", "gridifyClass", function(x, ...) {
)
),
env = list(
height_value = x@layout@object@height,
width_value = x@layout@object@width,
nrow_value = x@layout@object@row,
ncol_value = x@layout@object@col
ncol_value = x@layout@object@col,
vjust_value = x@layout@object@vjust,
HEIGHT_EXPR = height_expr
)
)
)
Expand Down Expand Up @@ -668,6 +675,7 @@ setMethod("show_spec", "gridifyLayout", function(object) {

cat(sprintf(" Width: %s\n", object@object@width))
cat(sprintf(" Height: %s\n", object@object@height))
cat(sprintf(" Vjust: %s\n", object@object@vjust))

cat("\nObject Row Heights:\n")
rows_span <- object_row[1]:object_row[length(object_row)]
Expand Down
Loading
Loading