The discovered scan window (green) converges on the planted target (red rectangle or disk) as the signal strength grows — Jaccard distance falls from 0.67 to 0.10 across five Arkansas-county trials.
Disk-shape recovery on Arkansas counties: Centroid (red) degenerates, Buchin (navy) oversizes, Geom-50 (magenta) recovers the planted disk at the right scale on both large (top) and small (bottom) targets.
Code and figure scripts for the paper:
Sampling for Region-Aggregated Spatial Scan Statistics. Foad Namjoo, Drew McClelland, Michael Matheny, Jeff M. Phillips. arXiv:2607.01451 — under review.
This repository contains the Python experiments and figure-rendering scripts that reproduce every figure and runtime table in the paper, built on top of pyScan.
We replace each spatial region with k = 20–50 uniformly-sampled points (instead of a single centroid). This simple change significantly improves the statistical power of point-based spatial scan statistics applied to region-aggregated input (census tracts, zip codes, counties), without changing the underlying scan algorithm. Runtime stays roughly constant because pyScan's fixed-resolution grid scan does not depend on the input point count.
We validate the method on six planted-region datasets (Arkansas, NYC, Utah, California, Georgia, USA) and on real data — California Valley Fever county-level incidence, where the endemic region is fixed by soil ecology rather than the case counts.
The repo lets you reproduce every claim in the paper from scratch.
Tested on Python 3.11, macOS 14 (Sonoma), and Ubuntu 22.04.
git clone https://github.com/foadnamjoo/sampling-region-scan.git
cd sampling-region-scan
python -m venv venv && source venv/bin/activate
pip install -r requirements.txtYou also need pyScan built locally. The paper was produced against pyScan main as of June 2026. Build following pyScan's README, then either install it into your venv or point PYTHONPATH at the build directory:
export PYTHONPATH=/path/to/pyscan/buildSmoke-test the install:
python -c "import pyscan; print(pyscan.__file__)"If that prints a path, you're set for the synthetic experiments (run_experiment.py, all figures 1–12).
Two scripts — src/run_experiment_real.py and src/run_buchin_comparison.py — call os.chdir(PYSCAN_BUILD) at import so pyScan can find its bundled shared libraries. Set it only if you run those two:
export PYSCAN_BUILD=/path/to/pyscan/buildOn macOS you also need to expose pyScan's third-party libraries to the dynamic linker:
export DYLD_LIBRARY_PATH=/path/to/pyscan/build/thirdparty/discrepancy:\
/path/to/pyscan/build/thirdparty/kernel/ANN:\
/path/to/pyscan/build/thirdparty/kernel/coresetLinux: not required (linker resolves via RPATH).
python src/experiments/run_arkansas.py # ~2 min, writes outputs/arkansas/*.pkl
python src/figures/fig02_jdarkansas.py # ~30 s, writes outputs/fig02_jdarkansas.pdfThat gives you the target-vs-discovered rectangle panels shown at the top of this README (paper Fig 2).
The repo does not redistribute shapefiles. See data/README.md for the original sources (US Census, state GIS portals) and download URLs.
Each figure corresponds to a single script under src/figures/. Many figures depend on cached experiment results; run the matching experiment script under src/experiments/ first.
| Paper figure / table | Experiment | Figure script |
|---|---|---|
| Fig 1 — Arkansas region sampling | — | src/figures/fig01_arkansas_sampling.py |
| Fig 2 — JD Arkansas, Geom 5 | src/experiments/run_arkansas.py |
src/figures/fig02_jdarkansas.py |
| Figs 3, 4, 5 — NYC, Utah, California | src/experiments/run_nyc.py, run_utah_california.py |
src/figures/fig03_06_state_curves.py |
| Fig 6 — USA counties | src/experiments/run_usa.py (cached at outputs/usa/) |
src/figures/fig07_georgia_size.py (render_fig6_usa) |
| Fig 7 — Georgia size sweep | src/experiments/run_georgia_size.py |
src/figures/fig07_georgia_size.py |
| Figs 8, 9 — Arkansas vs FlexScan + Buchin | src/experiments/run_buchin_rect.py |
src/figures/fig08_09_arkansas_buchin.py |
| Fig 10 — Rect map, all methods | src/experiments/run_buchin_rect.py |
src/figures/fig12_17_18_buchin_maps.py |
| Fig 11 — Georgia ablation | src/experiments/run_georgia_ablation.py |
src/figures/fig14_georgia_ablation.py |
| Fig 12 — k-sweep across datasets | (uses cached results) | src/figures/fig16_k_sweep.py |
| Fig 13 — California Valley Fever (real data) | src/run_experiment_real.py --valley |
src/figures/fig15_16_valley_fever.py |
| Figs 14, 15 — Disk Buchin comparison (App B) | src/experiments/run_buchin_disk.py |
src/figures/fig12_17_18_buchin_maps.py |
| Table 1 — Runtime | src/experiments/run_runtime.py |
(printed to stdout) |
All outputs are written under outputs/ (gitignored).
src/
_paths.py Repo-relative path constants
paper_plots.py Shared matplotlib styling (v8 / v9)
shape_floor.py Shape-family floor computation (Fig 2)
run_experiment.py Synthetic experiment registry + sampling helpers
run_experiment_real.py Real-data pipeline (Valley Fever, Fig 13)
run_buchin_comparison.py Buchin et al. (2012) Java head-to-head driver
arkansas_disk_stress.py Disk-family stress test (Figs 14, 15)
render_paper_figs_inset.py Inset-map renderer used by several figures
experiments/ Data-generating scripts (one pickle per run)
figures/ Plot rendering — one script per paper figure
data/
README.md Shapefile / CSV sources (no data redistributed)
outputs/ Generated figures and pickles (gitignored)
Machine-readable metadata is in CITATION.cff at the repo root; GitHub renders a "Cite this repository" button from it in the sidebar.
Preprint: arXiv:2607.01451. Camera-ready citation will be added after acceptance.
To cite the preprint, use the CITATION.cff metadata or the arXiv reference above.
This work uses pyScan by Michael Matheny. The Buchin et al. (2012) reference implementation was provided directly by the authors and is not redistributed in this repository.
MIT — see LICENSE.

