SSIMmap compares two maps using the Structural Similarity Index Measure (SSIM). It returns agreement in local means (SIM), dispersion (SIV), and co-patterning (SIP), together with their product, SSIM. Raster maps use square moving windows; polygon maps use an adaptive Gaussian kernel based on distances between polygon centroids.
Toronto_SSIM contains 279 Aggregate Dissemination Areas
(ADAs) in Toronto, using 2021 Census geography. Its columns include
ADAUID, the CIMD residential instability score
(CIMD) and the social dimension of the Pampalon index
(PP), and a derived commuting measure
(Commute). The numeric dataset is unchanged from version
0.4.0. The former description as 2016 Census Tracts is incorrect.
Commute is the unweighted mean of all stored DA percentages
for all intersecting DAs, including boundary-only intersections and
stored zeros. The nine zero-population DAs have stored zero percentages,
which are included in the means. For positive-population DAs, the
percentage is 100 times the Census count for commuting to a different
CSD and CD within the province or territory of
residence (characteristic 2601), divided by total DA Census population
(characteristic 1), rounded half-up to two decimals. It is not a
household or worker share, a pooled ADA population rate, or the share of
all commuting outside the CSD. Sixteen source numerator cells are
officially suppressed but stored as zero in the preserved source; their
values cannot be independently verified from the public release. See the
installed extdata/Toronto_SSIM_provenance.txt note.
The manuscript FWI examples use packed terra rasters for
British Columbia at 2 km resolution:
fwi_0816_bc: 16 August 2023.fwi_0818_bc: 18 August 2023.fwi_1111_bc: 11 November 2023, added
in version 0.4.1 from the actual source observation.The legacy fwi_1101_bc remains the unchanged 1
November 2023 observation for compatibility. It is not an alias
for November 11. The new raster was cropped and masked to the BC
boundary without resampling or transformation; all three manuscript
input grids match. Source checksums and preparation details are in
system.file("extdata", "fwi_1111_bc_provenance.txt", package = "SSIMmap").
The default transformation is "none" in all three
functions from version 0.4.2. Alternatives are
"normal_score", "percentile", and
"minmax". The manuscript explicitly uses percentiles for
the Toronto variables and "none" for FWI. A high SIM or SIV
after percentile transformation describes local agreement in ranks, not
agreement in original variable units. Inverse-normal scores can be
negative; the polygon function’s component-range checks can reject some
signed-input comparisons.
The dimensionless defaults are k1 = 0.01 and
k2 = 0.03. The functions compute stabilizing constants
after transformation. Raster calculations use the pooled full range on
common non-missing support; polygon calculations use the pooled
99th-minus-1st percentile range, with the documented fallback behavior
in the source.
ssim_bandwidth() evaluates integer neighbor counts from
12 to the user-supplied max_bandwidth. Bias and variance
curves are separately rescaled to [0,1] across that candidate range.
Each variable’s preferred count minimizes the absolute difference
between those two curves. The midpoint option rounds the mean of the two
preferred counts upward.
The manuscript uses a maximum of 200. The two midpoint bandwidths are
87 and 91. The square-root alternative is
ceiling(sqrt(nrow(Toronto_SSIM))), or 17.
S1 <- ssim_bandwidth(Toronto_SSIM, "CIMD", "PP",
max_bandwidth = 200,
transform = "percentile", option = "midpoint")
S2 <- ssim_bandwidth(Toronto_SSIM, "CIMD", "Commute",
max_bandwidth = 200,
transform = "percentile", option = "midpoint")
c(deprivation = S1$bandwidth, commuting = S2$bandwidth,
square_root = ceiling(sqrt(nrow(Toronto_SSIM))))
## deprivation commuting square_root
## 87 91 17
p1 <- S1$plot + labs(tag = "a)") +
theme(plot.tag = element_text(face = "plain"))
p2 <- S2$plot + labs(tag = "b)") +
theme(plot.tag = element_text(face = "plain"))
(p1 + p2) + plot_layout(guides = "collect")The descriptive local result is an ordinary sf object
containing SSIM, SIM, SIV, and
SIP.
local1 <- ssim_polygon(Toronto_SSIM, "CIMD", "PP", global = FALSE,
bandwidth = S1$bandwidth,
transform = "percentile", do_test = FALSE)
ggplot(local1) + geom_sf(aes(fill = SSIM), colour = NA) +
scale_fill_distiller(palette = "PRGn", limits = c(-1, 1)) + theme_void()For polygon inference, both variables are independently permuted over
polygons. From version 0.4.3, the global means and local values of all
four statistics use a two-sided test centered on the corresponding
permutation mean. Global p-values are unadjusted. With
fdr = TRUE, local p-values are BH-adjusted across polygons
separately for each statistic. Results have _p,
_q, and _sig suffixes, and significance uses
q <= alpha, matching rasters. With
fdr = FALSE, polygon _q columns equal the
unadjusted p-values and significance uses p <= alpha.
The existing p_value, q_value, and
sig columns remain aliases for SSIM_p,
SSIM_q, and SSIM_sig.
The longer inference examples are not executed during vignette building. Running them calculates new seeded results; it does not load significance results from the manuscript.
global1 <- ssim_polygon(Toronto_SSIM, "CIMD", "PP", global = TRUE,
bandwidth = S1$bandwidth, transform = "percentile",
do_test = TRUE, R = 1000, seed = 1)
global1$p_global
local1_test <- ssim_polygon(Toronto_SSIM, "CIMD", "PP", global = FALSE,
bandwidth = S1$bandwidth, transform = "percentile",
do_test = TRUE, R = 1000, fdr = TRUE, seed = 1)
head(local1_test[, c("SSIM", "SSIM_p", "SSIM_q", "SSIM_sig",
"SIM_p", "SIV_p", "SIP_p")])w is the half-window size: w = 1,
2, and 3 give 3x3, 5x5, and 7x7 windows. The
first step restricts the inputs to their common non-missing cells.
Windows containing missing cells are excluded, so valid spatial support
can change with window size or the date pair.
summer <- ssim_raster(aug16, aug18, w = 1, transform = "none")
fall <- ssim_raster(aug16, nov11, w = 1, transform = "none")
summer$summary
## metric mean min max sd
## 1 SSIM 0.7686929 -0.1976864 0.9999991 0.29695831
## 2 SIM 0.7888708 0.0034073 1.0000000 0.29035795
## 3 SIV 0.9603730 0.1852894 1.0000000 0.08892729
## 4 SIP 0.9915390 -0.2499358 1.0000000 0.02908319
fall$summary
## metric mean min max sd
## 1 SSIM 0.2259786 -0.2139426534 1 0.33614608
## 2 SIM 0.2339652 0.0001376689 1 0.33838033
## 3 SIV 0.7107652 0.0308876725 1 0.28760524
## 4 SIP 0.9940730 -0.2700576644 1 0.03425971These original-unit 3x3 comparisons have mean SSIM approximately
0.7687 for August 16 versus August 18 and 0.2260 for August 16 versus
November 11. Using November 1, omitting transform = "none",
or changing the window will produce different results.
summer_local <- ssim_raster(aug16, aug18, global = FALSE,
w = 1, transform = "none")
fall_local <- ssim_raster(aug16, nov11, global = FALSE,
w = 1, transform = "none")
par(mfrow = c(1, 2))
plot(summer_local[["SSIM"]], range = c(-1, 1), main = "16 vs 18 August")
plot(fall_local[["SSIM"]], range = c(-1, 1), main = "16 August vs 11 November")Raster inference holds the first map fixed and permutes the second
map over common non-missing cells. From version 0.4.2, both global and
local tests use the two-sided p-value
(1 + sum(abs(null - mean(null)) >= abs(observed - mean(null)))) / (R + 1),
matching the permutation-mean-centered definition used for polygons.
Departures above or below the null center can be significant;
significance does not by itself mean high similarity. Local centers are
estimated separately for each cell and statistic. Local inference uses
two passes through the same permutations to keep memory use independent
of the number of permutations, while retaining the random-number state
of one pass. With fdr = TRUE, the four global p-values are
BH-adjusted together; local p-values are adjusted across valid cells
separately for each statistic.
Local significance requires both do_test = TRUE and
local_test = TRUE. The returned layers use suffixes:
SSIM_p, SIM_p, SIV_p,
SIP_p, their _q counterparts when FDR
adjustment is requested, and _sig flags. Raster
significance uses q <= alpha when
fdr = TRUE.
fall_test <- ssim_raster(aug16, nov11, global = FALSE, w = 1,
transform = "none", do_test = TRUE,
local_test = TRUE, R = 1000, fdr = TRUE,
seed = 202610281)
plot(fall_test[[c("SSIM_p", "SIM_p", "SIV_p", "SIP_p")]])The analytical inputs are installed as package datasets. The
reproduction directory contains fixed seeds, scripts and
reference results for Tables 1 and 2, the Figure 6 bandwidth selection,
and the map values in Figures 3–7. Full reproduction includes 1,000
permutations for each comparison and verifies local significance against
the fixed-seed Figure 7 results (279 and 124 ADAs with q < 0.01). It
can take substantial time and is not run during vignette building. Use a
new writable output directory for each run:
source(system.file("reproduction", "reproduce_manuscript.R", package="SSIMmap"))
reproduce_manuscript("ssim-observed", full=FALSE)
reproduce_manuscript("ssim-full", full=TRUE)See reproduction/README.txt for parallel case execution
and the distinction between reproducing the analysis from the packaged
inputs and reconstructing every original external Toronto source record.
The portable map-rendering helper is in
system.file("figures", package="SSIMmap"). Static workflow
illustrations (Figures 1 and 2) and their export helper are in
system.file("workflows", package="SSIMmap"); they are
explanatory diagrams, not computed analysis results.