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
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ tests/testthat/_snaps/removal_functions.md
tests/testthat/test-rows_add.R
tests/testthat/_snaps/rows_add.md

tests/testthat/test-row_order.R

tests/testthat/test-rtf_cols_width.R
tests/testthat/_snaps/rtf_cols_width.md

Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export(rm_spanners)
export(rm_stubhead)
export(row_group)
export(row_group_order)
export(row_order)
export(rows_add)
export(starts_with)
export(stub)
Expand Down
5 changes: 4 additions & 1 deletion R/build_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ build_data <- function(data, context) {
data <- render_substitutions(data = data, context = context)
data <- migrate_unformatted_to_output(data = data, context = context)
data <- perform_col_merge(data = data, context = context)
data <- dt_body_reassemble(data = data)

# Reorder stub_df first (handles group ordering and row_order() directives),
# then reassemble body using the reordered stub_df
data <- reorder_stub_df(data = data)
data <- dt_body_reassemble(data = data)

data <- reorder_footnotes(data = data)
data <- reorder_styles(data = data)

Expand Down
9 changes: 3 additions & 6 deletions R/dt_body.R
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,9 @@ dt_body_reassemble <- function(data) {
body <- dt_body_get(data = data)
stub_df <- dt_stub_df_get(data = data)

groups <- dt_row_groups_get(data = data)

# Get the reordering df (`rows_df`) for the data rows
rows_df <- get_row_reorder_df(groups = groups, stub_df = stub_df)

rows <- rows_df$rownum_final
# Use the rownum_i values from stub_df which reflect the current row order
# (including both group ordering and any row_order() directives)
rows <- stub_df$rownum_i

cols <- dt_boxhead_get_vars(data = data)

Expand Down
64 changes: 64 additions & 0 deletions R/dt_row_order.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#------------------------------------------------------------------------------#
#
# /$$
# | $$
# /$$$$$$ /$$$$$$
# /$$__ $$|_ $$_/
# | $$ \ $$ | $$
# | $$ | $$ | $$ /$$
# | $$$$$$$ | $$$$/
# \____ $$ \___/
# /$$ \ $$
# | $$$$$$/
# \______/
#
# This file is part of the 'rstudio/gt' project.
#
# Copyright (c) 2018-2026 gt authors
#
# For full copyright and license information, please look at
# https://gt.rstudio.com/LICENSE.html
#
#------------------------------------------------------------------------------#


.dt_row_order_key <- "_row_order"

dt_row_order_get <- function(data) {
dt__get(data, .dt_row_order_key)
}

dt_row_order_set <- function(data, row_order) {
dt__set(data, .dt_row_order_key, row_order)
}

dt_row_order_init <- function(data) {
dt_row_order_set(data = data, row_order = list())
}

#' Add a row ordering directive
#'
#' @param data The gt table data object.
#' @param by A quosure or list of quosures for ordering.
#' @param groups Character vector of group IDs to target, or NULL for all.
#' @param reverse Logical indicating whether to reverse (descend) the order.
#'
#' @noRd
dt_row_order_add <- function(data, by, groups, reverse) {

existing_order <- dt_row_order_get(data = data)

added_directive <- list(
by = by,
groups = groups,
reverse = reverse
)

row_order <-
c(
existing_order,
list(added_directive)
)

dt_row_order_set(data = data, row_order = row_order)
}
81 changes: 81 additions & 0 deletions R/dt_stub_df.R
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ reorder_stub_df <- function(data) {

row_groups <- dt_row_groups_get(data = data)

# First, reorder by row groups
rows_df <-
get_row_reorder_df(
groups = row_groups,
Expand All @@ -245,9 +246,89 @@ reorder_stub_df <- function(data) {

stub_df <- stub_df[rows_df$rownum_final, ]

# Then, apply any row ordering directives
stub_df <- apply_row_order_directives(data = data, stub_df = stub_df)

dt_stub_df_set(data = data, stub_df = stub_df)
}

# Function to apply the lazy row ordering directives captured by `row_order()`
apply_row_order_directives <- function(data, stub_df) {

# Get the row order directives
row_order_directives <- dt_row_order_get(data = data)

# If there are no directives, return stub_df unchanged
if (length(row_order_directives) == 0) {
return(stub_df)
}

# Get the original data table for evaluating ordering expressions
data_tbl <- dt_data_get(data = data)

# Apply each directive in order
for (directive in row_order_directives) {

by <- directive$by
groups <- directive$groups
reverse <- directive$reverse

# Determine which rows to order
if (is.null(groups)) {
# Order all rows together (within their current group context)
unique_groups <- unique(stub_df$group_id)
} else {
# Only order rows in specified groups
unique_groups <- groups
}

# Process each group separately to maintain group boundaries
for (grp in unique_groups) {

# Find rows belonging to this group
if (is.na(grp)) {
grp_mask <- is.na(stub_df$group_id)
} else {
grp_mask <- stub_df$group_id == grp & !is.na(stub_df$group_id)
}

grp_indices <- which(grp_mask)

if (length(grp_indices) <= 1) {
next # No need to sort a single row or empty group
}

# Get the original row numbers for this group
original_rownum <- stub_df$rownum_i[grp_indices]

# Create a temporary data frame for ordering
# using the original data values at those row positions
temp_df <- data_tbl[original_rownum, , drop = FALSE]

# Build the ordering using the quosures
# Evaluate each quosure in the context of the temp data
order_args <- lapply(by, function(quo) {
rlang::eval_tidy(quo, data = temp_df)
})

# Add decreasing argument if reverse is TRUE
order_args$decreasing <- reverse

# Get the new order for this group
new_order <- do.call(order, order_args)

# Reorder the group indices in stub_df
stub_df[grp_indices, ] <- stub_df[grp_indices[new_order], ]
}
}

# Reset row names

rownames(stub_df) <- NULL

stub_df
}

dt_stub_groupname_has_na <- function(data) {

stub_df <- dt_stub_df_get(data = data)
Expand Down
4 changes: 3 additions & 1 deletion R/extract.R
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ extract_body <- function(
return(out_df)
}

# Reorder stub_df first (handles group ordering and row_order() directives),
# then reassemble body using the reordered stub_df
data <- reorder_stub_df(data = data)
data <- dt_body_reassemble(data = data)

if (identical(build_stage, "body_reassembled")) {
Expand All @@ -341,7 +344,6 @@ extract_body <- function(
return(out_df)
}

data <- reorder_stub_df(data = data)
data <- reorder_footnotes(data = data)
data <- reorder_styles(data = data)

Expand Down
1 change: 1 addition & 0 deletions R/gt.R
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ gt <- function(
process_md = process_md
)
data <- dt_row_groups_init(data = data)
data <- dt_row_order_init(data = data)
data <- dt_heading_init(data = data)
data <- dt_spanners_init(data = data)
data <- dt_stubhead_init(data = data)
Expand Down
Loading