IO 方法
概述
常规的文件 IO 流(或方法)以 File
类描述文件的基本信息,使用单个字节作为数据写入和读取的最小单位。GBC 以 GTBManager 类描述 GTB 文件的基本信息,使用单个位点 Variant 作为数据写入和读取的最小单位。以下是最常用的 API 列表:
- edu.sysu.pmglab.gbc.variant.Variant:标准变异位点对象
- edu.sysu.pmglab.gbc.variant.Variants:具有相同坐标的多个变异位点对象
- edu.sysu.pmglab.gbc.GTBIndexer:GTB 索引器,用于快速定位指定染色体所在的文件指针范围
- edu.sysu.pmglab.gbc.GTBManager:GTB 管理器,用于描述 GTB 文件的基本信息
- edu.sysu.pmglab.gbc.GTBWriter:GTB 写入器,用于将 Variant 对象写入 GTB 文件
- edu.sysu.pmglab.gbc.GTBPartWriter:GTB 分部写入器,用于并行地将多个 Variant 写入 GTB 文件
- edu.sysu.pmglab.gbc.GTBReader:GTB 读取器,从 GTB 文件中读取变异位点
- edu.sysu.pmglab.gbc.GTBFilter:GTB 过滤器,将变异位点水平的质控条件(如 AC、AN、坐标范围等)作用到 GTBReader 中
- edu.sysu.pmglab.gbc.GTBFormat:GTB 基本格式声明
- edu.sysu.pmglab.gbc.GTBMeta:GTB 元信息管理类,用于管理 GTB 文件的元信息
以下是简单的进行 GTB 文件 IO 的示例,它读取 https://pmglab.top/gbc/download/assoc.hg19.gtb
上的变异位点,筛选出坐标范围在 chr1:0-200000
的变异位点,并进行 LiftOver:
// 创建文件对象
GTBManager manager = GTBManager.load("https://pmglab.top/gbc/download/assoc.hg19.gtb");
// 创建 GTB 文件写入器
GTBWriter writer = GTBWriter.Builder.of(new File("./assoc.hg19.gtb"))
.addField("hg38_CHROM", FieldType.Int)
.addField("hg38_POS", FieldType.Int)
.addSubjects(manager.getSubjects())
.build()
.writeMeta(manager.getMeta());
// 创建 GTB 读取器
GTBReader reader = new GTBReader(manager);
// 创建过滤器
GTBFilter filter = new GTBFilter().filterByCoordinateRange(Chromosome.get("chr1"), new Interval<>(0, 200000));
// 创建 LiftOver
LiftOver liftOver = LiftOver.load(RefGenomeVersion.hg19, RefGenomeVersion.hg38);
Variant variant;
// 按照过滤器读取位点, 只有满足条件的位点会被读入
while ((variant = reader.read(filter)) != null) {
// liftover 并写入新坐标
Entry<Chromosome, Integer> hg38Coordinates = liftOver.convertCoordinate(variant.getChromosome(), variant.getPosition());
// 写入位点的新属性值
variant.setProperty("hg38_CHROM", hg38Coordinates.getKey().getChromosomeIndex());
variant.setProperty("hg38_POS", hg38Coordinates.getValue());
// 写入位点
writer.write(variant);
}
reader.close();
writer.close();
GTB 基本格式声明
GTB 的基本格式 GTBFormat 包括压缩级别、每个块最多包含的位点数量、基因型向型 3 个参数。
- 压缩级别越高,压缩比越高,但压缩速度越慢;
- 每个块包含的位点数越多,压缩比越高,但会影响访问性能和读写时的内存开销
为保证并行操作大规模基因型数据的可行性,GTB 文件的每个基因型块都不超过 128 MB 大小。
此外,GTBFormat 提供了以下两个常用方法,用于标准化补充列名和受试者名称:
- checkSubjectName(String subjectName):检查受试者名称。不可见字符(如空格、制表符、换行符等)、反斜杠、等号、冒号、分号、逗号、单引号和双引号都被替换为下划线
_
。 - fieldNameChecker(String fieldName):检查字段名称是否合法。字段名称不允许为 CHROM, POS, ALLELE, GENOTYPE。
GTB 元信息
GTB 使用 GTBMeta 管理元信息。主要包含 add(String metaKey, String metaValue)
和 add(ByteCode metaKey, ByteCode metaValue)
方法。作为强制性的规定,GTBMeta 拒绝写入以 $gtbformat.
开头的元信息。
以下是使用 GTBMeta 写入和读取元信息的实例:
GTBMeta meta = new GTBMeta();
// 写入元信息
meta.add("fileformat", "VCFv4.4");
meta.add("contig", "<ID=1,assembly=b37,length=249250621>");
meta.add("contig", "<ID=2,assembly=b37,length=243199373>");
meta.add("FORMAT", "<ID=GT,Number=1,Type=String,Description=\"Genotype\">");
// 读取元信息, 返回结果为所有的键为 contig 的元信息值数组
BaseArray<ByteCode> contigs = meta.get("contig").values();
GTB 写入器
GTB 写入器 GTBWriter 和 GTBPartWriter 使用建造者模式进行初始化,GTBWriter.Builder 是它们的初始化方法。在初始化阶段,使用以下方法配置信息:
- setFormat(GTBFormat format):设置 GTB 文件格式
- addSubject(String subjectName):添加受试者
- addSubjects(String[] subjectNames):添加多个受试者
- addSubjects(
Iterable<String>
subjectNames):添加多个受试者 - addField(String fieldName, FieldType fieldType):添加其他字段
- addFields(
Map<String, FieldType>
fields):添加其他字段
有关 FieldType 支持的类型,请参阅:枚举 FieldType。GTBWriter 中添加了其他字段时,需要向 Variant
对象添加相应字段的属性值,否则会引发空指针异常。
完成配置后,使用 .build()
方法实例化 GTB 写入器 GTBWriter,或使用 .build(int nThreads)
实例化 GTB 分部写入器 GTBPartWriter。分部写入器将文件分为指定数量的子部份,每一个部份都独立使用 GTBWriter 进行数据写入,全部写入任务完成后根据分部索引拼接子文件:
----- ++++++ ~~~~~~ ---> -----++++++~~~~~~
Part1 Part2 Part3 合并
分部写入器最常用的场景是为每一个染色体分配一个子部份,完成压缩后按照染色体编号进行拼接。
GTBWriter 和 GTBPartWriter 都通过 writeMeta(String metaKey, String metaValue)
、 writeMeta(ByteCode metaKey, ByteCode metaValue)
或 writeMeta(GTBMeta metas)
写入元信息。GTBWriter 通过调用 write(Variant variant)
和 write(Variants variants)
写入变异位点。GTBPartWriter 则需要先指定分部索引,获得相应的 GTBWriter 后执行写入变异位点。完成写入后,请务必调用 close()
方法关闭文件 IO 流。
GTB 管理器
GTB 管理器对象 GTBManager 用于维护同个文件路径指向的 GTB 文件信息。它通过缓存结构设计,使得多次请求同个文件的管理器时仅扫描一次文件的索引信息,后续所有的请求都返回同一个管理器对象。加载一个 GTB 文件的管理器,请使用 GTBManager.load(Object fileObject)
。
GTBManager 包含如下常用的方法:
- getFieldNum():获取当前数据表包含的列数(添加的字段数)
- getVariantNum():获取位点数
- getSubjectNum():获取样本数
- containField(String fieldName):是否包含指定的列字段
- containSubject(String subject):是否包含指定的样本名
- getFields():获取补充的其他字段及其类型
- getSubjects():获取样本序列
- getFieldType(String fieldName):获取指定字段的类型
- indexOfSubject(String subject):获取指定样本的索引
- subjectOfIndex(int index):获取指定索引对应的样本名
- getMeta():获取元信息管理器
- isOrdered():检查文件是否坐标有序
GTB 过滤器
GTB 过滤器 GTBFilter 对象用于读取 GTB 变异位点时快速进行过滤。它包含以下常用方法,这些方法建立了变异位点对象 Variant 和基因型序列 Genotypes 的筛选条件:
- filterByAC(
Interval<Integer>
range):按照等位基因频数过滤 - filterByAN(
Interval<Integer>
range):按照等位基因总数过滤 - filterByAF(
Interval<Float>
range):按照等位基因频率过滤 - filterByAlleleNum(
Interval<Float>
range):按照可变等位基因数过滤位点 - filterByChromosome(Chromosome chromosome):按照染色体进行过滤(只读取指定的染色体)
- filterByChromosomes(Chromosome... chromosomes):按照多个染色体进行过滤(只读取指定的染色体)
- filterByChromosomes(
Iterable<Chromosome>
chromosomes):按照多个染色体进行过滤(只读取指定的染色体) - filterByCoordinate(Chromosome chromosome, int position):添加染色体-坐标过滤器(只读取指定的坐标)
- filterByCoordinates(Chromosome chromosome,
Iterable<Integer>
poses):添加染色体-坐标过滤器(只读取指定的坐标)。当指定的染色体的筛选坐标为 null 时,表示读取该染色体的所有位点 - filterByCoordinates(
Map<Chromosome, Iterable<Integer>>
poses):添加多个染色体-坐标过滤器(只读取指定的坐标) - filterByCoordinateRange(Chromosome chromosome,
Interval<Integer>
ranges):添加染色体-坐标范围过滤器(只读取指定的坐标) - filterByCoordinateRanges(
Map<Chromosome, Interval<Integer>>
poses):添加多个染色体-坐标范围过滤器(只读取指定的坐标)。当指定的染色体的筛选坐标范围为 null 时,表示读取该染色体的所有位点 - filterByVariantIndex(
Interval<Long>
indexRangeOfVariant):添加变异位点指针范围过滤器
此外,对于复杂的条件判断,可以使用以下方法进行:
- filterByVariant(
Function<Variant, Boolean>
function):位点过滤器
GTBFilter 支持通过链式调用的方式添加过滤器,如下所示添加多个复杂过滤器方法:
LiftOver liftOver = LiftOver.load(RefGenomeVersion.hg19, RefGenomeVersion.hg38);
GTBFilter filter = new GTBFilter()
.filterByAC(new Interval<>(0, 100))
.filterByAF(new Interval<>(0.1f, 0.9f))
.filterByChromosome(Chromosome.get("chr1"))
.filterByVariant(variant -> liftOver.convertCoordinate(variant) != null);
GTB 读取器
GTB 读取器 GTBReader 用于创建一个按行读取变异位点的读取器实例,包含以下构造器方法:
- GTBReader(Object manager):默认构造器方法,加载所有的基因和补充字段
- GTBReader(Object manager, boolean loadGenotype):构造器方法,可选是否加载基因型
- GTBReader(Object manager, boolean loadGenotype, boolean loadField):构造器方法,可选是否加载基因型、补充字段
- GTBReader(Object manager, boolean loadGenotype,
Iterable<String>
fields):构造器方法,可选是否加载基因型,以及筛选加载的补充字段。fields
为null
时表示加载所有的补充字段
请注意,单个 GTBReader 是线程不安全的,如果需要并行读取文件,请创建多个 GTBReader 实例。
实例化的 GTBReader 主要包含以下方法:
- read():读取并返回一个变异位点对象,到达文件尾部时返回 null
- reads():读取连续地、坐标相同的多个变异位点,并返回一个多位点对象,当 GTB 文件无序时,它无法返回正确的结果
- read(GTBFilter filter):读取一个满足过滤条件的位点,当不存在这样的位点时返回
null
,并且文件指针移动到末尾 - tell():获取文件的位点指针(即位点索引)
- seek(long variantIndex):移动文件位点指针到指定位置
- seek(GTBFilter filter):移动文件位点指针到满足过滤器条件的位置,当不存在这样的位点时返回
false
,文件指针保持不变 - limit(
Interval<Long>
ranges):设置当前读取器的读取范围 - remaining():获取当前读取器剩余可读的记录条目数
- part(int nParts):将 GTBReader 从当前指针位置到文件末尾均等地分为
nPart
份
对于读取的位点,通过 Variant.getProperty(IGenotypes.class)
获得基因型序列。有关基因型序列的操作方法详见 IGenotypes。