## ----global.options, include = FALSE------------------------------------------
knitr::opts_knit$set(
    collapse = TRUE,
    comment = "#>",
    fig.align   = 'center'
)

knitr::opts_chunk$set(
    out.extra = 'style="display:block; margin:auto;"',
    warning = FALSE,
    message = FALSE,
    # Compact, HTML-friendly rendering. JPEG (rather than PNG) is the
    # right choice for the H&E histology overlays — photographic raster
    # compresses ~5x better as JPEG at quality 80, keeping the rendered
    # vignette under Bioconductor's 5 MB per-file size guideline.
    dev = "jpeg",
    dev.args = list(quality = 80),
    dpi = 72,
    fig.width = 5,
    fig.height = 4,
    fig.retina = 1
)


## ----eval = FALSE-------------------------------------------------------------
# if (!require("BiocManager", quietly = TRUE))
#     install.packages("BiocManager")
# 
# BiocManager::install("SpaceMarkers")

## ----message = FALSE, warning = FALSE-----------------------------------------
library(SpaceMarkers)

## -----------------------------------------------------------------------------
data_dir <- "visiumBrCA"
unlink(file.path(data_dir), recursive = TRUE)
dir.create(data_dir, showWarnings = FALSE)
main_10xlink <- "https://cf.10xgenomics.com/samples/spatial-exp/1.3.0"
counts_folder <- "Visium_Human_Breast_Cancer"
counts_file <- "Visium_Human_Breast_Cancer_filtered_feature_bc_matrix.h5"
counts_url <- paste(c(main_10xlink, counts_folder, counts_file), collapse = "/")
sp_folder <- "Visium_Human_Breast_Cancer"
sp_file <- "Visium_Human_Breast_Cancer_spatial.tar.gz"
sp_url <- paste(c(main_10xlink, sp_folder, sp_file), collapse = "/")

## -----------------------------------------------------------------------------
bfc <- BiocFileCache::BiocFileCache(ask = FALSE)
counts_cache <- BiocFileCache::bfcrpath(bfc, counts_url)
sp_cache     <- BiocFileCache::bfcrpath(bfc, sp_url)
file.copy(counts_cache, file.path(data_dir, counts_file), overwrite = TRUE)
untar(sp_cache, exdir = data_dir)

## ----message=FALSE, warning=FALSE---------------------------------------------
cogaps_result <- readRDS(system.file("extdata", "CoGAPS_result.rds",
    package = "SpaceMarkers", mustWork = TRUE))

sme <- load10X(data_dir, features = cogaps_result, method = "CoGAPS")
sme

## ----eval=FALSE---------------------------------------------------------------
# # Step 1: Load without features
# sme <- load10X(data_dir)
# 
# # Step 2: Add features later
# sme <- add_features(sme, cogaps_result, method = "CoGAPS")

## -----------------------------------------------------------------------------
# Expression matrix
dim(assay(sme, "logcounts"))

# Spatial coordinates
head(spatialCoords(sme))

# Spatial patterns stored in colData
head(spatial_patterns(sme))

## -----------------------------------------------------------------------------
data("curated_genes")
good_gene_threshold <- 3
keep_genes <- rownames(sme)[
    apply(assay(sme, "logcounts"), 1, function(x) sum(x > 0) >= good_gene_threshold)
]
keep_genes <- intersect(keep_genes, curated_genes)
sme <- sme[keep_genes, ]

# Keep all patterns for now; we will subset per analysis below
sme

## ----message=FALSE, warning=FALSE---------------------------------------------
sme_undirected <- SpaceMarkers(
    x = sme,
    directed = FALSE,
    min.gene.expr = 3,
    pattern_pairs = rbind(c("Pattern_1", "Pattern_2"))
)

## -----------------------------------------------------------------------------
# Analysis type
analysis_type(sme_undirected)

# IM scores (summary: genes x pattern pairs)
head(undirected_scores(sme_undirected))

## -----------------------------------------------------------------------------
# Undirected hotspots
hs <- hotspots(sme_undirected, type = "undirected")
head(hs)

## -----------------------------------------------------------------------------
# Per-pair interaction details
pair_names <- names(interactions(sme_undirected))
pair_names

# Detailed stats for the first pair (if any interactions were found)
if (length(pair_names) > 0) {
    pair1 <- interactions(sme_undirected, pair = pair_names[1])
    if (length(pair1$interacting_genes) > 0) {
        head(pair1$interacting_genes[[1]])
    } else {
        message("No interacting genes found for this pair.")
    }
}

## ----message=FALSE, warning=FALSE---------------------------------------------
sme_directed <- SpaceMarkers(
    x = sme,
    directed = TRUE,
    min.gene.expr = 3,
    pattern_pairs = rbind(c("Pattern_1", "Pattern_5"))
)

