Skip to content

Commit be21096

Browse files
Use data.table subsetting to avoid copy of large objects (#180)
* Use drop=FALSE to avoid losing dimension in double-elided case * avoid copy of potentially large data.table input * Need drop=FALSE for data.table too * test * Redundant withr Suggests * importFrom(utils,str)
1 parent 8809fc9 commit be21096

File tree

4 files changed

+97
-11
lines changed

4 files changed

+97
-11
lines changed

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ Suggests:
3232
Cairo,
3333
stringr,
3434
testthat (>= 3.0.0),
35-
leaflet
35+
leaflet,
36+
withr
3637
Enhances:
3738
data.table,
3839
tibble,

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
S3method(partition_from_parts,data.table)
4+
S3method(partition_from_parts,default)
35
S3method(repr_geojson,SpatialCollections)
46
S3method(repr_geojson,SpatialGrid)
57
S3method(repr_geojson,SpatialGridDataFrame)
@@ -137,4 +139,5 @@ importFrom(tools,Rd2latex)
137139
importFrom(tools,Rd2txt)
138140
importFrom(utils,capture.output)
139141
importFrom(utils,head)
142+
importFrom(utils,str)
140143
importFrom(utils,tail)

R/repr_matrix_df.r

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,20 @@ onload_chars <- function() {
3333
chars$times_s <- .char_fallback('\u00D7', 'x')
3434
}
3535

36-
arr_partition <- function(a, rows, cols) {
37-
stopifnot(rows >= 2L, cols >= 2L)
38-
39-
# create sequences of indices to bisect rows and columns
40-
part_r <- partition(nrow(a), rows)
41-
part_c <- partition(ncol(a), cols)
42-
43-
# assign a list of parts that can be coerced to strings
36+
#' Assign a list of parts that can be coerced to strings
37+
#' @noRd
38+
partition_from_parts <- function(a, part_r, part_c) {
39+
UseMethod("partition_from_parts")
40+
}
41+
42+
#' @export
43+
partition_from_parts.default <- function(a, part_r, part_c) {
4444
if (!is.null(part_r) && !is.null(part_c)) {
4545
structure(list(
46-
ul = a[part_r$start, part_c$start], ll = a[part_r$end, part_c$start],
47-
ur = a[part_r$start, part_c$end ], lr = a[part_r$end, part_c$end ]),
46+
ul = a[part_r$start, part_c$start, drop = FALSE],
47+
ll = a[part_r$end , part_c$start, drop = FALSE],
48+
ur = a[part_r$start, part_c$end, drop = FALSE],
49+
lr = a[part_r$end , part_c$end, drop = FALSE]),
4850
omit = 'both')
4951
} else if (!is.null(part_r)) {
5052
structure(list(
@@ -61,6 +63,40 @@ arr_partition <- function(a, rows, cols) {
6163
}
6264
}
6365

66+
#' @export
67+
partition_from_parts.data.table <- function(a, part_r, part_c) {
68+
if (!is.null(part_r) && !is.null(part_c)) {
69+
structure(list(
70+
ul = a[part_r$start, part_c$start, with = FALSE, drop = FALSE],
71+
ll = a[part_r$end , part_c$start, with = FALSE, drop = FALSE],
72+
ur = a[part_r$start, part_c$end, with = FALSE, drop = FALSE],
73+
lr = a[part_r$end , part_c$end, with = FALSE, drop = FALSE]),
74+
omit = 'both')
75+
} else if (!is.null(part_r)) {
76+
structure(list(
77+
upper = a[part_r$start, , with = FALSE, drop = FALSE],
78+
lower = a[part_r$end, , with = FALSE, drop = FALSE]),
79+
omit = 'rows')
80+
} else if (!is.null(part_c)) {
81+
structure(list(
82+
left = a[, part_c$start, with = FALSE, drop = FALSE],
83+
right = a[, part_c$end, with = FALSE, drop = FALSE]),
84+
omit = 'cols')
85+
} else {
86+
structure(list(full = a), omit = 'none')
87+
}
88+
}
89+
90+
arr_partition <- function(a, rows, cols) {
91+
stopifnot(rows >= 2L, cols >= 2L)
92+
93+
# create sequences of indices to bisect rows and columns
94+
part_r <- partition(nrow(a), rows)
95+
part_c <- partition(ncol(a), cols)
96+
97+
partition_from_parts(a, part_r, part_c)
98+
}
99+
64100
# unpack tibble and coerce to data.frame
65101
arr_part_unpack_tbl <- function(tbl) {
66102
tbl_col_format <- function(col, prefix = '') {
@@ -84,6 +120,7 @@ arr_part_unpack_tbl <- function(tbl) {
84120
}
85121

86122
arr_parts_format <- function(parts) structure(lapply(parts, arr_part_format), omit = attr(parts, 'omit'))
123+
#' @importFrom utils capture.output str
87124
arr_part_format <- function(part) {
88125
if (inherits(part, 'tbl')) {
89126
part <- arr_part_unpack_tbl(part)

tests/testthat/test_repr_array_df.r

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,48 @@ test_that('data.frame with list columns can be displayed', {
204204
expect_identical(repr_html(data.table::as.data.table(df)), sub('data\\.frame','data.table',expected))
205205
}
206206
})
207+
208+
test_that('forced-narrow inputs work', {
209+
withr::local_options(repr.matrix.max.rows = 2L, repr.matrix.max.cols = 2L)
210+
df <- data.frame(a = 1:3, b = 4:6, c = 7:9)
211+
expect_silent(repr_text(df))
212+
expect_identical(
213+
# Scrub non-ASCII characters to make the test platform-agnostic.
214+
gsub("[^a-zA-Z0-9.&;<>= '\"/:\n\t]", "*", repr_html(df)),
215+
"<table class=\"dataframe\">
216+
<caption>A data.frame: 3 * 3</caption>
217+
<thead>
218+
\t<tr><th scope=col>a</th><th scope=col>*</th><th scope=col>c</th></tr>
219+
\t<tr><th scope=col>&lt;int&gt;</th><th scope=col>*</th><th scope=col>&lt;int&gt;</th></tr>
220+
</thead>
221+
<tbody>
222+
\t<tr><td>1</td><td>*</td><td>7</td></tr>
223+
\t<tr><td>*</td><td>*</td><td>*</td></tr>
224+
\t<tr><td>3</td><td>*</td><td>9</td></tr>
225+
</tbody>
226+
</table>
227+
")
228+
})
229+
230+
test_that('data.table and data.frame elision is the same', {
231+
skip_if_not_installed('data.table')
232+
withr::local_options(list(repr.matrix.max.rows = 10L, repr.matrix.max.cols = 10L))
233+
DF <- data.frame(matrix(rnorm(100L*100L), 100L, 100L))
234+
expect_identical(repr_text(DF), repr_text(data.table::as.data.table(DF)))
235+
expect_identical(repr_text(DF[1:10, ]), repr_text(data.table::as.data.table(DF[1:10, ])))
236+
expect_identical(repr_text(DF[1:10, 1:10]), repr_text(data.table::as.data.table(DF[1:10, 1:10])))
237+
})
238+
239+
test_that('data.table elision works in 1-column and 1-row edge cases', {
240+
skip_if_not_installed('data.table')
241+
withr::local_options(list(repr.matrix.max.rows = 2L, repr.matrix.max.cols = 2L))
242+
243+
DF <- data.frame(a = 1:3)
244+
expect_identical(repr_text(DF), repr_text(data.table::as.data.table(DF)))
245+
246+
DF <- data.frame(a = 1L, b = 2L, c = 3L)
247+
expect_identical(repr_text(DF), repr_text(data.table::as.data.table(DF)))
248+
249+
DF <- data.frame(a = 1:3, b = 4:6, c = 7:9)
250+
expect_identical(repr_text(DF), repr_text(data.table::as.data.table(DF)))
251+
})

0 commit comments

Comments
 (0)