27  ppp

Function spatstat.geom::ppp() creates a two-dimensional point-pattern object (ppp.object), i.e., an R object of S3 class 'ppp'. A point-pattern contains the \(x\)- and \(y\)-coordinates in an observation window (Chapter 25) and may contain

Listing 27.1 - Listing 27.4 summarize the S3 methods for the class 'ppp' in the spatstat.* family of packages,

Listing 27.1: Existing S3 methods spatstat.geom::*.ppp
Code
suppressPackageStartupMessages(library(spatstat.geom))
.S3methods(class = 'ppp', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.geom')
#                       visible          from           generic  isS4
# [.ppp                    TRUE spatstat.geom                 [ FALSE
# [<-.ppp                  TRUE spatstat.geom               [<- FALSE
# affine.ppp               TRUE spatstat.geom            affine FALSE
# anyDuplicated.ppp        TRUE spatstat.geom     anyDuplicated FALSE
# as.data.frame.ppp        TRUE spatstat.geom     as.data.frame FALSE
# as.im.ppp                TRUE spatstat.geom             as.im FALSE
# as.layered.ppp           TRUE spatstat.geom        as.layered FALSE
# as.owin.ppp              TRUE spatstat.geom           as.owin FALSE
# as.ppp.ppp               TRUE spatstat.geom            as.ppp FALSE
# boundingbox.ppp          TRUE spatstat.geom       boundingbox FALSE
# boundingcentre.ppp       TRUE spatstat.geom    boundingcentre FALSE
# boundingcircle.ppp       TRUE spatstat.geom    boundingcircle FALSE
# boundingradius.ppp       TRUE spatstat.geom    boundingradius FALSE
# by.ppp                   TRUE spatstat.geom                by FALSE
# circumradius.ppp         TRUE spatstat.geom      circumradius FALSE
# closepairs.ppp           TRUE spatstat.geom        closepairs FALSE
# closing.ppp              TRUE spatstat.geom           closing FALSE
# connected.ppp            TRUE spatstat.geom         connected FALSE
# coords.ppp               TRUE spatstat.geom            coords FALSE
# coords<-.ppp             TRUE spatstat.geom          coords<- FALSE
# crossdist.ppp            TRUE spatstat.geom         crossdist FALSE
# crosspairs.ppp           TRUE spatstat.geom        crosspairs FALSE
# cut.ppp                  TRUE spatstat.geom               cut FALSE
# default.symbolmap.ppp    TRUE spatstat.geom default.symbolmap FALSE
# dilation.ppp             TRUE spatstat.geom          dilation FALSE
# distfun.ppp              TRUE spatstat.geom           distfun FALSE
# distmap.ppp              TRUE spatstat.geom           distmap FALSE
# domain.ppp               TRUE spatstat.geom            domain FALSE
# duplicated.ppp           TRUE spatstat.geom        duplicated FALSE
# edit.ppp                 TRUE spatstat.geom              edit FALSE
# erosion.ppp              TRUE spatstat.geom           erosion FALSE
# fardist.ppp              TRUE spatstat.geom           fardist FALSE
# flipxy.ppp               TRUE spatstat.geom            flipxy FALSE
# Frame<-.ppp              TRUE spatstat.geom           Frame<- FALSE
# has.close.ppp            TRUE spatstat.geom         has.close FALSE
# head.ppp                 TRUE spatstat.geom              head FALSE
# identify.ppp             TRUE spatstat.geom          identify FALSE
# intensity.ppp            TRUE spatstat.geom         intensity FALSE
# is.connected.ppp         TRUE spatstat.geom      is.connected FALSE
# is.empty.ppp             TRUE spatstat.geom          is.empty FALSE
# is.marked.ppp            TRUE spatstat.geom         is.marked FALSE
# is.multitype.ppp         TRUE spatstat.geom      is.multitype FALSE
# markformat.ppp           TRUE spatstat.geom        markformat FALSE
# marks.ppp                TRUE spatstat.geom             marks FALSE
# marks<-.ppp              TRUE spatstat.geom           marks<- FALSE
# multiplicity.ppp         TRUE spatstat.geom      multiplicity FALSE
# nncross.ppp              TRUE spatstat.geom           nncross FALSE
# nndist.ppp               TRUE spatstat.geom            nndist FALSE
# nnfun.ppp                TRUE spatstat.geom             nnfun FALSE
# nnwhich.ppp              TRUE spatstat.geom           nnwhich FALSE
# nobjects.ppp             TRUE spatstat.geom          nobjects FALSE
# npoints.ppp              TRUE spatstat.geom           npoints FALSE
# opening.ppp              TRUE spatstat.geom           opening FALSE
# pairdist.ppp             TRUE spatstat.geom          pairdist FALSE
# periodify.ppp            TRUE spatstat.geom         periodify FALSE
# persp.ppp                TRUE spatstat.geom             persp FALSE
# pixellate.ppp            TRUE spatstat.geom         pixellate FALSE
# plot.ppp                 TRUE spatstat.geom              plot FALSE
# print.ppp                TRUE spatstat.geom             print FALSE
# quadratcount.ppp         TRUE spatstat.geom      quadratcount FALSE
# quantess.ppp             TRUE spatstat.geom          quantess FALSE
# rebound.ppp              TRUE spatstat.geom           rebound FALSE
# relevel.ppp              TRUE spatstat.geom           relevel FALSE
# rescale.ppp              TRUE spatstat.geom           rescale FALSE
# rexplode.ppp             TRUE spatstat.geom          rexplode FALSE
# rjitter.ppp              TRUE spatstat.geom           rjitter FALSE
# rotate.ppp               TRUE spatstat.geom            rotate FALSE
# round.ppp                TRUE spatstat.geom             round FALSE
# rounding.ppp             TRUE spatstat.geom          rounding FALSE
# scalardilate.ppp         TRUE spatstat.geom      scalardilate FALSE
# shift.ppp                TRUE spatstat.geom             shift FALSE
# split.ppp                TRUE spatstat.geom             split FALSE
# split<-.ppp              TRUE spatstat.geom           split<- FALSE
# subset.ppp               TRUE spatstat.geom            subset FALSE
# summary.ppp              TRUE spatstat.geom           summary FALSE
# superimpose.ppp          TRUE spatstat.geom       superimpose FALSE
# tail.ppp                 TRUE spatstat.geom              tail FALSE
# text.ppp                 TRUE spatstat.geom              text FALSE
# unique.ppp               TRUE spatstat.geom            unique FALSE
# uniquemap.ppp            TRUE spatstat.geom         uniquemap FALSE
# unitname.ppp             TRUE spatstat.geom          unitname FALSE
# unitname<-.ppp           TRUE spatstat.geom        unitname<- FALSE
# unmark.ppp               TRUE spatstat.geom            unmark FALSE
# unstack.ppp              TRUE spatstat.geom           unstack FALSE
# Window.ppp               TRUE spatstat.geom            Window FALSE
# Window<-.ppp             TRUE spatstat.geom          Window<- FALSE
Listing 27.2: Existing S3 methods spatstat.explore::*.ppp
Code
suppressPackageStartupMessages(library(spatstat.explore))
.S3methods(class = 'ppp', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.explore')
#                              visible             from                  generic  isS4
# auc.ppp                         TRUE spatstat.explore                      auc FALSE
# berman.test.ppp                 TRUE spatstat.explore              berman.test FALSE
# bw.abram.ppp                    TRUE spatstat.explore                 bw.abram FALSE
# bw.relrisk.ppp                  TRUE spatstat.explore               bw.relrisk FALSE
# cdf.test.ppp                    TRUE spatstat.explore                 cdf.test FALSE
# density.ppp                     TRUE spatstat.explore                  density FALSE
# densityAdaptiveKernel.ppp       TRUE spatstat.explore    densityAdaptiveKernel FALSE
# densityfun.ppp                  TRUE spatstat.explore               densityfun FALSE
# densityHeat.ppp                 TRUE spatstat.explore              densityHeat FALSE
# densityVoronoi.ppp              TRUE spatstat.explore           densityVoronoi FALSE
# envelope.ppp                    TRUE spatstat.explore                 envelope FALSE
# nnclean.ppp                     TRUE spatstat.explore                  nnclean FALSE
# nndensity.ppp                   TRUE spatstat.explore                nndensity FALSE
# pcf.ppp                         TRUE spatstat.explore                      pcf FALSE
# quadrat.test.ppp                TRUE spatstat.explore             quadrat.test FALSE
# relrisk.ppp                     TRUE spatstat.explore                  relrisk FALSE
# relriskHeat.ppp                 TRUE spatstat.explore              relriskHeat FALSE
# resolve.lambda.ppp              TRUE spatstat.explore           resolve.lambda FALSE
# resolve.lambdacross.ppp         TRUE spatstat.explore      resolve.lambdacross FALSE
# resolve.reciplambda.ppp         TRUE spatstat.explore      resolve.reciplambda FALSE
# rhohat.ppp                      TRUE spatstat.explore                   rhohat FALSE
# roc.ppp                         TRUE spatstat.explore                      roc FALSE
# scanmeasure.ppp                 TRUE spatstat.explore              scanmeasure FALSE
# sdr.ppp                         TRUE spatstat.explore                      sdr FALSE
# segregation.test.ppp            TRUE spatstat.explore         segregation.test FALSE
# sharpen.ppp                     TRUE spatstat.explore                  sharpen FALSE
# Smooth.ppp                      TRUE spatstat.explore                   Smooth FALSE
# Smoothfun.ppp                   TRUE spatstat.explore                Smoothfun FALSE
# SmoothHeat.ppp                  TRUE spatstat.explore               SmoothHeat FALSE
# spatialCovariateEvidence.ppp    TRUE spatstat.explore spatialCovariateEvidence FALSE
# SpatialMedian.ppp               TRUE spatstat.explore            SpatialMedian FALSE
# SpatialQuantile.ppp             TRUE spatstat.explore          SpatialQuantile FALSE
Listing 27.3: Existing S3 methods spatstat.model::*.ppp
Code
suppressPackageStartupMessages(library(spatstat.model))
.S3methods(class = 'ppp', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.model')
#             visible           from generic  isS4
# kppm.ppp       TRUE spatstat.model    kppm FALSE
# lurking.ppp    TRUE spatstat.model lurking FALSE
# ppm.ppp        TRUE spatstat.model     ppm FALSE
Listing 27.4: Existing S3 methods spatstat.random::*.ppp
Code
suppressPackageStartupMessages(library(spatstat.random))
.S3methods(class = 'ppp', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.random')
#            visible            from generic  isS4
# rshift.ppp    TRUE spatstat.random  rshift FALSE

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

library(groupedHyperframe)

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

Table 27.1: S3 methods groupedHyperframe::*.ppp (v0.3.2)
visible generic isS4
.rmax.ppp TRUE groupedHyperframe::.rmax FALSE
aggregate_marks.ppp TRUE groupedHyperframe::aggregate_marks FALSE
append_marks<-.ppp TRUE groupedHyperframe::`append_marks<-` FALSE
density_marks.ppp TRUE groupedHyperframe::density_marks FALSE
Emark_.ppp TRUE groupedHyperframe::Emark_ FALSE
Gcross_.ppp TRUE groupedHyperframe::Gcross_ FALSE
is.numeric.ppp TRUE base::is.numeric FALSE
Jcross_.ppp TRUE groupedHyperframe::Jcross_ FALSE
Kcross_.ppp TRUE groupedHyperframe::Kcross_ FALSE
kerndens.ppp TRUE groupedHyperframe::kerndens FALSE
Kmark_.ppp TRUE groupedHyperframe::Kmark_ FALSE
Lcross_.ppp TRUE groupedHyperframe::Lcross_ FALSE
markconnect_.ppp TRUE groupedHyperframe::markconnect_ FALSE
markcorr_.ppp TRUE groupedHyperframe::markcorr_ FALSE
markvario_.ppp TRUE groupedHyperframe::markvario_ FALSE
Math.ppp TRUE methods::Math FALSE
na.exclude.ppp TRUE stats::na.exclude FALSE
na.omit.ppp TRUE stats::na.omit FALSE
nncross_.ppp TRUE groupedHyperframe::nncross_ FALSE
pairwise_cor_spatial.ppp TRUE groupedHyperframe::pairwise_cor_spatial FALSE
quantile.ppp TRUE stats::quantile FALSE
Vmark_.ppp TRUE groupedHyperframe::Vmark_ FALSE
Table 27.2: S3 methods currently not planned for class 'ppp'
Table 27.2: S3 methods currently not planned for class 'ppp'
Not Planned Explained in
na.fail.ppp(), na.pass.ppp() Section 33.1

27.1 Missing Marks Handling

The S3 methods na.omit.ppp() and na.exclude.ppp() omits and excludes, respectively, the missing marks from a point-pattern. Both functions return a point-pattern.

If missingness exists in the marks, the 'na.action'-attribute of the marks is saved as an attribute of the returned point-pattern.

Example: functions na.omit.ppp() and na.exclude.ppp() on 'none'-markformat
vesicles_omit = spatstat.data::vesicles |>
  na.omit()
vesicles_exclude = spatstat.data::vesicles |>
  na.exclude()
stopifnot(
  identical(vesicles_omit, spatstat.data::vesicles),
  identical(vesicles_exclude, spatstat.data::vesicles)
)
Example: functions na.omit.ppp() and na.exclude.ppp() on 'vector'-markformat, no missingness
ants_omit = spatstat.data::ants |>
  na.omit()
ants_exclude = spatstat.data::ants |>
  na.exclude()
stopifnot(
  identical(ants_omit, spatstat.data::ants),
  identical(ants_exclude, spatstat.data::ants)
)
Example: functions na.omit.ppp() and na.exclude.ppp() on 'dataframe'-markformat
spatstat.data::nbfires |> 
  spatstat.geom::npoints.ppp()
# [1] 7108
nbfires_omit = spatstat.data::nbfires |> 
  na.omit() 
nbfires_exclude = spatstat.data::nbfires |> 
  na.exclude() 
nbfires_omit |> 
  spatstat.geom::npoints.ppp()
# [1] 6989
nbfires_omit |> 
  attr(which = 'na.action', exact = TRUE) |> 
  attr(which = 'class', exact = TRUE)
# [1] "omit"
nbfires_exclude |> 
  attr(which = 'na.action', exact = TRUE) |> 
  attr(which = 'class', exact = TRUE)
# [1] "exclude"

Note that the function spatstat.geom::ppp() (v3.6.1) already removes missing \(x\)- and \(y\)-coords in the creation of a point-pattern.

Note that the S3 method spatstat.geom::plot.ppp() (v3.6.1) also removes missing marks (email with Dr. Baddeley, 2025-01-07).

27.2 Are Marks Numeric?

The S3 method is.numeric.ppp() determines whether the marks, if any, in a point-pattern are numeric.

Exception: function is.numeric.ppp() on 'none'-markformat
spatstat.data::vesicles |>
  is.numeric()
# logical(0)
Example: function is.numeric.ppp() on 'vector'-markformat
spatstat.data::longleaf |>
  is.numeric()
# [1] TRUE
spatstat.data::ants |>
  is.numeric()
# [1] FALSE

Note that the S3 methods is.numeric.ppp() and spatstat.geom::is.multitype.ppp() behave differently for a point-pattern with 'dataframe'-markformat, e.g., betacells (Section 10.4).

Review: functions spatstat.geom::is.multitype.ppp() (Baddeley, Rubak, and Turner 2015) on 'dataframe'-markformat
spatstat.data::betacells |>
  spatstat.geom::is.multitype.ppp()
# [1] FALSE
Example: functions is.numeric.ppp() on 'dataframe'-markformat
spatstat.data::betacells |>
  is.numeric()
#  type  area 
# FALSE  TRUE

27.3 Math-groupGeneric of numeric-marks

The S3 method Math.ppp() performs the transformations, in the Math-groupGeneric, on one or more numeric-marks of a point-pattern, and returns a point-pattern with the transformed marks. The \(x\)- and \(y\)-coords and the multi-type marks of the input point-pattern remain unchanged. This function serves a similar purpose to the S3 method spatstat.geom::Math.im().

Listing 27.5 applies log- and log1p-transformations on the point-pattern bronzefilter (Section 10.5) with 'vector'-markformat.

Listing 27.5: Example: log-transformations on 'vector'-markformat
Code
list(
  original = spatstat.data::bronzefilter,
  log = spatstat.data::bronzefilter |> log(),
  log1p = spatstat.data::bronzefilter |> log1p()
) |>
  lapply(FUN = \(i) {
    i |> 
      spatstat.geom::marks.ppp() |>
      summary.default()
  })
# $original
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   0.013   0.120   0.160   0.167   0.200   0.467 
# 
# $log
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
# -4.3428 -2.1203 -1.8326 -1.8989 -1.6094 -0.7614 
# 
# $log1p
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
# 0.01292 0.11333 0.14842 0.15244 0.18232 0.38322

Listing 27.6 applies log-transformations on the numeric-marks in the point-pattern betacells (Section 10.4) with 'dataframe'-markformat.

Listing 27.6: Example: log-transformations on numeric-marks in 'dataframe'-markformat
Code
list(
  original = spatstat.data::betacells,
  log = spatstat.data::betacells |> log()
) |>
  lapply(FUN = \(i) {
    i |> 
      spatstat.geom::marks.ppp() |>
      with.default(expr = area) |>
      summary.default()
  })
# $original
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   168.3   248.8   279.4   291.2   324.2   514.4 
# 
# $log
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   5.126   5.517   5.633   5.653   5.782   6.243

Listing 27.7 applies log-transformation on the \(x\)- and \(y\)-coordinates-only point-pattern vesicles (Section 10.19).

Listing 27.7: Exception: log-transformations on 'none'-markformat
Code
list(
  spatstat.data::vesicles |> log(),
  spatstat.data::vesicles |> log1p(),
  spatstat.data::vesicles |> log2(),
  spatstat.data::vesicles |> log10()
) |> 
  vapply(FUN = identical, y = spatstat.data::vesicles, FUN.VALUE = NA) |>
  stopifnot()

27.4 Kernel Density of numeric-marks

The S3 generic function density_marks() finds the kernel densitys (Becker, Chambers, and Wilks 1988) of the numeric-marks. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.3),

Table 27.3: S3 methods groupedHyperframe::density_marks.* (v0.3.2)
visible isS4
density_marks.ppp TRUE FALSE
density_marks.ppplist TRUE FALSE

The S3 method density_marks.ppp() finds the kernel densitys of one or more numeric-marks of a point-pattern.

Exception: function density_marks.ppp() on 'none'-markformat
spatstat.data::vesicles |>
  density_marks() |>
  is.null()
# [1] TRUE
Exception: function density_marks.ppp() on multi-type-marks in 'vector'-markformat
spatstat.data::ants |>
  density_marks() |>
  is.null()
# [1] TRUE
Example: function density_marks.ppp() on numeric-marks in 'vector'-markformat
spatstat.data::longleaf |>
  density_marks()
# 
# Call:
#   density.default(x = m)
# 
# Data: m (584 obs.);   Bandwidth 'bw' = 4.615
# 
#        x                y            
#  Min.   :-11.84   Min.   :1.759e-06  
#  1st Qu.: 13.55   1st Qu.:1.665e-03  
#  Median : 38.95   Median :1.227e-02  
#  Mean   : 38.95   Mean   :9.823e-03  
#  3rd Qu.: 64.35   3rd Qu.:1.624e-02  
#  Max.   : 89.74   Max.   :2.320e-02
Example: function density_marks.ppp() on numeric-marks in 'dataframe'-markformat
spatstat.data::betacells |>
  density_marks()
# $area
# 
# Call:
#   density.default(x = `$area`)
# 
# Data: $area (135 obs.);   Bandwidth 'bw' = 18.99
# 
#        x               y            
#  Min.   :111.3   Min.   :1.736e-06  
#  1st Qu.:226.3   1st Qu.:1.385e-04  
#  Median :341.4   Median :9.455e-04  
#  Mean   :341.4   Mean   :2.170e-03  
#  3rd Qu.:456.4   3rd Qu.:4.087e-03  
#  Max.   :571.4   Max.   :7.065e-03

Table 27.4 shows the difference between the function density_marks.ppp() versus the S3 method spatstat.explore::density.ppp(),

Table 27.4: Kernel density estimates density_marks.ppp() vs. spatstat.explore::density.ppp()
spatstat.explore::density.ppp() density_marks.ppp()
Computes fixed-bandwidth kernel estimate (Diggle 1985) of the intensity function from a point pattern, i.e., the \(x\)- and \(y\)-coords only (Listing 27.8) kernel density (Becker, Chambers, and Wilks 1988) of the numeric-mark(s)
Returns an im.object (Chapter 22) a (list of) stats::density object(s)
Listing 27.8: Review: function spatstat.explore::density.ppp() (Baddeley, Rubak, and Turner 2015)
Code
a1 = spatstat.data::betacells |> 
  spatstat.explore::density.ppp()
a0 = spatstat.data::betacells |>
  spatstat.geom::unmark.ppp() |>
  spatstat.explore::density.ppp()
stopifnot(identical(a0, a1))

27.4.1 Kernel Density Estimates

The S3 generic function kerndens() extracts the $y element of a density object. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.5),

Table 27.5: S3 methods groupedHyperframe::kerndens.* (v0.3.2)
visible isS4
kerndens.anylist TRUE FALSE
kerndens.default TRUE FALSE
kerndens.hyperframe TRUE FALSE
kerndens.ppp TRUE FALSE
kerndens.ppplist TRUE FALSE

The default method kerndens.default() is simply a wrapper of stats::density.default()$y.

Example: function kerndens.default()
d = faithful$eruptions |> 
  density(bw = 'sj')
kd = faithful$eruptions |> 
  kerndens(bw = 'sj')
stopifnot(identical(d$y, kd))

The S3 method kerndens.ppp() finds the kernel density estimates of one or more numeric-marks of a point-pattern. The S3 method kerndens.ppp() is simply a wrapper of the S3 method density_marks.ppp() (Section 27.4).

Exception: function kerndens.ppp() on 'none'-markformat
spatstat.data::vesicles |>
  kerndens() |>
  is.null()
# [1] TRUE
Example: function kerndens.ppp() on numeric-marks in 'vector'-markformat
spatstat.data::longleaf |>
  kerndens(n = 8L)
# [1] 8.403103e-05 2.019181e-02 1.471192e-02 1.438080e-02 1.612033e-02 4.244355e-03 6.127754e-04 1.759222e-06
Exception: function kerndens.ppp() on multi-type-marks in 'vector'-markformat
spatstat.data::ants |>
  kerndens() |>
  is.null()
# [1] TRUE
Example: function kerndens.ppp() on numeric-marks in 'dataframe'-markformat
spatstat.data::betacells |>
  kerndens(n = 8L)
# $area
# [1] 2.530826e-06 9.483771e-04 6.254928e-03 5.117580e-03 2.486671e-03 6.781429e-04 1.411284e-04 1.736171e-06

27.5 Quantile of numeric-marks

The S3 method quantile.ppp() finds the quantiles of one or more numeric marks of a point-pattern.

Example: function quantile.ppp() on 'none'-markformat
spatstat.data::vesicles |>
  quantile() |>
  is.null()
# [1] TRUE
Example: function quantile.ppp() on numeric-marks in 'vector'-markformat
spatstat.data::longleaf |>
  quantile()
#     0%    25%    50%    75%   100% 
#  2.000  9.100 26.150 42.125 75.900
Example: function quantile.ppp() on multi-type-marks in 'vector'-markformat
spatstat.data::ants |>
  quantile() |>
  is.null()
# [1] TRUE
Example: function quantile.ppp() on numeric-marks in 'dataframe'-markformat
spatstat.data::betacells |>
  quantile()
# $area
#     0%    25%    50%    75%   100% 
# 168.30 248.85 279.40 324.25 514.40
spatstat.data::finpines |>
  quantile()
# $diameter
#   0%  25%  50%  75% 100% 
#    0    1    2    3    7 
# 
# $height
#    0%   25%   50%   75%  100% 
# 0.800 1.825 2.850 3.600 5.400

Note that the S3 method quantile.ppp() is completely different from the S3 method spatstat.explore::SpatialQuantile.ppp().

27.6 Nearest Neighbours of multi-type-marks, Alternative Interface

Function .nncross() is a wrapper of function spatstat.geom::nncross(., what = 'dist'), designed to provide an interface consistent with function spatstat.explore::Gcross(), etc. This design allows the internal batch-processing mechanism (Section 27.14) to be shared between Table 27.19 and Table 27.20.

Example: interface of functions .nncross() and spatstat.explore::Gcross()
.nncross |> 
  args()
# function (X, i, j, ...) 
# NULL
spatstat.explore::Gcross |>
  args()
# function (X, i, j, r = NULL, breaks = NULL, ..., correction = c("rs", 
#     "km", "han")) 
# NULL

To compute the distance to the nearest neighbour of points with 'Messor'-mark for each point with 'Cataglyphis'-mark in the point-pattern ants (Section 10.2), one option (Listing 27.9) is to use function spatstat.geom::split.ppp(), then function spatstat.geom::nncross.ppp().

Listing 27.9: Review: function spatstat.geom::nncross.ppp() (Baddeley, Rubak, and Turner 2015)
Code
nn = spatstat.data::ants |>
  spatstat.geom::split.ppp() |>
  with.default(expr = {
    spatstat.geom::nncross.ppp(X = Cataglyphis, Y = Messor, what = 'dist')
  })
nn |>
  summary()
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   12.21   21.38   31.38   36.27   42.52   90.26

Alternative approaches are to use function .nncross(), specifying the parameters i and j

Listing 27.10: Example: function .nncross() with integer levels indices
nn1 = spatstat.data::ants |> 
  .nncross(i = 1L, j = 2L)
stopifnot(identical(nn, nn1))
Listing 27.11: Example: function .nncross() with character levels
nn2 = spatstat.data::ants |> 
  .nncross(i = 'Cataglyphis', j = 'Messor')
stopifnot(identical(nn, nn2))

Function .nncross() returns an invisible NULL-value (Listing 27.12) if the character values supplied to the i and j parameters do not match any levels of the multi-type-marks in ants (Section 10.2).

Listing 27.12: Exception: function .nncross(), non-existing levels
Code
spatstat.data::ants |>
  .nncross(i = 'a', j = 'b') |>
  is.null()
# [1] TRUE

27.7 Aggregate Marks-Statistics

The S3 generic function aggregate_marks() aggregates various statistics (other than the quantiles, Section 27.5) of the marks within a point-pattern, or within each point pattern of an object containing one or more point-patterns. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.6),

Table 27.6: S3 methods groupedHyperframe::aggregate_marks.* (v0.3.2)
visible isS4
aggregate_marks.hyperframe TRUE FALSE
aggregate_marks.ppp TRUE FALSE
aggregate_marks.ppplist TRUE FALSE

The S3 method aggregate_marks.ppp() aggregates a set of fully customizable summary statistics, in the parameter FUN or expr, of the marks within a point-pattern. For each type of the mark-format of the input point-pattern,

  • markformat = 'none' (Section 27.7.1): returns an invisible NULL-value.
  • markformat = 'vector' (Section 27.7.2): computes the summary statistics of the numeric- or multi-type-marks.
  • markformat = 'dataframe' (Section 27.7.3): aggregates the numeric- and/or multi-type-marks, according to a grouping structure determined by one-or-more multi-type-marks in the parameter by (Section 27.7.3.1), using the workhorse function stats::aggregate.data.frame().

The returned aggregated summary statistics can be vectorized for downstream use (Section 28.3).

The S3 method aggregate_marks.ppp() generalizes the aggregation-of-marks in the S3 method spatstat.geom::summary.ppp() (v3.6.1); the differences of the two functions are explained in Table 27.7. Listing 27.13 summarizes the S3 methods for the class 'summary.ppp' in the spatstat.* family of packages.

Table 27.7: Functions aggregate_marks.ppp() vs. spatstat.geom::summary.ppp() (v3.6.1)
aggregate_marks.ppp() spatstat.geom::summary.ppp()
Summary of \(x\)- and \(y\)-Coordinates Not Available Available
Summary of Observation Window Not Available Available
Mark(s) Statistics Fully customizable in parameters FUN or expr Those available in function base::summary.default()
By Group(s) Available (Section 27.7.3.1) Not Available (Listing 27.25)
Returns a list or vector a summary.ppp object (Listing 27.13)
Listing 27.13: Existing S3 methods spatstat.geom::*.summary.ppp
Code
suppressPackageStartupMessages(library(spatstat.geom))
.S3methods(class = 'summary.ppp', all.names = TRUE) |> 
  attr(which = 'info', exact = TRUE) |>
  subset.data.frame(subset = from == 'spatstat.geom')
#                   visible          from generic  isS4
# print.summary.ppp    TRUE spatstat.geom   print FALSE

27.7.1 'none'-markformat

Listing 27.14 demonstrates the exception handling with the point-pattern vesicles (Section 10.19) without any mark.

Listing 27.14: Exception: function aggregate_marks.ppp() on 'none'-markformat
spatstat.data::vesicles |> 
  aggregate_marks() |>
  is.null()
# [1] TRUE

Listing 27.15 shows the S3 method spatstat.geom::summary.ppp() on a point-pattern without any mark.

Listing 27.15: Review: function spatstat.geom::summary.ppp() on 'none'-markformat
Code
spatstat.data::vesicles |>
  spatstat.geom::summary.ppp() |>
  spatstat.geom::print.summary.ppp()
# Planar point pattern:  37 points
# Average intensity 0.0001336176 points per square nm
# 
# Coordinates are given to 12 decimal places
# 
# Window: polygonal boundary
# 2 separate polygons (1 hole)
#                  vertices     area relative.area
# polygon 1              69 317963.0         1.150
# polygon 2 (hole)       23 -41052.9        -0.148
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
#                      (563.5 x 1019 nm)
# Window area = 276910 square nm
# Unit of length: 1 nm
# Fraction of frame area: 0.482

27.7.2 'vector'-markformat

Listing 27.16, Listing 27.17 and Listing 27.18 aggregate the sample mean, or both the sample mean and the sample standard deviation sd, or the common summary statistics, of the numeric-mark in the point-pattern spruces (Section 10.17). The parameter z in Listing 27.17 represents the numeric-mark as a vector, and may be replaced by any other symbol of the user’s choice.

Listing 27.16: Example: sample mean
spatstat.data::spruces |> 
  aggregate_marks(FUN = mean)
#      mean 
# 0.2503731
Listing 27.17: Example: sample mean and sd
spatstat.data::spruces |> 
  aggregate_marks(FUN = \(z) c(mean = mean(z), sd = sd(z)))
#       mean         sd 
# 0.25037313 0.04697474
Listing 27.18: Example: common summary statistics
spatstat.data::spruces |> 
  aggregate_marks(FUN = summary.default)
#      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
# 0.1600000 0.2200000 0.2450000 0.2503731 0.2700000 0.3700000

Listing 27.19 provides equivalent return as Listing 27.18 using the S3 method spatstat.geom::summary.ppp().

Listing 27.19: Review: function spatstat.geom::summary.ppp(), numeric-mark in 'vector'-markformat
Code
spatstat.data::spruces |> 
  spatstat.geom::summary.ppp() |>
  spatstat.geom::print.summary.ppp()
# Marked planar point pattern:  134 points
# Average intensity 0.06296992 points per square metre
# 
# Coordinates are given to 1 decimal place
# i.e. rounded to the nearest multiple of 0.1 metres
# 
# marks are numeric, of type 'double'
# Summary:
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#  0.1600  0.2200  0.2450  0.2504  0.2700  0.3700 
# 
# Window: rectangle = [0, 56] x [0, 38] metres
# Window area = 2128 square metres
# Unit of length: 1 metre

Listing 27.20 and Listing 27.21 aggregate the (relative) frequencies of the multi-type-mark in the point-pattern ants (Section 10.2). The parameter z in Listing 27.21 represents the multi-type-mark as a vector, and may be replaced by any other symbol of the user’s choice.

Listing 27.20: Example: frequencies
spatstat.data::ants |> 
  aggregate_marks(FUN = table)
# Cataglyphis      Messor 
#          29          68
Listing 27.21: Example: relative frequencies
spatstat.data::ants |> 
  aggregate_marks(FUN = \(z) table(z)/length(z))
# Cataglyphis      Messor 
#   0.2989691   0.7010309

Listing 27.22 provides equivalent return as Listing 27.20 and Listing 27.21 using the S3 method spatstat.geom::summary.ppp().

Listing 27.22: Review: function spatstat.geom::summary.ppp(), multi-type-mark in 'vector'-markformat
Code
spatstat.data::ants |> 
  spatstat.geom::summary.ppp() |>
  spatstat.geom::print.summary.ppp()
# Marked planar point pattern:  97 points
# Average intensity 0.0002261486 points per square unit (one unit = 0.5 feet)
# 
# Coordinates are integers
# i.e. rounded to the nearest unit (one unit = 0.5 feet)
# 
# Multitype:
#             frequency proportion    intensity
# Cataglyphis        29  0.2989691 6.761144e-05
# Messor             68  0.7010309 1.585372e-04
# 
# Window: polygonal boundary
# single connected closed polygon with 11 vertices
# enclosing rectangle: [-25, 803] x [-49, 717] units
#                      (828 x 766 units)
# Window area = 428922 square units
# Unit of length: 0.5 feet
# Fraction of frame area: 0.676

27.7.3 'dataframe'-markformat

Listing 27.23 aggregates the numeric-mark area and multi-type-mark type in the point-pattern betacells (Section 10.4) using the statistics specified as R language in the parameter expr.

Listing 27.23: Example: numeric- and multi-type-mark in 'dataframe'-markformat
spatstat.data::betacells |>
  aggregate_marks(expr = list(
    area = summary.default(area),
    type = table(type)
  ))
# $area
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   168.3   248.8   279.4   291.2   324.2   514.4 
# 
# $type
# type
# off  on 
#  70  65

Listing 27.24 vectorizes the return of Listing 27.23.

Listing 27.24: Example: numeric- and multi-type-mark in 'dataframe'-markformat
spatstat.data::betacells |>
  aggregate_marks(expr = list(
    area = summary.default(area),
    type = table(type)
  ), vectorize = TRUE)
#    area.Min. area.1st Qu.  area.Median    area.Mean area.3rd Qu.    area.Max.     type.off      type.on 
#     168.3000     248.8500     279.4000     291.2081     324.2500     514.4000      70.0000      65.0000

Listing 27.25 provides equivalent return as Listing 27.23 using the S3 method spatstat.geom::summary.ppp().

Listing 27.25: Review: function spatstat.geom::summary.ppp(), numeric and multi-type-mark in 'dataframe'-markformat
Code
spatstat.data::betacells |>
  spatstat.geom::summary.ppp() |>
  spatstat.geom::print.summary.ppp()
# Marked planar point pattern:  135 points
# Average intensity 0.0001816677 points per square micron
# 
# Coordinates are given to 2 decimal places
# i.e. rounded to the nearest multiple of 0.01 microns
# 
# Mark variables: type, area
# Summary:
#   type         area      
#  off:70   Min.   :168.3  
#  on :65   1st Qu.:248.8  
#           Median :279.4  
#           Mean   :291.2  
#           3rd Qu.:324.2  
#           Max.   :514.4  
# 
# Window: rectangle = [28.08, 778.08] x [16.2, 1007.02] microns
#                     (750 x 990.8 microns)
# Window area = 743115 square microns
# Unit of length: 1 micron

27.7.3.1 Use of Parameter by

The S3 method aggregate_marks.ppp() accepts a two-sided formula for the parameter by, if the input point-pattern has 'dataframe'-markformat. The left-hand-side of the formula by contains the name(s) of one or more mark(s) to be summarized, e.g.,

The right-hand-side of the formula by contains the name(s) of one or more multi-type-mark(s) to indicate the grouping structure of the aggregation, e.g.,

Note that the S3 method spatstat.geom::summary.ppp() (v3.6.1) does not provide summary statistics by-group (Listing 27.25).

27.7.3.1.1 Aggregate by One Group

Listing 27.26 and Listing 27.27 aggregate the numeric-mark area by the multi-type-mark type of the point-pattern betacells (Section 10.4), using the sample mean, or both the sample mean and the sample standard deviation sd. The parameter z in Listing 27.27 represents the numeric-mark area in the left-hand-side of the formula by, and may be replaced by any other symbol of the user’s choice.

Listing 27.26: Example: sample mean of area-by-type
spatstat.data::betacells |>
  aggregate_marks(by = area ~ type, FUN = mean)
#   type     area
# 1  off 259.7214
# 2   on 325.1169
Listing 27.27: Example: sample mean and sd of area-by-type
spatstat.data::betacells |>
  aggregate_marks(by = area ~ type, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  })
