flower 0.1.2 → 0.2
raw patch · 4 files changed
+102/−88 lines, 4 filesdep ~bio
Dependency ranges changed: bio
Files
- flower.cabal +3/−3
- src/Flower.hs +84/−41
- src/Metrics.hs +15/−0
- src/Statistics.hs +0/−44
flower.cabal view
@@ -1,5 +1,5 @@ Name: flower-Version: 0.1.2+Version: 0.2 License: GPL Author: Ketil Malde@@ -15,13 +15,13 @@ The Darcs repository is at <http://malde.org/~ketil/biohaskell/flower>. HomePage: http://malde.org/~ketil/biohaskell/flower-Build-Depends: bio >= 0.3.5 && <0.4, base >= 3 && < 4, array >= 0.1, bytestring >= 0.9.1, binary+Build-Depends: bio >= 0.4, base >=3 && <4, array >= 0.1, bytestring >= 0.9.1, binary Build-Type: Simple Tested-with: GHC==6.8.3 -- Data-files: README Executable: flower Main-Is: Flower.hs-Other-Modules: Print, Statistics+Other-Modules: Print, Metrics Hs-Source-Dirs: src Ghc-Options:
src/Flower.hs view
@@ -11,6 +11,7 @@ import System.IO (stdout) import System.Environment (getArgs) import Numeric (showFFloat)+import Data.Char (toLower) import Data.List (intersperse, partition) import Data.ByteString.Char8 (pack,unpack,ByteString) import qualified Data.ByteString.Char8 as B@@ -21,33 +22,54 @@ import Data.Array.ST import Control.Monad.ST +import Metrics+ main :: IO () main = do args <- getArgs let (opts,files) = partition (\p -> case p of ('-':_) -> True; _ -> False) args- case opts of - ["-r"] -> mapM_ (\f -> hWriteFasta stdout . sffToSequence =<< readSFF f) files- ["-R"] -> mapM_ (\f -> writeFastaQual (f++".fasta") (f++".qual") . sffToSequence =<< readSFF f) files- ["-q"] -> mapM_ (\f -> hWriteFastQ stdout . sffToSequence =<< readSFF f) files- ["-f"] -> L1.putStrLn . L1.fromChunks . intersperse (B.pack "\n") . concat =<< mapM showflow files- ["-h"] -> mapM_ (\f -> (putStr . sffToHistogram) =<< readSFF f) files- ["-s"] -> mapM_ (\f -> summarize =<< readSFF f) files+ writer :: SFF -> IO ()+ writer = case opts of + ["-r"] -> hWriteFasta stdout . sffToSequence+ ["-R"] -> writeFastaQual ("flower.fasta") ("flower.qual") . sffToSequence+ ["-q"] -> hWriteFastQ stdout . sffToSequence+ ["-f"] -> L1.putStrLn . L1.fromChunks . intersperse (B.pack "\n") . showflow+ ["-h"] -> putStr . sffToHistogram+ ["-H"] -> putStr . sffToHistogramClip+ ["-i"] -> putStr . getHeader+ ["-s"] -> summarize - _ -> error ("Usage: flower -[f|q|r|R] <file.sff> [<file2.sff> ..]\n"- ++" -r output reads in Fasta format\n"- ++" -R output reads in Fasta format with associated .qual\n"- ++" (generates files instead of writing to <stdout>)\n"- ++" -q output in FastQ format\n"- ++" -f output the flowgram in tabular format\n"- ++" -h output a histogram table of flow values\n"- ++" -s output a summary of each read"- )+ _ -> error ("Usage: flower -[f|h|H|i|q|r|R|s] <file.sff> [<file2.sff> ..]\n"+ ++" -r output reads in Fasta format\n"+ ++" -R output reads in Fasta format with associated .qual\n"+ ++" (generates files instead of writing to <stdout>)\n"+ ++" -q output in FastQ format\n"+ ++" -f output the flowgram in tabular format\n"+ ++" -h output a histogram table of flow values\n"+ ++" -H output a histogram of flows after clipping\n"+ ++" -i output header information\n"+ ++" -s output a summary of each read"+ )+ writer `seq` mapM_ (\f -> writer =<< readSFF f) files +-- ------------------------------------------------------------+-- The -i option: Print header info+-- ------------------------------------------------------------+getHeader :: SFF -> String+getHeader (SFF h _) = unlines ["Index: \t" ++ show (index_offset h,index_length h)+ ,"Num_reads:\t" ++ show (num_reads h)+ ,"Num_flows:\t" ++ show (flow_length h)+ ,"Key: \t" ++ unpack (key h)+ ]+ -- ----------------------------------------------------------+-- The -s option: Summarize each read on one line+-- ---------------------------------------------------------- +-- | Summarize each read on one line of output summarize :: SFF -> IO () summarize (SFF _rh rs) = do- putStrLn "# name........\tdate......\ttime....\treg\tx_loc\ty_loc\tlen\tqual"+ putStrLn "# name........\tdate......\ttime....\treg\ttrim_l\ttrim_r\tx_loc\ty_loc\tlen\tqual\ttrimqual" L1.putStrLn . toLazyByteString . mconcat . map sum1 $ rs -- todo: date and time are usually constants!@@ -55,44 +77,52 @@ sum1 r = let rh = read_header r nb = num_bases rh h = read_name rh - rn = decodeReadName h- (y,m,d) = date rn- reg = region rn- (hh,mm,ss) = time rn- in mconcat ([fromByteString h, tb, putDate y m d, tb, putTime hh mm ss, tb, putInt2 reg- ,tb, putInt (fromIntegral $ x_loc rn), tb, putInt (fromIntegral $ y_loc rn), tb, putInt (fromIntegral nb)- ,tb, fromByteString (fi $ quals $ flowgram r), nl])---- | Take the fractional parts of the flows, and sum their squares-quals :: [Flow] -> Flow-quals q = floor $ (*(100/fromIntegral (length q))) $ sqrt $ sum $ map (fromIntegral . (^2) . (flip (-) 50) . (`mod` 100) . (+50)) $ q+ (rndec1,rndec2) = case decodeReadName h of Just rn -> let ((y,m,d),reg,(hh,mm,ss)) = (date rn,region rn,time rn)+ in ([putDate y m d, putTime hh mm ss, putInt2 reg]+ ,[putInt (fromIntegral $ x_loc rn), putInt (fromIntegral $ y_loc rn)])+ Nothing -> ([q,q,q],[q,q])+ (qleft,qright) = (clip_qual_left rh, clip_qual_right rh)+ in mconcat $ intersperse tb ([fromByteString h]+ ++ rndec1 ++ [putInt (fromIntegral $ qleft), putInt (fromIntegral $ qright)]+ ++ rndec2 ++ [putInt (fromIntegral nb), fromByteString (fi $ quals $ flowgram r)+ , fromByteString (fi $ quals $ take (fromIntegral (qright-qleft)) $ drop (fromIntegral qleft) $ flowgram r), nl]) -tb, nl :: Builder+tb, nl, q :: Builder tb = char '\t' nl = char '\n'+q = char '?' --- these are clumsy, since we just might need the file name-showflow :: FilePath -> IO [ByteString]-showflow f = return . {- map (\s -> B.concat [B.pack f,t,s]) . -} showrun =<< readSFF f+-- ----------------------------------------------------------+-- The -f option: Output the sequence of flows, one flow per line+-- ---------------------------------------------------------- +-- | output a list of flows+showflow :: SFF -> [ByteString]+showflow (SFF h rs) = concatMap (showread h) rs+ fi :: Flow -> ByteString-fi = (!) farray +fi f | f <= 9999 && f >= 0 = farray!f+ | otherwise = error ("Can't show a flow value of "++show f) farray :: Array Flow ByteString-farray = listArray (0,10000) [B.pack (showFFloat (Just 2) i "") | i <- [0,0.01..99.99::Double]]--showrun :: SFF -> [ByteString]-showrun (SFF h rs) = concatMap (showread h) rs+farray = listArray (0,9999) [B.pack (showFFloat (Just 2) i "") | i <- [0,0.01..99.99::Double]] tab :: ByteString tab = B.pack "\t" showread :: CommonHeader -> ReadBlock -> [ByteString]-showread h rd = let rn = read_name $ read_header rd+showread h rd = let rh = read_header rd+ rn = read_name rh+ maskFlows = mask rh 1 qgroups . unpack qgroups = qgroup (B1.unpack $ flow_index rd) (L1.unpack $ quality rd)- format p c v q = B.concat [rn,tab,B.pack (show p),tab,B.pack [c],tab,fi v,tab,B.pack (show q)]- in zipWith4 format [(1::Int)..] (unpack $ flow h) (flowgram rd) qgroups+ format p c v q = B.concat [rn,tab,B.pack (show p),tab,B.pack [c],tab,fi v,tab,B.pack (init $ drop 1 $ show q)]+ in zipWith4 format [(1::Int)..] (maskFlows $ flow h) (flowgram rd) qgroups +-- lower case based on the clip_qual values+mask rh p _ [] = [] -- qgroups are infinite+mask rh p (q1:qs) (c:cs) = c' : mask rh (p+length q1) qs cs+ where c' = if fromIntegral p < clip_qual_left rh || fromIntegral p > clip_qual_right rh then toLower c else c+ zipWith4 :: (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e] zipWith4 f (a:as) (b:bs) (c:cs) (d:ds) = f a b c d : zipWith4 f as bs cs ds zipWith4 _ _ _ _ _ = []@@ -107,8 +137,21 @@ in q1 : qgroup irest qrest qgroup (i:is) qs = [] : qgroup (i-1:is) qs -sffToHistogram :: SFF -> String++-- ----------------------------------------------------------+-- The -h and -H options: Output a histogram of flow values+-- ----------------------------------------------------------++-- | Generate a histogram of flow values from an SFF file+sffToHistogram, sffToHistogramClip :: SFF -> String sffToHistogram (SFF h rs) = showHist . histogram (B.unpack $ flow h) . map flowgram $ rs+sffToHistogramClip (SFF h rs) = showHist . histogram (B.unpack $ flow h) . map clip_flowgram $ rs++clip_flowgram rd = let (l,r) = (fromIntegral $ clip_qual_left (read_header rd)-1, fromIntegral $ clip_qual_right (read_header rd))+ ps = take r $ B1.unpack $ flow_index rd+ p1 = fromIntegral $ sum $ take l ps+ p2 = fromIntegral $ sum $ drop l ps+ in take p2 $ drop p1 $ flowgram rd type Hist = UArray Flow Int
+ src/Metrics.hs view
@@ -0,0 +1,15 @@+-- Calculate various characteristics on sequence quality++module Metrics where++import Bio.Sequence.SFF++-- import Test.QuickCheck++-- | Take the fractional parts of the flows, and sum their squares (the "K²" metric)+quals :: [Flow] -> Flow+quals q = floor $ (100 - 2*(sqrt $ (/fromIntegral (length q)) $ sum $ map (fromIntegral . (^2) . (flip (-) 50) . (`mod` 100) . (+50)) $ q))++prop_quals :: [Flow] -> Bool+prop_quals fs = let q = quals fs in q <= 100 && q >= 0+
− src/Statistics.hs
@@ -1,44 +0,0 @@--- | Yet another simple module for implementing statistics stuff.--module Statistics (normal, normals, stdnormal, stdnormals, module System.Random) where-import System.Random--stdnormal :: StdGen -> (Double,StdGen)-stdnormal = normal 0 1--stdnormals :: StdGen -> [Double]-stdnormals = normals 0 1--normal :: Double -> Double -> StdGen -> (Double,StdGen)-normal mu sigma = \g -> let (x,g') = randomR (0,1) g in (invcumnorm mu sigma x,g') --normals :: Double -> Double -> StdGen -> [Double]-normals mu sigma = \g -> let (x,g') = normal mu sigma g in x : normals mu sigma g'--lognormal :: Double -> Double -> StdGen -> Double-lognormal mu sigma = undefined---- support--invcumnorm mu sigma z = mu + search (-limit*sigma) (limit*sigma)- where search a b = let c = (a+b)/2- cn = cumnorm 0 sigma c- in if abs (z - cn) < 10*epsilon || abs (a-b) < epsilon then c- else if cn > z then search a c- else search c b--cumstdnorm :: Double -> Double-cumstdnorm x = 0.5*(1+erf (x/sqrt 2))--cumnorm :: Double -> Double -> Double -> Double-cumnorm mu sigma x = 0.5*(1+erf((x-mu)/(sigma*sqrt 2)))---- taylor expansion, see wikipedia "error function". Tested within the range (-limit..limit)-erf :: Double -> Double-erf x | x>limit = 1- | x< negate limit = 0- | otherwise = (2/sqrt pi)*sum (reverse $ takeWhile ((>=epsilon).abs) [ ((-1)**n*x**(2*n+1)) / (fac n*(2*n+1)) | n <- [0..]])--epsilon = 0.0000000001-limit = 4.4 :: Double-fac x = product [2..x]