16  hyperframe

ImportantDisclaimer

These packages (Note 1) are a one-person project undergoing rapid evolution. Backward compatibility (per Hadley Wickham) is provided as a courtesy rather than a guarantee.

Until further notice, these packages should

  • not be used as the basis for research grant applications or referenced in final research progress reports,
  • not be cited as an actively maintained tool in a peer-reviewed manuscript,
  • not be used to support or fulfill requirements for pursuing an academic degree.

In addition, work primarily based on these packages (Note 1) should not be presented at academic conferences or similar scholarly venues.

Furthermore, a person’s ability to use these packages (Note 1) does not necessarily imply an understanding of their underlying mechanisms. Accordingly, demonstration of their use alone should not be considered sufficient evidence of expertise, nor should it be credited as a basis for academic promotion or advancement.

These statements do not apply to the contributors (Tip 1) to these packages (Note 1) with respect to their specific contributions.

These statements do not apply when the maintainer of these packages (Note 1), Tingting Zhan, is credited as the first author, the lead author, and/or the corresponding author in a peer-reviewed manuscript, or as the Principal Investigator or Co-Principal Investigator in a research grant application and/or a final research progress report.

These statements are advisory in nature and do not modify or restrict the rights granted under the GNU General Public License https://www.r-project.org/Licenses/.

The function hyperframe() creates a hyper data frame, i.e., an R object of S3 class 'hyperframe'. The S3 generic function as.hyperframe() converts R objects of various classes into a hyper data frame. Note 16.1 and Note 1.2 summarize the S3 methods for the generic function as.hyperframe() and the S3 methods for the class 'hyperframe', respectively, in the spatstat.* family of packages,

S3 methods of spatstat.geom::as.hyperframe (v3.7.3)
visible isS4
as.hyperframe.anylist TRUE FALSE
as.hyperframe.data.frame TRUE FALSE
as.hyperframe.default TRUE FALSE
as.hyperframe.hyperframe TRUE FALSE
as.hyperframe.listof TRUE FALSE
as.hyperframe.ppx TRUE FALSE
TipExamples in Chapter 16 Require
library(groupedHyperframe)

Table 16.1 summarizes the S3 methods for the class 'hyperframe' in package groupedHyperframe (v0.4.0, GPL-2),

Table 16.1: S3 methods groupedHyperframe::*.hyperframe (v0.4.0)
visible generic isS4
aggregate.hyperframe FALSE stats::aggregate FALSE
as.groupedHyperframe.hyperframe FALSE groupedHyperframe::as.groupedHyperframe FALSE
get_nested_factor.hyperframe FALSE groupedHyperframe::get_nested_factor FALSE
getGroupsFormula.hyperframe FALSE nlme::getGroupsFormula FALSE
length.hyperframe FALSE base::length FALSE
superimpose.hyperframe FALSE spatstat.geom::superimpose FALSE
within.hyperframe FALSE base::within FALSE

16.1 Examples

Listing 16.1 creates a subset of the hyper data frame flu (Section 9.12).

Listing 16.1: Data: fluM, a subset of flu (Section 9.12)
fluM = spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(
    subset = (stain == 'M2-M1') & (virustype == 'wt'),
    select = c('pattern', 'frameid')
  )
fluM
Hyperframe:
            pattern frameid
wt M2-M1 13   (ppp)      13
wt M2-M1 22   (ppp)      22
wt M2-M1 27   (ppp)      27
wt M2-M1 43   (ppp)      43
wt M2-M1 49   (ppp)      49
wt M2-M1 65   (ppp)      65
wt M2-M1 71   (ppp)      71
wt M2-M1 84   (ppp)      84

Listing 16.2 shows that each member of the ppp-hypercolumn fluM$pattern (Listing 16.1) has one multi-type mark with two levels 'M2' and 'M1'.

Listing 16.2: Review: number of M1 and/or M2 points per point-pattern in fluM$pattern (Listing 16.1)
fluM$pattern |>
  sapply(FUN = \(i) {
    i |> 
      spatstat.geom::marks.ppp() |> 
      table()
  }) |>
  addmargins()
    wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 wt M2-M1 49 wt M2-M1 65
M2          117          65          71         241         150         116
M1          354         152         143         165         267         202
Sum         471         217         214         406         417         318
    wt M2-M1 71 wt M2-M1 84  Sum
M2           57         104  921
M1          208         405 1896
Sum         265         509 2817

16.2 Length

The S3 method length.hyperframe() finds the number of columns and/or hypercolumns of a hyper data frame. Table 16.2 explains its rational and similarity to other length methods in package base (R version 4.5.3 (2026-03-11)).