#   type area.mean   area.sd
# 1  off 259.72143  40.86083
# 2   on 325.11692  60.71534

Listing 27.28 and Listing 27.29 vectorize the returns of Listing 27.26 and Listing 27.27.

Listing 27.28: Example: sample mean of area-by-type, vectorized
spatstat.data::betacells |>
  aggregate_marks(by = area ~ type, FUN = mean, vectorize = TRUE)
# off.area  on.area 
# 259.7214 325.1169
Listing 27.29: Example: sample mean and sd of area-by-type, vectorized
spatstat.data::betacells |>
  aggregate_marks(by = area ~ type, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  }, vectorize = TRUE)
# off.area.mean   off.area.sd  on.area.mean    on.area.sd 
#     259.72143      40.86083     325.11692      60.71534

Listing 27.30 and Listing 27.31 aggregate one multi-type-mark season by another multi-type-mark group of the point-pattern gorillas (Section 10.11), using the (relative) frequencies. The parameter z in Listing 27.31 represents the multi-type-mark season in the left-hand-side of the formula by, and may be replaced by any other symbol of the user’s choice.

Listing 27.30: Example: frequencies of season-by-group
spatstat.data::gorillas |>
  aggregate_marks(by = season ~ group, FUN = table)
#   group season.dry season.rainy
# 1 major        150          200
# 2 minor        125          172
Listing 27.31: Example: relative frequencies of season-by-group
spatstat.data::gorillas |>
  aggregate_marks(by = season ~ group, FUN = \(z) table(z)/length(z))
