首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >代码分享 | 空间数据肿瘤交界区扩展--绘图

代码分享 | 空间数据肿瘤交界区扩展--绘图

作者头像
生信大杂烩
发布2025-12-29 11:41:45
发布2025-12-29 11:41:45
910
举报

前言

前面我们介绍了怎样在空间转录组数据分析中,基于定义好的细胞类型,自动识别出肿瘤边界,然后拟合处一条肿瘤边界线,最后分别统计每个细胞距离这条边界线的物理距离,将边界线往Tumor内部的距离定义成正值,边界往外的距离定义成负值,这样的话我们就能够得到所有细胞与肿瘤边界的距离,同时根据距离的正负值也能辨别细胞在边界线的哪个方向。

根据前面介绍的分析,拿到以下结果:

有了上述结果后,我们可以回答一系列生物学问题了,

  1. 在肿瘤与其周围环境的交界处,细胞是如何排布的?肿瘤微环境(TME)的空间异质性,因为肿瘤不是均匀的细胞团。肿瘤内部(Inside)、边界(Border)和外部基质(Outside)具有完全不同细胞组成。
  2. 评估免疫浸润 vs. 免疫排斥 (Immune Infiltration vs. Exclusion)。通过观察免疫细胞(如 CD8+ T cell)在不同区域的分布情况,观察是免疫浸润型(Hot Tumor)还是免疫排斥型(Excluded Tumor)。

绘图展示

以下介绍怎样实现文章中常用的展示方式,最终绘图结果如下:

绘图代码:

代码语言:javascript
复制
import pandas as pd
import numpy as np
import scanpy as sc
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# 定义函数
def plot_spatial_distance_distribution(
    adata, 
    celltype_col='celltype', 
    distance_col='distance', 
    target_celltypes=[],
    bin_width=20,
    x_range=(-240, 200)
):
    # 1. 准备数据
    df = adata.obs[[celltype_col, distance_col]].copy()
    df = df[df[celltype_col].isin(target_celltypes)]
    # 2. 定义分箱 (Bins), 创建从 x_range[0] 到 x_range[1] 的区间
    bins = np.arange(x_range[0], x_range[1] + bin_width, bin_width)
    df['bin'] = pd.cut(df[distance_col], bins=bins, include_lowest=True, right=False)
    # 3. 计算上方柱状图数据 (Total Cell Count per bin)
    count_data = df.groupby('bin', observed=False).size()
    # 4. 计算下方堆叠图数据 (Proportions), 交叉表:行是bin,列是celltype
    pivot_df = pd.crosstab(df['bin'], df[celltype_col])
    prop_df = pivot_df.div(pivot_df.sum(axis=1), axis=0).fillna(0)  # 归一化:将每行的计数转换为比例 (行和为1)
    prop_df = prop_df[target_celltypes]
    # 5. 准备绘图用的 X 轴坐标和标签, 获取每个bin的中心点用于绘图
    x_centers = [b.mid for b in count_data.index]
    x_labels = [f"[{int(b.left)}-{int(b.right)}]"for b in count_data.index]
    # 6. 设置颜色
    colors = sns.color_palette("tab20", len(target_celltypes))

    # ================= 绘图开始 =================
    fig = plt.figure(figsize=(8, 8))
    gs = gridspec.GridSpec(2, 1, height_ratios=[1, 4], hspace=0.05)
    # --- 上图:Cell Count (柱状图) ---
    ax0 = plt.subplot(gs[0])
    ax0.bar(x_centers, count_data.values, width=bin_width*0.9, color='#6096BA', align='center')
    # 样式调整
    ax0.set_ylabel("Cell count", fontsize=12)
    ax0.axvline(x=0, color='gray', linestyle='--', linewidth=1.5) # 0点虚线
    ax0.set_xticks([]) # 隐藏X轴刻度
    ax0.spines['top'].set_visible(False)
    ax0.spines['right'].set_visible(False)
    ax0.spines['bottom'].set_visible(False)
    ax0.set_xlim(x_range[0], x_range[1])
    # --- 下图:Proportion (堆叠面积图) ---
    ax1 = plt.subplot(gs[1])
    # 绘制堆叠图 (Stackplot), transpose() 是因为 stackplot 需要 y 轴数据为 (M, N)
    ax1.stackplot(x_centers, prop_df.T.values, labels=target_celltypes, colors=colors, alpha=0.9)
    # 样式调整
    ax1.set_ylabel("Proportion", fontsize=16)
    ax1.set_ylim(0, 1)
    ax1.set_xlim(x_range[0], x_range[1])
    ax1.axvline(x=0, color='gray', linestyle='--', linewidth=1.5) # 0点虚线
    # 设置X轴标签
    ax1.set_xticks(x_centers)
    ax1.set_xticklabels(x_labels, rotation=90, fontsize=10)
    ax1.set_xlabel("Unit: µm", loc='left', fontsize=12)
    # 添加底部箭头和文字 (Inside / Outside), 这里需要手动调整位置坐标
    y_arrow = -0.35 # 箭头在X轴下方的位置
    ax1.text(-120, y_arrow+0.05, "Inside", ha='center', fontsize=14)
    ax1.arrow(-60, y_arrow, -100, 0, head_width=0.05, head_length=15, fc='k', ec='k', clip_on=False)
    ax1.text(120, y_arrow+0.05, "Outside", ha='center', fontsize=14)
    ax1.arrow(60, y_arrow, 100, 0, head_width=0.05, head_length=15, fc='k', ec='k', clip_on=False)
    ax1.text(0, y_arrow, "Tumor border", ha='center', fontsize=16, clip_on=False)
    # Legend (图例), 将图例放在底部
    handles, labels = ax1.get_legend_handles_labels()
    ax1.legend(
        handles, labels, 
        loc='center left',           # 图例盒子的锚点在"左中"
        bbox_to_anchor=(1.02, 0.5),  # 将锚点固定在坐标轴右边缘外侧 (X=1.02 稍微留点空隙, Y=0.5 垂直居中)
        ncol=1,                      # 设为单列,垂直排列
        frameon=False,               # 去除图例边框
        fontsize=14,
        borderaxespad=0              # 减少内边距
    )
    # 边框清理
    ax1.spines['top'].set_visible(False)
    ax1.spines['right'].set_visible(False)
    plt.show()

函数使用:

代码语言:javascript
复制
plot_spatial_distance_distribution(
    adata,
    celltype_col='celltype', 
    distance_col='is_fitted_boundary_dist_', 
    target_celltypes=adata.obs['celltype'].drop_duplicates(),
    bin_width=20,
    x_range=(-240, 240),
)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信大杂烩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档