Longitudinal change with sppt_longitudinal()

sppt_longitudinal() extends the spatial point pattern test to a time series. Every period is compared with the first (the base), and each unit’s trajectory over the whole series is classified (Andresen 2026).

library(sppt)

Getting started

Give the count columns in time order, one per period. Column names that end in the year, such as BNER2003, label the time axis and set the prefix of the output columns (BNER_).

res <- sppt_longitudinal(
  data             = vancouver_ct,
  group_col        = "id",
  count_col        = paste0("BNER", 2003:2025),
  B                = 999,
  alpha            = 0.05,
  seed             = 171717,
  verbose          = FALSE,
  create_maps      = FALSE
)

The time plot shows total events per period with the summed bootstrap envelopes.

Two sets of results are returned. The p-value results test each period against 2003 at alpha: a unit is stable when no period differs significantly. The envelope results use bootstrap confidence intervals: a unit is stable when all its intervals overlap. For units that are not stable, a trend is fitted to the unit’s share of events over time.

# Share of units with no significant change in any period
attr(res, "si_overlap_p")
#> [1] 0.007874016

# Trend classes on the p-value results:
#  2 / -2 significant increase / decrease, 1 / -1 not significant, 0 stable
table(res$BNER_Trend_p)
#> 
#> -2 -1  0  1  2 
#> 42 32  1 27 25

The trend outcomes are also tabulated by the Jenks class of each unit’s base-period count:

attr(res, "interval_table_p_linear")
#>   BNER_baseline_interval Min_Count Max_Count Increasing_All Decreasing_All
#> 1                 [0, 1]         1         1              1              0
#> 2                [1, 32]         7        32             11             13
#> 3               [32, 53]        33        53             23             21
#> 4               [53, 80]        55        80             12             25
#> 5              [80, 146]        83       146              5             15
#>   Sig_Increasing Sig_Decreasing
#> 1              1              0
#> 2              5              5
#> 3             11             12
#> 4              5             14
#> 5              3             11

Maps

With create_maps = TRUE (the default) the function prints up to 18 maps and stores them on the result. sppt_map() redraws any of them with a different layout; its help page lists the map names.

sppt_map(res, "p_trend")

The built-in layout places categorical legends inside the panel at the top left, which suits Vancouver. For a study area with a different shape, move them:

sppt_map(res, "p_trend", legend_position = "bottom",
         north_arrow = "tl", scale_bar = "br")

Saving results

Nothing is written to disk unless you ask. Each export option uses export_dir:

res <- sppt_longitudinal(
  vancouver_ct, group_col = "id", count_col = paste0("BNER", 2003:2025),
  export_dir       = "sppt_output",
  export_maps      = TRUE,    # every map
  map_format       = "tif",   # png, tif, eps, svg or pdf
  map_dpi          = 600,
  include_title    = FALSE,   # journals usually set their own captions
  figure_prefix    = "AndresenFigure",  # AndresenFigure1.tif, ...
  export_time_plot = TRUE,    # time plot as PNG
  export_tables    = TRUE,    # S indices and Jenks tables as CSV
  export_results   = TRUE,    # the result itself
  export_format    = "gpkg"
)

All options

The call below lists every argument with its default value.

res <- sppt_longitudinal(
  data                = vancouver_ct,
  group_col           = "id",
  count_col           = paste0("BNER", 2003:2025), # first = base period
  B                   = 4999,       # bootstrap replicates; odd avoids ties
  seed                = NULL,       # set for reproducible results
  alpha               = 0.05,       # unit-level significance level
  calculate_pvalues   = TRUE,       # p-value results alongside envelopes
  conf_level          = 0.683,      # envelope level; matches alpha = 0.05
  fix_base            = FALSE,      # TRUE = do not bootstrap the base period
  use_percentages     = TRUE,       # shares (0-100) rather than counts
  prefix              = NULL,       # output prefix; NULL derives "BNER_"
  min_zero_streak     = 3,          # final zero periods for sustained zero
  trend_type          = "linear",   # or "quadratic" (4+ periods)
  trend_alpha         = 0.05,       # significance level of trend fits
  jenks               = "optimal",  # or a fixed number of classes
  jenks_gvf_threshold = 0.05,       # GVF stopping rule for "optimal"
  verbose             = TRUE,       # print the console report
  create_maps         = TRUE,       # build, print and store the maps
  create_time_plot    = TRUE,       # plot totals and envelopes over time
  export_dir          = NULL,       # required for any export
  export_maps         = FALSE,
  map_format          = "png",
  map_dpi             = 300,
  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"      # gpkg, shp, csv, txt or rds
)

Reference

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.