#   group season.dry season.rainy
# 1 major  0.4285714    0.5714286
# 2 minor  0.4208754    0.5791246

Listing 27.32 and Listing 27.33 vectorize the returns of Listing 27.30 and Listing 27.31.

Listing 27.32: Example: frequencies of season-by-group, vectorized
spatstat.data::gorillas |>
  aggregate_marks(by = season ~ group, FUN = table, vectorize = TRUE)
#   major.season.dry major.season.rainy   minor.season.dry minor.season.rainy 
#                150                200                125                172
Listing 27.33: Example: relative frequencies of season-by-group, vectorized
spatstat.data::gorillas |>
  aggregate_marks(by = season ~ group, FUN = \(z) {
    table(z)/length(z)
  }, vectorize = TRUE)
#   major.season.dry major.season.rainy   minor.season.dry minor.season.rainy 
#          0.4285714          0.5714286          0.4208754          0.5791246
27.7.3.1.2 Aggregate One-or-More Marks by Interaction of Multiple Groups

Listing 27.34 creates a point-pattern nbfL from the point-pattern nbfires (Section 10.15) by

  1. appending a numeric mark hr.last (Section 27.9), the time difference in hours between the put-out out.date and the discovery dis.date, to the existing marks;
  2. selecting a subset of points that represent 'forest' and/or 'grass' fires caused by railroads 'rrds' and/or recreation 'rec';
  3. removing the points with any missing marks (Section 27.1);
  4. performing log1p-transformations on the numeric-marks (Section 27.3) fnl.size and hr.last.
