BLISA Workflow

Introduction

BLISA identifies spatially enriched ligand–receptor interactions from spatial transcriptomics data using local bivariate Moran’s I statistics.

This vignette demonstrates a typical BLISA workflow using Xenium data.

Load Package

library(blisa)
library(scider)
library(CellChat)
library(patchwork)

Load Example Data

Example Xenium dataset distributed with the package:

spe <- readRDS(
  system.file("extdata", "xenium380Cell_spe.rds", package = "blisa")
)

dim(spe)

Visualize Spatial Cell Types

cell_type_colors <- c(
  RColorBrewer::brewer.pal(7, "Set1"),
  RColorBrewer::brewer.pal(6, "Set2")
)

names(cell_type_colors) <- unique(spe$cell_type)

scider::plotSpatial(
  spe,
  group.by = "cell_type",
  pt.size = 0.2,
  pt.alpha = 0.9,
  cols = cell_type_colors
)

Filter Ligand–Receptor Pairs

Restrict CellChat ligand–receptor database to genes present in the panel:

counts_matrix <- SummarizedExperiment::assay(spe, "counts")

LR_pairs_filtered <- filterLRpairs(
  counts = counts_matrix,
  min_ligand = 1,
  min_receptor = 1,
  LR_df = CellChatDB.human$interaction
)

head(LR_pairs_filtered)

Run BLISA

system.time(BLISAres<- runBLISA.spe.isolates.removed(
    spe, 
    LR_df = LR_pairs_filtered))

BLISAres$LR_out

Summarize Ligand–Receptor Interaction Enrichment

plotLRIsum(BLISAres$LR_out)

Visualize Spatial Distribution of Top LR Pairs

plots <- lapply(seq_len(nrow(BLISAres$LR_results)), function(i) {
  plotHotspots(BLISAres, index = i)
})

combined_plot <- patchwork::wrap_plots(plots, ncol = 3)

combined_plot

pdf("xenium_LRI_spatial_plots.pdf", width = 15, height = 12)
print(combined_plot)
dev.off()

Run Cell–Cell Interaction Analysis

When blisa() is called with a group argument (e.g. group = "cell_type"), CCI scores are computed automatically and stored in BLISAres$CCI_scores. To compute or recompute them after the fact, call runCCI() on the blisa object and supply counts_by_group from hexBinCells():

# CCI already computed inside blisa() — retrieve directly
CCIres <- BLISAres$CCI_scores

# Alternatively, compute on an existing blisa object that lacks CCI_scores:
# binned  <- hexBinCells(coords, counts_matrix, bin_size = 50, group = cell_type_vec)
# BLISAres <- runCCI(BLISAres, counts_by_group = binned$counts_by_group)
# CCIres  <- BLISAres$CCI_scores

head(CCIres)

Visualize CCI Heatmap

plotCCI(BLISAres)
plotCCI(BLISAres, sender = "Invasive_Tumor", receiver = "Invasive_Tumor")

Visualize One Ligand–Receptor Pair

p <- plotCCIpair(BLISAres, ligand = "CXCL12", receptor = "CXCR4")

draw(
  p,
  heatmap_legend_side = "right",
  padding = unit(c(5, 5, 10, 10), "mm")
)
CCIspatial(
  spe,
  BLISAres,
  index = 2
)

Session Information

sessionInfo()