@@ -158,3 +158,226 @@ SS3_extract_fleet <- function(dat, vers) {
158158
159159# create notin operator
160160`%notin%` <- Negate(`%in%` )
161+
162+ # ----------------------------------------------------------
163+
164+ # gt_split()
165+ # ' Split a table into a group of tables (a `gt_group`)
166+ # '
167+ # ' @description
168+ # '
169+ # ' With a **gt** table, you can split it into multiple tables and get that
170+ # ' collection in a `gt_group` object. This function is useful for those cases
171+ # ' where you want to section up a table in a specific way and print those
172+ # ' smaller tables across multiple pages (in RTF and Word outputs, primarily via
173+ # ' \link[gt]{gtsave}, or, with breaks between them when the output context is HTML.
174+ # '
175+ # ' @param data *The gt table data object*
176+ # '
177+ # ' `obj:<gt_tbl>` // **required**
178+ # '
179+ # ' This is the **gt** table object that is commonly created through use of the
180+ # ' [gt()] function.
181+ # '
182+ # ' @param row_every_n *Split at every n rows*
183+ # '
184+ # ' `scalar<numeric|integer>` // *default:* `NULL` (`optional`)
185+ # '
186+ # ' A directive to split at every *n* number of rows. This argument expects a
187+ # ' single numerical value.
188+ # '
189+ # ' @param row_slice_i *Row-slicing indices*
190+ # '
191+ # ' `vector<numeric|integer>` // *default:* `NULL` (`optional`)
192+ # '
193+ # ' An argument for splitting at specific row indices. Here, we expect either a
194+ # ' vector of index values or a function that evaluates to a numeric vector.
195+ # '
196+ # ' @param col_slice_at *Column-slicing locations*
197+ # '
198+ # ' `<column-targeting expression>` // *default:* `NULL` (`optional`)
199+ # '
200+ # ' Any columns where vertical splitting across should occur. The splits occur
201+ # ' to the right of the resolved column names. Can either be a series of column
202+ # ' names provided in `c()`, a vector of column indices, or a select helper
203+ # ' function (e.g. \link[gt]{starts_with}, \link[gt]{ends_with}, \link[gt]{contains}, \link[gt]{matches},
204+ # ' \link[gt]{num_range}, and \link[gt]{everything}).
205+ # '
206+ # ' @return An object of class `gt_group`.
207+ # '
208+ # ' @note
209+ # ' This function is a temporary export of asar, but all development and rights
210+ # ' belong to `rstudio/gt`. This function provides a fix to the function
211+ # ' introduced by a bug in gt v1.3.0. Until this is corrected in the package, we
212+ # ' are using the function here. Once this bug is patched, we will deprecate
213+ # ' and remove this function from asar and direct users to use the gt package
214+ # ' version of this function.rom
215+ # '
216+ # ' @section Examples:
217+ # '
218+ # ' Use a subset of the [`gtcars`] dataset to create a **gt** table. Format the
219+ # ' `msrp` column to display numbers as currency values, set column widths with
220+ # ' \link[gt]{cols_width}, and split the table at every five rows with `gt_split()`.
221+ # ' This creates a `gt_group` object containing two tables. Printing this object
222+ # ' yields two tables separated by a line break.
223+ # '
224+ # ' ```r
225+ # ' gtcars |>
226+ # ' dplyr::slice_head(n = 10) |>
227+ # ' dplyr::select(mfr, model, year, msrp) |>
228+ # ' gt() |>
229+ # ' fmt_currency(columns = msrp) |>
230+ # ' cols_width(
231+ # ' year ~ px(80),
232+ # ' everything() ~ px(150)
233+ # ' ) |>
234+ # ' gt_split(row_every_n = 5)
235+ # ' ```
236+ # '
237+ # ' Use a smaller subset of the [`gtcars`] dataset to create a **gt** table.
238+ # ' Format the `msrp` column to display numbers as currency values, set the table
239+ # ' width with [tab_options()] and split the table at the `model` column This
240+ # ' creates a `gt_group` object again containing two tables but this time we get
241+ # ' a vertical split. Printing this object yields two tables of the same width.
242+ # '
243+ # ' ```r
244+ # ' gtcars |>
245+ # ' dplyr::slice_head(n = 5) |>
246+ # ' dplyr::select(mfr, model, year, msrp) |>
247+ # ' gt() |>
248+ # ' fmt_currency(columns = msrp) |>
249+ # ' tab_options(table.width = px(400)) |>
250+ # ' gt_split(col_slice_at = "model")
251+ # ' ```
252+ # '
253+ # ' @family table group functions
254+ # ' @section Function ID:
255+ # ' 14-2
256+ # '
257+ # ' @section Function Introduced:
258+ # ' `v0.9.0` (Mar 31, 2023)
259+ # '
260+ # ' @export
261+ gt_split <- function (
262+ data ,
263+ row_every_n = NULL ,
264+ row_slice_i = NULL ,
265+ col_slice_at = NULL
266+ ) {
267+
268+ # Perform input object validation
269+ gt ::: stop_if_not_gt_tbl(data = data )
270+
271+ # Resolution of columns as character vectors
272+ col_slice_at <-
273+ gt ::: resolve_cols_c(
274+ expr = {{ col_slice_at }},
275+ data = data ,
276+ null_means = " nothing"
277+ )
278+
279+ gt_tbl_built <- gt ::: build_data(data = data , context = " html" )
280+
281+ # Get row count for table (data rows)
282+ n_rows_data <- nrow(gt_tbl_built [[" _stub_df" ]])
283+
284+ row_slice_vec <- rep.int(1L , n_rows_data )
285+
286+ row_every_n_idx <- NULL
287+ if (! is.null(row_every_n )) {
288+ row_every_n_idx <- seq_len(n_rows_data )[seq(0 , n_rows_data , row_every_n )]
289+ }
290+
291+ row_slice_i_idx <- NULL
292+ if (! is.null(row_slice_i )) {
293+ row_slice_i_idx <- row_slice_i
294+ }
295+
296+ row_idx <- sort(unique(c(row_every_n_idx , row_slice_i_idx )))
297+
298+ group_i <- 0L
299+
300+ for (i in seq_along(row_slice_vec )) {
301+
302+ if (i %in% (row_idx + 1 )) {
303+ group_i <- group_i + 1L
304+ }
305+
306+ row_slice_vec [i ] <- row_slice_vec [i ] + group_i
307+ }
308+
309+ row_range_list <-
310+ split(
311+ seq_len(n_rows_data ),
312+ row_slice_vec
313+ )
314+
315+ gt_tbl_main <- data
316+
317+ gt_group <- gt :: gt_group(.use_grp_opts = FALSE )
318+
319+ for (i in seq_along(row_range_list )) {
320+
321+ gt_tbl_i <- gt_tbl_main
322+
323+ gt_tbl_i [[" _data" ]] <- gt_tbl_i [[" _data" ]][row_range_list [[i ]], ]
324+ gt_tbl_i [[" _stub_df" ]] <- gt_tbl_i [[" _stub_df" ]][seq_along(row_range_list [[i ]]), ]
325+
326+ if (! is.null(col_slice_at )) {
327+
328+ # Get all visible vars in their finalized order
329+ visible_col_vars <- gt ::: dt_boxhead_get_vars_default(data = data )
330+
331+ # Stop function if any of the columns to split at aren't visible columns
332+ if (! all(col_slice_at %in% visible_col_vars )) {
333+ cli :: cli_abort(
334+ " All values provided in `col_slice_at` must correspond to visible columns."
335+ )
336+ }
337+
338+ # Obtain all of the column indices for vertical splitting
339+ col_idx <- which(visible_col_vars %in% col_slice_at )
340+
341+ col_slice_vec <- rep.int(1L , length(visible_col_vars ))
342+
343+ group_j <- 0L
344+
345+ for (i in seq_along(col_slice_vec )) {
346+
347+ if (i %in% (col_idx + 1 )) {
348+ group_j <- group_j + 1L
349+ }
350+
351+ col_slice_vec [i ] <- col_slice_vec [i ] + group_j
352+ }
353+
354+ col_range_list <-
355+ split(
356+ seq_along(visible_col_vars ),
357+ col_slice_vec
358+ )
359+
360+ for (j in seq_along(col_range_list )) {
361+
362+ gt_tbl_j <- gt_tbl_i
363+
364+ gt_tbl_j [[" _data" ]] <-
365+ gt_tbl_j [[" _data" ]][, visible_col_vars [col_range_list [[j ]]]]
366+
367+ gt_tbl_j [[" _boxhead" ]] <-
368+ gt_tbl_j [[" _boxhead" ]][
369+ gt_tbl_j [[" _boxhead" ]]$ var %in% visible_col_vars [col_range_list [[j ]]],
370+ ]
371+
372+ gt_group <- gt :: grp_add(gt_group , gt_tbl_j )
373+ }
374+
375+
376+ } else {
377+ gt_group <- gt :: grp_add(gt_group , gt_tbl_i )
378+ }
379+ }
380+
381+ gt_group
382+ }
383+
0 commit comments