## -----------------------------------------------------------------------------
analysis_type(sme_directed)
head(directed_scores(sme_directed))

## -----------------------------------------------------------------------------
# Pattern hotspots
head(hotspots(sme_directed, type = "pattern"))

# Influence hotspots
head(hotspots(sme_directed, type = "influence"))

# Influence map
head(influence_map(sme_directed))

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme, feature_col = "Pattern_1", title = "Pattern_1 (immune)")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme, feature_col = "Pattern_5", title = "Pattern_5 (cancer)")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_undirected, feature_col = "Pattern_1",
             source = "hotspots", hotspot_type = "undirected",
             colors = "steelblue", title = "Pattern_1 hotspots")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_undirected, feature_col = "Pattern_2",
             source = "hotspots", hotspot_type = "undirected",
             colors = "firebrick", title = "Pattern_2 hotspots")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_overlap_scores(sme_undirected, title = "Undirected overlap")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_undirected,
             source = "interaction", hotspot_type = "undirected",
             interaction_patterns = c("Pattern_1", "Pattern_2"),
             colors = c(Pattern_1   = "steelblue",
                        interacting = "purple",
                        Pattern_2   = "firebrick"))

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
pair_col <- setdiff(colnames(undirected_scores(sme_undirected)), "Gene")[1]
plot_im_scores(sme_undirected, interaction = pair_col, nGenes = 10)

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
ims <- undirected_scores(sme_undirected)
top_genes <- head(ims[order(ims[[pair_col]], decreasing = TRUE), "Gene"], 5)

for (g in top_genes) {
    print(plot_spatial(sme_undirected, feature_col = g, title = g))
}

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_directed, feature_col = "Pattern_1",
             source = "hotspots", hotspot_type = "pattern",
             colors = "steelblue", title = "Pattern_1 GMM hotspots")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_directed, feature_col = "Pattern_5",
             source = "hotspots", hotspot_type = "pattern",
             colors = "firebrick", title = "Pattern_5 GMM hotspots")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_overlap_scores(sme_directed, title = "Directed overlap (relative abundance)")

## -----------------------------------------------------------------------------
labs_fwd <- overlap_map(sme_directed, c("Pattern_1", "Pattern_5"),
                        direction = "forward")
table(labs_fwd, useNA = "ifany")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_directed,
             source = "interaction",
             interaction_patterns = c("Pattern_1", "Pattern_5"),
             direction = "forward",
             colors = c(Pattern_1                  = "steelblue",
                        "Pattern_1 near Pattern_5" = "purple",
                        "Pattern_5 influence"      = "gray60"))

## -----------------------------------------------------------------------------
labs_rev <- overlap_map(sme_directed, c("Pattern_1", "Pattern_5"),
                        direction = "reverse")
table(labs_rev, useNA = "ifany")

## ----message=FALSE, warning=FALSE, dpi=60, fig.width=6------------------------
plot_spatial(sme_directed,
             source = "interaction",
             interaction_patterns = c("Pattern_1", "Pattern_5"),
             direction = "reverse",
             colors = c(Pattern_5                  = "firebrick",
                        "Pattern_5 near Pattern_1" = "goldenrod",
                        "Pattern_1 influence"      = "gray60"))

## -----------------------------------------------------------------------------
mat <- matrix(rnorm(100), nrow = 10, ncol = 10)
rownames(mat) <- paste0("gene_", 1:10)
colnames(mat) <- paste0("spot_", 1:10)

coords <- matrix(runif(20) * 100, ncol = 2)
colnames(coords) <- c("y", "x")
rownames(coords) <- colnames(mat)

cd <- S4Vectors::DataFrame(
    CellType_A = runif(10),
    CellType_B = runif(10),
    row.names = colnames(mat)
)

my_sme <- SpaceMarkersExperiment(
    assays = list(logcounts = mat),
    colData = cd,
    spatialCoords = coords,
    spaceMarkers = list(
        params = list(pattern_names = c("CellType_A", "CellType_B"))
    )
)
my_sme

## -----------------------------------------------------------------------------
spe <- SpatialExperiment::SpatialExperiment(
    assays = list(logcounts = mat),
    colData = cd,
    spatialCoords = coords
)

# Extract numeric colData columns as spatial features
features <- get_spatial_features(spe)
head(features)

## ----eval = FALSE-------------------------------------------------------------
# # Legacy usage (returns data.frame, not SME)
# result <- SpaceMarkers(
#     features = "path/to/features.rds",
#     data = "path/to/visium_dir",
#     directed = FALSE,
#     returnSME = FALSE
# )

## -----------------------------------------------------------------------------
unlink(file.path(data_dir), recursive = TRUE)

## -----------------------------------------------------------------------------
sessionInfo()

