--- title: "Exploring cell-cell interaction with blisa" output: rmarkdown::html_vignette: self_contained: true pandoc_args: ["--embed-resources", "--standalone"] vignette: > %\VignetteIndexEntry{Exploring cell-cell interaction with blisa} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ## Introduction `blisa` identifies spatially enriched ligand-receptor (LR) interactions from spatial transcriptomics data using bivariate Local Moran's I (LISA) statistics. The core idea is to bin cells into a hexagonal grid, compute spatial co-enrichment of every ligand-receptor pair across bins, and flag "High-High" hotspot bins where both partners are spatially co-expressed beyond chance. This vignette walks through a typical workflow on a Xenium breast cancer dataset. ## Load Package ``` r library(blisa) library(SpatialExperiment) ``` ## Load Example Data The example dataset is a small `SpatialExperiment` object (one Xenium breast cancer section) hosted as a GitHub Release asset. Download it once and cache locally: ``` r data_url <- "https://github.com/ChenLaboratory/example_data/releases/download/v1.0.0/spe_xenium_bc_s1rep1.rds" cache_dir <- tools::R_user_dir("blisa", "cache") data_file <- file.path(cache_dir, "spe_xenium_bc_s1rep1.rds") if (!file.exists(data_file)) { dir.create(cache_dir, recursive = TRUE, showWarnings = FALSE) download.file(data_url, data_file, mode = "wb") } spe <- readRDS(data_file) spe #> class: SpatialExperiment #> dim: 313 163797 #> metadata(0): #> assays(1): counts #> rownames(313): ABCC11 ACTA2 ... ZEB2 ZNF562 #> rowData names(3): ID Symbol Type #> colnames(163797): cell_1 cell_2 ... cell_167779 cell_167780 #> colData names(12): cell_id transcript_counts ... gene_counts cell_type #> reducedDimNames(0): #> mainExpName: NULL #> altExpNames(0): #> spatialCoords names(2) : x_centroid y_centroid #> imgData names(1): sample_id ``` ## Bin Cells into Hexagons `hexBinCells()` aggregates cells into hexagonal bins. When a `group` argument is supplied (here, cell type), it also returns per-cell-type bin matrices in `counts_by_group`, which are needed downstream for CCI scoring and spatial visualisation. ``` r coords <- as.data.frame(SpatialExperiment::spatialCoords(spe)) counts <- SummarizedExperiment::assay(spe, "counts") binned <- hexBinCells( coords_df = coords, counts_matrix = counts, bin_size = 50, group = spe$cell_type ) # Components: # binned$counts_matrix - gene x bin sparse matrix (all cells) # binned$bins - sf polygons (with n_cells column) # binned$counts_by_group - named list of gene x bin matrices, one per cell type ``` ## Run BLISA `blisa()` does everything in one call: spatial weights, LR pair filtering against CellChatDB, bivariate Moran's I per LR pair, hotspot identification, and (when `counts_by_group` is supplied) cell-cell interaction scoring. ``` r res <- blisa( binned$counts_matrix, bins = binned$bins, n_cells_col = "n_cells", counts_by_group = binned$counts_by_group ) #> Downloading CellChatDB.human from GitHub (once per session)... #> Testing 12 LR pairs... #> |========================================| 100% res #> A blisa object #> LR pairs tested : 12 #> Significant pairs: 12 #> Bins : 17215 #> CCI computed : TRUE ``` The result is a `blisa` object with four slots: - `LR_results` — one row per LR pair, sorted by number of hotspot bins - `bins` — the hexagonal grid as an `sf` object - `spatial_weights` — queen and distance-decay weights from `computeSpatialWeights()` - `CCI_scores` — wide data frame of sender-receiver interaction scores per LR pair ## Rank LR Pairs by Hotspot Count ``` r plotLRrank(res, top = 30) ``` ## Spatial Map of Hotspot Bins For a chosen LR pair (here, the top-ranked pair by default), shows which bins are significant hotspots, coloured by p-value or LISA score. ``` r plotHotspots(res, index = 1) ``` ``` r # Or by gene names: # plotHotspots(res, ligand = "CXCL12", receptor = "CXCR4") ``` ## Cell-Cell Interaction (CCI) Heatmaps ### Across all LR pairs Rows are sender→receiver cell-type pairs; columns are LR pairs. ``` r plotCCI(res, top_lr = 20, top_pairs = 30) ``` Filter by specific senders or receivers: ``` r plotCCI(res, sender = c("CD4+_T_Cells", "CD8+_T_Cells", "B_Cells", "Macrophages", "DCs"), receiver = c("Invasive_Tumor", "DCIS", "Myoepi") ) ``` ### For a single LR pair ``` r plotCCILR(res, ligand = "CXCL12", receptor = "CXCR4") ``` ### Aggregated across LR pairs Sender × receiver heatmap with scores summed (or any user-supplied function) across all LR pairs: ``` r plotCCIsummary(res) ``` ``` r # With a different aggregation: # plotCCIsummary(res, agg_fun = mean) ``` ## Spatial Map of Dominant Cell-Type Pairs For each hotspot bin of a chosen LR pair, identifies the dominant sender→receiver cell-type combination based on ligand expression in the neighbourhood and receptor expression inside the bin. ``` r plotCCIspatial( res, counts_by_group = binned$counts_by_group, index = 1 ) ``` ## Session Information ``` r sessionInfo() #> R version 4.6.0 (2026-04-24 ucrt) #> Platform: x86_64-w64-mingw32/x64 #> Running under: Windows 11 x64 (build 26200) #> #> Matrix products: default #> LAPACK version 3.12.1 #> #> locale: #> [1] LC_COLLATE=English_Australia.utf8 LC_CTYPE=English_Australia.utf8 LC_MONETARY=English_Australia.utf8 #> [4] LC_NUMERIC=C LC_TIME=English_Australia.utf8 #> #> time zone: Australia/Sydney #> tzcode source: internal #> #> attached base packages: #> [1] stats4 stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] SpatialExperiment_1.21.0 SingleCellExperiment_1.33.2 SummarizedExperiment_1.41.1 Biobase_2.71.0 #> [5] GenomicRanges_1.63.2 Seqinfo_1.1.0 IRanges_2.45.0 S4Vectors_0.49.2 #> [9] BiocGenerics_0.57.1 generics_0.1.4 MatrixGenerics_1.23.0 matrixStats_1.5.0 #> [13] blisa_1.0.0 #> #> loaded via a namespace (and not attached): #> [1] gtable_0.3.6 circlize_0.4.18 shape_1.4.6.1 rjson_0.2.23 xfun_0.57 #> [6] ggplot2_4.0.3 GlobalOptions_0.1.4 lattice_0.22-9 Cairo_1.7-0 vctrs_0.7.3 #> [11] tools_4.6.0 spdep_1.4-2 parallel_4.6.0 tibble_3.3.1 proxy_0.4-29 #> [16] cluster_2.1.8.2 pkgconfig_2.0.3 Matrix_1.7-5 KernSmooth_2.23-26 RColorBrewer_1.1-3 #> [21] S7_0.2.2 lifecycle_1.0.5 deldir_2.0-4 compiler_4.6.0 farver_2.1.2 #> [26] codetools_0.2-20 ComplexHeatmap_2.28.0 clue_0.3-68 class_7.3-23 fastLISA_1.0.1 #> [31] pillar_1.11.1 crayon_1.5.3 classInt_0.4-11 DelayedArray_0.37.1 dbscan_1.2.4 #> [36] wk_0.9.5 magick_2.9.1 iterators_1.0.14 boot_1.3-32 abind_1.4-8 #> [41] foreach_1.5.2 tidyselect_1.2.1 digest_0.6.39 sf_1.1-1 dplyr_1.2.1 #> [46] labeling_0.4.3 grid_4.6.0 colorspace_2.1-2 cli_3.6.6 SparseArray_1.11.13 #> [51] magrittr_2.0.5 S4Arrays_1.11.1 e1071_1.7-17 withr_3.0.3 scales_1.4.0 #> [56] sp_2.2-1 spData_2.3.5 XVector_0.51.0 otel_0.2.0 png_0.1-9 #> [61] GetoptLong_1.1.1 evaluate_1.0.5 knitr_1.51 doParallel_1.0.17 viridisLite_0.4.3 #> [66] s2_1.1.11 rlang_1.2.0 Rcpp_1.1.1-1.1 glue_1.8.1 DBI_1.3.0 #> [71] R6_2.6.1 units_1.0-1 ```