课前准备--大panel高精度空转(Xenium、seqFISH、CosMx等)依赖空间距离的细胞邻域通讯

作者,Evil Genius

我们的课程很快了,我也需要准备大量的内容,如果大家有兴趣并且有条件可以参加一下培训课程,链接在2025年单细胞空间系列课程,我们21号开始上第一课。

今天我们准备一下关于高精度空间细胞通讯相关的内容。

对于细胞通讯,无论是单细胞还是空间,都是分析重要的一环,就难度上而言,空间通讯因为要考虑细胞之间的空间位置关系,所以分析更为复杂一点,其中通过三角网络计算细胞间的物理距离和配体-受体相互作用分数是一种常用的方法。

其中构建细胞类型的空间关系,就分为以下几步。

1、将每个细胞视为空间中的一个点
2、构建网络连接邻近细胞
3、基于这些连接计算细胞间的相互作用

那么空间通讯的主要分析思路如下:

1、构建空间网络
2、确定配体-受体基因对
3、计算相邻细胞间的配体-受体相互作用分数。

相互作用分数计算原理

对于每对相邻细胞(i,j),相互作用分数计算通常考虑:

细胞i中配体基因的表达水平
细胞j中受体基因的表达水平
两者的乘积或更复杂的统计量

我们来实现一下

其中R脚本的传参与python是类似的,示例如下

# 创建参数解析器
parser <- ArgumentParser(description = "空间转录组配受体分析")

# 添加参数
parser$add_argument("--expression", type = "character", help = "表达矩阵文件路径")
parser$add_argument("--locations", type = "character", help = "细胞位置文件路径")
parser$add_argument("--output", type = "character", help = "输出目录路径")
parser$add_argument("--lr_pairs", type = "character", default = NULL, 
                    help = "自定义配体-受体对文件路径(可选)")
parser$add_argument("--n_cores", type = "integer", default = 4, 
                    help = "使用的CPU核心数")

# 解析参数
args <- parser$parse_args()

其中无论是哪种空间平台,都会有表达矩阵和空间坐标信息,只是放的位置可能不同,像CosMx就是单独给的,所以大家要灵活运用。

高精度平台的细胞注释,也是大家需要认真做的。

完整脚本如下,比较简单,cell_types为细胞注释的列。

#!/usr/bin/env Rscript
###zhaoyunfei
###20250417

suppressPackageStartupMessages({
  library(Giotto)
  library(data.table)
  library(ggplot2)
  library(argparse)
})


parser <- ArgumentParser(description = "空间转录组配受体分析")
parser$add_argument("--expression", type = "character", help = "表达矩阵文件路径")
parser$add_argument("--locations", type = "character", help = "细胞位置文件路径")
parser$add_argument("--output", type = "character", help = "输出目录路径")
parser$add_argument("--lr_pairs", type = "character", default = NULL, 
                    help = "自定义配体-受体对文件路径(可选)")
parser$add_argument("--n_cores", type = "integer", default = 4, 
                    help = "使用的CPU核心数")
args <- parser$parse_args()

if (!file.exists(args$expression)) {
  stop(paste("表达矩阵文件不存在:", args$expression))
}
if (!file.exists(args$locations)) {
  stop(paste("位置文件不存在:", args$locations))
}

if (!dir.exists(args$output)) {
  dir.create(args$output, recursive = TRUE)
}

cat("加载数据...\n")
expr_mat <- data.table::fread(args$expression)
loc_mat <- data.table::fread(args$locations)

if (!all(c("cell_ID", "x", "y") %in% colnames(loc_mat))) {
  stop("位置文件必须包含'cell_ID', 'x', 'y'列")
}

cat("创建Giotto对象...\n")
my_giotto_object <- createGiottoObject(
  expression = list(raw = as.matrix(expr_mat[, -1], rownames = expr_mat[[1]])),
  spatial_locs = as.matrix(loc_mat[, .(x, y)]),
  cell_metadata = data.frame(cell_ID = loc_mat$cell_ID),
  gene_metadata = data.frame(gene_ID = colnames(expr_mat)[-1])
)

cat("处理数据...\n")
my_giotto_object <- filterGiotto(gobject = my_giotto_object)
my_giotto_object <- normalizeGiotto(gobject = my_giotto_object)
my_giotto_object <- addStatistics(gobject = my_giotto_object)

cat("创建Delaunay空间网络...\n")
my_giotto_object <- createSpatialNetwork(gobject = my_giotto_object, 
                                        method = "Delaunay",
                                        name = "delaunay_network")

cat("进行配体-受体分析...\n")

if (!is.null(args$lr_pairs) && file.exists(args$lr_pairs)) {
  lr_pairs <- fread(args$lr_pairs)
} else {
  # 使用Giotto内置的配体-受体对
  lr_pairs <- Giotto::getLigandReceptors()
}

# 计算配体-受体分数
lr_scores <- exprCellCellcom(
  gobject = my_giotto_object,
  cluster_column = "cell_types", 
  spatial_network_name = "delaunay_network",
  random_iter = 100,
  gene_set_1 = lr_pairs$ligand,
  gene_set_2 = lr_pairs$receptor,
  cores = args$n_cores
)

cat("保存结果...\n")
fwrite(lr_scores, file.path(args$output, "ligand_receptor_scores.csv"))

cat("生成可视化...\n")

### 可视化空间网络
spatial_plot <- spatPlot(
  gobject = my_giotto_object,
  show_network = TRUE,
  network_color = "blue",
  spatial_network_name = "delaunay_network",
  point_size = 1.5,
  save_param = list(
    save_name = "spatial_network",
    save_dir = args$output
  )
)

# 可视化配体-受体相互作用热图
heatmap_plot <- heatmAPCellCellcom(
  gobject = my_giotto_object,
  comScores = lr_scores,
  save_param = list(
    save_name = "lr_interaction_heatmap",
    save_dir = args$output
  )
)

# 可视化特定配体-受体对的空间模式
if (nrow(lr_scores) > 0) {
  top_lr <- lr_scores[order(-LR_expr)][1:5, unique(LR_comb)]
  
  for (lr in top_lr) {
    lr_plot <- spatCellCellcom(
      gobject = my_giotto_object,
      comScores = lr_scores,
      selected_LR = lr,
      show_plot = FALSE,
      save_param = list(
        save_name = paste0("lr_interaction_", gsub(" ", "_", lr)),
        save_dir = args$output
      )
    )
  }
}

cat("分析完成! 结果保存在:", args$output, "\n")


生活很好,有你更好

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容