37  ppplist from solist,anylist

Function spatstat.geom::solist() returns an R object of S3 class 'ppplist', if all of the input objects are two-dimensional point-patterns (ppp.object, Chapter 36). The S3 class 'ppplist' inherits from the classes 'solist' (Chapter 39), 'anylist' (Chapter 15), 'listof' and 'list'. Listing 37.1 summarizes the S3 methods for the class 'ppplist' in the spatstat.* family of packages,

Listing 37.1: S3 methods spatstat.*::*.ppplist
Code
suppressPackageStartupMessages(library(spatstat))
.S3methods(class = 'ppplist', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = grepl(pattern = '^spatstat\\.', x = from))
#                               visible             from               generic  isS4
# as.data.frame.ppplist            TRUE    spatstat.geom         as.data.frame FALSE
# density.ppplist                  TRUE spatstat.explore               density FALSE
# densityAdaptiveKernel.ppplist    TRUE spatstat.explore densityAdaptiveKernel FALSE
# superimpose.ppplist              TRUE    spatstat.geom           superimpose FALSE

The examples in Chapter 37 require

library(groupedHyperframe)
search path & loadedNamespaces on author’s computer
search()
#  [1] ".GlobalEnv"                "package:groupedHyperframe" "package:stats"             "package:graphics"          "package:grDevices"         "package:utils"             "package:datasets"         
#  [8] "package:methods"           "Autoloads"                 "package:base"
loadedNamespaces() |> sort.int()
#  [1] "abind"             "base"              "cli"               "cluster"           "codetools"         "compiler"          "datasets"          "deldir"            "digest"           
# [10] "doParallel"        "dplyr"             "evaluate"          "farver"            "fastmap"           "fastmatrix"        "foreach"           "generics"          "geomtextpath"     
# [19] "GET"               "ggplot2"           "glue"              "goftest"           "graphics"          "grDevices"         "grid"              "gridExtra"         "groupedHyperframe"
# [28] "gtable"            "htmltools"         "htmlwidgets"       "iterators"         "jsonlite"          "knitr"             "lattice"           "lifecycle"         "magrittr"         
# [37] "Matrix"            "matrixStats"       "methods"           "nlme"              "otel"              "parallel"          "patchwork"         "pillar"            "pkgconfig"        
# [46] "polyclip"          "pracma"            "R6"                "RColorBrewer"      "rlang"             "rmarkdown"         "rstudioapi"        "S7"                "scales"           
# [55] "SpatialPack"       "spatstat.data"     "spatstat.explore"  "spatstat.geom"     "spatstat.random"   "spatstat.sparse"   "spatstat.univar"   "spatstat.utils"    "stats"            
# [64] "systemfonts"       "tensor"            "textshaping"       "tibble"            "tidyselect"        "tools"             "utils"             "vctrs"             "viridisLite"      
# [73] "xfun"              "yaml"

Table 37.1 summarizes the S3 methods for the class 'ppplist' in package groupedHyperframe (v0.3.2.20251225),

Table 37.1: S3 methods groupedHyperframe::*.ppplist (v0.3.2.20251225)
visible generic isS4
.rmax.ppplist TRUE groupedHyperframe::.rmax FALSE
aggregate_marks.ppplist TRUE groupedHyperframe::aggregate_marks FALSE
density_marks.ppplist TRUE groupedHyperframe::density_marks FALSE
Emark_.ppplist TRUE groupedHyperframe::Emark_ FALSE
Gcross_.ppplist TRUE groupedHyperframe::Gcross_ FALSE
Jcross_.ppplist TRUE groupedHyperframe::Jcross_ FALSE
Kcross_.ppplist TRUE groupedHyperframe::Kcross_ FALSE
kerndens.ppplist TRUE groupedHyperframe::kerndens FALSE
Kmark_.ppplist TRUE groupedHyperframe::Kmark_ FALSE
Lcross_.ppplist TRUE groupedHyperframe::Lcross_ FALSE
markconnect_.ppplist TRUE groupedHyperframe::markconnect_ FALSE
markcorr_.ppplist TRUE groupedHyperframe::markcorr_ FALSE
markvario_.ppplist TRUE groupedHyperframe::markvario_ FALSE
Math.ppplist TRUE methods::Math FALSE
nncross_.ppplist TRUE groupedHyperframe::nncross_ FALSE
pairwise_cor_spatial.ppplist TRUE groupedHyperframe::pairwise_cor_spatial FALSE
quantile.ppplist TRUE stats::quantile FALSE
rlabelRes.ppplist TRUE groupedHyperframe::rlabelRes FALSE
Vmark_.ppplist TRUE groupedHyperframe::Vmark_ FALSE

