library(groupedHyperframe)
13 fv
The examples in Chapter 13 require that the
search
path contains the followingnamespace
s,
Function spatstat.explore::fv()
creates a function-value-table object (fv.object
), i.e., an R object of S3
class 'fv'
. In addition to the existing S3
method dispatches spatstat.explore::*.fv
(v3.5.3.3, Listing 13.1),
S3
method dispatches spatstat.explore::*.fv
Code
suppressPackageStartupMessages(library(spatstat.explore))
methods(class = 'fv', all.names = TRUE) |>
attr(which = 'info', exact = TRUE) |>
subset.data.frame(subset = from == 'spatstat.explore')
# visible from generic isS4
# [.fv TRUE spatstat.explore [ FALSE
# [<-.fv TRUE spatstat.explore [<- FALSE
# $<-.fv TRUE spatstat.explore $<- FALSE
# as.data.frame.fv TRUE spatstat.explore as.data.frame FALSE
# as.function.fv TRUE spatstat.explore as.function FALSE
# as.fv.fv TRUE spatstat.explore as.fv FALSE
# cbind.fv TRUE spatstat.explore cbind FALSE
# collapse.fv TRUE spatstat.explore collapse FALSE
# compatible.fv TRUE spatstat.explore compatible FALSE
# Complex.fv TRUE spatstat.explore Complex FALSE
# deriv.fv TRUE spatstat.explore deriv FALSE
# formula.fv TRUE spatstat.explore formula FALSE
# formula<-.fv TRUE spatstat.explore formula<- FALSE
# harmonise.fv TRUE spatstat.explore harmonise FALSE
# harmonize.fv TRUE spatstat.explore harmonize FALSE
# integral.fv TRUE spatstat.explore integral FALSE
# Math.fv TRUE spatstat.explore Math FALSE
# names<-.fv TRUE spatstat.explore names<- FALSE
# Ops.fv TRUE spatstat.explore Ops FALSE
# pcf.fv TRUE spatstat.explore pcf FALSE
# plot.fv TRUE spatstat.explore plot FALSE
# pool.fv TRUE spatstat.explore pool FALSE
# print.fv TRUE spatstat.explore print FALSE
# rose.fv TRUE spatstat.explore rose FALSE
# Smooth.fv TRUE spatstat.explore Smooth FALSE
# StieltjesCalc.fv TRUE spatstat.explore StieltjesCalc FALSE
# Summary.fv TRUE spatstat.explore Summary FALSE
# with.fv TRUE spatstat.explore with FALSE
Package groupedHyperframe
(v0.3.0.20251020) implements more S3
method dispatches to the class 'fv'
(Listing 13.2, Table 13.1),
S3
method dispatches groupedHyperframe::*.fv
Code
methods2kable(class = 'fv', package = 'groupedHyperframe', all.names = TRUE)
S3
method dispatches groupedHyperframe::*.fv
(v0.3.0.20251020)
visible | from | generic | isS4 | |
---|---|---|---|---|
.disrecommend2theo.fv |
TRUE | groupedHyperframe | groupedHyperframe::.disrecommend2theo |
FALSE |
.illegal2theo.fv |
TRUE | groupedHyperframe | groupedHyperframe::.illegal2theo |
FALSE |
.rmax.fv |
TRUE | groupedHyperframe | groupedHyperframe::.rmax |
FALSE |
cumvtrapz.fv |
TRUE | groupedHyperframe | groupedHyperframe::cumvtrapz |
FALSE |
visualize_vtrapz.fv |
TRUE | groupedHyperframe | groupedHyperframe::visualize_vtrapz |
FALSE |
vtrapz.fv |
TRUE | groupedHyperframe | groupedHyperframe::vtrapz |
FALSE |
13.1 Recommended Function Values
The recommended function values in an fv.object
are visualized as a black-solid-curve by the S3
method dispatch spatstat.explore::plot.fv()
(Listing 13.3).
spatstat.explore::plot.fv()
(Baddeley, Rubak, and Turner 2015)
Code
::spruces |>
spatstat.data::markcorr() |>
spatstat.explore::plot.fv(main = 'markcorr(spruces)') spatstat.explore
Function spatstat.explore::fvnames
finds the columns in an fv.object
that,
- abbreviation
a = '.x'
finds the “name” of the function argument (Listing 13.4); - abbreviation
a = '.y'
finds the “name” of the recommended function value (Listing 13.5).
spatstat.explore::fvnames(., a = '.x')
(Baddeley, Rubak, and Turner 2015)
::spruces |>
spatstat.data::markcorr() |>
spatstat.explore::fvnames(a = '.x')
spatstat.explore# [1] "r"
spatstat.explore::fvnames(., a = '.y')
(Baddeley, Rubak, and Turner 2015)
::spruces |>
spatstat.data::markcorr() |>
spatstat.explore::fvnames(a = '.y')
spatstat.explore# [1] "iso"
Function keyval.fv()
(Listing 13.6) finds various function values (default being the recommended) in an fv.object
, with the corresponding function argument as the vector
names
. Function keyval.fv()
is a “psuedo” S3
method dispatch, because the authors do not have an S3
generic function keyval()
defined as of package groupedHyperframe
v0.3.0.20251020.
keyval.fv()
::spruces |>
spatstat.data::markcorr() |>
spatstat.explorekeyval.fv() |>
head(n = 3L)
# 0 0.0185546875 0.037109375
# 0.8091085 0.8109143 0.8128058
Functions trapz.fv()
(Listing 13.7) and cumtrapz.fv()
(Listing 13.8) calculate the (cumulative) trapezoidal integration (Chapter 9) under the recommended-function-values. They are both “psuedo” S3
method dispatches, as the workhorse functions pracma::trapz()
and pracma::cumtrapz()
(Borchers 2023, v2.4.4) are not S3
generic functions.
trapz.fv()
::spruces |>
spatstat.data::markcorr() |>
spatstat.exploretrapz.fv()
# [1] 9.252769
cumtrapz.fv()
::spruces |>
spatstat.data::markcorr() |>
spatstat.explorecumtrapz.fv() |>
tail(n = 3L)
# 9.462890625 9.4814453125 9.5
# 9.214840 9.233797 9.252769
The S3
generic functions vtrapz()
and cumvtrapz()
have been introduced in Section 9.1. The S3
method dispatches vtrapz.fv()
(Listing 13.9) and cumvtrapz.fv()
(Listing 13.10) calculate the (cumulative) average vertical height of the trapezoidal integration (Section 9.1) under the recommended-function-values.
vtrapz.fv()
::spruces |>
spatstat.data::markcorr() |>
spatstat.explorevtrapz.fv()
# [1] 0.9739757
cumvtrapz.fv()
::spruces |>
spatstat.data::markcorr() |>
spatstat.explorecumvtrapz.fv() |>
tail(n = 3L)
# 9.462890625 9.4814453125 9.5
# 0.9737870 0.9738807 0.9739757
13.2 \(r_\text{max}\)
The S3
generic function .rmax()
has been introduced in Section 23.11. The S3
method dispatch .rmax.fv()
(Listing 13.11), often used as an internal utility function, simply grabs the maximum value of the \(r\)-vector in an fv.object
.
.rmax.fv()
Code
= spatstat.data::spruces |>
sprucesK_r1 ::Emark() |>
spatstat.explore.rmax.fv()
= spatstat.data::spruces |>
sprucesK_r2 ::Emark() |>
spatstat.explore::with.fv(expr = r) |>
spatstat.exploremax()
stopifnot(identical(sprucesK_r1, sprucesK_r2))
13.3 Legal \(r_\text{max}\)
Function spatstat.explore::markcorr()
is the workhorse inside functions Emark()
, Vmark()
and markvario()
(v3.5.3.3). Function markcorr()
relies on the un-export
ed workhorse function spatstat.explore:::sewsmod()
, whose default method = "density"
contains a ratio of two kernel densities. Due to the floating-point precision of R (Listing 13.12), such density ratios may have exceptional/illegal returns of
0
from \(0/\delta\), orInf
from \(\delta/0\), with a real number \(\delta\geq\) (approximately)2.6e-324
NaN
from \(0/\varepsilon\) or \(\varepsilon/0\), with a real number \(\varepsilon\leq\) (approximately)2.5e-324
Code
list(
0 / c(2.6e-324, 2.5e-324),
c(2.5e-324, 2.6e-324) / 0
)# [[1]]
# [1] 0 NaN
#
# [[2]]
# [1] NaN Inf
Function spatstat.explore::markcorr()
provides a default argument of parameter \(r\)-vector
(Section 23.11), at which the mark correlation function \(k_f(r)\) are evaluated. The S3
method dispatch spatstat.explore::print.fv()
(Listing 13.13) prints the recommended range (and available range) of \(r\)-vector
.
spatstat.explore::print.fv()
(Baddeley, Rubak, and Turner 2015)
Code
::spruces |>
spatstat.data::markcorr() |>
spatstat.explore::print.fv()
spatstat.explore# Function value object (class 'fv')
# for the function r -> k[mm](r)
# ................................................................................
# Math.label Description
# r r distance argument r
# theo {k[mm]^{iid}}(r) theoretical value (independent marks) for k[mm](r)
# trans {hat(k)[mm]^{trans}}(r) translation-corrected estimate of k[mm](r)
# iso {hat(k)[mm]^{iso}}(r) Ripley isotropic correction estimate of k[mm](r)
# ................................................................................
# Default plot formula: .~r
# where "." stands for 'iso', 'trans', 'theo'
# Recommended range of argument r: [0, 9.5]
# Available range of argument r: [0, 9.5]
# Unit of length: 1 metre
Exceptional/illegal values of 0
, Inf
and/or NaN
may appear in the mark correlation function \(k_f(r)\), if the \(r\)-vector
goes well beyond the recommended range. The authors construct a malformed function-value-table object fv_mal
(Listing 13.14, Listing 13.15) to demonstrate various recovery procedures applicable in such cases.
fv_mal
with \(r\)-vector out-of-range
= spatstat.data::spruces |>
fv_mal ::markcorr(r = 0:100) spatstat.explore
spatstat.explore::plot.fv()
on fv_mal
Code
|>
fv_mal ::plot.fv(xlim = c(0, 100)) spatstat.explore
The helper function lastLegal()
(Listing 13.19, Listing 13.20) returns the index of the last consecutive legal values in a double
(Listing 13.16) vector
, i.e., the first exceptional/illegal value of 0
, Inf
, or NaN
appears at the next index. The term “legal”, as in the function lastLegal()
, is defined as
a
double
scalar being not-NA_real_
, not-NaN
, not-Inf
, and withabs
olute value greater than.Machine$double.eps
(Listing 13.17, Listing 13.18).
NaN
and Inf
are double
, not integer
(R Core Team 2025)
Code
list(Inf, NaN) |>
vapply(FUN = typeof, FUN.VALUE = '')
# [1] "double" "double"
base::is.finite()
Code
c(NA_real_, NaN, Inf) |>
is.finite()
# [1] FALSE FALSE FALSE
lastLegal()
, definition of legal
Code
as.list(body(lastLegal))[[2L]]
# vok <- is.finite(v) & (abs(v) > .Machine$double.eps)
lastLegal()
, toy examples
Code
list(
c(exp(1), pi),
c(exp(1), pi, NaN),
c(exp(1), pi, NaN, 1, 0, Inf)
|>
) lapply(FUN = lastLegal)
# [[1]]
# [1] 2
# attr(,"value")
# [1] 3.141593
#
# [[2]]
# [1] 2
# attr(,"value")
# [1] 3.141593
#
# [[3]]
# [1] 2
# attr(,"value")
# [1] 3.141593
lastLegal()
of keyval.fv()
= fv_mal |>
spruces_k_lastLegal keyval.fv() |>
lastLegal()
spruces_k_lastLegal# [1] 75
# attr(,"value")
# 74
# 1.549766
The term Legal \(r_\text{max}\) indicates (the index) of the \(r\)-vector
, where the last of the consecutive legal recommended-function-values appears. In Listing 13.20, the last consecutive legal recommended-function-value of fv_mal
(Listing 13.14) of \(k_f(r)=1.550\) appears at the 75-th index of the \(r\)-vector
, i.e., \(r=74\).
Legality of the function spatstat.explore::markcorr()
returns depends not only on the input ppp.object
, but also on the values of the \(r\)-vector
. In other words, the creation of an fv.object
by function markcorr()
is a numerical procedure. Therefore, the discussion of Legal \(r_\text{max}\) pertains to the fv.object
(Chapter 13), instead of to the ppp.object
(Chapter 23).
Example: Legality of spatstat.explore::markcorr()
return depends on \(r\)-vector
::spruces |>
spatstat.data::markcorr(r = seq.int(from = 0, to = 100, by = .1)) |>
spatstat.explorekeyval.fv() |>
lastLegal()
# [1] 742
# attr(,"value")
# 74.1
# 0.3191326
13.3.1 Handling Illegal Recommended-Function-Value
The S3
generic functions .illegal2theo()
and .disrecommend2theo()
are exploratory approaches to remove the illegal recommended-function-values (Section 13.3) from an fv.object
. These approaches replace the recommended-function-values with the theo
retical values starting at different locations, and return an updated fv.object
.
Function .illegal2theo.fv()
(Listing 13.21) replaces the recommended function values after the first illegal \(r\) (Section 13.3) of the function-value-table object fv_mal
(Listing 13.14) with its theo
retical values.
.illegal2theo.fv()
Code
|>
fv_mal .illegal2theo() |>
::plot.fv(xlim = c(0, 100))
spatstat.explore# r≥75.0 replaced with theo
Function .disrecommend2theo.fv()
(Listing 13.22) replaces the recommended function values after the first \(r\) outside the recommended range attr(.,'alim')[2L]
of the function-value-table object fv_mal
(Listing 13.14) with its theo
retical values.
.disrecommend2theo.fv()
Code
|>
fv_mal .disrecommend2theo() |>
::plot.fv(xlim = c(0, 100))
spatstat.explore# r≥10.0 replaced with theo
13.4 Interpolation
The authors use the toy example of a “coarse” and a “fine” fv.object
(Listing 13.23, Listing 13.24) to illustrate various interpolation methods of the \(x\)- and \(y\)-values (Listing 13.4, Listing 13.5) in the function-value-table object.
= 0:9
r_coarse = seq.int(from = 0, to = 9, by = .01) r_fine
fv.object
= spatstat.data::spruces |>
sprucesE0 ::Emark(r = r_coarse)
spatstat.explore= spatstat.data::spruces |>
sprucesE1 ::Emark(r = r_fine) spatstat.explore
Functions approxfun.fv()
(Listing 13.25) performs a linear interpolation. This is a “psuedo” S3
method dispatch, as the workhorse function stats::approxfun()
is not an S3
generic function.
approxfun.fv()
= sprucesE0 |>
sprucesE_approx approxfun.fv() |>
visualize_vtrapz(draw.rect = FALSE) +
::labs(title = '(A). linear interpolation via stats::approxfun()') ggplot2
Functions splinefun.fv()
(Listing 13.26) performs a spline interpolation. This is a “psuedo” S3
method dispatch, as the workhorse function stats::splinefun()
is not an S3
generic function.
splinefun.fv()
= sprucesE0 |>
sprucesE_spline splinefun.fv() |>
visualize_vtrapz(draw.rect = FALSE) +
::labs(title = '(B). spline interpolation via stats::splinefun()') ggplot2
An experienced reader may wonder: is it truly advantageous to compute a coarse fv.object
and then perform interpolation, rather than computing a fine fv.object
to start with? This is an excellent question! In fact, we observe no substantial difference in computation time via package microbenchmark
(Mersmann 2024, v1.5.0) even when the grid of the \(r\)-vector is 100 times finer (Listing 13.27), as of package spatstat.explore
(v3.5.3.3)! This observation justifies the use of the plain-and-naïve trapezoidal integration (Chapter 9, Section 9.1) on a fine fv.object
(Figure 13.1 D), rather than employing more sophisticated numerical integration methods, e.g., the adaptive Simpson quadrature pracma::quad()
, on an interpolation of a coarse fv.object
(Figure 13.1 A,B).
fv.object
, benchmarks
Code
suppressPackageStartupMessages(library(spatstat))
::microbenchmark(
microbenchmarkcoarse = Emark(spruces, r = r_coarse),
fine = Emark(spruces, r = r_fine)
|>
) suppressWarnings()
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# coarse 1.998053 2.049733 2.179651 2.086531 2.121689 5.239062 100 a
# fine 2.324495 2.399238 2.657508 2.456330 2.490196 5.386211 100 b
Figure: Interpolations vs. Trapezoidal Integration
= sprucesE0 |>
spruce_fig0 visualize_vtrapz(draw.rect = FALSE) +
::labs(title = '(C). trapezoidal integration, coarse')
ggplot2= sprucesE1 |>
spruce_fig1 visualize_vtrapz(draw.rect = FALSE) +
::labs(title = '(D). trapezoidal integration, fine')
ggplot2+ sprucesE_spline + spruce_fig0 + spruce_fig1 + patchwork::plot_layout(ncol = 2L)) &
(sprucesE_approx ::theme_minimal() ggplot2
