【函数整理版】从Scanpy的Anndata对象提取信息并转成Seurat对象2022-06-15

适用背景

昨天写的文章介绍了Anndata对象转成Seurat对象的流程,但是比较稀碎,所以这篇文章就补充了一个整理成函数的版本。

为什么要转格式

目前使用最为广泛的2个单细胞分析的软件包是基于R语言的Seurat和基于Python的Scanpy。Seurat的分析对象是一个S4 method的Seurat对象,S4 method可以简单理解为可以存储很多种格式的对象类型,不用过于深究,里面存了原始矩阵,各种处理过后的矩阵以及降维信息,样本信息等等,可以通过操作符@$进行访问,如果还不熟悉其结构可以通过Rstudio使用Tab键查看其有关属性,也可以使用str函数快速查看其拓扑结构。而Scanpy的存储对象则为一个Anndata,其结构也类似Seurat对象,但其属性命名规则则与Seurat几乎完全不同,例如其meta.data信息存在obs里,矩阵存在属性X里。
之所以要转格式,是因为目前绝大多数单细胞分析工具都是基于这两种对象进行开发的,有些工具是R语言的,有些是Python语言的,所以常常需要转格式之后才能使用相关分析工具

更新2023-06-29

偶然发现,SeuratDisk包能进行这种格式转换。教程网址

library(Seurat)
library(SeuratData)
library(SeuratDisk)
InstallData("pbmc3k")
data("pbmc3k.final")

#从Seurat转成h5ad
SaveH5Seurat(pbmc3k.final, filename = "pbmc3k.h5Seurat")
Convert("pbmc3k.h5Seurat", dest = "h5ad")
#从h5ad转成Seurat
Convert("pbmc3k_final.h5ad", dest = "h5seurat", overwrite = TRUE)
pbmc3k <- LoadH5Seurat("pbmc3k_final.h5seurat")

出现报错“Ambiguous assays”怎么办?

#添加assay参数
Convert("pbmc3k_final.h5ad", dest = "h5seurat", overwrite = TRUE,assay='Spatial')
ob1 <- LoadH5Seurat("pbmc3k_final.h5seurat",assays='Spatial')

Python 函数

我把函数写进一个function_anndata.py脚本里,这是脚本里的内容:

import os
import sys
import scanpy as sc
import anndata as ad
import numpy as np
import pandas as pd
import h5py

def extra_adata_info(infile,cord_name='spatial'):
    ob1=sc.read(infile)
    mat=pd.DataFrame(data=ob1.X.todense(),index=ob1.obs_names,columns=ob1.var_names)
    mat.to_hdf("mat.h5","mat")
    meta=pd.DataFrame(data=ob1.obs)
    meta.to_csv('metadata.tsv',sep="\t")
    cord=pd.DataFrame(data=ob1.obsm[cord_name],index=ob1.obs_names,columns=['x','y'])
    cord.to_csv('position_'+cord_name+'.tsv',sep="\t")

然后在另一个脚本文件里加载这个脚本,网上收到加载脚本可以用import,但是需要先进入加载脚本所在路径,并且import的时候不用加.py后缀,然后再调用里面的函数extra_adata_info,需注意运行函数前需把目录转回输出目录:

import os
outdir=os.getcwd()
infile='tmp.h5ad'
cord_name='spatial'
os.chdir('/path/to/scripts/')
import function_anndata
from function_anndata import extra_adata_info
os.chdir(outdir)
extra_adata_info(infile,cord_name)

函数extra_adata_info只有两个参数,infile是Scanpy存储的Anndata对象,而cord_name是需保存坐标的slot名,默认是‘spatial’,因为我主要是想做空间组信息,如果要保留UMAP坐标,可以填‘X_umap’。

函数运行好后可以得到矩阵mat.h5,metadata信息metadata.tsv和坐标信息position_spatial.tsv共3个文件。

R函数

我把重建Seurat对象的函数rebulid_seob封装到一个脚本function_transfer_adata.R里:

library(rhdf5)
library(dplyr)
library(data.table)
library(Matrix)
library(rjson)
library(Seurat)

rebulid_seob <- function(fmat="mat.h5",cord_name='spatial',fmeta='metadata.tsv',fpos='position_spatial.tsv',assay='Spatial'){
mydata <- h5read(fmat,"mat")
mat <- mydata$block0_values
rownames(mat) <- mydata$axis0
colnames(mat) <- mydata$axis1
mat <- Matrix(mat, sparse = TRUE)
meta <- read.table(fmeta,sep="\t",header=T,row.names=1)
pos <- read.table(fpos,sep="\t",header=T,row.names=1)
obj <- CreateSeuratObject(mat, project = assay, assay = assay, min.cells=5, min.features=5,meta.data=meta)

##以下脚本将重建空间组对象
if (assay=='Spatial') {
tissue_lowres_image <- matrix(1, max(pos$y), max(pos$x))
tissue_positions_list <- data.frame(row.names = colnames(obj),
                                    tissue = 1,
                                    row = pos$y, col = pos$x,
                                    imagerow = pos$y, imagecol = pos$x)
scalefactors_json <- toJSON(list(fiducial_diameter_fullres = 1,
                                 tissue_hires_scalef = 1,
                                 tissue_lowres_scalef = 1))
seurat_spatialObj <- obj
generate_spatialObj <- function(image, scale.factors, tissue.positions, filter.matrix = TRUE)
{
    if (filter.matrix) {
        tissue.positions <- tissue.positions[which(tissue.positions$tissue == 1), , drop = FALSE]
    }

    unnormalized.radius <- scale.factors$fiducial_diameter_fullres * scale.factors$tissue_lowres_scalef
    spot.radius <- unnormalized.radius / max(dim(image))
    return(new(Class = 'VisiumV1',
               image = image,
               scale.factors = scalefactors(spot = scale.factors$tissue_hires_scalef,
                                            fiducial = scale.factors$fiducial_diameter_fullres,
                                            hires = scale.factors$tissue_hires_scalef,
                                            lowres = scale.factors$tissue_lowres_scalef),
               coordinates = tissue.positions,
               spot.radius = spot.radius))
}

spatialObj <- generate_spatialObj(image = tissue_lowres_image,
                                  scale.factors = fromJSON(scalefactors_json),
                                  tissue.positions = tissue_positions_list)

spatialObj <- spatialObj[Cells(seurat_spatialObj)]
DefaultAssay(spatialObj) <- 'Spatial'
seurat_spatialObj[['slice1']] <- spatialObj
return(seurat_spatialObj)
}else{
return(obj)
}
}

函数rebulid_seob需要传入上面Python函数生成的3个文件,对应三个参数:fmat,fmeta,fpos,如果是在同一个目录下,则可以不用传入这3个参数。另外还有2个参数:cord_name与之前一致是表示坐标的slot名,assay决定是返回什么类型的对象,默认是‘Spatial’,会返回空间组数据对象,如果不是‘Spatial’则返回普通的单细胞对象。

函数使用示例

  • 返回单细胞对象
    que <- rebulid_seob(assay="RNA")
    等价于
    que <- rebulid_seob(fmat="mat.h5",cord_name='spatial',fmeta='metadata.tsv',fpos='position_spatial.tsv',assay='RNA')

  • 返回空间组对象
    que <- rebulid_seob()
    等价于
    que <- rebulid_seob(fmat="mat.h5",cord_name='spatial',fmeta='metadata.tsv',fpos='position_spatial.tsv',assay='Spatial')

小结与补充

重构的Seurat对象是没有降维和聚类等信息的,需要根据具体需求进行后续分析。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容