---
title: "Getting Started with neuromapr"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with neuromapr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4
)
```

Two brain maps look correlated. But the brain is spatially
autocorrelated---nearby regions tend to have similar values simply
because they are neighbours. A standard correlation test ignores this
structure, which inflates p-values and produces false positives.

neuromapr exists to answer one question honestly: **is the similarity
between two brain maps more than spatial structure alone would predict?**

It generates surrogate maps that preserve the spatial autocorrelation of
the original data, then measures where the real correlation falls in that
null distribution. The framework follows Markello et al. (2022).

```{r setup}
library(neuromapr)
```

## Comparing two brain maps

The core workflow: load data, compare, interpret. We simulate two
brain maps here to keep things self-contained, but in practice you would
read real data from GIFTI or NIfTI files.

```{r simulate-data}
set.seed(42)
n <- 100
coords <- matrix(rnorm(n * 3), ncol = 3)
distmat <- as.matrix(dist(coords))

map_a <- rnorm(n)
map_b <- 0.4 * map_a + rnorm(n, sd = 0.8)
```

Two maps with a planted correlation around 0.4, plus a distance matrix
describing the spatial layout. The simplest comparison:

```{r simple-compare}
result <- compare_maps(map_a, map_b, verbose = FALSE)
result
```

The `r` and parametric `p` tell the familiar story. But that `p`
assumes independence between observations---an assumption the brain
violates everywhere.

## Adding a spatial null model

To get an honest p-value, we generate surrogate versions of `map_a`
that preserve its spatial autocorrelation, then check whether the
observed correlation is unusual against correlations with those
surrogates.

neuromapr provides eight null model methods. For parcellated data with
a distance matrix, variogram matching (`burt2020`) is a strong default:

```{r null-comparison}
result_null <- compare_maps(
  map_a, map_b,
  null_method = "burt2020",
  distmat = distmat,
  n_perm = 500L,
  seed = 1,
  verbose = FALSE
)
result_null
```

The `p_null` value now accounts for spatial autocorrelation. If it
remains small, the relationship between the two maps is unlikely to be
an artifact of shared spatial structure.

## Visualising the null distribution

The comparison object stores all null correlations, making it
straightforward to see where the observed value falls:

```{r null-distribution-plot, fig.cap = "Null correlations from 500 variogram-matching surrogates. The dashed red line marks the observed correlation."}
null_df <- data.frame(r = result_null$null_r)
obs_r <- result_null$r

ggplot2::ggplot(null_df, ggplot2::aes(x = r)) +
  ggplot2::geom_histogram(
    bins = 30, fill = "steelblue", alpha = 0.7
  ) +
  ggplot2::geom_vline(
    xintercept = obs_r,
    linetype = "dashed", color = "red", linewidth = 1
  ) +
  ggplot2::labs(
    x = "Null correlation (r)",
    y = "Count"
  ) +
  ggplot2::theme_minimal()
```

When the observed correlation sits well outside the null distribution,
the relationship is more likely genuine. When it sits inside, spatial
autocorrelation alone can explain the similarity.

## Pre-computing null distributions

Generating nulls is the expensive part. If you want to compare the same
map against several targets, generate once and reuse:

```{r precompute}
nulls <- generate_nulls(
  map_a,
  method = "moran",
  distmat = distmat,
  n_perm = 200L,
  seed = 42
)
nulls
```

The `null_distribution` object has `print`, `summary`, `plot`, and
`as.matrix` methods. The `summary` gives per-element null means and
standard deviations. The `plot` method shows the null distribution for
a chosen element:

```{r plot-nulls, fig.cap = "Built-in plot method for a null_distribution object."}
plot(nulls, parcel = 1L)
```

Pass the pre-computed object to `compare_maps()`:

```{r reuse-nulls}
compare_maps(map_a, map_b, nulls = nulls, verbose = FALSE)
```

No redundant computation when the same source map appears in multiple
comparisons.

## Working with real brain map files

In practice, brain maps live on disk. `compare_maps()` and
`read_brain_map_values()` accept file paths directly:

```r
values <- read_brain_map_values("cortical_thickness.func.gii")

result <- compare_maps(
  "path/to/map_a.func.gii",
  "path/to/map_b.func.gii",
  null_method = "moran",
  distmat = distmat
)
```

Both GIFTI (`.func.gii`) and NIfTI (`.nii.gz`) formats are supported.
No separate reading step needed.

## Accessing the neuromaps atlas collection

The neuromaps project curates a registry of published brain map
annotations---PET receptor maps, gene expression, cortical thickness,
and more. neuromapr provides direct access to this collection:

```r
neuromaps_available()

neuromaps_available(source = "beliveau", tags = "pet")
```

Once you find the annotation you want, download it:

```r
paths <- fetch_neuromaps_annotation(
  "abagen", "genepc1", "fsaverage",
  density = "10k"
)
```

Files are cached locally, so subsequent calls skip the download. The
registry is fetched from the neuromaps GitHub repository and cached for
the session.

## Custom metrics with `permtest_metric()`

`compare_maps()` is built around correlation. For other metrics---mean
absolute error, cosine similarity, anything that takes two vectors and
returns a scalar---`permtest_metric()` provides the same null model
machinery:

```{r permtest}
mae <- function(a, b) mean(abs(a - b))

result_mae <- permtest_metric(
  map_a, rnorm(n),
  metric_func = mae,
  n_perm = 200L,
  seed = 1
)
result_mae$observed
result_mae$p_value
```

Add `null_method` for spatially-constrained surrogates instead of
random permutation:

```{r permtest-spatial}
result_spatial <- permtest_metric(
  map_a, rnorm(n),
  metric_func = mae,
  n_perm = 200L,
  seed = 1,
  null_method = "burt2020",
  distmat = distmat
)
result_spatial$p_value
```

## Choosing a null model

The right model depends on your data:

| Situation | Recommended method |
|---|---|
| Parcellated data with distance matrix | `"burt2020"` or `"moran"` |
| Vertex-level with sphere coordinates | `"spin_hungarian"` or `"alexander_bloch"` |
| Parcellated with sphere coordinates | `"baum"` or `"cornblath"` |
| Spatial autoregressive structure | `"burt2018"` |

`vignette("null-models")` walks through each method in detail.

## What comes next

This vignette covered the essential workflow: compare maps, generate
spatially-constrained null distributions, and interpret results.
From here:

- `vignette("null-models")` dives into all eight null model methods
  and their assumptions.
- `vignette("parcellation")` covers aggregating vertex data into
  parcels and parcel-level null models.
- `vignette("surface-geometry")` explains geodesic distances, surface
  graphs, and vertex area calculations.

## References

Markello RD, Hansen JY, Liu Z-Q, et al. (2022). neuromaps: structural
and functional interpretation of brain maps. *Nature Methods*, 19,
1472--1480. doi:10.1038/s41592-022-01625-w
