20  hyperframe

Function spatstat.geom::hyperframe() creates a hyper data frame, i.e., an R object of S3 class 'hyperframe'.

Listing 20.1 summarizes the S3 methods for the class 'hyperframe' in the spatstat.* family of packages,

Listing 20.1: Existing S3 methods spatstat.geom::*.hyperframe
Code
suppressPackageStartupMessages(library(spatstat.geom))
.S3methods(class = 'hyperframe', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.geom')
#                          visible          from       generic  isS4
# [.hyperframe                TRUE spatstat.geom             [ FALSE
# [[.hyperframe               TRUE spatstat.geom            [[ FALSE
# [[<-.hyperframe             TRUE spatstat.geom          [[<- FALSE
# [<-.hyperframe              TRUE spatstat.geom           [<- FALSE
# $.hyperframe                TRUE spatstat.geom             $ FALSE
# $<-.hyperframe              TRUE spatstat.geom           $<- FALSE
# as.data.frame.hyperframe    TRUE spatstat.geom as.data.frame FALSE
# as.hyperframe.hyperframe    TRUE spatstat.geom as.hyperframe FALSE
# as.list.hyperframe          TRUE spatstat.geom       as.list FALSE
# cbind.hyperframe            TRUE spatstat.geom         cbind FALSE
# dim.hyperframe              TRUE spatstat.geom           dim FALSE
# dimnames.hyperframe         TRUE spatstat.geom      dimnames FALSE
# dimnames<-.hyperframe       TRUE spatstat.geom    dimnames<- FALSE
# edit.hyperframe             TRUE spatstat.geom          edit FALSE
# head.hyperframe             TRUE spatstat.geom          head FALSE
# is.na.hyperframe            TRUE spatstat.geom         is.na FALSE
# names.hyperframe            TRUE spatstat.geom         names FALSE
# names<-.hyperframe          TRUE spatstat.geom       names<- FALSE
# plot.hyperframe             TRUE spatstat.geom          plot FALSE
# print.hyperframe            TRUE spatstat.geom         print FALSE
# rbind.hyperframe            TRUE spatstat.geom         rbind FALSE
# row.names.hyperframe        TRUE spatstat.geom     row.names FALSE
# row.names<-.hyperframe      TRUE spatstat.geom   row.names<- FALSE
# split.hyperframe            TRUE spatstat.geom         split FALSE
# split<-.hyperframe          TRUE spatstat.geom       split<- FALSE
# str.hyperframe              TRUE spatstat.geom           str FALSE
# subset.hyperframe           TRUE spatstat.geom        subset FALSE
# summary.hyperframe          TRUE spatstat.geom       summary FALSE
# tail.hyperframe             TRUE spatstat.geom          tail FALSE
# with.hyperframe             TRUE spatstat.geom          with FALSE

The examples in Chapter 20 require that the search path contains the following namespaces,

library(groupedHyperframe)

Package groupedHyperframe (v0.3.2) implements more S3 methods to the class 'hyperframe' (Table 20.1),

Table 20.1: S3 methods groupedHyperframe::*.hyperframe (v0.3.2)
visible generic isS4
.disrecommend2theo.hyperframe TRUE groupedHyperframe::.disrecommend2theo FALSE
.illegal2theo.hyperframe TRUE groupedHyperframe::.illegal2theo FALSE
.rmax.hyperframe TRUE groupedHyperframe::.rmax FALSE
aggregate_marks.hyperframe TRUE groupedHyperframe::aggregate_marks FALSE
aggregate.hyperframe TRUE stats::aggregate FALSE
as.groupedHyperframe.hyperframe TRUE groupedHyperframe::as.groupedHyperframe FALSE
cumvtrapz.hyperframe TRUE groupedHyperframe::cumvtrapz FALSE
Emark_.hyperframe TRUE groupedHyperframe::Emark_ FALSE
Gcross_.hyperframe TRUE groupedHyperframe::Gcross_ FALSE
Jcross_.hyperframe TRUE groupedHyperframe::Jcross_ FALSE
Kcross_.hyperframe TRUE groupedHyperframe::Kcross_ FALSE
kerndens.hyperframe TRUE groupedHyperframe::kerndens FALSE
keyval.hyperframe TRUE groupedHyperframe::keyval FALSE
Kmark_.hyperframe TRUE groupedHyperframe::Kmark_ FALSE
Lcross_.hyperframe TRUE groupedHyperframe::Lcross_ FALSE
length.hyperframe TRUE base::length FALSE
markconnect_.hyperframe TRUE groupedHyperframe::markconnect_ FALSE
markcorr_.hyperframe TRUE groupedHyperframe::markcorr_ FALSE
markvario_.hyperframe TRUE groupedHyperframe::markvario_ FALSE
nncross_.hyperframe TRUE groupedHyperframe::nncross_ FALSE
quantile.hyperframe TRUE stats::quantile FALSE
superimpose.hyperframe TRUE spatstat.geom::superimpose FALSE
Vmark_.hyperframe TRUE groupedHyperframe::Vmark_ FALSE
Table 20.2: S3 methods currently not planned for class 'hyperframe'
Table 20.2: S3 methods currently not planned for class 'hyperframe'
Not Planned Explained in
as.environment.hyperframe() Section 35.1
merge.hyperframe() Section 35.2

20.1 Plot

Section 20.1 is intended as an educational handbook for beginners to package spatstat.geom (v3.6.1). This section does not discuss the functionality of package groupedHyperframe (v0.3.2).

The S3 method spatstat.geom::plot.hyperframe() plots the plot-able hypercolumn(s) in a hyper data frame.

Listing 20.2 deems the multi-type ppp-hypercolumn flu$pattern (Section 10.10) to be plot-able, and plots them (Figure 20.1).

Listing 20.2: Review: spatstat.geom::plot.hyperframe(); plot ppp-hypercolumn flu$pattern
par(mar = c(0,0,1,0))
spatstat.data::flu[1:2, ] |>
  spatstat.geom::plot.hyperframe()
Figure 20.1: Plot ppp-hypercolumn flu$pattern

20.2 Length

The S3 method length.hyperframe() finds the number of columns and/or hypercolumns of a hyper data frame. Listing 20.3 reveals that the hyper data frame demohyper (Section 10.8) has 3 (hyper)columns.

Listing 20.3: Example: function length.hyperframe()
spatstat.data::demohyper |>
  length()
# [1] 3

The S3 method length.hyperframe() reproduces the behavior of the .Primitive S3 generic function base::length() when dispatched to objects of class 'data.frame'. Listing 20.4 reveals that the data frame Formaldehyde from package datasets shipped with R version 4.5.2 (2025-10-31) has 2 columns.

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

The S3 method length.hyperframe() returns the user-perceived length, instead of internal structure length (Listing 20.5), of a hyper data frame. This behavior parallels that of the S3 method base::length.POSIXlt(), which returns the user-perceived length (Listing 20.7) of a POSIXlt object (Listing 20.6), rather than its internal structure length (Listing 20.8).

Listing 20.5: Review: length of hyper data frame, internal-structure
Code
spatstat.data::demohyper |>
  unclass() |>
  length()
# [1] 8
Listing 20.6: Review: a POSIXlt object
Code
tm = Sys.time() |> 
  as.POSIXlt.POSIXct(tz = 'GMT')
tm
# [1] "2025-11-25 15:37:18 GMT"
Listing 20.7: Review: length of a POSIXlt object, user-perceived
Code
tm |> 
  length.POSIXlt()
# [1] 1
Listing 20.8: Review: length of a POSIXlt object, internal-structure
Code
tm |> 
  unclass() |>
  length()
# [1] 11

20.3 Kernel Density

The S3 method kerndens.hyperframe() finds the kernel density (Becker, Chambers, and Wilks 1988) estimates,

and appends additional numeric-hypercolumns to the input. Example has been discussed extensively in Section 3.3.4.

20.4 Quantile

The S3 method quantile.hyperframe() finds the quantiles

and appends the returned quantiles as numeric-hypercolumns to the input. Example has been discussed extensively in Section 3.3.3.

20.5 Aggregation

The S3 method aggregate.hyperframe()

  • splits (Section 13.3), according to the grouping level specified in the parameter by,
    • the hypercolumn(s) that are ppplist(s) (Chapter 28) into list(s) of ppplist;
    • the hypercolumn(s) that are imlist(s) (Chapter 23) into list(s) of imlist;
    • the hypercolumn(s) that are fvlist(s) (Chapter 16) into list(s) of fvlist;
    • the hypercolumn(s) that are solist(s) (Chapter 30) 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;
    • the hypercolumn(s) that are vectorlist(s) (Chapter 32) using the aggregation method provided in the parameter fun (Section 32.4).
  • returns a hyperframe.

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

20.6 Aggregate Marks-Statistics from ppp-hypercolumn

The S3 generic function aggregate_marks() has been introduced in Section 27.7 (Table 27.6). The S3 method aggregate_marks.hyperframe()

  • aggregates the marks of one-and-only-one (Section 20.14) ppp-hypercolumn in the input (Section 28.3);
  • appends the returned numeric-vectorlist to the input as a new hypercolumn named 'markstats'.

The author uses the hyper data frame flu (Section 10.10) to illustrate the aggregation of relative frequencies of the sole multi-type-mark in the ppp-hypercolumn $pattern.

Review: flu$pattern is a ppp-hypercolumn with one multi-type-mark
spatstat.data::flu$pattern[[1L]] |>
  spatstat.geom::marks.ppp() |>
  table()
# 
#  M2  M1 
# 117 354
Example: function aggregate_marks.hyperframe(), for relative frequencies
flu_mfreq = spatstat.data::flu |> 
  aggregate_marks(FUN = \(z) table(z)/length(z))
flu_mfreq |>
  head(n = 3L)
# Hyperframe:
#             pattern virustype stain frameid markstats
# wt M2-M1 13   (ppp)        wt M2-M1      13 (numeric)
# wt M2-M1 22   (ppp)        wt M2-M1      22 (numeric)
# wt M2-M1 27   (ppp)        wt M2-M1      27 (numeric)
flu_mfreq$markstats
# wt M2-M1 13:
#        M2        M1 
# 0.2484076 0.7515924 
# 
# wt M2-M1 22:
#        M2        M1 
# 0.2995392 0.7004608 
# 
# wt M2-M1 27:
#        M2        M1 
# 0.3317757 0.6682243 
# 
# wt M2-M1 43:
#        M2        M1 
# 0.5935961 0.4064039 
# 
# wt M2-M1 49:
#        M2        M1 
# 0.3597122 0.6402878 
# 
# wt M2-M1 65:
#        M2        M1 
# 0.3647799 0.6352201 
# 
# wt M2-M1 71:
#        M2        M1 
# 0.2150943 0.7849057 
# 
# wt M2-M1 84:
#        M2        M1 
# 0.2043222 0.7956778 
# 
# wt M2-HA 3:
#        M2        HA 
# 0.1235955 0.8764045 
# 
# wt M2-HA 4:
#         M2         HA 
# 0.08552632 0.91447368 
# 
# wt M2-HA 5:
#        M2        HA 
# 0.1532067 0.8467933 
# 
# wt M2-HA 17:
#         M2         HA 
# 0.07642031 0.92357969 
# 
# wt M2-HA 54:
#        M2        HA 
# 0.0488746 0.9511254 
# 
# wt M2-HA 74:
#         M2         HA 
# 0.07753623 0.92246377 
# 
# wt M2-HA 78:
#         M2         HA 
# 0.08067093 0.91932907 
# 
# wt M2-HA 82:
#         M2         HA 
# 0.08860759 0.91139241 
# 
# wt M2-HA 85:
#         M2         HA 
# 0.08832808 0.91167192 
# 
# wt M2-HA 100:
#         M2         HA 
# 0.08317699 0.91682301 
# 
# wt M2-HA 110:
#        M2        HA 
# 0.1409456 0.8590544 
# 
# mut1 M2-M1 11:
#        M2        M1 
# 0.7816901 0.2183099 
# 
# mut1 M2-M1 13:
#        M2        M1 
# 0.8134328 0.1865672 
# 
# mut1 M2-M1 15:
#        M2        M1 
# 0.9205298 0.0794702 
# 
# mut1 M2-M1 17:
#         M2         M1 
# 0.93874539 0.06125461 
# 
# mut1 M2-M1 28:
#         M2         M1 
# 0.93222506 0.06777494 
# 
# mut1 M2-M1 29:
#        M2        M1 
# 0.7755474 0.2244526 
# 
# mut1 M2-M1 33:
#        M2        M1 
# 0.7953668 0.2046332 
# 
# mut1 M2-M1 38:
#        M2        M1 
# 0.3823529 0.6176471 
# 
# mut1 M2-M1 41:
#        M2        M1 
# 0.8075314 0.1924686 
# 
# mut1 M2-M1 44:
#        M2        M1 
# 0.7272727 0.2727273 
# 
# mut1 M2-M1 59:
#        M2        M1 
# 0.8545994 0.1454006 
# 
# mut1 M2-HA 8:
#        M2        HA 
# 0.4059829 0.5940171 
# 
# mut1 M2-HA 14:
#        M2        HA 
# 0.2336343 0.7663657 
# 
# mut1 M2-HA 23:
#        M2        HA 
# 0.3895582 0.6104418 
# 
# mut1 M2-HA 42:
#        M2        HA 
# 0.4547619 0.5452381 
# 
# mut1 M2-HA 51:
#       M2       HA 
# 0.532097 0.467903 
# 
# mut1 M2-HA 59:
#        M2        HA 
# 0.3274232 0.6725768 
# 
# mut1 M2-HA 73:
#        M2        HA 
# 0.3585799 0.6414201 
# 
# mut1 M2-HA 79:
#       M2       HA 
# 0.477195 0.522805 
# 
# mut1 M2-HA 86:
#        M2        HA 
# 0.2168979 0.7831021 
# 
# mut1 M2-HA 104:
#        M2        HA 
# 0.2893726 0.7106274 
# 
# mut1 M2-HA 147:
#        M2        HA 
# 0.2068966 0.7931034

As explained in Section 28.3, the S3 method t.vectorlist() (Section 32.3) is the fastest way to extract a “slice” from the numeric-hypercolumn, e.g., flu_mfreq$markstats.

Advanced: function t.vectorlist()
flu_mfreq$markstats[1:4] |>
  t.vectorlist()
# M2:
# wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 
#   0.2484076   0.2995392   0.3317757   0.5935961 
# 
# M1:
# wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 
#   0.7515924   0.7004608   0.6682243   0.4064039

Unfortunately, package spatstat.data (v3.1.9) does not have a hyper data frame with (any) ppp-hypercolumn of

  • 'dataframe'-markformat, to showcase the use of parameter by in the S3 method aggregate_marks.hyperframe().
  • 'vector'-markformat and numeric-marks, to showcase the aggregation by sample mean and standard deviation.

20.7 Create groupedHyperframe

The S3 generic function as.groupedHyperframe() has been introduced in Section 14.1 (Table 14.2). 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 20.9 adds a nested grouping structure ~id/brick to the hyper data frame osteo (Section 10.16).

Listing 20.9: Example: function as.groupedHyperframe.hyperframe()
spatstat.data::osteo |> 
  as.groupedHyperframe(group = ~ id/brick)
# Grouped Hyperframe: ~id/brick
# 
# 40 brick nested in
# 4 id
# 
# Preview of first 10 (or less) rows:
# 
#        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

20.8 Superimpose

Listing 20.10 summarizes the S3 methods of the generic function spatstat.geom::superimpose() in the spatstat.* family of packages,

Listing 20.10: Existing S3 methods spatstat.geom::superimpose.*
Code
suppressPackageStartupMessages(library(spatstat.geom))
.S3methods(generic = 'superimpose', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.geom')
#                      visible          from     generic  isS4
# superimpose.default     TRUE spatstat.geom 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() superimposes multiple hyper data frames if-and-only-if they have identical

  • dimensions, i.e., spatstat.geom::dim.hyperframe()
  • columns, i.e., unclass(.)$df
  • names and class of the hyper columns, i.e., unclass(.)$hypercolumns

The author uses the hyper data frame fluM (Section 10.10) to illustrate the superimpose of multiple hyper data frames.

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

The hyper data frame fluM contains 8 subjects, each of them has a point-pattern with 200-500 points.

Review: number of points per point-pattern in hypercolumn fluM$pattern
fluM$pattern |>
  sapply(FUN = spatstat.geom::npoints.ppp)
# wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 wt M2-M1 49 wt M2-M1 65 wt M2-M1 71 wt M2-M1 84 
#         471         217         214         406         417         318         265         509
Review: number of M1 and/or M2 points per point-pattern in hypercolumn fluM$pattern
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 wt M2-M1 71 wt M2-M1 84  Sum
# M2          117          65          71         241         150         116          57         104  921
# M1          354         152         143         165         267         202         208         405 1896
# Sum         471         217         214         406         417         318         265         509 2817

The author creates a hyper data frame fluM1 which consists of the same columns as fluM, but a ppp-hypercolumn pattern with M1 marks only. Similarly, the author creates another hyper data frame fluM2 which consists of the M2 marks only. Note that as of package spatstat.geom v3.6.1, the tedious code below is the only way to avoid using the row names of hyper data frame as the element-names of the hypercolumns. In other words, function unclass() avoids invoking the S3 method spatstat.geom::`$.hyperframe`(). The S3 method spatstat.geom::`$<-.hyperframe` is fine in this application.

Data: two hyper data frames fluM1 and fluM2
fluM1 = fluM2 = fluM
fluM1$pattern = unclass(fluM)$hypercolumns$pattern |> 
  spatstat.geom::solapply(FUN = spatstat.geom::subset.ppp, subset = (marks == 'M1'))
fluM2$pattern = unclass(fluM)$hypercolumns$pattern |> 
  spatstat.geom::solapply(FUN = spatstat.geom::subset.ppp, subset = (marks == 'M2'))
Review: number of M1 points per point-pattern in hypercolumn fluM1$pattern
fluM1$pattern |>
  sapply(FUN = spatstat.geom::npoints.ppp)
# wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 wt M2-M1 49 wt M2-M1 65 wt M2-M1 71 wt M2-M1 84 
#         354         152         143         165         267         202         208         405
Review: number of M2 points per point-pattern in hypercolumn fluM2$pattern
fluM2$pattern |>
  sapply(FUN = spatstat.geom::npoints.ppp)
# wt M2-M1 13 wt M2-M1 22 wt M2-M1 27 wt M2-M1 43 wt M2-M1 49 wt M2-M1 65 wt M2-M1 71 wt M2-M1 84 
#         117          65          71         241         150         116          57         104

The S3 method superimpose.hyperframe() recreates the hyper data frame fluM by combining the hyper data frames fluM2 and fluM1. Note that the order of fluM2-then-fluM1 matters, because the points are arranged in M2-then-M1 in the original hypercolumn fluM$pattern.

Example: function superimpose.hyperframe()
fluS = superimpose.hyperframe(fluM2, fluM1)
stopifnot(identical(fluS, fluM))

The S3 method spatstat.geom::superimpose.ppplist() (v3.6.1) superimposes all point-patterns from all input ppplists, instead of performing a by-element superimpose of all input ppplists as intended for the S3 method superimpose.hyperframe().

Review: spatstat.geom::superimpose.ppplist() (Baddeley, Rubak, and Turner 2015) not what we need
spatstat.geom::superimpose.ppplist(
  unclass(fluM2)$hypercolumns$pattern, 
  unclass(fluM1)$hypercolumns$pattern
)
# Marked planar point pattern: 2817 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
fluM2$pattern |> 
  vapply(FUN = spatstat.geom::npoints.ppp, FUN.VALUE = NA_integer_) |>
  sum()
# [1] 921
fluM1$pattern |> 
  vapply(FUN = spatstat.geom::npoints.ppp, FUN.VALUE = NA_integer_) |>
  sum()
# [1] 1896

20.9 Default \(r_\text{max}\)

The S3 generic function .rmax() has been introduced in Section 27.10 (Table 27.9). The S3 method .rmax.hyperframe() obtains the default \(r_\text{max}\) of the one-or-more ppp-hypercolumn(s) (Section 28.4) before the (potentially) very slow batch processes.

Example: function .rmax.hyperframe() for Emark_(), Vmark_(), markcorr_(), markvario_() on numeric- and multi-type-mark
s |> .rmax(fun = 'K')
Example: function .rmax.hyperframe() for Kcross_() on multi-type-mark
s |> .rmax(fun = 'K', i = 'CK+.CD8-', j = 'CK-.CD8+')
s |> .rmax(fun = 'K', i = 'CK-.CD8+', j = 'CK+.CD8-')
Example: function .rmax.hyperframe() for Gcross_() on multi-type-mark
s |> .rmax(fun = 'G', i = 'CK+.CD8-', j = 'CK-.CD8+')
s |> .rmax(fun = 'G', i = 'CK-.CD8+', j = 'CK+.CD8-')
Example: function .rmax.hyperframe() for Jcross_() on multi-type-mark
s |> .rmax(fun = 'J', i = 'CK+.CD8-', j = 'CK-.CD8+')
s |> .rmax(fun = 'J', i = 'CK-.CD8+', j = 'CK+.CD8-')

20.10 Function Value from fv-Hypercolumns

The S3 generic function keyval() has been introduced in Section 15.1 (Table 15.3). The S3 method keyval.hyperframe()

  • applies the S3 method keyval.fvlist() (Section 16.3) across all fv-hypercolumns of the input (grouped) hyper data frame;
  • appends an additional numeric-hypercolumn <mark>.<fv>.<selected_value> to the input (grouped) hyper data frame.

Listing 20.11 works on a subset of hyper data frame flu (Section 10.10) to

  1. apply the S3 method Gcross_.hyperframe() (Section 20.14) and create an fv-hypercolumn m.G in the returned hyper data frame fluG_v (Listing 20.14);
  2. apply the S3 method keyval.hyperframe() and create a numeric-hypercolumn m.G.y of the recommended function values in the returned hyper data frame fluG_v (Listing 20.14).
  3. apply the S3 method keyval.hyperframe(., key = 'theo') and create a numeric-hypercolumn m.G.theo of the theoretical function values in the returned hyper data frame fluG_v (Listing 20.14).
Listing 20.11: Example: function keyval.hyperframe()
fluG_v = spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(
    subset = (stain == 'M2-M1') & (virustype == 'wt')
  ) |>
  Gcross_(i = 'M1', j = 'M2', r = seq.int(from = 0, to = 100, by = 5)) |>
  keyval() |>
  keyval(key = 'theo')
# 
Listing 20.12: Example: hyper data frame fluG
fluG_v
# Hyperframe:
#             pattern virustype stain frameid  m.G     m.G.y  m.G.theo
# wt M2-M1 13   (ppp)        wt M2-M1      13 (fv) (numeric) (numeric)
# wt M2-M1 22   (ppp)        wt M2-M1      22 (fv) (numeric) (numeric)
# wt M2-M1 27   (ppp)        wt M2-M1      27 (fv) (numeric) (numeric)
# wt M2-M1 43   (ppp)        wt M2-M1      43 (fv) (numeric) (numeric)
# wt M2-M1 49   (ppp)        wt M2-M1      49 (fv) (numeric) (numeric)
# wt M2-M1 65   (ppp)        wt M2-M1      65 (fv) (numeric) (numeric)
# wt M2-M1 71   (ppp)        wt M2-M1      71 (fv) (numeric) (numeric)
# wt M2-M1 84   (ppp)        wt M2-M1      84 (fv) (numeric) (numeric)

20.11 Cumulative Average Vertical Height of Trapzoidal Integration of fv-Hypercolumn

The S3 generic function cumvtrapz() has been introduced in Section 11.1 (Table 11.1). The S3 method cumvtrapz.hyperframe()

  • runs the workhorse function cumvtrapz.fvlist() (Section 16.5) across all fv-hypercolumns of the input (grouped) hyper data frame;
  • appends additional numeric-hypercolumns <mark>.<fv>.cumvtrapz to the input.

The S3 method t.vectorlist() (Section 32.3) is the fastest way to extract a “slice” from a numeric-hypercolumn, e.g., out_fv$hladr.E.cumvtrapz from Chapter 3, Listing 3.1, Listing 3.4, Listing 3.8. The numeric-hypercolumns created by function summary_fv() are 'vectorlist's (although not supported as hypercolumns in hyperframe as of package spatstat.geom v3.6.1), as they contain tabulated values on common \(r\)-vector(s). A “slice” of the hypercolumn out_fv$hladr.E.cumvtrapz at the 5th index of the \(r\)-vector, i.e., \(r=50\), may be extracted by calling the S3 method spatstat.geom::with.hyperframe(), but the S3 method t.vectorlist() is much faster.

Example: function t.vectorlist(); a ‘slice’ from hypercolumn out_fv$hladr.E.cumvtrapz
if (FALSE) {
E_r50_a = out_fv |>
  spatstat.geom::with.hyperframe(expr = {
    hladr.E.cumvtrapz['50']
  })
E_r50_a
E_r50_b = out_fv |>
  spatstat.geom::with.hyperframe(expr = {
    hladr.E.cumvtrapz[5L]
  })
stopifnot(identical(E_r50_a, E_r50_b))
tE = out_fv$hladr.E.cumvtrapz |>
  t.vectorlist()
stopifnot(identical(E_r50_a, tE[[5L]]))
}

20.12 Handling Illegal Recommended-Function-Value

The S3 generic functions .illegal2theo() and .disrecommend2theo() have been introduced in Section 15.4.1 (Table 15.4, Table 15.5). The S3 methods .illegal2theo.hyperframe() and .disrecommend2theo.hyperframe()

  • apply the S3 methods .illegal2theo.fvlist() and .disrecommend2theo.fvlist() (Section 16.4) to all fv-hypercolumns of the input (grouped) hyper data frame;
  • overwrite the fv-hypercolumns in the input (grouped) hyper data frame.

Listing 20.13 works on a subset of hyper data frame flu (Section 10.10) to

  1. apply the S3 method Gcross_.hyperframe() (Section 20.14) and create an fv-hypercolumn m.G in the returned hyper data frame fluG (Listing 20.14);
  2. apply the S3 method .disrecommend2theo.hyperframe() and overwrite the fv-hypercolumn m.G in the returned hyper data frame fluG (Listing 20.14).
Listing 20.13: Example: function .disrecommend2theo.hyperframe()
fluG = spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(
    subset = (stain == 'M2-M1') & (virustype == 'wt')
  ) |>
  Gcross_(i = 'M1', j = 'M2', r = seq.int(from = 0, to = 100, by = 5)) |>
  .disrecommend2theo()
# 
Listing 20.14: Example: hyper data frame fluG
fluG
# Hyperframe:
#             pattern virustype stain frameid  m.G
# wt M2-M1 13   (ppp)        wt M2-M1      13 (fv)
# wt M2-M1 22   (ppp)        wt M2-M1      22 (fv)
# wt M2-M1 27   (ppp)        wt M2-M1      27 (fv)
# wt M2-M1 43   (ppp)        wt M2-M1      43 (fv)
# wt M2-M1 49   (ppp)        wt M2-M1      49 (fv)
# wt M2-M1 65   (ppp)        wt M2-M1      65 (fv)
# wt M2-M1 71   (ppp)        wt M2-M1      71 (fv)
# wt M2-M1 84   (ppp)        wt M2-M1      84 (fv)

20.13 \(k\)-Means Clustering

Function kmeans.hyperframe()

  • is a “pseudo” S3 method, as the workhorse function stats::kmeans() shipped with R version 4.5.2 (2025-10-31) is not an S3 generic function.
  • performs \(k\)-means clustering on the one-and-only-one (Section 20.14) ppp-hypercolumn via kmeans.ppplist() (Section 28.5).
  • returns an object of class 'hyperframekm', which inherits from 'hyperframe'.

Package groupedHyperframe (v0.3.2) implements the following S3 methods to the class 'hyperframekm' (Table 20.3),

Table 20.3: S3 methods groupedHyperframe::*.hyperframekm (v0.3.2)
visible from generic isS4
split.hyperframekm TRUE groupedHyperframe base::split FALSE

20.13.1 Examples

The author uses the hyper data frame flu (Section 10.10) to illustrate this usage.

Example: function kmeans.hyperframe()
set.seed(13); flu_k = spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(subset = (stain == 'M2-M1') & (virustype == 'wt')) |> 
  kmeans.hyperframe(formula = ~ x + y, centers = 3L)
flu_k |>
  class()
# [1] "hyperframekm" "hyperframe"   "list"
flu_k$pattern[1:3]
# List of point patterns
# 
# wt M2-M1 13:
# Marked planar point pattern: 471 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# with k-means clustering of 153, 147, 171 points
# 
# wt M2-M1 22:
# Marked planar point pattern: 217 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# with k-means clustering of 85, 68, 64 points
# 
# wt M2-M1 27:
# Marked planar point pattern: 214 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# with k-means clustering of 84, 71, 59 points

20.13.2 Split by \(k\)-Means Clustering

The S3 method split.hyperframekm() splits a hyperframekm by the \(k\)-means clustering indices of the one-and-only-one (Section 20.14) ppp-hypercolumn. The returned object is a grouped hyper data frame with grouping structure

  • ~.id/.cluster, if the input is a hyper data frame
  • ~ <existing/grouping/structure>/.cluster, if the input is a grouped hyper data frame. Note that the grouping level .id is believed to be equivalent to the lowest level of existing grouping structure.

The author uses the hyper data frame flu (Section 10.10) to illustrate this usage.

Example: function split.hyperframekm()
set.seed(13); spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(subset = (stain == 'M2-M1') & (virustype == 'wt')) |> 
  kmeans.hyperframe(formula = ~ x + y, centers = 3L) |> 
  split()
# Grouped Hyperframe: ~.id/.cluster
# 
# 24 .cluster nested in
# 8 .id
# 
# Preview of first 10 (or less) rows:
# 
#    pattern .id .cluster virustype stain frameid
# 1    (ppp)   1        1        wt M2-M1      13
# 2    (ppp)   1        2        wt M2-M1      13
# 3    (ppp)   1        3        wt M2-M1      13
# 4    (ppp)   2        1        wt M2-M1      22
# 5    (ppp)   2        2        wt M2-M1      22
# 6    (ppp)   2        3        wt M2-M1      22
# 7    (ppp)   3        1        wt M2-M1      27
# 8    (ppp)   3        2        wt M2-M1      27
# 9    (ppp)   3        3        wt M2-M1      27
# 10   (ppp)   4        1        wt M2-M1      43

20.14 Batch Process on Eligible Marks

The S3 methods Emark_.hyperframe(), Vmark_.hyperframe(), etc., in Table 20.1 are user-friendly wrappers of the low-level utility function op_hyperframe(), for batch operation on hyper data frame (Section 3.2). Function op_hyperframe()

  • performs the batch operation on the one-and-only-one ppp-hypercolumn (Section 28.6) of the input hyper data frame. The batch operation is not designed to handle a hyper data frame containing multiple ppp-hypercolumns, e.g., cetaceans (Section 10.7). Supporting such functionality would require resolving potential name clashes in the marks across multiple ppp-hypercolumns.
  • column-binds the two-level hierarchical list returned from the previous step to the input hyper data frame.