Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 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
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## 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) keeps the previous
centered behaviour, 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. Reported and proposed by Monika Beh.
* Added support for `fill_empty = NA` in the `paginate_table()` function.

## Bug fixes
Expand Down
9 changes: 7 additions & 2 deletions R/complex_layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#' 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.
#' @param object_vjust A numeric value in `[0, 1]` controlling the vertical anchoring of the
#' object within its row. `0` aligns to the bottom, `0.5` (default) centers it, `1` aligns
#' to the top. Useful when the object's row is taller than the object itself.
#' Has no effect on flexible grobs (e.g. `ggplot2::ggplotGrob()`), which always fill the full row.
#'
#' @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 +85,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 +108,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.

65 changes: 56 additions & 9 deletions R/gridify-classes.R
Original file line number Diff line number Diff line change
Expand Up @@ -439,28 +439,55 @@ 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, `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`.
#' @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 +496,32 @@ 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, `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`.
#'
#' @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 +686,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
28 changes: 22 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,15 @@ 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%s\n",
object@object@vjust,
if (object@object@vjust == 0.5) {
" (default; the object fills the full row regardless of grob type)"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

i do not think so it is a good description

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We already documented it well so I think we can remove this additional text.

} else {
" (anchors fixed-size grobs; flexible grobs e.g. ggplot still fill the row)"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

i do not think so it is a good description

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We already documented it well so I think we can remove this additional text.

}
))

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