diff --git a/NEWS.md b/NEWS.md index 80031441d..c7744d7d7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # crane 0.3.3 +* `add_forest()` now removes the horizontal padding of the forest-plot column in flextable output so the fixed-width plot fits its cell exactly and wide forest tables no longer spill off the page in docx. (#270) + * Fixed minor typo in the DESCRIPTION file. # crane 0.3.2 diff --git a/R/add_forest.R b/R/add_forest.R index f5242412a..cc898735a 100644 --- a/R/add_forest.R +++ b/R/add_forest.R @@ -217,13 +217,21 @@ add_forest <- function(x, ") |> gt::tab_style(style = gt::cell_text(whitespace = "nowrap"), locations = gt::cells_body()) } else if (table_engine == "flextable") { + # The plot column has a fixed width. Render the image to exactly that width + # and remove the cell's horizontal padding so the raster fills its content + # box instead of being forced wider than the cell (which, under Word's fixed + # table layout, pushes the column out and makes the table overflow the page). + # The plot's proportions are unchanged; only the cell geometry is matched. + ggplot_col_width <- 2.5 out <- out |> gtsummary::as_flex_table() |> flextable::mk_par( j = "ggplot", value = flextable::as_paragraph( suppressMessages( # avoid `height` was translated to `width`. message - flextable::gg_chunk(value = lst_ggplots_final, height = 0.4, width = 2.5) + flextable::gg_chunk( + value = lst_ggplots_final, height = 0.4, width = ggplot_col_width + ) ) ) ) |> @@ -231,10 +239,13 @@ add_forest <- function(x, flextable::line_spacing(j = "ggplot", space = 0, part = "body") |> flextable::valign(valign = "center", part = "body") |> flextable::align(j = "ggplot", align = "center", part = "header") |> - flextable::width(j = "ggplot", width = 2.5) |> flextable::padding(padding.top = 0, part = "body") |> flextable::padding(padding.bottom = 7, part = "body") |> flextable::padding(j = "ggplot", padding.bottom = 0, part = "body") |> + # zero horizontal padding on the plot column so the fixed-width image fits + # the cell content box exactly (default 5pt L/R padding would overflow it) + flextable::padding(j = "ggplot", padding.left = 0, padding.right = 0, part = "all") |> + flextable::width(j = "ggplot", width = ggplot_col_width) |> flextable::valign(valign = "bottom", part = "body") } diff --git a/inst/WORDLIST b/inst/WORDLIST index 0a17e3c7f..7cd9efaa7 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -27,6 +27,7 @@ cardx custiomization customizations de +docx efron fleming flextable diff --git a/tests/testthat/test-add_forest.R b/tests/testthat/test-add_forest.R index 7f7c7ad40..ff72db1a3 100644 --- a/tests/testthat/test-add_forest.R +++ b/tests/testthat/test-add_forest.R @@ -28,7 +28,7 @@ test_that("add_forest(table_engine = 'flextable') works", { ) expect_error( - tbl <- trial |> + forest_ft <- trial |> tbl_roche_subgroups( subgroups = c("grade", "stage"), rsp = "response", @@ -45,6 +45,14 @@ test_that("add_forest(table_engine = 'flextable') works", { ), NA ) + + # The plot column has a fixed width and holds an image of exactly that width. + # The default 5pt horizontal cell padding would push the image past the column + # and overflow the page in docx; zeroing it makes the image fit the cell + # content box exactly so the table stays on the page (#270). + gg <- which(forest_ft$col_keys == "ggplot") + expect_identical(unique(forest_ft$body$styles$pars$padding.left$data[, gg]), 0) + expect_identical(unique(forest_ft$body$styles$pars$padding.right$data[, gg]), 0) }) test_that("add_forest handles extreme limits and character NA p-values safely", {