Source code for snputils.ibd.io.read.hap_ibd

import logging
import re
from io import StringIO
from typing import Optional

import numpy as np
import polars as pl

from snputils.ibd.genobj.ibdobj import IBDObject
from snputils.ibd.io.read.base import IBDBaseReader, open_text


log = logging.getLogger(__name__)


[docs] class HapIBDReader(IBDBaseReader): """ Reads an IBD file in Hap-IBD format and processes it into an `IBDObject`. """
[docs] def read(self, separator: Optional[str] = None) -> IBDObject: """ Read a Hap-IBD file into an `IBDObject`. The Hap-IBD format is a delimited text without a header with columns: sample_id_1, haplotype_id_1, sample_id_2, haplotype_id_2, chromosome, start, end, length_cm Notes: - Haplotype identifiers are 1-based and take values in {1, 2}. Args: separator (str, optional): Field delimiter. If None, whitespace (any number of spaces or tabs) is assumed. Returns: **IBDObject**: An IBDObject instance. """ log.info(f"Reading {self.file}") # Column names for Hap-IBD files (no header present in input) col_names = [ 'sample_id_1', 'haplotype_id_1', 'sample_id_2', 'haplotype_id_2', 'chrom', 'start', 'end', 'length_cm' ] if separator is None: # Polars does not support regex separators, so normalize arbitrary # whitespace to tabs before parsing. with open_text(self.file) as handle: lines = [ re.sub(r"\s+", "\t", line.strip()) for line in handle if line.strip() ] source = StringIO("\n".join(lines)) parse_separator = "\t" else: source = str(self.file) parse_separator = separator df = pl.read_csv( source=source, has_header=False, separator=parse_separator, new_columns=col_names, schema_overrides={ 'sample_id_1': pl.Utf8, 'haplotype_id_1': pl.Int8, 'sample_id_2': pl.Utf8, 'haplotype_id_2': pl.Int8, 'chrom': pl.Utf8, 'start': pl.Int64, 'end': pl.Int64, 'length_cm': pl.Float64, }, ) ibdobj = IBDObject( sample_id_1=df['sample_id_1'].to_numpy(), haplotype_id_1=df['haplotype_id_1'].to_numpy(), sample_id_2=df['sample_id_2'].to_numpy(), haplotype_id_2=df['haplotype_id_2'].to_numpy(), chrom=df['chrom'].to_numpy(), start=df['start'].to_numpy(), end=df['end'].to_numpy(), length_cm=df['length_cm'].to_numpy(), segment_type=np.array(["IBD1"] * df.height), # hap-IBD does not distinguish; treat as IBD1 ) log.info(f"Finished reading {self.file}") return ibdobj