Skip to content

Deprecate gt in favor of lt - #629

Open
yihui wants to merge 36 commits into
mainfrom
replace-gt-with-lt
Open

Deprecate gt in favor of lt#629
yihui wants to merge 36 commits into
mainfrom
replace-gt-with-lt

Conversation

@yihui

@yihui yihui commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Remove the gt package from Imports and replace with the lightweight lt package
  • New lt() S3 methods for fixed_design_summary and gs_design_summary, fully replacing as_gt()
  • All 14 vignettes updated to use lt functions (lt(), lt_header(), lt_spanner(), lt_format(), lt_footnote(), lt_note(), lt_label())
  • Tests updated for lt_tbl assertions

Comparison of dependencies

# gt
> setdiff(tools::package_dependencies('gt', recursive = TRUE)[[1]], xfun::base_pkgs())
 [1] "base64enc"    "bigD"         "bitops"       "cli"          "commonmark"  
 [6] "dplyr"        "fs"           "glue"         "htmltools"    "htmlwidgets" 
[11] "juicyjuice"   "magrittr"     "markdown"     "reactable"    "rlang"       
[16] "sass"         "scales"       "tidyselect"   "vctrs"        "xml2"        
[21] "generics"     "lifecycle"    "pillar"       "R6"           "tibble"      
[26] "digest"       "fastmap"      "jsonlite"     "knitr"        "rmarkdown"   
[31] "yaml"         "V8"           "xfun"         "litedown"     "reactR"      
[36] "rappdirs"     "farver"       "labeling"     "RColorBrewer" "viridisLite" 
[41] "withr"        "evaluate"     "highr"        "utf8"         "bslib"       
[46] "fontawesome"  "jquerylib"    "tinytex"      "pkgconfig"    "Rcpp"        
[51] "curl"         "cachem"       "memoise"      "mime"    

# lt
> setdiff(tools::package_dependencies('lt', recursive = TRUE)[[1]], xfun::base_pkgs())
[1] "xfun"

However, since gsDesign depends on gt and gsDesign2 depends on gsDesign, this PR alone won't reduce the number of (recursive) dependencies.

Migration mapping

https://pkg.yihui.org/lt/examples/03-gt

Test plan

  • as_lt() unit tests pass for fixed and GS designs
  • All design types render correctly (fixed_ahr, gs_ahr, gs_wlr, gs_rd)
  • Visual comparison with gt output confirms structural equivalence
  • Non-binding design body footnote renders correctly
  • Custom footnotes (colname, title, analysis, spanner) all work
  • R CMD check passes
  • All vignettes build without error

Vignette comparison

This zip archive contains all vignettes and articles built with gt and lt, respectively. You can compare the rendered HTML pages side by side: vignette-compare.zip

Question

Why did we test the LaTeX output of gt::as_latex()?

gt_to_latex <- function(data) cat(as.character(gt::as_latex(data)))

yihui and others added 4 commits May 21, 2026 14:05
Remove the gt package dependency entirely and use the lightweight lt
package for table rendering. This reduces install weight and aligns
with the project's move toward minimal dependencies.

Changes:
- New as_lt() generic + methods replacing as_gt()
- All vignettes updated: gt() → lt(), tab_header() → lt_header(),
  fmt_number() → lt_format(), tab_spanner() → lt_spanner(),
  tab_footnote() → lt_footnote()/lt_note(), cols_label() → lt_cols_label()
