biocore 0.2 → 0.3.1
raw patch · 2 files changed
Files
- biocore.cabal +2/−2
- src/Bio/Core/Sequence.hs +61/−17
biocore.cabal view
@@ -1,5 +1,5 @@ Name: biocore-Version: 0.2+Version: 0.3.1 License: LGPL Cabal-Version: >= 1.6@@ -22,7 +22,7 @@ Location: http://malde.org/~ketil/biohaskell/biocore/ Library- Build-Depends: base >= 3 && < 5, bytestring+ Build-Depends: base >= 3 && < 5, bytestring, stringable Exposed-Modules: Bio.Core, Bio.Core.Sequence, Bio.Core.Strand Ghc-Options: -Wall Hs-Source-Dirs: src
src/Bio/Core/Sequence.hs view
@@ -6,7 +6,8 @@ is available). The data types are mostly wrappers from lazy bytestrings from- 'Data.ByteString.Lazy' and 'Data.ByteString.Lazy.Char8'.+ 'Data.ByteString.Lazy' and 'Data.ByteString.Lazy.Char8', but most users+ of this module should not need to access the underlying data types directly. -} {-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}@@ -20,7 +21,10 @@ BioSeq (..), BioSeqQual (..), -- * Helper functions- toFasta, toFastaQual, toFastQ+ toFasta, toFastaQual, toFastQ,++ module Data.Stringable+ ) where import qualified Data.ByteString.Lazy.Char8 as LC@@ -29,46 +33,86 @@ import Data.Typeable (Typeable) import Data.Word import Data.String+import Data.Stringable hiding (length)+import Data.Monoid -- | Sequence data are lazy bytestrings of ASCII characters.-newtype SeqData = SeqData { unSD :: LC.ByteString } deriving (Eq,Ord,IsString,Show,Typeable)+newtype SeqData = SeqData { unSD :: LC.ByteString }+ deriving (Eq,Ord,IsString,Show,Typeable,Stringable) +instance Monoid SeqData where+ mempty = SeqData mempty+ mappend (SeqData s1) (SeqData s2) = SeqData (mappend s1 s2)+ mconcat = SeqData . mconcat . map unSD+ -- | Sequence data are lazy bytestrings of ASCII characters.-newtype SeqLabel = SeqLabel { unSL :: LC.ByteString } deriving (Eq,Ord,IsString,Show,Typeable)+newtype SeqLabel = SeqLabel { unSL :: LC.ByteString }+ deriving (Eq,Ord,IsString,Show,Typeable,Stringable) +instance Monoid SeqLabel where+ mempty = SeqLabel mempty+ mappend (SeqLabel s1) (SeqLabel s2) = let+ (i1:r1) = LC.words s1+ (i2:r2) = LC.words s2+ sid = mconcat [i1,(LC.pack ":"),i2]+ in SeqLabel (LC.unwords ([sid]++r1++[LC.pack ":"]++r2))+ -- mconcat default+ -- | A quality value is in the range 0..255.-newtype Qual = Qual { unQual :: Word8 } deriving (Show,Eq,Ord,Num)+newtype Qual = Qual { unQual :: Word8 }+ deriving (Show,Eq,Ord,Num,Enum,Real,Integral,Typeable) -- | Quality data are lazy bytestrings of 'Qual's.-newtype QualData = QualData { unQD :: L.ByteString } deriving (Eq,Ord,Show,Typeable)+newtype QualData = QualData { unQD :: L.ByteString }+ deriving (Eq,Ord,Show,Typeable,Stringable) +instance Monoid QualData where+ mempty = QualData mempty+ mappend (QualData s1) (QualData s2) = QualData (mappend s1 s2)+ mconcat = QualData . mconcat . map unQD+ -- | An 'Offset' is a zero-based index into a sequence-newtype Offset = Offset { unOff :: Int64 } deriving (Show,Eq,Ord,Num,Enum,Real,Integral,Typeable)+newtype Offset = Offset { unOff :: Int64 }+ deriving (Show,Eq,Ord,Num,Enum,Real,Integral,Typeable) -- | The 'BioSeq' class models sequence data, and any data object that -- represents a biological sequence should implement it. class BioSeq s where- seqlabel :: s -> SeqLabel- seqdata :: s -> SeqData- seqlength :: s -> Offset+ seqid :: s -> SeqLabel -- ^ Sequence identifier (typically first word of the header)+ seqid = seqlabel+ seqheader :: s -> SeqLabel -- ^ Sequence header (may contain whitespace), by convention the+ -- first word matches the 'seqid'+ seqheader = seqlabel+ seqdata :: s -> SeqData -- ^ Sequence data+ seqlength :: s -> Offset -- ^ Sequence length +-- slice :: s -> (Offset,Offset) -> s -- ^ Cut a slice of a sequence.+-- copy :: s -> s -- ^ Create a copy of a sequence.++ seqlabel :: s -> SeqLabel -- ^ Deprecated. Instead, use 'seqid' if you + -- want the unique ID, or 'seqheader' if you + -- want the FASTA style header with ID and comments.+ seqlabel = seqid ++{-# DEPRECATED seqlabel "Warning: 'seqlabel' is deprecated, use 'seqid' or 'seqheader' instead." #-}+ -- | Any 'BioSeq' can be formatted as Fasta, 60-char lines. toFasta :: BioSeq s => s -> LC.ByteString -- any kind of string-like data type? Use builder?-toFasta s = LC.concat (gt:unSL (seqlabel s):nl:wrap (unSD $ seqdata s))+toFasta s = LC.concat (gt:unSL (seqheader s):nl:wrap (unSD $ seqdata s)) where wrap x = if LC.null x then [] else let (ln,rest) = LC.splitAt 60 x in ln : nl : wrap rest nl = LC.pack "\n" gt = LC.pack ">"- --- | The BioSeqQual class extends BioSeq with quality data. Any correspondig data object++-- | The BioSeqQual class extends 'BioSeq' with quality data. Any correspondig data object -- should be an instance, this will allow Fasta formatted quality data 'toFastaQual', as -- well as the combined FastQ format (via 'toFastQ'). class BioSeq sq => BioSeqQual sq where seqqual :: sq -> QualData --- | Output Fasta-formatted quality data (.qual files), where quality values are output as +-- | Output Fasta-formatted quality data (.qual files), where quality values are output as -- whitespace-separated integers. toFastaQual :: BioSeqQual s => s -> LC.ByteString-toFastaQual s = LC.concat (gt:unSL (seqlabel s):nl:wrap (L.unpack $ unQD $ seqqual s))+toFastaQual s = LC.concat (gt:unSL (seqheader s):nl:wrap (L.unpack $ unQD $ seqqual s)) where wrap x = if null x then [] else let (ln,rest) = splitAt 20 x in LC.pack (unwords $ map show ln) : nl : wrap rest nl = LC.pack "\n" gt = LC.pack ">"@@ -76,7 +120,7 @@ -- | Output FastQ-formatted data. For simplicity, only the Sanger quality format is supported, -- and only four lines per sequence (i.e. no line breaks in sequence or quality data). toFastQ :: BioSeqQual s => s -> LC.ByteString-toFastQ s = LC.unlines [LC.cons '@' (unSL $ seqlabel s)+toFastQ s = LC.unlines [LC.cons '@' (unSL $ seqid s) , unSD (seqdata s)- , LC.cons '+' (unSL $ seqlabel s)+ , LC.cons '+' (unSL $ seqid s) , L.map (+33) (unQD $ seqqual s)]