Listing 27.34: Data: a point-pattern nbfL
nbfL. = spatstat.data::nbfires
append_marks(nbfL.) = nbfL. |>
  spatstat.geom::marks.ppp() |>
  with.default(expr = {
    tmp = out.date - dis.date
    units(tmp) = 'hours'
    list(hr.last = as.numeric(tmp))
  })
nbfL = nbfL. |>
  spatstat.geom::subset.ppp(
    subset = (fire.type %in% c('forest', 'grass')) & (cause %in% c('rrds', 'rec')), 
    select = c('fire.type', 'cause', 'fnl.size', 'hr.last')
  ) |>
  na.omit() |>
  log1p()
rm(nbfL.)

Listing 27.35 aggregates the log1p-transformed numeric-mark fnl.size by the interaction of two multi-type-marks fire.type and cause in the point-pattern nbfL (Listing 27.34), using the sample mean and the sample standard deviation sd. The parameter z in Listing 27.35 represents the log1p-transformed numeric-mark fnl.size in the left-hand-side of the formula by, and may be replaced by any other symbol of the user’s choice.

Listing 27.35: Example: sample mean and sd of log1p-transformed fnl.size-by-fire.type:cause
nbfL |>
  aggregate_marks(by = fnl.size ~ fire.type:cause, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  })