37.1 Examples

Listing 37.2 creates a point-pattern-list pppL_num that contains the point-patterns anemones (Section 10.1) and longleaf (Section 10.15), both with one numeric mark.

Listing 37.2: Data: a point-pattern-list with one numeric mark
pppL_num = spatstat.geom::solist(
  anemones = spatstat.data::anemones,
  longleaf = spatstat.data::longleaf
)
Listing 37.3: Figure: pppL_num (Listing 37.2)
Code
par(mar = c(0,0,0,0))
pppL_num |>
  spatstat.geom::plot.solist(main = NULL)
Figure 37.1: pppL_num (Listing 37.2)

Listing 37.4 creates a point-pattern-list pppL_mt that contains the point-patterns ants (Section 10.2) and hyytiala (Section 10.13), both with one multi-type mark.

Listing 37.4: Data: a point-pattern-list with one multi-type mark
pppL_mt = spatstat.geom::solist(
  ants = spatstat.data::ants,
  hyytiala = spatstat.data::hyytiala
)
Listing 37.5: Figure: pppL_mt (Listing 37.4)
Code
par(mar = c(0,0,0,0))
pppL_mt |>
  spatstat.geom::plot.solist(main = NULL)
Figure 37.2: pppL_mt (Listing 37.4)

Listing 37.6 splits the point-pattern betacells (Section 10.4) by its multi-type mark type.

Listing 37.6: Data: a point-pattern-list betacells_type
betacells_type = spatstat.data::betacells |>
  spatstat.geom::split.ppp(f = 'type')

37.2 Kernel Density of Numeric Mark(s)

The S3 method density_marks.ppplist() (Section 36.4, Table 36.4) applies the S3 method density_marks.ppp() (Section 36.4) to each point-pattern in the input point-pattern-list.

The S3 method kerndens.ppplist() (Section 33.1, Table 33.2) applies the S3 method kerndens.ppp() (Section 36.4) to each point-pattern in the input point-pattern-list.

Listing 37.7 and Listing 37.8 find the kernel density (estimates) of all numeric marks of the split-ted betacells_type (Listing 37.6).

Listing 37.7: Example: function density_marks.ppplist() (Listing 37.6)
betacells_type |>
  density_marks()
# $off
# $off$area
# 
# Call:
#   density.default(x = `$area`)
# 
# Data: $area (70 obs.);    Bandwidth 'bw' = 11.44
# 
#        x               y            
#  Min.   :134.0   Min.   :6.323e-06  
#  1st Qu.:199.1   1st Qu.:9.940e-04  
#  Median :264.2   Median :3.102e-03  
#  Mean   :264.2   Mean   :3.832e-03  
#  3rd Qu.:329.3   3rd Qu.:5.410e-03  
#  Max.   :394.4   Max.   :1.184e-02  
# 
# 
# $on
# $on$area
# 
# Call:
#   density.default(x = `$area`)
# 
# Data: $area (65 obs.);    Bandwidth 'bw' = 23.46
# 
#        x               y            
#  Min.   :137.5   Min.   :2.919e-06  
#  1st Qu.:249.3   1st Qu.:2.427e-04  
#  Median :361.1   Median :1.414e-03  
#  Mean   :361.1   Mean   :2.231e-03  
#  3rd Qu.:473.0   3rd Qu.:4.368e-03  
#  Max.   :584.8   Max.   :6.075e-03
Listing 37.8: Example: function kerndens.ppplist() (Listing 37.6)
betacells_type |>
  kerndens(n = 8L)
