为clr_A0.chromnames元素添加chr前缀时触发AttributeError问题
解决cooler库中chromnames无法直接赋值的AttributeError问题
问题背景
需要给clr_A0.chromnames的所有元素添加chr前缀,原代码尝试直接赋值但触发AttributeError: can't set attribute。
原代码
import cooler import cooltools.lib.plotting import cooltools from pathlib import Path pathlist = Path(data_dir).glob('**/*.mcool') for path in pathlist: cool_file = str(path) filename = cool_file.split("/",1)[1] resolution = [i.rsplit("/", 1)[1] for i in cooler.fileops.list_coolers(cool_file)] ### load a cooler for each resolution for j in resolution: if filename.startswith("A0"): clr_A0 = cooler.Cooler(f'{cool_file}::resolutions/{j}') clr_A0.chromnames = ["chr" + s for s in clr_A0.chromnames]
报错信息
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Input In [37], in <cell line: 2>() 10 if filename.startswith("A0"): 11 clr_A0 = cooler.Cooler(f'{cool_file}::resolutions/{j}') ---> 12 clr_A0.chromnames = ["chr" + s for s in clr_A0.chromnames] AttributeError: can't set attribute
输入的clr_A0.chromnames
['M', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', 'X', 'Y']
期望输出
['chrM', 'chr1', 'chr2', 'chr3', 'chr4', 'chr5', 'chr6', 'chr7', 'chr8', 'chr9', 'chr10', 'chr11', 'chr12', 'chr13', 'chr14', 'chr15', 'chr16', 'chr17', 'chr18', 'chr19', 'chr20', 'chr21', 'chr22', 'chrX', 'chrY']
原因分析
cooler.Cooler对象的chromnames是只读属性,无法直接赋值修改。它是从底层HDF5文件中读取的元数据,直接修改会破坏数据一致性,因此被设计为不可写。
解决方法
方案1:创建新Cooler对象并保存
复制原Cooler的所有数据,替换染色体名称后写入新文件,不修改原数据:
import cooler import cooltools.lib.plotting import cooltools from pathlib import Path pathlist = Path(data_dir).glob('**/*.mcool') for path in pathlist: cool_file = str(path) filename = cool_file.split("/",1)[1] resolution = [i.rsplit("/", 1)[1] for i in cooler.fileops.list_coolers(cool_file)] for j in resolution: if filename.startswith("A0"): clr_A0 = cooler.Cooler(f'{cool_file}::resolutions/{j}') # 生成带chr前缀的新染色体名称 new_chroms = [f"chr{s}" for s in clr_A0.chromnames] # 复制bins表并替换染色体名称 new_bins = clr_A0.bins()[:].assign(chrom=new_chroms) # 创建新的Cooler对象并保存 new_cool_path = f'{cool_file}_chr_prefix::resolutions/{j}' cooler.Cooler.create( new_cool_path, clr_A0.matrix(balance=False), bins=new_bins, metadata=clr_A0.metadata )
方案2:直接修改原文件的bins表(需谨慎)
如果需要直接修改原文件,可通过可写模式打开Cooler,修改底层bins表的染色体名称:
import cooler import cooltools.lib.plotting import cooltools from pathlib import Path pathlist = Path(data_dir).glob('**/*.mcool') for path in pathlist: cool_file = str(path) filename = cool_file.split("/",1)[1] resolution = [i.rsplit("/", 1)[1] for i in cooler.fileops.list_coolers(cool_file)] for j in resolution: if filename.startswith("A0"): # 以可写模式打开cooler文件 with cooler.Cooler(f'{cool_file}::resolutions/{j}', mode='r+') as clr_A0: # 读取bins表并修改染色体名称 bins = clr_A0.bins()[:] bins['chrom'] = bins['chrom'].apply(lambda x: f"chr{x}") # 将修改后的bins表写回文件 clr_A0.bins()[:] = bins
注意:方案2会直接修改原文件,操作前务必备份数据,避免不可逆的错误。
内容的提问来源于stack exchange,提问作者Anon
相关产品推荐
相关产品推荐