#   fire.type cause fnl.size.mean fnl.size.sd
# 1    forest  rrds     0.8647287   0.9269129
# 2     grass  rrds     0.3416982   0.4392035
# 3    forest   rec     0.4799249   0.7390220
# 4     grass   rec     0.3740750   0.5717532

Listing 27.36 aggregates the log1p-transformed numeric-marks fnl.size and hr.last by the interaction of two multi-type-marks fire.type and cause in the point-pattern nbfL (Listing 27.34), using the sample mean and the sample standard deviation sd. The parameter z in Listing 27.36 represents the log1p-transformed numeric-marks fnl.size and hr.last, respectively, in the left-hand-side of the formula by, and may be replaced by any other symbol of the user’s choice. Note that the use of cbind() in the formula by follows that of the S3 method stats::aggregate.data.frame().

Listing 27.36: Example: sample mean and sd of log1p-transformed fnl.size-and-hr.last-by-fire.type:cause
nbfL |>
  aggregate_marks(by = cbind(fnl.size, hr.last) ~ fire.type:cause, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  })
#   fire.type cause fnl.size.mean fnl.size.sd hr.last.mean hr.last.sd
# 1    forest  rrds     0.8647287   0.9269129    3.2775133  1.0379506
# 2     grass  rrds     0.3416982   0.4392035    2.1677729  1.1694497
# 3    forest   rec     0.4799249   0.7390220    2.7868615  1.3290827
# 4     grass   rec     0.3740750   0.5717532    1.3526997  0.9957785

Listing 27.37 and Listing 27.38 vectorize the returns of Listing 27.35 and Listing 27.36.

Listing 27.37: Example: sample mean and sd of log1p-transformed fnl.size-by-fire.type:cause, vectorized
nbfL |>
  aggregate_marks(by = fnl.size ~ fire.type:cause, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  }, vectorize = TRUE)
# forest.rrds.fnl.size.mean   forest.rrds.fnl.size.sd  grass.rrds.fnl.size.mean    grass.rrds.fnl.size.sd  forest.rec.fnl.size.mean    forest.rec.fnl.size.sd   grass.rec.fnl.size.mean 
#                 0.8647287                 0.9269129                 0.3416982                 0.4392035                 0.4799249                 0.7390220                 0.3740750 
#     grass.rec.fnl.size.sd 
#                 0.5717532
Listing 27.38: Example: sample mean and sd of log1p-transformed fnl.size-and-hr.last-by-fire.type:cause
nbfL |>
  aggregate_marks(by = cbind(fnl.size, hr.last) ~ fire.type:cause, FUN = \(z) {
    c(mean = mean(z), sd = sd(z))
  }, vectorize = TRUE)
# forest.rrds.fnl.size.mean   forest.rrds.fnl.size.sd  forest.rrds.hr.last.mean    forest.rrds.hr.last.sd  grass.rrds.fnl.size.mean    grass.rrds.fnl.size.sd   grass.rrds.hr.last.mean 
#                 0.8647287                 0.9269129                 3.2775133                 1.0379506                 0.3416982                 0.4392035                 2.1677729 
#     grass.rrds.hr.last.sd  forest.rec.fnl.size.mean    forest.rec.fnl.size.sd   forest.rec.hr.last.mean     forest.rec.hr.last.sd   grass.rec.fnl.size.mean     grass.rec.fnl.size.sd 
#                 1.1694497                 0.4799249                 0.7390220                 2.7868615                 1.3290827                 0.3740750                 0.5717532 
#    grass.rec.hr.last.mean      grass.rec.hr.last.sd 
#                 1.3526997                 0.9957785

27.8 Extract via [

In an email to the author, Prof. Adrian Baddeley (Baddeley and Turner 2005) has kindly explained that in the package spatstat.geom (v3.6.1)

The design of the S3 class 'ppp' specifies that if the marks are a data frame with only 1 column, then the marks will be converted to a vector.

This design choice was made a long time ago, in order to avoid problems that would otherwise occur in the rest of the spatstat code.

If we were to retrospectively change the specification, we would have a lot of work to do in the rest of the code, and the documentation.

On the other hand, function grouped_ppp() (Chapter 3, Section 19.1) relies on the support of ncol-1L 'dataframe'-marks. As an ad hoc solution, the author defines

  • an (internal) derived class 'ppp_tzh' (initials of T. Zhan) that inherits from the S3 class 'ppp', and
  • an S3 method `[.ppp_tzh` that respects the ncol-1L 'dataframe'-marks. The S3 method `[.ppp_tzh` is a teeny-tiny modification of the S3 method spatstat.geom::`[.ppp`. Permision from Dr. Baddeley? GPL-2?

Listing 27.39 retains the name of the mark hladr as the column name of the ncol-1L 'dataframe'-marks (Listing 27.40), for downstream analysis.

Listing 27.39: Example: function grouped_ppp() with one mark
s_a = wrobel_lung |>
   grouped_ppp(formula = hladr ~ OS + gender + age | patient_id/image_id)
Listing 27.40: Example: support of ncol-1L 'dataframe'-markformat, name of mark retained
s_a$ppp.[[1L]] |>
  spatstat.geom::marks.ppp(drop = FALSE) |> 
  head(n = 3L)
#   hladr
# 1 0.115
# 2 0.239
# 3 0.268

27.9 Append to (Existing) Marks

The S3 generic syntactic sugar `append_marks<-`() appends an additional mark to the existing marks. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.8),

Table 27.8: S3 methods groupedHyperframe::append_marks<-.* (v0.3.2)
visible from generic isS4
append_marks<-.ppp TRUE groupedHyperframe groupedHyperframe::`append_marks<-` FALSE

The S3 method `append_marks<-.ppp`() appends an additional mark to (the existing marks of) an point-pattern.

Example: function `append_marks<-.ppp`(), no existing marks
ves = spatstat.data::vesicles
(npt = spatstat.geom::npoints.ppp(ves))
# [1] 37
set.seed(12); append_marks(ves) = rlnorm(n = npt)
ves |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 37 points
# marks are numeric, of storage type  'double'
# window: polygonal boundary
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
set.seed(31); append_marks(ves) = replicate(n = 2L, expr = rpois(n = npt, lambda = 4), simplify = FALSE)
ves |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 37 points
# Mark variables: m1, m2, m3 
# window: polygonal boundary
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
Example: function `append_marks<-.ppp`(), existing numeric-marks
spru = spatstat.data::spruces
set.seed(23); append_marks(spru) = rlnorm(n = spatstat.geom::npoints.ppp(spru))
spru |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 134 points
# Mark variables: m1, m2 
# window: rectangle = [0, 56] x [0, 38] metres
Example: function `append_marks<-.ppp`(), existing multi-type marks
ant = spatstat.data::ants
set.seed(42); append_marks(ant) = rlnorm(n = spatstat.geom::npoints.ppp(ant))
ant |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 97 points
# Mark variables: m1, m2 
# window: polygonal boundary
# enclosing rectangle: [-25, 803] x [-49, 717] units (one unit = 0.5 feet)

