| Type: | Package |
| Title: | Spatial Point Pattern Test for Areal Data |
| Version: | 1.0.0 |
| Description: | Implements the area-based nonparametric spatial point pattern test of Andresen (2009) <doi:10.1016/j.apgeog.2008.12.004> for comparing two spatial distributions of events aggregated to areal units, with the applications and extensions reviewed in Andresen (2016) <doi:10.1177/2059799116630659>. Unit-level inference uses bounded Monte Carlo bootstrap p-values, with marginal confidence interval overlap retained as an option. Global similarity is summarised by the robust S index, accompanied by a test of whether two patterns are more different than two realisations of a single process, and a test of the spatial arrangement of the differences. A longitudinal extension compares each period of a time series against a base period and classifies unit-level trajectories. Publication-ready maps can be redrawn with user-chosen layouts. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| LazyData: | true |
| LazyDataCompression: | xz |
| Depends: | R (≥ 4.1.0) |
| Imports: | classInt, ggplot2 (≥ 3.5.0), ggspatial, graphics, grDevices, Matrix, rlang, scales, sf, spdep, stats, tools, utils |
| Suggests: | knitr, rmarkdown, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| RoxygenNote: | 7.3.3 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-16 07:21:59 UTC; andre |
| Author: | Martin A. Andresen
|
| Maintainer: | Martin A. Andresen <andresen@sfu.ca> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-27 15:00:11 UTC |
sppt: Spatial Point Pattern Test for Areal Data
Description
Compares spatial distributions of events aggregated to areal units.
Details
-
sppt()compares two patterns (a base and a test) unit by unit, using bounded Monte Carlo bootstrap p-values and, optionally, marginal confidence interval overlap. -
sppt_longitudinal()compares every period of a time series against the first period and classifies unit-level trajectories. -
sppt_sameness()tests a robust S index against sameness. -
sppt_map()redraws the maps from either analysis with a chosen layout.
Author(s)
Maintainer: Martin A. Andresen andresen@sfu.ca (ORCID) [copyright holder]
References
Andresen, M.A. (2009). Testing for similarity in area-based spatial patterns: A nonparametric Monte Carlo approach. Applied Geography, 29(3), 333-345. doi:10.1016/j.apgeog.2008.12.004
Andresen, M.A. (2016). An area-based nonparametric spatial point pattern test: The test, its applications, and the future. Methodological Innovations, 9, Article 12. doi:10.1177/2059799116630659
Andresen, M.A. (2026). Testing longitudinal change in spatial distributions and patterns: An extension of the spatial point pattern test. Annals of the American Association of Geographers, in press.
Spatial point pattern test with bootstrap p-values
Description
Compares two spatial point patterns, a base and a test, across a set of
areal units. Each unit is tested with a bounded Monte Carlo bootstrap
p-value and, optionally, with marginal confidence interval overlap
(Andresen 2009). Both are derived from a single shared set of B
bootstrap replicates.
Global similarity is summarised by the robust S index, the proportion of eligible units (those not empty in both patterns) that are not flagged as different. It is accompanied by two further tests:
a sameness test (
sppt_sameness()), which asks whether the two patterns are more different than two realisations of a single process;an arrangement test, global Moran's I on the signed evidence surface
\mathrm{sign}(d) \times -\log_{10}(p), which asks whether the differences, however many there are, are spatially organised. Local Moran clusters are outlined on the p-value map.
Usage
sppt(
data,
group_col = "group",
count_col,
B = 4999L,
seed = NULL,
alpha = 0.05,
calculate_pvalues = TRUE,
sameness_tau = 0.05,
arrangement = TRUE,
nsim_moran = 999L,
calculate_ci = FALSE,
conf_level = 0.683,
fix_base = FALSE,
use_percentages = TRUE,
verbose = TRUE,
create_maps = TRUE,
map_crs = NULL,
export_maps = FALSE,
export_dir = NULL,
map_dpi = 300L,
export_results = FALSE,
export_format = "gpkg",
export_results_dir = NULL
)
Arguments
data |
An |
group_col |
Character. Name of the column that uniquely identifies
each spatial unit (for example |
count_col |
Character vector of length 2 giving the base and test
count columns, in that order (for example |
B |
Integer. Number of bootstrap replicates. Default |
seed |
Integer or |
alpha |
Numeric in (0, 1). Significance level for flagging a unit.
Default |
calculate_pvalues |
Logical. Compute bootstrap p-values. Default
|
sameness_tau |
Numeric in (0, 1). Significance level for the sameness
test on the robust S index. Separate from |
arrangement |
Logical. Run the arrangement test (global and local
Moran's I on the signed evidence surface). Requires polygon geometry.
Default |
nsim_moran |
Integer. Permutations for the global Moran's I test.
Default |
calculate_ci |
Logical. Also compute marginal bootstrap confidence
intervals and the CI-based S index (Andresen 2009). Default |
conf_level |
Numeric in (0, 1). Confidence level for the interval
overlap criterion. Default |
fix_base |
Logical. If |
use_percentages |
Logical. Express proportions as percentages
(0-100) rather than as proportions (0-1). Default |
verbose |
Logical. Print the test summary to the console. Default
|
create_maps |
Logical. Build the maps and print them. The maps are
always stored on the result (see Value) when this is |
map_crs |
CRS for the maps, passed to |
export_maps |
Logical. Save the maps as PNG files in |
export_dir |
Character. Directory for exported maps and results.
Required when |
map_dpi |
Integer. Resolution of exported maps. Default |
export_results |
Logical. Write the result to |
export_format |
Character. Format for exported results: |
export_results_dir |
Character or |
Details
P-values. For each unit the observed difference in proportions (test minus base) is compared with the centred bootstrap distribution of that difference. The p-value is the bounded Monte Carlo form
p = \frac{1 + r}{B + 1},
where r counts centred bootstrap differences at least as large in
absolute value as the observed difference. The smallest attainable
p-value is therefore 1/(B + 1). Units with no events in either
pattern are excluded from inference and receive NA.
No multiple testing correction is applied. Simulation evidence shows that corrections remove power at fine spatial scales without a meaningful benefit in false discovery rate; the sameness and arrangement tests address the global question instead.
Power. lambda_min, the mean number of events per unit in the rarer
pattern, governs power. Below 1.5 a low-power warning is issued and below
0.5 a critical warning; at those resolutions, interpret groups of adjacent
flagged units rather than isolated ones, or aggregate to coarser units.
Value
An sf object of class sppt_result containing the columns of
data plus:
base_prop,test_propObserved share of base and test events in each unit.
differencetest_propminusbase_prop.lambda_minMean events per unit for the rarer pattern (the same for every row).
low_power_warningTRUEwhenlambda_min < 1.5.pvalueBootstrap p-value;
NAfor units empty in both patterns.sig_pvalue1 if
pvalue <= alpha, otherwise 0.sig_pvalue_dir1 = test > base, -1 = base > test, 0 = not significant.
signed_evidence\mathrm{sign}(d) \times -\log_{10}(p).moran_hh,moran_ll,moran_clusterLocal Moran clusters of the signed evidence surface (arrangement test only).
ci_lower,ci_upper,ci_lower_test,ci_upper_testMarginal confidence bounds for base and test (CI only).
intervals_overlap1 = intervals overlap (similar), 0 = they do not (CI only).
sig_ci_dirDirection of CI-based differences (CI only).
The attribute "sppt_summary" holds the robust S index, the sameness and
arrangement tests and the settings; summary() prints it. The attribute
"sppt_maps" holds the maps as a named list of ggplot objects
(difference, pvalue and, with CI, ci); use sppt_map() to redraw
them with a different layout.
References
Andresen, M.A. (2009). Testing for similarity in area-based spatial patterns: A nonparametric Monte Carlo approach. Applied Geography, 29(3), 333-345. doi:10.1016/j.apgeog.2008.12.004
Andresen, M.A. (2016). An area-based nonparametric spatial point pattern test: The test, its applications, and the future. Methodological Innovations, 9, Article 12. doi:10.1177/2059799116630659
See Also
sppt_longitudinal(), sppt_sameness(), sppt_map(),
vancouver_ct
Examples
res <- sppt(vancouver_ct, group_col = "id",
count_col = c("BNER2003", "BNER2025"),
B = 199, seed = 42, create_maps = FALSE)
summary(res)
table(res$sig_pvalue_dir)
Longitudinal spatial point pattern test
Description
Extends the spatial point pattern test to a time series of three or more periods (Andresen 2026). Every period is compared with the first period (the base), and each unit's trajectory is classified.
Two parallel sets of results are produced:
-
Envelope results. Bootstrap confidence intervals are computed for every unit and period. A unit is stable when its intervals overlap in all periods; the largest set of mutually overlapping periods gives a partial-stability measure. Trends are fitted only for units that are not stable.
-
P-value results (
calculate_pvalues = TRUE). Each period is tested against the base with the bounded Monte Carlo bootstrap p-valuep = (1 + r)/(B + 1)used bysppt(). A unit is stable when no period is significant atalpha; trends are fitted only for units with at least one significant period.
Trends are ordinary least squares fits of each unit's share (or count)
on time, linear or quadratic, tested at trend_alpha. Units are also
grouped into Jenks natural-breaks classes of their base-period count, and
trend outcomes are tabulated by class. Units that had events and then
recorded none in each of the last min_zero_streak periods are flagged
as sustained zeros.
Usage
sppt_longitudinal(
data,
group_col = "group",
count_col,
B = 4999L,
seed = NULL,
alpha = 0.05,
calculate_pvalues = TRUE,
conf_level = 0.683,
fix_base = FALSE,
use_percentages = TRUE,
prefix = NULL,
min_zero_streak = 3L,
trend_type = "linear",
trend_alpha = 0.05,
jenks = "optimal",
jenks_gvf_threshold = 0.05,
verbose = TRUE,
create_maps = TRUE,
create_time_plot = TRUE,
export_dir = NULL,
export_maps = FALSE,
map_format = "png",
map_dpi = 300L,
map_width_in = 7,
map_height_in = 5.5,
include_title = TRUE,
figure_prefix = NULL,
export_time_plot = FALSE,
export_tables = FALSE,
export_results = FALSE,
export_format = "gpkg"
)
Arguments
data |
An |
group_col |
Character. Name of the column that uniquely identifies
each spatial unit (for example |
count_col |
Character vector of three or more count columns, one per
period, in time order (for example |
B |
Integer. Number of bootstrap replicates. Default |
seed |
Integer or |
alpha |
Numeric in (0, 1). Significance level for flagging a unit.
Default |
calculate_pvalues |
Logical. Compute bootstrap p-values. Default
|
conf_level |
Numeric in (0, 1). Confidence level of the bootstrap
envelopes. Default |
fix_base |
Logical. If |
use_percentages |
Logical. Express proportions as percentages
(0-100) rather than as proportions (0-1). Default |
prefix |
Character or |
min_zero_streak |
Integer. Number of final periods with no events
that, after earlier events, mark a unit as a sustained zero. Default |
trend_type |
Character. |
trend_alpha |
Numeric in (0, 1). Significance level for the trend
regressions; independent of |
jenks |
|
jenks_gvf_threshold |
Numeric in (0, 1). With |
verbose |
Logical. Print the test summary to the console. Default
|
create_maps |
Logical. Build the maps and print them. Default |
create_time_plot |
Logical. Plot total events per period with the
summed envelope bounds. Default |
export_dir |
Character. Directory for every export option. Required
when any |
export_maps |
Logical. Save the maps in |
map_format |
Character. File type for exported maps: |
map_dpi |
Integer. Resolution of exported maps and the time plot.
Default |
map_width_in, map_height_in |
Numeric. Size of exported maps in
inches. Defaults |
include_title |
Logical. Keep map titles in exported maps. |
figure_prefix |
Character or |
export_time_plot |
Logical. Save the time plot as a PNG in
|
export_tables |
Logical. Save the summary indices and the Jenks trend
tables as a CSV in |
export_results |
Logical. Write the result to |
export_format |
Character. Format for exported results: |
Value
An sf object containing the columns of data plus, for each
period, <count_col>_L and <count_col>_U (envelope bounds) and, with
p-values, pvalue_<count_col> (NA for the base period). Unit-level
results are named with prefix:
intervals_overlap1 if all envelopes overlap (stable).
max_overlap_proportionLargest share of periods whose envelopes mutually overlap.
sustained_zero1 if the unit declined to zero and stayed there.
TrendTrend class. Linear: 2 / -2 significant increase / decrease, 1 / -1 non-significant, 0 stable. Quadratic: 1 / -1 significant linear only, 2 / 3 significant increase with negative / positive curvature, -2 / -3 significant decrease with positive / negative curvature, 0 otherwise.
Trend_All,Trend_Linear_SigLinear direction, and significant linear direction (1, -1, 0).
Linear_R2,Linear_b0,Linear_bt,Linear_bt_sigLinear fit;
Linear_bt_sigis the slope for significant units only.Quad_R2,Quad_b0,Quad_bt,Quad_bt2,Quad_SigQuadratic fit and the sign of a significant quadratic term (quadratic only).
*_pversionsThe same quantities gated on p-value significance:
intervals_overlap_p,max_overlap_proportion_p(share of non-significant periods),prop_sig_p,sustained_zero_p,Trend_p,Trend_p_All,Trend_p_Linear_Sig,Linear_p_R2,Linear_p_b0,Linear_p_bt,Linear_p_bt_sig,Quad_p_R2,Quad_p_b0,Quad_p_bt,Quad_p_bt2,Quad_p_Sig.jenks_level,jenks_min,jenks_max,baseline_intervalJenks class of the base-period count, its bounds and label.
The S indices, Jenks breaks, trend tables and p-value matrix are stored as
attributes (for example attr(x, "s_index_overlap"),
attr(x, "interval_table_linear"), attr(x, "pvalue_matrix")). With
create_maps = TRUE the maps are stored as a named list of ggplot
objects in attr(x, "sppt_maps"); use sppt_map() to redraw them with a
different layout.
References
Andresen, M.A. (2026). Testing longitudinal change in spatial distributions and patterns: An extension of the spatial point pattern test. Annals of the American Association of Geographers, in press.
See Also
sppt(), sppt_map(), vancouver_ct
Examples
res <- sppt_longitudinal(vancouver_ct, group_col = "id",
count_col = paste0("BNER", 2003:2025),
B = 199, seed = 42, verbose = FALSE,
create_maps = FALSE, create_time_plot = FALSE)
table(res$BNER_Trend_p)
attr(res, "si_overlap_p")
Redraw SPPT maps with a different layout
Description
sppt() and sppt_longitudinal() draw their maps with a fixed layout
that suits Vancouver: north arrow top right, scale bar along the bottom,
and legends placed where the city's shape leaves room. sppt_map()
rebuilds any of those maps from a result object with the legend, north
arrow and scale bar placed wherever suits your study area.
Every map is an ordinary ggplot object, so anything not covered by the
arguments here can be changed by adding layers or a theme, for example
sppt_map(res, "pvalue") + ggplot2::theme(legend.text = ggplot2::element_text(size = 12)).
Usage
sppt_map(
result,
which = NULL,
legend_position = NULL,
north_arrow = NULL,
scale_bar = NULL,
crs = NULL,
title = TRUE
)
Arguments
result |
A result returned by |
which |
Character vector of map names. |
legend_position |
Where to put the legend: |
north_arrow |
Location of the north arrow: |
scale_bar |
Location of the scale bar, with the same options as
|
crs |
CRS to project the maps to, passed to |
title |
Logical. Keep the map titles. |
Value
A ggplot object when which names a single map, otherwise a
named list of ggplot objects.
See Also
Examples
res <- sppt(vancouver_ct, group_col = "id",
count_col = c("BNER2003", "BNER2025"),
B = 199, seed = 42, verbose = FALSE, create_maps = FALSE)
p <- sppt_map(res, "pvalue", legend_position = "right",
north_arrow = "tl", scale_bar = "br")
p
Test a robust S index against sameness
Description
Tests whether two spatial patterns are more different than two realisations
of a single process would be. The null distribution of the S index follows
from the calibration of the test itself: with units flagged at alpha, a
proportion alpha of eligible units flag by chance under identity, so the
number flagged is \mathrm{Binomial}(n, \alpha) and S is centred at
1 - \alpha with standard error \sqrt{\alpha(1 - \alpha)/n},
where n is the number of eligible units.
Verified against 10,120 simulated combinations (8 crime types, 23 years,
55 spatial scales; 5,000 iterations each). The mean error of the
closed-form threshold is +0.0099 at alpha = 0.05 across the full grid,
and +0.0006 where at least 95 percent of units are eligible. Where many
units are empty in both patterns the test is mildly conservative, because
discreteness in sparse units lowers the realised flagging rate below
nominal.
sppt() calls this function automatically; it is exported so that the
test can be applied to S indices computed elsewhere.
Usage
sppt_sameness(
s_index,
n_sig,
n_eligible,
alpha = 0.05,
tau = 0.05,
exact = NULL
)
Arguments
s_index |
Numeric. Observed robust S index. |
n_sig |
Integer. Number of units flagged as dissimilar. Used for the
exact binomial tail; may be |
n_eligible |
Integer. Number of units in the S index denominator, that is, the total less units empty in both patterns. |
alpha |
Numeric in (0, 1). The unit-level significance level used in
the spatial point pattern test. Default |
tau |
Numeric in (0, 1). Significance level for the sameness test
itself. This is a separate choice from |
exact |
Logical or |
Value
A list with elements s_index, n_eligible, alpha, tau,
s_expected, se, threshold, z, p_value, method, and same
(TRUE when the two patterns are no more different than two
realisations of one process).
See Also
Examples
sppt_sameness(s_index = 0.90, n_sig = 20, n_eligible = 200, alpha = 0.05)
Summarise an SPPT result
Description
Prints the robust S index, the sameness and arrangement tests and the
settings of a sppt() result.
Usage
## S3 method for class 'sppt_result'
summary(object, ...)
## S3 method for class 'sppt_result'
print(x, ...)
Arguments
object, x |
An object of class |
... |
Further arguments passed to the |
Value
summary() invisibly returns the summary list stored in the
"sppt_summary" attribute. print() invisibly returns x.
Examples
res <- sppt(vancouver_ct, group_col = "id",
count_col = c("BNER2003", "BNER2025"),
B = 199, seed = 1, verbose = FALSE, create_maps = FALSE)
summary(res)
Residential and commercial burglary in Vancouver, 2003-2025
Description
Annual counts of residential burglary (break and enter, residential) and commercial burglary (break and enter, commercial) in the City of Vancouver, British Columbia, from 2003 to 2025, aggregated to 2021 Census spatial units.
-
vancouver_ct: 127 census tracts. -
vancouver_da: 1,016 dissemination areas.
Census tracts are coarse enough that most period comparisons have good
power, which makes vancouver_ct the better choice for examples and first
analyses. Dissemination areas show the fine-scale behaviour of the test,
including the low-power warnings.
Usage
vancouver_ct
vancouver_da
Format
An sf object with polygon geometry in NAD83(CSRS) / UTM zone 10N
and the following columns:
idInteger. Sequential unit identifier, for use as
group_col. It is not a Statistics Canada code.BNER2003, ...,BNER2025Integer. Residential burglaries in each year.
BNEC2003, ...,BNEC2025Integer. Commercial burglaries in each year.
geometrysfc_MULTIPOLYGONboundaries of the unit.
vancouver_ct has 127 rows and vancouver_da has 1,016 rows.
An object of class sf (inherits from data.frame) with 1016 rows and 48 columns.
Source
Crime counts: Vancouver Police Department open crime data, https://geodash.vpd.ca/opendata/. Boundaries: Statistics Canada, 2021 Census boundary files, https://www12.statcan.gc.ca/census-recensement/2021/geo/sip-pis/boundary-limites/index2021-eng.cfm. Events were aggregated to the 2021 units by the package author.
Examples
vancouver_ct
colSums(sf::st_drop_geometry(vancouver_ct)[, c("BNER2003", "BNER2025")])
plot(vancouver_ct["BNER2025"])