# $area
# $area$off
# [1] 6.860440e-06 1.241176e-03 4.217601e-03 1.094990e-02 6.417054e-03 3.925757e-03 1.168156e-03 6.322900e-06
# 
# $area$on
# [1] 3.516447e-06 9.294044e-04 4.454117e-03 6.067291e-03 3.010829e-03 7.952900e-04 2.538680e-04 2.918730e-06

Listing 37.9 and Listing 37.10 showcase the exception handling, as the input point-pattern-list btb.extra (Section 10.6) does not contain numeric mark.

Listing 37.9: Exception: function density_marks.ppplist(), no numeric marks
spatstat.data::btb.extra |> 
  density_marks() |>
  lengths()
#     full standard 
#        0        0
Listing 37.10: Exception: function kerndens.ppplist(), no numeric marks
spatstat.data::btb.extra |> 
  kerndens() |>
  is.null() |> stopifnot()

As explained in Section 36.4, Table 36.5, the S3 method density_marks.ppplist() is different from the S3 method spatstat.explore::density.ppplist(), which uses the \(x\)- and \(y\)-coords only thus provides an identical return with the marks removed from the input point-pattern-list (Listing 37.11).

Listing 37.11: Review: function spatstat.explore::density.ppplist()
a1 = spatstat.data::btb.extra |>
  spatstat.explore::density.ppplist()
a0 = spatstat.data::btb.extra |>
  spatstat.geom::solapply(FUN = spatstat.geom::unmark.ppp) |>
  spatstat.explore::density.ppplist()
stopifnot(identical(a1, a0))

37.3 Quantile of Numeric Mark(s)

The S3 method quantile.ppplist() finds the quantiles of all numeric marks in all point-patterns (Section 36.5).

Listing 37.12 finds the quantiles of the numeric mark area in each split-ted point-pattern in betacells_type (Listing 37.6).

Listing 37.12: Example: function quantile.ppplist() (Listing 37.6)
betacells_type |>
  quantile()
# $area
# $area$off
#     0%    25%    50%    75%   100% 
# 168.30 239.40 257.35 279.25 360.10 
# 
# $area$on
#    0%   25%   50%   75%  100% 
# 207.9 281.7 321.3 362.2 514.4

Listing 37.13 showcases the exception handling, as the input point-pattern-list btb.extra (Section 10.6) does not contain numeric mark.

Listing 37.13: Example: function quantile.ppplist(), no numeric marks
spatstat.data::btb.extra |> 
  quantile()
# named list()

37.4 Aggregate Marks-Statistics

The S3 method aggregate_marks.ppplist() (Section 36.7, Table 36.7)

  • aggregates and vectorizes the marks of each point-pattern in the input point-pattern-list using the S3 method aggregate_marks.ppp() (Section 36.7);
  • returns a numeric list or vectorlist (Chapter 41).

Listing 37.14 and Listing 37.15 aggregate the sample mean, or both the sample mean and the sample standard deviation sd, of the numeric mark in the point-pattern-list pppL_num (Listing 37.2) and return a numeric vectorlist (Chapter 41).

Listing 37.14: Example: function aggregate_marks.ppplist(), for sample mean (Listing 37.2)
pppL_num |>
  aggregate_marks(FUN = mean)
# A 'vectorlist' of 2 vectors 
# Name(s): anemones, longleaf 
# Storage Mode: numeric 
# Individual Vector Length: 1
Listing 37.15: Example: function aggregate_marks.ppplist(), for sample mean and sd (Listing 37.2)
pppL_num |>
  aggregate_marks(FUN = \(z) c(mean = mean(z), sd = sd(z)))
# A 'vectorlist' of 2 vectors 
# Name(s): anemones, longleaf 
# Storage Mode: numeric 
# Individual Vector Length: 2

Listing 37.16 aggregates the relative frequencies of the multi-type mark in the point-pattern-list pppL_mt (Listing 37.4). Note that Listing 37.16 returns a numeric list, but not a vectorlist (Chapter 41).

Listing 37.16: Example: function aggregate_marks.ppplist(), for relative frequencies (Listing 37.4)
pppL_mt |>
  aggregate_marks(FUN = \(z) table(z)/length(z))
# ants:
# Cataglyphis      Messor 
#   0.2989691   0.7010309 
# 
# hyytiala:
#       aspen       birch        pine       rowan 
# 0.005952381 0.101190476 0.761904762 0.130952381

