sequence-formats-1.6.6.0: src/SequenceFormats/Genomic.hs
module SequenceFormats.Genomic where
import SequenceFormats.Bed (BedEntry(..))
import SequenceFormats.Eigenstrat (EigenstratSnpEntry(..))
import SequenceFormats.FreqSum (FreqSumEntry(..))
import SequenceFormats.Pileup (PileupRow(..))
import SequenceFormats.Utils (Chrom)
import SequenceFormats.VCF (VCFentry(..))
import Control.Monad.Trans.Class (lift)
import Pipes (Producer, next, yield)
class Genomic a where
genomicPosition :: a -> (Chrom, Int)
genomicChrom :: a -> Chrom
genomicChrom = fst . genomicPosition
genomicBase :: a -> Int
genomicBase = snd . genomicPosition
instance Genomic EigenstratSnpEntry where
genomicPosition (EigenstratSnpEntry c p _ _ _ _) = (c, p)
instance Genomic FreqSumEntry where
genomicPosition (FreqSumEntry c p _ _ _ _ _) = (c, p)
instance Genomic PileupRow where
genomicPosition (PileupRow c p _ _ _) = (c, p)
instance Genomic VCFentry where
genomicPosition (VCFentry c p _ _ _ _ _ _ _ _) = (c, p)
data IntervalStatus = BedBehind | BedOn | BedAhead
filterThroughBed :: (Monad m, Genomic e) => Producer BedEntry m () -> Producer e m () -> Producer e m ()
filterThroughBed bedProd gProd = do
b <- lift $ next bedProd
let (bedCurrent, bedRest) = case b of
Left _ -> error "Bed file empty or not readable"
Right r -> r
f' <- lift $ next gProd
let (gCurrent, gRest) = case f' of
Left _ -> error "Genomic stream empty or not readable"
Right r -> r
go bedCurrent gCurrent bedRest gRest
where
go bedCurrent gCurrent bedRest gRest = do
let recurseNextBed = do
b <- lift $ next bedRest
case b of
Left () -> return ()
Right (nextBed, bedRest') -> go nextBed gCurrent bedRest' gRest
recurseNextG = do
f' <- lift $ next gRest
case f' of
Left () -> return ()
Right (nextG, gRest') -> go bedCurrent nextG bedRest gRest'
case bedCurrent `checkIntervalStatus` gCurrent of
BedBehind -> recurseNextBed
BedAhead -> recurseNextG
BedOn -> do
yield gCurrent
recurseNextG
checkIntervalStatus :: (Genomic e) => BedEntry -> e -> IntervalStatus
checkIntervalStatus (BedEntry bedChrom bedStart bedEnd) g =
case bedChrom `compare` genomicChrom g of
LT -> BedBehind
GT -> BedAhead
EQ -> if bedStart + 1 > genomicBase g then
BedAhead
else
if bedEnd < genomicBase g then BedBehind else BedOn
chromFilter :: (Genomic e) => [Chrom] -> e -> Bool
chromFilter exclusionList = (`notElem` exclusionList) . genomicChrom