Listing 27.41 appends a new mark to the existing 'dataframe' marks of the point-pattern gorillas (Section 10.11). The new mark is automatically named m4 in addition to the three existing marks.

Listing 27.41: Example: function `append_marks<-.ppp`(), existing 'dataframe' marks
goril_a = spatstat.data::gorillas
set.seed(33); append_marks(goril_a) = rlnorm(n = spatstat.geom::npoints.ppp(goril_a))
goril_a |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 647 points
# Mark variables: group, season, date, m4 
# window: polygonal boundary
# enclosing rectangle: [580457.9, 585934] x [674172.8, 678739.2] metres

Listing 27.42 appends multiple new marks with user-specified mark names to the existing 'dataframe' marks of the point-pattern gorillas (Section 10.11).

Listing 27.42: Example: function `append_marks<-.ppp`(), existing 'dataframe' marks, multiple new marks
goril_b = spatstat.data::gorillas
set.seed(33); append_marks(goril_b) = replicate(n = 3L, expr = rlnorm(n = spatstat.geom::npoints.ppp(goril_b)), simplify = FALSE) |>
  setNames(nm = c('newm1', 'newm2', 'newm3'))
goril_b |> 
  spatstat.geom::print.ppp()
# Marked planar point pattern: 647 points
# Mark variables: group, season, date, newm1, newm2, newm3 
# window: polygonal boundary
# enclosing rectangle: [580457.9, 585934] x [674172.8, 678739.2] metres

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

The S3 generic function .rmax() provides the default \(r_\text{max}\) used in functions from package spatstat.explore (v3.6.0.1) that return a function-value-table (fv.object, Chapter 15), i.e., the workhorse functions in Table 27.18 and Table 27.19. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.9),

Table 27.9: S3 methods groupedHyperframe::.rmax.* (v0.3.2)
visible isS4
.rmax.fv TRUE FALSE
.rmax.hyperframe TRUE FALSE
.rmax.ppp TRUE FALSE
.rmax.ppplist TRUE FALSE

The S3 method .rmax.ppp() finds the default \(r_\text{max}\) used by various functions applicable to a point-pattern and returning a function-value-table. It is

Table 27.10: an off-label use of functions spatstat.explore::rmax.rule() and spatstat.geom::handle.r.b.args()
Table 27.10: Default \(r_\text{max}\) used in functions from package spatstat.explore (v3.6.0.1) that return an fv.object
Function from package spatstat.explore Call of spatstat.explore::rmax.rule Default \(r_\text{max}\) via .rmax()
markcorr, the workhorse function of Emark and Vmark, markvario rmax.rule(fun = 'K', ...) .rmax(fun = 'K')
Kinhom, the workhorse function of Kmark and markcorrint rmax.rule(fun = 'K', ...) .rmax(fun = 'K')
Kcross, and its workhorse functions Kest and Kmulti rmax.rule(fun = 'K', ...) .rmax(fun = 'K') or .rmax(fun = 'K', i, j)
Gcross, and its workhorse functions Gest and Gmulti rmax.rule(fun = 'G', ...) .rmax(fun = 'G') or .rmax(fun = 'G', i, j)
Jcross, and its workhorse functions Jest and Jmulti rmax.rule(fun = 'J', ...) .rmax(fun = 'J') or .rmax(fun = 'J', i, j)
Advanced: function .rmax.ppp() for spatstat.explore::markcorr() on numeric- and/or integer-mark in 'vector'-markformat
sprucesK_r1 = spatstat.data::spruces |>
  spatstat.explore::markcorr() |>
  .rmax.fv()
sprucesK_r2 = spatstat.data::spruces |> 
  .rmax(fun = 'K')
stopifnot(identical(sprucesK_r1, sprucesK_r2))
anemonesK_r1 = spatstat.data::anemones |>
  spatstat.explore::markcorr() |>
  .rmax.fv()
anemonesK_r2 = spatstat.data::anemones |> 
  .rmax(fun = 'K')
stopifnot(identical(anemonesK_r1, anemonesK_r2))
Advanced: function .rmax.ppp() for spatstat.explore::markcorr() on numeric-mark in 'dataframe'-markformat
spatstat.data::finpines |>
  spatstat.explore::markcorr() |>
  vapply(FUN = .rmax.fv, FUN.VALUE = NA_real_)
# diameter   height 
#      2.5      2.5
spatstat.data::finpines |>
  .rmax(fun = 'K')
# [1] 2.5
Advanced: function .rmax.ppp() for spatstat.explore::Gcross() on multi-type-mark
r1a = spatstat.data::ants |>
  spatstat.explore::Gcross(i = 'Messor', j = 'Cataglyphis') |>
  .rmax.fv()
r2a = spatstat.data::ants |> 
  .rmax(fun = 'G', i = 'Messor', j = 'Cataglyphis')
stopifnot(identical(r1a, r2a))
r1b = spatstat.data::ants |>
  spatstat.explore::Gcross(i = 'Cataglyphis', j = 'Messor') |>
  .rmax.fv()
r2b = spatstat.data::ants |> 
  .rmax(fun = 'G', i = 'Cataglyphis', j = 'Messor')
stopifnot(identical(r1b, r2b))
r1c = spatstat.data::ants |>
  spatstat.explore::Gcross(i = 'Messor', j = 'Messor') |>
  .rmax.fv()
r2c = spatstat.data::ants |> 
  .rmax(fun = 'G', i = 'Messor', j = 'Messor')
stopifnot(identical(r1c, r2c))
r1d = spatstat.data::ants |>
  spatstat.explore::Gcross(i = 'Cataglyphis', j = 'Cataglyphis') |>
  .rmax.fv()
r2d = spatstat.data::ants |> 
  .rmax(fun = 'G', i = 'Cataglyphis', j = 'Cataglyphis')
stopifnot(identical(r1d, r2d))
Advanced: function .rmax.ppp() for spatstat.explore::Jcross() on multi-type-mark
r1a = spatstat.data::ants |>
  spatstat.explore::Jcross(i = 'Messor', j = 'Cataglyphis') |>
  .rmax.fv()
r2a = spatstat.data::ants |> 
  .rmax(fun = 'J', i = 'Messor', j = 'Cataglyphis')
stopifnot(identical(r1a, r2a))
r1b = spatstat.data::ants |>
  spatstat.explore::Jcross(i = 'Cataglyphis', j = 'Messor') |>
  .rmax.fv()
r2b = spatstat.data::ants |> 
  .rmax(fun = 'J', i = 'Cataglyphis', j = 'Messor')
stopifnot(identical(r1b, r2b))
r1c = spatstat.data::ants |>
  spatstat.explore::Jcross(i = 'Messor', j = 'Messor') |>
  .rmax.fv()
r2c = spatstat.data::ants |> 
  .rmax(fun = 'J', i = 'Messor', j = 'Messor')
stopifnot(identical(r1c, r2c))
r1d = spatstat.data::ants |>
  spatstat.explore::Jcross(i = 'Cataglyphis', j = 'Cataglyphis') |>
  .rmax.fv()
r2d = spatstat.data::ants |> 
  .rmax(fun = 'J', i = 'Cataglyphis', j = 'Cataglyphis')
stopifnot(identical(r1d, r2d))

27.11 \(k\)-Means Clustering

Function kmeans.ppp() performs \(k\)-means clustering (Hartigan and Wong 1979) on a point-pattern. This 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. Note that to reproduce a \(k\)-means clustering using stats::kmeans(), readers must set the .Random.seed beforehand.

Function kmeans.ppp() has parameters

  • formula, \(x\)- and/or \(y\)- coordinate(s) and/or (one or more of the) numeric-marks
  • (optional) centers, number of clusters
  • (optional) clusterSize, “expected” number of points per cluster.

User should specify one of the two optional parameters centers and clusterSize. If both are specified, then parameter clusterSize takes priority and parameter centers is ignored.

Function kmeans.ppp() returns an object of S3 class 'pppkm', which inherits from the class 'ppp' with additional attributes,

  • attr(.,'f'), a factor indicating the \(k\)-means clustering indices.

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

Table 27.11: S3 methods groupedHyperframe::*.pppkm (v0.3.2)
visible generic isS4
plot.pppkm TRUE base::plot FALSE
print.pppkm TRUE base::print FALSE
split.pppkm TRUE base::split FALSE

Most of the S3 methods in Table 27.11 are straightforward extensions of their counterparts for the class 'ppp' (Chapter 27).

Table 27.12: Inheritance of S3 Class 'pppkm'
S3 Method … is a trivial wrapper of
plot.pppkm(), Section 27.11.1 spatstat.geom::plot.ppp()
print.pppkm(), Section 27.11.1 spatstat.geom::print.ppp()
split.pppkm(), Section 27.11.2 spatstat.geom::split.ppp()

27.11.1 Print & Plot

Listing 27.43 performs 3L-means clustering on the \(x\)- and \(y\)-coordinates-only point-pattern vesicles (Section 10.19) by the \(x\)-coordinates.

Listing 27.43: Example: function kmeans.ppp(); cluster vesicles by ~ x
set.seed(12); spatstat.data::vesicles |> 
  kmeans.ppp(formula = ~ x, centers = 3L)
# Planar point pattern: 37 points
# window: polygonal boundary
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
# with k-means clustering of 10, 15, 12 points

Listing 27.44 performs 3L-means clustering on vesicles (Section 10.19) by the \(x\)- and \(y\)-coordinates. Figure 27.1 visualizes the \(x\)- and \(y\)-coordinates and the 3L-means clustering indices.

Listing 27.44: Example: function kmeans.ppp(); cluster vesicles by ~ x + y
set.seed(21); vesicles_k2 = spatstat.data::vesicles |> 
  kmeans.ppp(formula = ~ x + y, centers = 3L)