Table 16.2: Rational of S3 Method length.hyperframe()
length() of 'data.frame' length.POSIXlt() length.hyperframe()
User-Perceived Length Yes (Listing 16.3), the number of columns Yes (Listing 16.6), the number of elements Yes (Listing 16.4), the number of (hyper)columns
Internal Structure Length Yes, the number of list elements No (Listing 16.7) No (Listing 16.5)

Listing 16.3 reveals that the data frame Formaldehyde from package datasets (R version 4.5.3 (2026-03-11)) has 2 columns, using the .Primitive S3 generic function length().

Listing 16.3: Review: function length() on data.frame
datasets::Formaldehyde |>
  length()
[1] 2

Listing 16.4 reveals that the hyper data frame demohyper (Section 9.9) has 3 (hyper)columns. The internal structure length of a hyper data frame (Listing 16.5) is not relevant to end users and may change without notice in package spatstat.geom (v3.7.3, GPL (>= 2)).

Listing 16.4: Example: function length.hyperframe()
spatstat.data::demohyper |>
  length()
[1] 3
Listing 16.5: Review: length of hyper data frame, internal-structure
spatstat.data::demohyper |>
  unclass() |>
  length()
[1] 8

The S3 method length.POSIXlt() (R version 4.5.3 (2026-03-11)) (Listing 16.6) returns the user-perceived length of a POSIXlt object, rather than its internal structure length (Listing 16.7).

Listing 16.6: Review: length of a POSIXlt object, user-perceived
tm = Sys.time() |> 
  as.POSIXlt.POSIXct(tz = 'GMT')
tm |> 
  length.POSIXlt()
[1] 1
Listing 16.7: Review: length of a POSIXlt object, internal-structure (Listing 16.6)
tm |> 
  unclass() |>
  length()
[1] 11

16.3 Aggregation

The S3 method aggregate.hyperframe()

  • splits, according to the grouping level specified in the parameter by,
    • the hypercolumn(s) that are ppplist (Chapter 25) into list(s) of ppplist;
    • the hypercolumn(s) that are imlist (Chapter 19) into list(s) of imlist;
    • the hypercolumn(s) that are solist (Chapter 27) into list(s) of solist.
  • aggregates, according to the grouping level specified in the parameter by,
    • the regular column(s) by simply taking their unique-value, as the elements in each column must be all.equal within each grouping of by;
  • returns a hyper data frame.

When the primary input is a grouped hyper data frame (Chapter 15), the aggregation may be specified at either one of the nested grouping levels (Chapter 34) \(g_1,\cdots,g_{m-1}\). Aggregation at the lowest grouping level \(g_m\) is ignored, i.e., no aggregation to be performed.

16.4 Adding group

The S3 generic function as.groupedHyperframe() creates a (grouped) hyper data frame. Package groupedHyperframe (v0.4.0, GPL-2) implements the following S3 methods (Table 16.3),

Table 16.3: S3 methods of groupedHyperframe::as.groupedHyperframe (v0.4.0)
visible generic isS4
as.groupedHyperframe.hyperframe FALSE groupedHyperframe::as.groupedHyperframe FALSE

The S3 method as.groupedHyperframe.hyperframe() converts a hyper data frame into a grouped hyper data frame by inspecting and adding a (nested) grouping structure to the input.

Listing 16.8 adds a nested grouping structure ~id to the hyper data frame osteo (Section 9.20).

Listing 16.8: Example: function as.groupedHyperframe.hyperframe()
spatstat.data::osteo |> 
  as.groupedHyperframe(group = ~ id)
Grouped Hyper Data Frame: ~id

4 id

        id shortid brick   pts depth
1   c77za4       4     1 (pp3)    45
2   c77za4       4     2 (pp3)    60
3   c77za4       4     3 (pp3)    55
4   c77za4       4     4 (pp3)    60
5   c77za4       4     5 (pp3)    85
6   c77za4       4     6 (pp3)    90
7   c77za4       4     7 (pp3)    95
8   c77za4       4     8 (pp3)    65
9   c77za4       4     9 (pp3)   100
10  c77za4       4    10 (pp3)   100
11  c77za5       5     1 (pp3)    45
21  c77za5       5     2 (pp3)    30
31  c77za5       5     3 (pp3)    40
41  c77za5       5     4 (pp3)    45
51  c77za5       5     5 (pp3)    40
61  c77za5       5     6 (pp3)    50
71  c77za5       5     7 (pp3)    40
81  c77za5       5     8 (pp3)    60
91  c77za5       5     9 (pp3)    65
101 c77za5       5    10 (pp3)    60
12  c77za8       8     1 (pp3)    40
22  c77za8       8     2 (pp3)    55
32  c77za8       8     3 (pp3)    60
42  c77za8       8     4 (pp3)    50
52  c77za8       8     5 (pp3)    45
62  c77za8       8     6 (pp3)    30
72  c77za8       8     7 (pp3)    50
82  c77za8       8     8 (pp3)    45
92  c77za8       8     9 (pp3)    70
102 c77za8       8    10 (pp3)   110
13  c77za9       9     1 (pp3)    60
23  c77za9       9     2 (pp3)    65
33  c77za9       9     3 (pp3)    55
43  c77za9       9     4 (pp3)    70
53  c77za9       9     5 (pp3)    55
63  c77za9       9     6 (pp3)   100
73  c77za9       9     7 (pp3)    80
83  c77za9       9     8 (pp3)    75
93  c77za9       9     9 (pp3)    85
103 c77za9       9    10 (pp3)    60