- README.Rmd: use knitr::kable() for GitHub rendering
- DESCRIPTION: gt removed from Imports, lt added
- Tests updated for lt_tbl assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
lt requires character strings for column names (unlike gt's tidy-select).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yihui
yihui marked this pull request as draft May 21, 2026 19:07
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@jdblischak jdblischak left a comment

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.

When I run the tests locally, I get two failures:

library("testit")
test_pkg()
## Error: -- Assertion failed: as_lt: footnote=FALSE removes footnote --
##    1. count_footnotes(z1) (LHS) ==>
##        int 0
##       ----------
##        int 1
##       <== (RHS) 1L
##       count_footnotes(z1) %==% 1L is not TRUE but FALSE at tests/testit/test-developer-as_lt.R#14
##    2. count_footnotes(z1) (LHS) ==>
##        int 0
##       ----------
##        int 2
##       <== (RHS) 2L
##       count_footnotes(z1) %==% 2L is not TRUE but FALSE at tests/testit/test-developer-as_lt.R#22

sessioninfo::package_info(c("gsDesign2", "lt"), dependencies = FALSE)
##  package   * version date (UTC) lib source
##  gsDesign2 * 1.1.8   2026-05-28 [1] local
##  lt          0.0.7   2026-05-28 [1] Github (yihui/lt@e485eb6)
##
##  [1] C:/Users/john/AppData/Local/R/win-library/4.4
##  [2] C:/Program Files/R/R-4.4.3/library
##  * ── Packages attached to the search path.

Comment thread R/as_gt.R
@jdblischak

This comment was marked as outdated.

@yihui

This comment was marked as outdated.

yihui and others added 14 commits June 2, 2026 14:26
- Restore as_gt() as a thin, deprecated wrapper that warns and delegates
  to as_lt(), so existing users get a migration path instead of a hard
  break.
- Bundle inst/css/gt-style.css and apply it from both as_lt() methods via
  lt::lt_css(), making lt output nearly indistinguishable from the old gt
  tables (top caption, light-grey rules, system-ui font, bare footnote
  superscripts). lt dedups the stylesheet across a knitted document.
- Fix count_footnotes() test helper to read $footnotes (where lt_footnote
  stores them) instead of $ops.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
as_gt() is exported again (as a deprecated wrapper), so pkgdown requires
it in the reference index.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop properties already set by lt's default stylesheet or by browser
defaults (caption-side, empty-spanner border, normal-weight subtitle/th),
keeping only the rules that actually change the appearance toward gt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the gt-era prose; the help page now just states as_gt() is
superseded by as_lt() and points there.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
lt now ships the gt-like theme as lt-gt.css and lt_css() resolves bare
filenames against the package, so gsDesign2 no longer needs its own copy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
lt's default stylesheet is now gt-like, so as_lt() no longer needs to
attach a separate theme via lt_css().

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Define lt.fixed_design_summary() and lt.gs_design_summary() that
dispatch when users call lt::lt() on gsDesign2 summary objects.
as_lt() is removed (never released). as_gt() remains as a deprecated
wrapper pointing to lt::lt().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
lt_cols_label doesn't exist in lt; the correct function is lt_label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yihui

yihui commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Just a quick update: I've submitted lt v0.1 to CRAN. Currently there are 132 newbies in the queue. I guess the initial review may take place a week later. Fingers crossed.

LittleBeannie and others added 5 commits July 1, 2026 18:16
* Update DESCRIPTION and NEWS.md for v1.1.9

* Fix grammar

* I guess 2x is not that substantial [ci skip]

---------

Co-authored-by: Yihui Xie <xie@yihui.name>
- Remove `Remotes: yihui/lt` since lt is now on CRAN
- Remove redundant `lt::` prefix in vignettes where library(lt) is loaded
- Add library(lt) to story-seven-test-types.Rmd
- Delete gt_to_latex snapshot tests (gt no longer available)
- Bump version to 1.2.0; update NEWS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace dual-block pattern (eval=FALSE lt() + hidden knitr::kable())
with single lt() calls rendered via lt_html(fragment=TRUE, css=FALSE).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yihui
yihui force-pushed the replace-gt-with-lt branch from b79e349 to 961c996 Compare July 4, 2026 04:48
@yihui
yihui marked this pull request as ready for review July 4, 2026 15:43
yihui added a commit to keaven/gsDesign that referenced this pull request Jul 10, 2026
Replace the gt package dependency with the lightweight lt package for all
table output, mirroring Merck/gsDesign2#629.

- Add lt.gsBinomialExactTable() S3 method (R/as_lt.R) and deprecate as_gt()
  in favor of lt::lt().
- Swap gt for lt in DESCRIPTION Imports; add Remotes: yihui/lt pending the
  next lt release on CRAN.
- Migrate all table-bearing vignettes to lt, dropping the bundled
  html_vignette CSS in favor of a minimal vignettes/vignette.css.
- Update tests, docs, and _pkgdown.yml accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@jdblischak jdblischak left a comment

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.

When comparing the tables in the rendered GitHub READMEs, I noticed that the {lt}-generated tables lack the titles and footnotes, and also have different number of default decimal places

Image

Comment thread inst/achieved_vignettes/style.Rmd Outdated
Comment thread R/as_gt.R Outdated
Comment thread R/lt.R
Comment thread R/lt.R
Comment thread vignettes/gsDesign2.Rmd
The committed README.md was built against an older lt where lt() on a
design summary did not emit the caption title and footnotes. Rebuild it
with the current lt so the fixed-design and group-sequential summary
tables show their titles and footnotes again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yihui

yihui commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

the {lt}-generated tables lack the titles and footnotes

Good catch — thanks. The committed README.md was stale: it had been rendered against an older {lt} where lt() on a design summary didn't emit the caption title or footnotes. The S3 methods themselves (lt.fixed_design_summary, lt.gs_design_summary) do set them via lt_header()/lt_footnote(), and current {lt} (0.2.4) renders them. I've regenerated README.md (6d02908) and the titles + footnotes are back for both the fixed-design and group-sequential tables.

different number of default decimal places

This one is a deliberate {lt} vs {gt} difference rather than something gsDesign2 sets. Neither as_gt() nor lt() applies explicit number formatting to the fixed-design summary, so each falls back to its package default: {gt} prints the stored value verbatim (420.6346), while {lt} auto-formats to ~4 significant digits (cap of 4 - integer_width decimals), so 420.63458… displays as 420.6 with the full value preserved in the cell's title= tooltip. If we'd prefer a fixed precision here we can add an explicit lt_format(decimals = …) in the S3 method — happy to do that if you think matching the old look is worth it.

yihui and others added 2 commits August 19, 2026 11:14
Address PR review: the file defines S3 methods for lt::lt(), so name it
R/lt.R to match the generic. Also add [lt-methods] to as_gt()'s @Seealso
so users can find the gsDesign2 lt() methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve conflicts from the harm-bound feature (#640) landing on main while
this branch replaces gt with lt:

- DESCRIPTION: keep version 1.2.0; Imports lt (not gt).
- NEWS.md: keep both the gt->lt 'Major changes' note and main's harm
  'New features'/'Documentation' entries; reword the table entry to say
  lt() (with deprecated as_gt()) instead of as_gt().
- R/as_gt.R + man/as_gt.Rd: keep the deprecation shim; as_gt() is no longer
  an S3 generic, so main's as_gt.* method edits (incl. as_gt.simtrial_gs_wlr)
  don't apply.
- R/lt.R: port main's harm changes into the lt S3 methods -- factor Bound on
  the display levels, arrange by (Analysis, Bound), compute alpha from the
  Efficacy bound, and default display_bound to include 'Harm'.
- tests/testit/test-independent-as_gt.md: keep it deleted (gt_to_latex
  snapshots removed with the gt dependency).
- vignettes/articles/story-harm-bound-schoenfeld.Rmd (new on main): convert
  gt()/fmt_number()/fmt_scientific()/groupname_col to lt()/lt_format()/
  lt_group(); pre-format scientific columns as text since lt has no
  scientific formatter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yihui
yihui requested a review from LittleBeannie August 20, 2026 01:34
Comment thread R/as_gt.R Outdated
as_gt <- function(x, ...) {
.Deprecated("lt", package = "lt",
msg = "as_gt() is deprecated; please use lt::lt() instead.")
lt::lt(x, ...)

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.

As discussed today, this immediate deprecation of as_gt() might break user code if they customize the output with other {gt} related functions. A more gentle deprecation would allow at least one release where as_gt() and lt() are both available, with as_gt() clearly marked with .Deprecated()

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.

Done in 347ec76. Softened to a gentle deprecation:

  • Restored the gt-based as_gt() S3 methods, so as_gt() still returns a gt_tbl — user code that customizes the output with {gt} functions (e.g. tab_options()) keeps working.
  • as_gt() now emits .Deprecated() pointing to lt::lt(), and both are available this release.
  • Moved {gt} from Imports to Suggests; as_gt() checks for it at call time and errors with an install hint if missing.
  • Kept the source lean (dropped the long @examples, deferred arg docs to lt-methods); the gsd_* helpers stay shared with the lt() methods, so harm-bound support carries over.

Verified: summary(fixed_design_ahr(...)) |> as_gt() warns once and returns a gt_tbl that still accepts gt::tab_options().

Comment thread NAMESPACE
Comment thread NEWS.md Outdated
yihui and others added 4 commits August 21, 2026 15:02
Co-authored-by: John Blischak <jdblischak@gmail.com>
Import and re-export lt::lt() so users can call lt() on a design summary
after loading only gsDesign2, without also attaching lt or qualifying
with lt::. This also makes S3 dispatch robust regardless of package load
order, following the r-lib/generics recommendation.

See yihui/lt#4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per PR review, an immediate hard deprecation of as_gt() (redirecting to
lt()) would break user code that customizes the output with gt functions,
since lt() returns an lt_tbl rather than a gt_tbl. Restore the gt-based
as_gt() S3 methods so as_gt() keeps returning a gt_tbl for one release,
but mark it deprecated with .Deprecated() pointing to lt::lt().

- Move gt from a hard dependency to Suggests; as_gt() checks for gt at
  call time and errors with an install hint if it is missing.
- Keep the gsd_* helpers shared with the lt() methods (in R/lt.R); the
  harm-bound support carries over unchanged.
- Keep the as_gt.R source lean: drop the long @examples and defer the
  argument docs to lt-methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yihui yihui changed the title Replace gt dependency with lt Deprecate gt in favor of lt Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants