---
title: "Loading CosMx and Xenium data with SpaceTrooper"
author: "Dario Righelli"
date: "`r BiocStyle::doc_date()`"
pkg: SpaceTrooper
output:
    BiocStyle::html_document:
        toc: true
        toc_float: true
vignette: >
    %\VignetteIndexEntry{Loading CosMx and Xenium data with SpaceTrooper}
    %\VignetteEncoding{UTF-8}
    %\VignetteEngine{knitr::rmarkdown}
---

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

# Overview

This vignette shows how to build a `SpatialExperiment` (SPE) from: - **Nanostring CosMx** (RNA/protein) outputs - **10x Genomics Xenium** outputs

For each technology, we demonstrate: - **Route A**: SpaceTrooper’s high-level reader (`readCosmxSPE`, `readCosmxProteinSPE`, `readXeniumSPE`) - **Route B**: read with **SpatialExperimentIO**, then standardize with `updateCosmxSPE` / `updateXeniumSPE`

# CosMx (Nanostring)

We begin with **CosMx**. The package ships with a small CosMx example for demonstration.

```{r cosmx-path}
cospath <- system.file(file.path("extdata", "CosMx_DBKero_Tiny"), package="SpaceTrooper")
cospath
```

## Route A — Direct loading with SpaceTrooper

Use `readCosmxSPE()` to construct an SPE from CosMx outputs; it also normalizes names/metadata and records polygons/FOV info if present.

```{r cosmx-route-a}
spe_cos <- readCosmxSPE(
    dirName=cospath,
    sampleName="DBKero_Tiny",
    coordNames=c("CenterX_global_px", "CenterY_global_px"),
    countMatFPattern="exprMat_file.csv",
    metadataFPattern="metadata_file.csv",
    polygonsFPattern="polygons.csv",
    fovPosFPattern="fov_positions_file.csv",
    fovdims=c(xdim=4256, ydim=4256)
)
spe_cos
```

Inspect essentials:

```{r cosmx-route-a-inspect}
assayNames(spe_cos)
dim(spe_cos)
head(colnames(spatialCoords(spe_cos)))
metadata(spe_cos)$technology
metadata(spe_cos)$polygons
```

### CosMx protein

If working with **CosMx Protein**, use the convenience wrapper:

```{r cosmx-protein, eval=FALSE}
protfolder <- system.file("extdata", "S01_prot", package = "SpaceTrooper")
spe_cos_prot <- readCosmxProteinSPE(
    dirName=protfolder,
    sampleName="cosmx_prots",
    coordNames=c("CenterX_global_px", "CenterY_global_px"),
    countMatFPattern="exprMat_file.csv",
    metadataFPattern="metadata_file.csv",
    polygonsFPattern="polygons.csv",
    fovPosFPattern="fov_positions_file.csv",
    fovdims=c(xdim=4256, ydim=4256)
)
metadata(spe_cos_prot)$technology
```

## Route B — Via SpatialExperimentIO, then standardize

If you prefer to read with **SpatialExperimentIO** first, upgrade the object with `updateCosmxSPE()` to harmonize names/metadata and attach polygons.

```{r cosmx-route-b}
spe_cos_raw <- SpatialExperimentIO::readCosmxSXE(
    dirName=cospath,
    returnType="SPE",
    countMatPattern="exprMat_file.csv",
    metaDataPattern="metadata_file.csv",
    coordNames=c("CenterX_global_px", "CenterY_global_px"),
    addFovPos=TRUE,
    fovPosPattern="fov_positions_file.csv",
    altExps=NULL,
    addParquetPaths=FALSE
)

spe_cos_std <- updateCosmxSPE(
    spe=spe_cos_raw,
    dirName=cospath,
    sampleName="DBKero_Tiny",
    polygonsFPattern="polygons.csv",
    fovdims=c(xdim=4256, ydim=4256)
)

identical(spe_cos_std, spe_cos)
```

# Xenium (10x Genomics)

A small Xenium example is also included for demonstration.

```{r xenium-path}
xepath <- system.file("extdata", "Xenium_small", package = "SpaceTrooper")
xepath
```

## Route A — Direct loading with SpaceTrooper

`readXeniumSPE()` builds the SPE from a Xenium Output Bundle (root or `outs/`) and standardizes metadata.

Key options: - `type`: `"HDF5"` or `"sparse"` (feature matrix) - `boundariesType`: `"parquet"` or `"csv"` (cell boundaries) - `computeMissingMetrics`: compute QC metrics (area/aspect ratio) if needed - `keepPolygons`: append polygons to `colData` - `addFOVs`: derive FOV IDs from transcript parquet

```{r xenium-route-a}
spe_xen_a <- readXeniumSPE(
    dirName=xepath,
    type="HDF5",
    coordNames=c("x_centroid", "y_centroid"),
    boundariesType="parquet",
    computeMissingMetrics=TRUE,
    keepPolygons=TRUE,
    countsFilePattern="cell_feature_matrix",
    metadataFPattern="cells.csv.gz",
    polygonsFPattern="cell_boundaries",
    polygonsCol="polygons",
    txPattern="transcripts",
    addFOVs=FALSE
)
spe_xen_a
```

Quick checks:

```{r xenium-route-a-inspect}
assayNames(spe_xen_a)
dim(spe_xen_a)
colnames(spatialCoords(spe_xen_a))
metadata(spe_xen_a)$polygons
metadata(spe_xen_a)$technology
```

## Route B — Via SpatialExperimentIO, then standardize

Read with **SpatialExperimentIO** and then pass through `updateXeniumSPE()` for SpaceTrooper-standardized metadata and optional metrics/FOV extraction.

```{r xenium-route-b}
spe_xen_b <- SpatialExperimentIO::readXeniumSXE(
    dirName=xepath,
    countMatPattern="cell_feature_matrix.h5",
    metaDataPattern="cells.csv.gz",
    coordNames=c("x_centroid", "y_centroid"),
    returnType="SPE",
    addExperimentXenium=FALSE,
    altExps=NULL,
    addParquetPaths=FALSE
) 

spe_xen_b <- updateXeniumSPE(
    spe=spe_xen_b,
    dirName=xepath,
    boundariesType="parquet",
    computeMissingMetrics=TRUE,
    keepPolygons=TRUE,
    polygonsFPattern="cell_boundaries",
    polygonsCol="polygons",
    txPattern="transcripts",
    addFOVs=FALSE
) 

spe_xen_b
```

Validate:

```{r xenium-route-b-validate}
identical(metadata(spe_xen_b)$technology, "10X_Xenium")
identical(spe_xen_a, spe_xen_b)
```

------------------------------------------------------------------------

# File layout notes

-   **CosMx**: per-cell metadata (e.g. `metadata_file.csv`), expression matrix (`exprMat_file.csv`), optional polygon CSV (`polygons.csv`), and FOV positions. `updateCosmxSPE()` also fixes common field names and records FOV dims in `metadata`.
-   **Xenium**: unzipped bundle contains an `outs/` folder. Feature matrix may be `cell_feature_matrix.h5` (HDF5) or sparse folder; cells metadata `cells.csv.gz`; boundaries as `.parquet` or `.csv.gz`; transcript parquet for FOV attribution. `readXeniumSPE()` auto-detects `outs/` if you pass the bundle root.

# Session info

```{r session-info}
sessionInfo()
```