vesicles_k2
# Planar point pattern: 37 points
# window: polygonal boundary
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
# with k-means clustering of 11, 10, 16 points
Listing 27.45: Figure: function plot.pppkm(); cluster vesicles by ~ x + y
Code
par(mar = c(0,0,1,0))
vesicles_k2 |>
  plot.pppkm()
Figure 27.1: Cluster vesicles by ~ x + y

Listing 27.46 performs \(k\)-means clustering on vesicles (Section 10.19) by the \(x\)- and \(y\)-coordinates, with an expected cluster size of 10L.

Listing 27.46: Example: function kmeans.ppp(); cluster vesicles by ~ x + y and parameter clusterSize
set.seed(43); spatstat.data::vesicles |> 
  kmeans.ppp(formula = ~ x + y, clusterSize = 10L)
# Planar point pattern: 37 points
# window: polygonal boundary
# enclosing rectangle: [22.6796, 586.2292] x [11.9756, 1030.7] nm
# with k-means clustering of 9, 10, 12, 6 points

Listing 27.47 - Listing 27.48 perform 3L-means clustering in the point-pattern spruces (Section 10.17) with 'vector'-markformat.

Listing 27.47: Example: function kmeans.ppp(); cluster spruces by ~ x + marks
set.seed(30); spatstat.data::spruces |> 
  kmeans.ppp(formula = ~ x + marks, centers = 3L)
# Marked planar point pattern: 134 points
# marks are numeric, of storage type  'double'
# window: rectangle = [0, 56] x [0, 38] metres
# with k-means clustering of 47, 39, 48 points
Listing 27.48: Example: function kmeans.ppp(); cluster spruces by ~ x + y + marks
set.seed(62); spatstat.data::spruces |> 
  kmeans.ppp(formula = ~ x + y + marks, centers = 3L)
# Marked planar point pattern: 134 points
# marks are numeric, of storage type  'double'
# window: rectangle = [0, 56] x [0, 38] metres
# with k-means clustering of 40, 38, 56 points

Listing 27.49 - Listing 27.50 perform 3L-means clustering in the point-pattern finpines (Section 10.9) with 'dataframe'-markformat.

Listing 27.49: Example: function kmeans.ppp(); cluster finpines by ~ x + y + height
set.seed(18); spatstat.data::finpines |> 
  kmeans.ppp(formula = ~ x + y + height, centers = 3L)
# Marked planar point pattern: 126 points
# Mark variables: diameter, height 
# window: rectangle = [-5, 5] x [-8, 2] metres
# with k-means clustering of 38, 42, 46 points
Listing 27.50: Example: function kmeans.ppp(); cluster finpines by ~ x + diameter + height
set.seed(20); spatstat.data::finpines |> 
  kmeans.ppp(formula = ~ x + diameter + height, centers = 3L)
# Marked planar point pattern: 126 points
# Mark variables: diameter, height 
# window: rectangle = [-5, 5] x [-8, 2] metres
# with k-means clustering of 37, 45, 44 points

27.11.2 Split by \(k\)-Means Clustering

Package groupedHyperframe (v0.3.2) implements the following S3 methods of the generic function base::split() (Table 27.13),

Table 27.13: S3 methods groupedHyperframe::split.* (v0.3.2)
visible isS4
split.hyperframekm TRUE FALSE
split.pppkm TRUE FALSE
split.pppkmlist TRUE FALSE

The S3 method split.pppkm() (Listing 27.51) splits the \(k\)-means clustered point-pattern flu$pattern[[1L]] (Section 10.10) by its \(k\)-means clustering indices.

Listing 27.51: Example: function split.pppkm()
Code
set.seed(15); spatstat.data::flu$pattern[[1L]] |> 
  kmeans.ppp(formula = ~ x + y, centers = 3L) |>
  split()
# Point pattern split by factor 
# 
# 1:
# Marked planar point pattern: 169 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# 2:
# Marked planar point pattern: 157 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm
# 
# 3:
# Marked planar point pattern: 145 points
# Multitype, with levels = M2, M1 
# window: rectangle = [0, 3331] x [0, 3331] nm

27.12 Pairwise Tjøstheim (1978)’s Coefficient

The S3 generic function pairwise_cor_spatial() calculates the nonparametric, rank-based, Tjøstheim (1978)’s correlation coefficients (Hubert and Golledge 1982) in a pairwise-combination fashion, using the workhorse function SpatialPack::cor.spatial() (Vallejos, Osorio, and Bevilacqua 2020, v0.4.1). Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.14),

Table 27.14: S3 methods groupedHyperframe::pairwise_cor_spatial.* (v0.3.2)
visible isS4
pairwise_cor_spatial.ppp TRUE FALSE
pairwise_cor_spatial.ppplist TRUE FALSE

All S3 methods in Table 27.14 return an object of S3 class 'pairwise_cor_spatial', which inherits from the class 'dist' defined in package stats shipped with R version 4.5.2 (2025-10-31). Such inheritance enables us to make use of existing S3 methods to class 'dist', e.g., stats:::print.dist(), stats:::as.matrix.dist(), stats:::format.dist() and stats:::labels.dist(). Table 27.15 explains the motivation of this inheritance, that the class 'pairwise_cor_spatial' shares intrinsic similarity in data structure as the class 'dist'.

Table 27.15: Similarity in Data Structure, 'pairwise_cor_spatial' & 'dist'
'pairwise_cor_spatial' object 'dist' object
Constant diagonal values of 1; i.e., perfect correlation of 0; i.e., zero distance

The S3 method pairwise_cor_spatial.ppp() finds the nonparametric Tjøstheim (1978)’s correlation coefficients from the pairwise-combinations of all numeric-marks in a point-pattern, e.g., finpines (Section 10.9).

Example: function pairwise_cor_spatial.ppp()
finpines_paircor = spatstat.data::finpines |>
  pairwise_cor_spatial()

The S3 method stats:::print.dist() displays a 'pairwise_cor_spatial' object.

A pairwise_cor_spatial object finpines_paircor
finpines_paircor
#         diameter
# height 0.7287879

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

Table 27.16: S3 methods groupedHyperframe::*.pairwise_cor_spatial (v0.3.2)
visible from generic isS4
as.matrix.pairwise_cor_spatial TRUE groupedHyperframe base::as.matrix FALSE

The S3 method as.matrix.pairwise_cor_spatial() returns a matrix of pairwise Tjøstheim (1978)’s coefficients with diagonal values of 1. This matrix, however, is not a correlation matrix, because Tjøstheim (1978)’s correlation coefficient

  • is nonparametric, i.e., there is no definition of the corresponding covariance, standard deviation sd, nor the conversion cov2cor method;
  • does not provide a mathematical mechanism to ensure that this matrix is positive definite.
Example: function as.matrix.pairwise_cor_spatial()
finpines_paircor |> 
  as.matrix()
#           diameter    height
# diameter 1.0000000 0.7287879
# height   0.7287879 1.0000000

27.13 🚧 Global Envelope Test

🚧 This section is under construction. Expected delivery by 2025-12-31.

Global envelope test GET::global_envelope_test() (Myllymäki and Mrkvička 2024, v1.0.7).

27.14 Batch Process on Eligible marks

Table 27.18, Table 27.19 and Table 27.20 delve into the intricate mechanics of the batch processes (Section 3.2), offering insights that will resonate with advanced R practitioners. Package groupedHyperframe (v0.3.2) implements the following S3 methods (Table 27.17),

Table 27.17: S3 methods groupedHyperframe::Emark_.*, groupedHyperframe::Vmark_.*, groupedHyperframe::markcorr_.*, groupedHyperframe::markvario_.*, groupedHyperframe::Gcross_.*, groupedHyperframe::Kcross_.*, groupedHyperframe::Jcross_.*, groupedHyperframe::Lcross_.*, groupedHyperframe::markconnect_.*, groupedHyperframe::nncross_.* (v0.3.2)
visible generic isS4
Emark_.hyperframe TRUE groupedHyperframe::Emark_ FALSE
Emark_.ppp TRUE groupedHyperframe::Emark_ FALSE
Emark_.ppplist TRUE groupedHyperframe::Emark_ FALSE
Vmark_.hyperframe TRUE groupedHyperframe::Vmark_ FALSE
Vmark_.ppp TRUE groupedHyperframe::Vmark_ FALSE
Vmark_.ppplist TRUE groupedHyperframe::Vmark_ FALSE
markcorr_.hyperframe TRUE groupedHyperframe::markcorr_ FALSE
markcorr_.ppp TRUE groupedHyperframe::markcorr_ FALSE
markcorr_.ppplist TRUE groupedHyperframe::markcorr_ FALSE
markvario_.hyperframe TRUE groupedHyperframe::markvario_ FALSE
markvario_.ppp TRUE groupedHyperframe::markvario_ FALSE
markvario_.ppplist TRUE groupedHyperframe::markvario_ FALSE
Gcross_.hyperframe TRUE groupedHyperframe::Gcross_ FALSE
Gcross_.ppp TRUE groupedHyperframe::Gcross_ FALSE
Gcross_.ppplist TRUE groupedHyperframe::Gcross_ FALSE
Kcross_.hyperframe TRUE groupedHyperframe::Kcross_ FALSE
Kcross_.ppp TRUE groupedHyperframe::Kcross_ FALSE
Kcross_.ppplist TRUE groupedHyperframe::Kcross_ FALSE
Jcross_.hyperframe TRUE groupedHyperframe::Jcross_ FALSE
Jcross_.ppp TRUE groupedHyperframe::Jcross_ FALSE
Jcross_.ppplist TRUE groupedHyperframe::Jcross_ FALSE
Lcross_.hyperframe TRUE groupedHyperframe::Lcross_ FALSE
Lcross_.ppp TRUE groupedHyperframe::Lcross_ FALSE
Lcross_.ppplist TRUE groupedHyperframe::Lcross_ FALSE
markconnect_.hyperframe TRUE groupedHyperframe::markconnect_ FALSE
markconnect_.ppp TRUE groupedHyperframe::markconnect_ FALSE
markconnect_.ppplist TRUE groupedHyperframe::markconnect_ FALSE
nncross_.hyperframe TRUE groupedHyperframe::nncross_ FALSE
nncross_.ppp TRUE groupedHyperframe::nncross_ FALSE
nncross_.ppplist TRUE groupedHyperframe::nncross_ FALSE