Listing 37.17 creates a point-pattern-list by duplicating the point-pattern betacells (Section 10.4), aggregates the numeric mark area by the multi-type mark type using the sample mean and the sample standard deviation sd, and returns a numeric vectorlist (Chapter 41).

Listing 37.17: Example: function aggregate_marks.ppplist(), for sample mean and sd of area-by-type
spatstat.geom::solist(
  spatstat.data::betacells,
  spatstat.data::betacells
) |>
  aggregate_marks(by = area ~ type, FUN = \(z) c(mean = mean(z), sd = sd(z)))
# A 'vectorlist' of 2 vectors 
# Storage Mode: numeric 
# Individual Vector Length: 4

Listing 37.18 creates a point-pattern-list by duplicating the point-pattern gorillas (Section 10.11), aggregates one multi-type mark season by another multi-type mark group using the relative frequencies, and returns a numeric vectorlist (Chapter 41).

Listing 37.18: Example: function aggregate_marks.ppplist(), for relative frequencies of season-by-group
spatstat.geom::solist(
  spatstat.data::gorillas,
  spatstat.data::gorillas
) |>
  aggregate_marks(by = season ~ group, FUN = \(z) table(z)/length(z))
# A 'vectorlist' of 2 vectors 
# Storage Mode: numeric 
# Individual Vector Length: 4

Listing 37.19 shows that the S3 method t.vectorlist() (Section 41.3) is the fastest way to extract a “slice” from the returned numeric-vectorlist.

Listing 37.19: Advanced: function t.vectorlist()
spatstat.geom::solist(
  spatstat.data::gorillas,
  spatstat.data::gorillas
) |>
  aggregate_marks(by = season ~ group, FUN = \(z) table(z)/length(z)) |>
  t.vectorlist()
# A 'vectorlist' of 4 vectors 
# Name(s): major.season.dry, major.season.rainy, minor.season.dry, minor.season.rainy 
# Storage Mode: numeric 
# Individual Vector Length: 2

37.5 Math Group-Generic of Numeric Mark(s)

The S3 method Math.ppplist()

  • applies the S3 method Math.ppp() (Section 36.3) to all point-patterns of the input point-pattern-list;
  • returns a point-pattern-list.

The S3 method Math.ppplist(), as well as the S3 method Math.fvlist() (Section 21.7), serves a similar purpose (Table 37.2) to the S3 method spatstat.geom::Math.imlist() (v3.6.1.16).

Table 37.2: Functions Math.ppplist(), Math.fvlist() and Math.imlist()
Math.ppplist() Math.fvlist() Math.imlist()
Input & Output ppplist (Chapter 37) fvlist (Chapter 21) imlist (Chapter 29)
Iterates Math.ppp() (Section 36.3) Math.fv() Math.im()

Listing 37.20 applies the log-transformation on the numeric marks of each point-pattern in the point-pattern-list pppL_num (Listing 37.2, Figure 37.1) and visualize the result in Figure 37.3.

Listing 37.20: Figure: log-transformed numeric marks in pppL_num (Listing 37.2)
par(mar = c(0,0,0,0))
pppL_num |>
  log() |>
  spatstat.geom::plot.solist(main = NULL)
Figure 37.3: log-transformed numeric marks in pppL_num (Listing 37.2)

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

The S3 method .rmax.ppplist() (Section 36.10, Table 36.11) obtains the default \(r_\text{max}\) before the (potentially) very slow batch processes.

Listing 37.22, Listing 37.21.

Listing 37.21: Example: function .rmax.fv() (Section 20.4)
spatstat.data::btb.extra |>
  lapply(FUN = \(i) {
    i |>
      spatstat.explore::markcorr() |> 
      vapply(FUN = .rmax.fv, FUN.VALUE = NA_real_)
  })
# $full
#        year spoligotype 
#    26.96117    26.96117 
# 
# $standard
#        year spoligotype 
#    26.96117    26.96117
Listing 37.22: Example: function .rmax.ppplist()
spatstat.data::btb.extra |> 
  .rmax(fun = 'K')