16.5 Superimpose

Listing 16.9 summarizes the S3 methods of the generic function superimpose() (v3.7.3, GPL (>= 2)) in the spatstat.* family of packages,

Listing 16.9: S3 methods spatstat.*::superimpose.*
library(spatstat)
.S3methods(generic = 'superimpose', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = grepl(pattern = '^spatstat\\.', x = from))
                     visible            from     generic  isS4
superimpose.default     TRUE   spatstat.geom superimpose FALSE
superimpose.lpp         TRUE spatstat.linnet superimpose FALSE
superimpose.ppp         TRUE   spatstat.geom superimpose FALSE
superimpose.ppplist     TRUE   spatstat.geom superimpose FALSE
superimpose.psp         TRUE   spatstat.geom superimpose FALSE
superimpose.splitppp    TRUE   spatstat.geom superimpose FALSE

The S3 method superimpose.hyperframe() performs a by-element superimpose of the

  • point-pattern (ppp) hypercolumns
  • line-segment-pattern (psp) hypercolumns 🚧

of multiple hyper data frames, if-and-only-if all input hyper data frames have identical

  • dimensions, i.e., dim.hyperframe() (v3.7.3, GPL (>= 2))
  • columns, i.e., unclass(.)$df
  • names and class of the hyper columns, i.e., unclass(.)$hypercolumns

The hypercolumn fluM$pattern (Listing 16.1) contains 8 point-patterns, each of them has 200-500 points (Listing 16.2). Listing 16.10 creates a hyper data frame fluM1 which consists of the same columns as fluM, but a ppp-hypercolumn $pattern with M1 marks only; and another hyper data frame fluM2 which consists of the M2 marks only.

Listing 16.10: Data: two hyper data frames fluM1 and fluM2 (Listing 16.1)
fluM1 = fluM2 = fluM
fluM1$pattern = fluM$pattern |> 
  spatstat.geom::solapply(
    FUN = spatstat.geom::subset.ppp, 
    subset = (marks == 'M1')
  )
fluM2$pattern = fluM$pattern |> 
  spatstat.geom::solapply(
    FUN = spatstat.geom::subset.ppp, 
    subset = (marks == 'M2')
  )

Listing 16.11 recreates the hyper data frame fluM (Listing 16.1) by superimposing the hyper data frames fluM2 and fluM1 (Listing 16.10). Note that the order of fluM2-then-fluM1 matters, because the points are arranged in M2-then-M1 in the original hypercolumn fluM$pattern (Listing 16.1, Listing 16.2).

Listing 16.11: Example: function superimpose.hyperframe() (Listing 16.1, Listing 16.10)
superimpose(fluM2, fluM1) |>
  identical(y = fluM) |>
  stopifnot()

Note that the S3 method superimpose.ppplist() (v3.7.3, GPL (>= 2)) superimposes all point-patterns from all input point-pattern-lists (Listing 16.12).

Listing 16.12: Review: superimpose.ppplist() not what we need (Listing 16.10)
list(
  'all superimposed' = spatstat.geom::superimpose.ppplist(
    unclass(fluM2)$hypercolumns$pattern, 
    unclass(fluM1)$hypercolumns$pattern
  ) |>
    spatstat.geom::npoints.ppp(),
  'all M2' = fluM2$pattern |> 
    vapply(FUN = spatstat.geom::npoints.ppp, FUN.VALUE = NA_integer_) |>
    sum(),
  'all M1' = fluM1$pattern |> 
    vapply(FUN = spatstat.geom::npoints.ppp, FUN.VALUE = NA_integer_) |>
    sum()
)
$`all superimposed`
[1] 2817

$`all M2`
[1] 921

$`all M1`
[1] 1896