Each batch process listed in Table 27.18,

  • identifies all eligible numeric-marks in the input point-pattern (ppp.object, Chapter 27);
  • applies the workhorse function from package spatstat.explore per numeric-mark;
  • returns a list of fv.objects, named in the fashion of <numeric-mark>.<suffix>, where <suffix> is determined by <fv.object> |> attr(which = 'fname'). Note that the returned object is not an fvlist (Chapter 16).
Table 27.18: Batch processes; eligible numeric-marks to fv.objects
Batch Process Workhorse function in Package spatstat.explore fv.object Suffix
Emark_.ppp(), Vmark_.ppp() Emark and Vmark, conditional mean \(E(r)\) and variance \(V(r)\), diagnostics for dependence between the points and the marks (Schlather, Ribeiro, and Diggle 2003) .E, .V
markcorr_.ppp() markcorr, marked correlation \(k_{mm}(r)\) or generalized mark correlation \(k_f(r)\) (Stoyan and Stoyan 1994) .k
markvario_.ppp() markvario, mark variogram \(\gamma(r)\) (Wälder and Stoyan 1996) .gamma
Kmark_.ppp() Kmark, mark-weighted \(K_f(r)\) function (Penttinen, Stoyan, and Henttonen 1992) .K

Each batch process listed in Table 27.19,

  • identifies all eligible multi-type-marks in the input point-pattern (ppp.object, Chapter 27);
  • applies the workhorse function from package spatstat.explore per multi-type-mark;
  • returns a list of fv.objects, named in the fashion of <multitype-mark>.<suffix>, where <suffix> is determined by <fv.object> |> attr(which = 'fname'). Note that the returned object is not an fvlist (Chapter 16).
Table 27.19: Batch processes; eligible multi-type-marks to fvlists
Batch Process Workhorse function in Package spatstat.explore fv.object Suffix
Gcross_.ppp() Gcross, multi-type nearest-neighbor distance \(G_{ij}(r)\) .G
Kcross_.ppp() Kcross, multi-type \(K_{ij}(r)\) .K
Jcross_.ppp() Jcross, multi-type \(J_{ij}(r)\) (Van Lieshout and Baddeley 1999) .J
Lcross_.ppp() Lcross, multi-type \(L_{ij}(r)=\sqrt{\frac{K_{ij}(r)}{\pi}}\) .L
markconnect_.ppp() markconnect, multi-type \(p_{ij}(r)\) .p

Each batch process listed in Table 27.20,

  • identifies all eligible multi-type-marks in the input point-pattern (ppp.object, Chapter 27);
  • applies the workhorse function from package spatstat.explore per multi-type-mark;
  • returns a list of numeric vectors, named in the fashion of <multitype-mark>.<suffix>, where <suffix> is the deparsed function call. Note that the returned object is not a vectorlist (Chapter 32).
Table 27.20: Batch processes; eligible multi-type-marks to numeric-vectors
Batch Process Workhorse function numeric-vector Suffix
nncross_.ppp() .nncross() (Section 27.6), nearest neighbor distance .nncross

27.14.1 Examples for Table 27.18 and Table 27.19

The S3 methods in Table 27.18 and Table 27.19 are user-friendly wrappers of the low-level utility functions ppp_numeric2fv() and ppp_multitype2fv(), respectively.

Listing 27.52 identifies the eligible numeric-mark area in the point-pattern betacells (Section 10.4) for the workhorse function spatstat.explore::Emark(), and applies it.

Listing 27.52: Example: function Emark_.ppp()
spatstat.data::betacells |>
  Emark_() |>
  names()
# [1] "area.E"

Listing 27.53 identifies the eligible multi-type-mark type in the point-pattern betacells (Section 10.4), which contains (at least) the two levels of 'off' and 'on', for the workhorse function spatstat.explore::Gcross(), and applies it.

Listing 27.53: Example: function Gcross_.ppp(., i = 'off', j = 'on')
spatstat.data::betacells |>
  Gcross_(i = 'off', j = 'on') |>
  names()
# [1] "type.G"

Listing 27.54 shows that a generic name m is used for the 'vector'-markformat of the point-pattern spruces (Section 10.17).

Listing 27.54: Example: function Emark_.ppp(), 'vector'-markformat
spatstat.data::spruces |> 
  Emark_() |>
  names()
# [1] "m.E"

Listing 27.55 returns an invisible NULL-value for the point-pattern ants (Section 10.2) without any numeric-mark for the workhorse function spatstat.explore::Emark().

Listing 27.55: Exception: function Emark_.ppp(), no numeric-mark
Code
spatstat.data::ants |> 
  Emark_() |>
  is.null()
# [1] TRUE

A similar batch mechanism already exists in package spatstat.explore (v3.6.0.1) for ppp.object with 'dataframe'-markformat. Table 27.21 shows the difference between the batch mechanism in Table 27.18 versus that in package spatstat.explore.

Table 27.21: Batch mechanism for ppp.object with 'dataframe'-markformat: Table 27.18 vs. package spatstat.explore
In Package spatstat.explore (v3.6.0.1) In Table 27.18
Marks of input ppp.object must be all-numeric select only the eligible numeric-marks
Output list of fv.object not named with suffix of attr(.,'fname') named with suffix of attr(.,'fname')

Listing 27.56 - Listing 27.58 show the differences and connections between the batch processes in Table 27.18 versus those in package spatstat.explore, using a point-pattern finpines (Section 10.9) with two numeric-marks.

Listing 27.56: Advanced: function markcorr_.ppp() vs. spatstat.explore::markcorr()
Code
finpinesK = spatstat.data::finpines |> 
  spatstat.explore::markcorr()
names(finpinesK) = paste0(names(finpinesK), '.k')
finpinesK_ = spatstat.data::finpines |>
  markcorr_()
stopifnot(identical(finpinesK, finpinesK_))
Listing 27.57: Advanced: function Emark_.ppp() vs. spatstat.explore::Emark()
Code
finpinesE = spatstat.data::finpines |> 
  spatstat.explore::Emark()
names(finpinesE) = paste0(names(finpinesE), '.E')
finpinesE_ = spatstat.data::finpines |>
  Emark_()
stopifnot(identical(finpinesE, finpinesE_))
Listing 27.58: Advanced: function Vmark_.ppp() vs. spatstat.explore::Vmark()
Code
finpinesV = spatstat.data::finpines |>
  spatstat.explore::Vmark()
names(finpinesV) = paste0(names(finpinesV), '.V')
finpinesV_ = spatstat.data::finpines |>
  Vmark_()
stopifnot(identical(finpinesV, finpinesV_))

27.14.2 Examples for Table 27.20

The S3 methods in Table 27.20 are user-friendly wrappers of the low-level utility function ppp2dist().

Listing 27.59 identifies the eligible multi-type-mark type in the point-pattern betacells (Section 10.4), which contains (at least) the two levels of 'off' and 'on', for the workhorse function .nncross() (Section 27.6), and applies it.

Listing 27.59: Example: function nncross_.ppp(., i = 'off', j = 'on')
spatstat.data::betacells |>
  nncross_(i = 'off', j = 'on') |>
  names()
# [1] "type.nncross"

Listing 27.60 identifies the eligible multi-type-mark group in the point-pattern gorillas (Section 10.11), which contains (at least) the two levels of 'major' and 'minor', for the workhorse function .nncross() (Section 27.6), and applies it;

Listing 27.60: Example: function nncross_.ppp(., i = 'major', j = 'minor')
spatstat.data::gorillas |>
  nncross_(i = 'major', j = 'minor') |>
  names()
# [1] "group.nncross"

Listing 27.61 identifies the eligible multi-type-mark season in the point-pattern gorillas (Section 10.11), which contains (at least) the two levels of 'rainy' and 'dry' for the workhorse function .nncross() (Section 27.6), and applies it.

Listing 27.61: Example: function nncross_.ppp(., i = 'rainy', j = 'dry')
spatstat.data::gorillas |>
  nncross_(i = 'rainy', j = 'dry') |>
  names()
# [1] "season.nncross"

Listing 27.62 determines that no eligible multi-type-mark exists in the point-pattern gorillas (Section 10.11) that contains both levels 'alpha' and 'beta', and therefore returns an invisible NULL-value.

Listing 27.62: Exception: function nncross_.ppp(., i = 'male', j = 'female')
Code
spatstat.data::gorillas |>
  nncross_(i = 'male', j = 'female') |>
  is.null()
# [1] TRUE

Listing 27.63 shows that a generic name m is used for the 'vector'-markformat of the point-pattern ants (Section 10.2),

Listing 27.63: Example: function nncross_.ppp(), 'vector'-markformat
spatstat.data::ants |> 
  nncross_(i = 'Cataglyphis', j = 'Messor') |>
  names()
# [1] "m.nncross"

Listing 27.64 returns an invisible NULL-value, since the input point-pattern spruces (Section 10.17) does not contain a multi-type-mark for the workhorse function .nncross() (Section 27.6).

Listing 27.64: Exception: function nncross_.ppp(), no multi-type-mark
Code
spatstat.data::spruces |> 
  nncross_() |>
  is.null()
# [1] TRUE