#     full standard 
# 26.96117 26.96117

37.7 \(k\)-Means Clustering

Function kmeans.ppplist()

  • 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.
  • is a simple iteration of the function kmeans.ppp() (Section 36.11).
  • returns an object of class 'pppkmlist', which inherits from 'ppplist'.

Package groupedHyperframe (v0.3.2.20251225) implements the following S3 methods to the class 'pppkmlist' (Table 37.3),

Table 37.3: S3 methods groupedHyperframe::*.pppkmlist (v0.3.2.20251225)
visible from generic isS4
split.pppkmlist TRUE groupedHyperframe base::split FALSE

37.7.1 Split by \(k\)-Means Clustering

The S3 method split.pppkmlist() splits a pppkmlist by the \(k\)-means clustering indices of each 'pppkm' member. The returned object has attributes

  • attr(,'id'), indices of the point-patterns before splitting.
  • attr(,'cluster'), indices of \(k\)-means clusters, nested in id.

Listing 37.23 uses a subset of the hyper data frame flu (Section 10.10) to illustrate this concept.

Listing 37.23: Example: function split.pppkmlist()
set.seed(14); spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(subset = (stain == 'M2-M1') & (virustype == 'wt')) |>
  spatstat.geom::`$.hyperframe`(name = 'pattern') |> 
  kmeans.ppplist(formula = ~ x + y, centers = 2L) |>
  split()
# $`wt M2-M1 13.1`
# Marked planar point pattern: 236 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# $`wt M2-M1 13.2`
# Marked planar point pattern: 235 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# $`wt M2-M1 22.1`
# Marked planar point pattern: 102 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# $`wt M2-M1 22.2`
# Marked planar point pattern: 115 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# ✂️ --- output truncated --- ✂️

37.8 Random Re-Labelling Envelope Residual & Test

The S3 method rlabelRes.ppplist() (Section 36.13, Table 36.18)

Listing 37.24 performs the random re-labelling envelope residual and test on the point-pattern-list pppL_num (Listing 37.2).

Listing 37.24: Example: functions rlabelRes.ppplist() & global_envelope_test_.anylist() (Section 15.3) (Listing 37.2)
pppL_num |>
  rlabelRes(fun = spatstat.explore::Kmark, f = `*`) |>
  global_envelope_test_()
# anemones:
# Global envelope test (1d):
#  * Based on the measure: "erl"
#  * 95% global envelope
#  * p-value of the global test: 0.01
#  * Significance level of the global test: 0.05
#  * Number of r with observed function outside the envelope: 424
#  * Total number of argument values r                      : 513
# The object contains: 
# $r - Argument values                       :  num [1:513] 0 0.0879 0.1758 0.2637 0.3516 ...
# $obs - Observed function                   :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $central - Central function                :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $lo - Lower boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $hi - Upper boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# 
# longleaf:
# Global envelope test (1d):
#  * Based on the measure: "erl"
#  * 95% global envelope
#  * p-value of the global test: 0.01
#  * Significance level of the global test: 0.05
#  * Number of r with observed function outside the envelope: 508
#  * Total number of argument values r                      : 513
# The object contains: 
# $r - Argument values                       :  num [1:513] 0 0.0977 0.1953 0.293 0.3906 ...
# $obs - Observed function                   :  num [1:513] 0 0 0 -0.401 -0.783 ...
# $central - Central function                :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $lo - Lower boundary of the global envelope:  num [1:513] 0 0 0 -0.384 -0.801 ...
# $hi - Upper boundary of the global envelope:  num [1:513] 0 0 0 1.03 1.91 ...

Listing 37.25 performs the random re-labelling envelope residual and test on the point-pattern-list pppL_mt (Listing 37.4).

Listing 37.25: Example: function rlabelRes.ppplist() & global_envelope_test_.anylist() (Section 15.3) (Listing 37.4)
pppL_mt |>
  rlabelRes(fun = spatstat.explore::Gcross) |>
  global_envelope_test_()
# ants:
# Global envelope test (1d):
#  * Based on the measure: "erl"
#  * 95% global envelope
#  * p-value of the global test: 0.02
#  * Significance level of the global test: 0.05
#  * Number of r with observed function outside the envelope: 122
#  * Total number of argument values r                      : 513
# The object contains: 
# $r - Argument values                       :  num [1:513] 0 0.297 0.594 0.891 1.188 ...
# $obs - Observed function                   :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $central - Central function                :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $lo - Lower boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $hi - Upper boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# 
# hyytiala:
# Global envelope test (1d):
#  * Based on the measure: "erl"
#  * 95% global envelope
#  * p-value of the global test: 0.75
#  * Significance level of the global test: 0.05
#  * Number of r with observed function outside the envelope: 0
#  * Total number of argument values r                      : 513
# The object contains: 
# $r - Argument values                       :  num [1:513] 0 0.0181 0.0363 0.0544 0.0725 ...
# $obs - Observed function                   :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $central - Central function                :  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $lo - Lower boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...
# $hi - Upper boundary of the global envelope:  num [1:513] 0 0 0 0 0 0 0 0 0 0 ...

37.9 Batch Process on Eligible Marks

The S3 methods Emark_.ppplist(), Vmark_.ppplist(), etc., in Table 37.1,

  • collects the return of the corresponding S3 method in Table 36.20, for each point-pattern (ppp.object, Chapter 36) in the input point-pattern-list;
  • organizes these returns into a list-of-fvlist (Chapter 21) per numeric mark, e.g., Listing 37.26.

The S3 methods Gcross_.ppplist(), Kcross_.ppplist(), etc., in Table 37.1,

  • collects the return of the corresponding S3 method in Table 36.22, for each point-pattern (ppp.object, Chapter 36) in the input point-pattern-list;
  • organizes these returns into a list-of-fvlist (Chapter 21) per multi-type mark, e.g., Listing 37.27.

The S3 method nncross_.ppplist() in Table 37.1,

  • collects the return of the corresponding S3 method in Table 36.23, for each point-pattern (ppp.object, Chapter 36) in the input point-pattern-list;
  • organizes these returns into a list-of-anylist (Chapter 15) per multi-type mark, e.g., Listing 37.28.

The low-level utility function op_ppplist(), for batch operation on ppplist, is the underlying mechanism of the batch processes (Section 3.2). Function op_ppplist()

  • applies the operation to each point-pattern (ppp.object, Chapter 36) in the input point-pattern-list, and returns a two-level hierarchical list, the first level corresponds to the individual point-patterns, and the second level corresponds to the eligible numeric marks (for operations in Table 36.20) or eligible multi-type marks (foroperations in Table 36.22 and Table 36.23);
  • ‘flips’ the hierarchy, such that the first level represents the eligible marks, and the second level corresponds to the individual point-patterns.
Listing 37.26: Example: function markcorr_.ppplist() (Listing 37.6)
betacells_type |>
  markcorr_()
# $area
# An 'fvlist' of 2 fv.objects k[mm](r) 
# Name(s): off, on 
# Available rmax: 187.5 
# Minimum Legal rmax: 187.5
Listing 37.27: Example: function Gcross_.ppplist()
flu_pattern = spatstat.data::flu |>
  spatstat.geom::subset.hyperframe(subset = (stain == 'M2-M1') & (virustype == 'wt')) |>
  spatstat.geom::`$.hyperframe`(name = 'pattern')
flu_pattern_r = flu_pattern |>
  .rmax(fun = 'G') |> 
  median.default() |>
  seq.int(from = 0, to = _, length.out = 513L)
flu_pattern |> 
  Gcross_(i = 'M2', j = 'M1', r = flu_pattern_r)
# $m
# An 'fvlist' of 8 fv.objects G[M2,M1](r) 
# Name(s): 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 
# Available rmax: 337.026271763927 
# Minimum Legal rmax: 337
Listing 37.28: Example: function nncross_.ppplist()
spatstat.data::gorillas |> 
  spatstat.geom::split.ppp(f = 'group') |>
  nncross_(i = 'dry', j = 'rainy') |>
  lapply(FUN = spatstat.geom::summary.anylist)
# $season
# major:
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#    0.00   43.56   67.63   80.18  107.80  263.51 
# 
# minor:
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   9.117  43.825  74.924  92.316 113.309 361.513