slynx 0.3.0 → 0.3.1
raw patch · 8 files changed
+187/−125 lines, 8 filesdep +attoparsecdep −megaparsecdep −scientific
Dependencies added: attoparsec
Dependencies removed: megaparsec, scientific
Files
- ChangeLog.md +8/−1
- README.md +27/−27
- slynx.cabal +3/−6
- src/SLynx/Examine/Examine.hs +24/−24
- src/SLynx/Filter/Filter.hs +3/−3
- src/SLynx/Simulate/PhyloModel.hs +28/−48
- src/SLynx/Simulate/Simulate.hs +93/−13
- src/SLynx/Tools.hs +1/−3
ChangeLog.md view
@@ -2,7 +2,14 @@ # Changelog for ELynx -## Version 0.3.1; in development+## Version 0.3.2; in development+++## Version 0.3.1++- Use Attoparsec.+- Use ByteString consistently.+- Remove elynx-tools dependency from libaries. ## Version 0.3.0
README.md view
@@ -2,7 +2,7 @@ # The ELynx Suite -Version: 0.3.0.+Version: 0.3.1. Reproducible evolution made easy. <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>@@ -90,9 +90,9 @@ slynx --help | head -n -16 - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] [-f|--force] COMMAND@@ -136,9 +136,9 @@ slynx concatenate --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE Concatenate sequences found in input files.@@ -157,9 +157,9 @@ slynx examine --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site] Examine sequences. If data is a multi sequence alignment, additionally analyze columns.@@ -179,9 +179,9 @@ slynx filter-rows --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] [--shorter-than LENGTH] [--standard-characters]@@ -202,9 +202,9 @@ slynx filter-columns --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE [--standard-chars DOUBLE]@@ -226,9 +226,9 @@ slynx simulate --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] [-m|--mixture-model MODEL] [-e|--edm-file NAME] @@ -305,9 +305,9 @@ slynx sub-sample --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE (-n|--number-of-sites INT)@@ -335,9 +335,9 @@ slynx translate --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT) (-u|--universal-code CODE)@@ -360,9 +360,9 @@ tlynx --help | head -n -16 - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] [-f|--force] COMMAND@@ -399,9 +399,9 @@ tlynx compare --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] [-f|--newick-format FORMAT] NAMES@@ -428,9 +428,9 @@ tlynx examine --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT] Compute summary statistics of phylogenetic trees.@@ -452,9 +452,9 @@ tlynx simulate --help - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE] [-M|--condition-on-mrca] [-l|--lambda DOUBLE] @@ -491,9 +491,9 @@ elynx --help | head -n -16 - ELynx Suite version 0.3.0.+ ELynx Suite version 0.3.1. Developed by Dominik Schrempf.- Compiled on July 30, 2020, at 12:40 pm, UTC.+ Compiled on August 3, 2020, at 12:12 pm, UTC. Usage: elynx COMMAND Validate and redo past ELynx analyses
slynx.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 826b98c0606c81f3576251bedb9ae6aa528a2afeb1a782a01a6f17578ce698af+-- hash: 286f8b4edbcbe74a920bfa98bfeb769b685b7591ba79d26c1a024faa2889e888 name: slynx-version: 0.3.0+version: 0.3.1 synopsis: Handle molecular sequences description: Examine, modify, and simulate molecular sequences in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>. category: Bioinformatics@@ -54,6 +54,7 @@ ghc-options: -Wall -fllvm build-depends: async+ , attoparsec , base >=4.7 && <5 , bytestring , containers@@ -62,11 +63,9 @@ , elynx-tools , elynx-tree , hmatrix- , megaparsec , monad-logger , mwc-random , optparse-applicative- , scientific , text , transformers , vector@@ -81,7 +80,5 @@ ghc-options: -Wall -fllvm -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5- , elynx-seq- , elynx-tools , slynx default-language: Haskell2010
src/SLynx/Examine/Examine.hs view
@@ -20,7 +20,7 @@ import Control.Monad.Logger import Control.Monad.Trans.Reader (ask)-import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.Set as S import qualified ELynx.Data.Alphabet.Alphabet as A import qualified ELynx.Data.Alphabet.Character as C@@ -31,53 +31,53 @@ import SLynx.Tools import Text.Printf -pRow :: String -> String -> L.ByteString+pRow :: String -> String -> BL.ByteString pRow name val = alignLeft 50 n <> alignRight 10 v where- n = L.pack name- v = L.pack val+ n = BL.pack name+ v = BL.pack val -examineAlignment :: Bool -> M.Alignment -> L.ByteString+examineAlignment :: Bool -> M.Alignment -> BL.ByteString examineAlignment perSiteFlag a =- L.unlines- [ L.pack+ BL.unlines+ [ BL.pack "Sequences have equal length (multi sequence alignment, or single sequence).", pRow "Total number of columns in alignment:" $ show (M.length a), pRow "Number of columns without gaps:" $ show (M.length aNoGaps), pRow "Number of columns with standard characters only:" $ show (M.length aOnlyStd),- L.empty,+ BL.empty, pRow "Total number of characters:" $ show nTot, pRow "Standard (i.e., not extended IUPAC) characters:" $ show (nTot - nIUPAC - nGaps - nUnknowns), pRow "Extended IUPAC characters:" $ show nIUPAC, pRow "Gaps:" $ show nGaps, pRow "Unknowns:" $ show nUnknowns,- L.empty,+ BL.empty, pRow "Percentage of standard characters:" $ printf "%2.2f" (100.0 - percentIUPAC - percentGaps - percentUnknowns), pRow "Percentage of extended IUPAC characters:" $ printf "%2.2f" percentIUPAC, pRow "Percentage of gaps:" $ printf "%2.2f" percentGaps, pRow "Percentage of unknowns:" $ printf "%2.2f" percentUnknowns,- L.empty,- L.pack "Distribution of characters:",+ BL.empty,+ BL.pack "Distribution of characters:", -- Holy crap.- L.pack $+ BL.pack $ concatMap ((: " ") . C.toChar) $ S.toList $ A.std $ A.alphabetSpec $ M.alphabet a,- L.pack $ unwords $ map (printf "%.3f") charFreqs,- L.empty,- L.pack "Mean effective number of states (measured using entropy):",+ BL.pack $ unwords $ map (printf "%.3f") charFreqs,+ BL.empty,+ BL.pack "Mean effective number of states (measured using entropy):", pRow "Across whole alignment:" $ printf "%.3f" kEffMean, pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGaps, pRow "Across columns without extended IUPAC characters:" $ printf "%.3f" kEffMeanOnlyStd,- L.empty,- L.pack "Mean effective number of states (measured using homoplasy):",+ BL.empty,+ BL.pack "Mean effective number of states (measured using homoplasy):", pRow "Across whole alignment:" $ printf "%.3f" kEffMeanHomo, pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGapsHomo, pRow "Across columns without extended IUPAC characters:" $@@ -113,17 +113,17 @@ perSiteBS = if perSiteFlag then- L.unlines- [ L.pack "Effective number of used states per site:",- L.pack . show $ kEffs+ BL.unlines+ [ BL.pack "Effective number of used states per site:",+ BL.pack . show $ kEffs ]- else L.empty+ else BL.empty -examine :: Bool -> [Seq.Sequence] -> L.ByteString+examine :: Bool -> [Seq.Sequence] -> BL.ByteString examine perSiteFlag ss = Seq.summarizeSequences ss <> case M.fromSequences ss of- Left _ -> L.empty- Right a -> L.pack "\n" <> examineAlignment perSiteFlag a+ Left _ -> BL.empty+ Right a -> BL.pack "\n" <> examineAlignment perSiteFlag a -- | Examine sequences. examineCmd :: ELynx ExamineArguments ()
src/SLynx/Filter/Filter.hs view
@@ -21,7 +21,7 @@ import Control.Monad (when) import Control.Monad.Logger import Control.Monad.Trans.Reader (ask)-import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.ByteString.Lazy.Char8 as BL import Data.Maybe (fromMaybe) import qualified Data.Text as T import qualified ELynx.Data.Sequence.Alignment as M@@ -31,7 +31,7 @@ import SLynx.Filter.Options import SLynx.Tools -filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> L.ByteString+filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> BL.ByteString filterRows ml ms std ss = sequencesToFasta $ compose filters ss where filters' =@@ -62,7 +62,7 @@ let result = filterRows long short std ss out "filtered sequences" result ".fasta" -filterCols :: Maybe Double -> [S.Sequence] -> L.ByteString+filterCols :: Maybe Double -> [S.Sequence] -> BL.ByteString filterCols ms ss = sequencesToFasta . M.toSequences $ compose filters a where a = either error id (M.fromSequences ss)
src/SLynx/Simulate/PhyloModel.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- | -- Module : SLynx.Simulate.PhyloModel -- Description : Parse and interpret the model string@@ -14,14 +16,13 @@ ) where +import Control.Applicative import Control.Monad (when)-import qualified Data.ByteString.Lazy.Char8 as L+import Data.Attoparsec.ByteString.Char8+import qualified Data.ByteString.Char8 as BS import Data.Either (rights) import Data.List.NonEmpty (fromList) import Data.Maybe-import Data.Scientific hiding (scientific)-import Data.Void-import Data.Word (Word8) import ELynx.Data.MarkovProcess.AminoAcid import ELynx.Data.MarkovProcess.CXXModels import qualified ELynx.Data.MarkovProcess.MixtureModel as M@@ -38,15 +39,7 @@ size, vector, )-import Text.Megaparsec-import Text.Megaparsec.Byte-import Text.Megaparsec.Byte.Lexer -type Parser = Parsec Void L.ByteString--bs :: String -> L.ByteString-bs = L.pack- nNuc :: Int -- nNuc = length (alphabet :: [Nucleotide]) nNuc = 4@@ -56,53 +49,42 @@ nAA = 20 -- Model parameters between square brackets.-paramsStart :: Word8-paramsStart = c2w '['+paramsStart :: Char+paramsStart = '[' -paramsEnd :: Word8-paramsEnd = c2w ']'+paramsEnd :: Char+paramsEnd = ']' -- Stationary distribution between curly brackets.-sdStart :: Word8-sdStart = c2w '{'+sdStart :: Char+sdStart = '{' -sdEnd :: Word8-sdEnd = c2w '}'+sdEnd :: Char+sdEnd = '}' -- Mixture model components between round brackets.-mmStart :: Word8-mmStart = c2w '('+mmStart :: Char+mmStart = '(' -mmEnd :: Word8-mmEnd = c2w ')'+mmEnd :: Char+mmEnd = ')' -separator :: Word8-separator = c2w ','+separator :: Char+separator = ',' name :: Parser String name =- L.unpack- <$> takeWhile1P- (Just "Model name")- ( `notElem` [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator]- )+ BS.unpack+ <$> takeWhile1 (notInClass [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator]) params :: Parser [Double]-params =- map toRealFloat- <$> between- (char paramsStart)- (char paramsEnd)- (sepBy1 scientific (char separator))+params = char paramsStart *> double `sepBy1` char separator <* char paramsEnd stationaryDistribution :: Parser StationaryDistribution stationaryDistribution = do- f <-- vector . map toRealFloat- <$> between- (char sdStart)- (char sdEnd)- (sepBy1 scientific (char separator))+ _ <- char sdStart+ f <- vector <$> double `sepBy1` char separator+ _ <- char sdEnd if nearlyEq (norm_1 f) 1.0 then return f else@@ -172,7 +154,7 @@ edmModel :: [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel edmModel cs mws = do- _ <- chunk (bs "EDM")+ _ <- string "EDM" _ <- char mmStart n <- name mps <- optional params@@ -192,13 +174,13 @@ cxxModel :: Maybe [M.Weight] -> Parser M.MixtureModel cxxModel mws = do- _ <- char (c2w 'C')+ _ <- char 'C' n <- decimal :: Parser Int return $ cxx n mws standardMixtureModel :: [M.Weight] -> Parser M.MixtureModel standardMixtureModel ws = do- _ <- chunk (bs "MIXTURE")+ _ <- string "MIXTURE" _ <- char mmStart sms <- parseSubstitutionModel `sepBy1` char separator _ <- char mmEnd@@ -233,7 +215,6 @@ Right $ P.SubstitutionModel $ parseStringWith- "Substitution model string" parseSubstitutionModel s getPhyloModel (Just _) Nothing (Just _) _ =@@ -245,6 +226,5 @@ Right $ P.MixtureModel $ parseStringWith- "Mixture model string" (mixtureModel mcs mws) m
src/SLynx/Simulate/Simulate.hs view
@@ -28,8 +28,8 @@ import Control.Monad.Logger import Control.Monad.Trans.Class import Control.Monad.Trans.Reader (ask)-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Lazy.Char8 as LC+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy.Char8 as BL import Data.List.NonEmpty (toList) import Data.Maybe import qualified Data.Set as Set@@ -48,9 +48,7 @@ ) import ELynx.Data.Tree import ELynx.Export.Sequence.Fasta-import ELynx.Import.MarkovProcess.EDMModelPhylobayes hiding- ( Parser,- )+import ELynx.Import.MarkovProcess.EDMModelPhylobayes import ELynx.Import.MarkovProcess.SiteprofilesPhylobayes import ELynx.Import.Tree.Newick import ELynx.Simulate.MarkovProcessAlongTree@@ -62,6 +60,7 @@ import SLynx.Simulate.Options import SLynx.Simulate.PhyloModel import System.Random.MWC+import Text.Printf -- Simulate a 'Alignment' for a given phylogenetic model, -- phylogenetic tree, and alignment length.@@ -110,9 +109,9 @@ return $ either error id $ A.fromSequences sequences -- Summarize EDM components; line to be printed to screen or log.-summarizeEDMComponents :: [EDMComponent] -> L.ByteString+summarizeEDMComponents :: [EDMComponent] -> BL.ByteString summarizeEDMComponents cs =- LC.pack $+ BL.pack $ "Empiricial distribution mixture model with " ++ show (length cs) ++ " components."@@ -128,8 +127,88 @@ $(logInfo) "No output file provided; omit writing machine-readable phylogenetic model." Just _ ->- out "model definition (machine readable)" (bShow m <> "\n") ".model.gz"+ out "model definition (machine readable)" (BL.pack (show m) <> "\n") ".model.gz" +pretty :: BranchLength -> String+pretty = printf "%.5f"++prettyRow :: String -> String -> BL.ByteString+prettyRow name val = alignLeft 33 n <> alignRight 8 v+ where+ n = BL.pack name+ v = BL.pack val++-- | Examine branches of a tree.+summarizeBranchLengths :: Measurable e => Tree e a -> BL.ByteString+summarizeBranchLengths t =+ BL.intercalate+ "\n"+ [ prettyRow "Origin height: " $ pretty h,+ prettyRow "Average distance origin to leaves: " $ pretty h',+ prettyRow "Total branch length: " $ pretty b+ ]+ where+ n = length $ leaves t+ h = height t+ h' = sum (distancesOriginLeaves t) / fromIntegral n+ b = totalBranchLength t++-- Summarize a substitution model; lines to be printed to screen or log.+summarizeSM :: SM.SubstitutionModel -> [BL.ByteString]+summarizeSM sm =+ map BL.pack $+ (show (SM.alphabet sm) ++ " substitution model: " ++ SM.name sm ++ ".") :+ ["Parameters: " ++ show (SM.params sm) ++ "." | not (null (SM.params sm))]+ ++ case SM.alphabet sm of+ DNA ->+ [ "Stationary distribution: "+ ++ dispv precision (SM.stationaryDistribution sm)+ ++ ".",+ "Exchangeability matrix:\n"+ ++ dispmi 2 precision (SM.exchangeabilityMatrix sm)+ ++ ".",+ "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."+ ]+ Protein ->+ [ "Stationary distribution: "+ ++ dispv precision (SM.stationaryDistribution sm)+ ++ ".",+ "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."+ ]+ _ ->+ error+ "Extended character sets are not supported with substitution models."++-- Summarize a mixture model component; lines to be printed to screen or log.+summarizeMMComponent :: M.Component -> [BL.ByteString]+summarizeMMComponent c =+ BL.pack "Weight: "+ <> (BB.toLazyByteString . BB.doubleDec $ M.weight c) :+ summarizeSM (M.substModel c)++-- Summarize a mixture model; lines to be printed to screen or log.+summarizeMM :: M.MixtureModel -> [BL.ByteString]+summarizeMM m =+ [ BL.pack $ "Mixture model: " ++ M.name m ++ ".",+ BL.pack $ "Number of components: " ++ show n ++ "."+ ]+ ++ detail+ where+ n = length $ M.components m+ detail =+ if n <= 100+ then+ concat+ [ BL.pack ("Component " ++ show i ++ ":") : summarizeMMComponent c+ | (i, c) <- zip [1 :: Int ..] (toList $ M.components m)+ ]+ else []++-- Summarize a phylogenetic model; lines to be printed to screen or log.+summarizePM :: P.PhyloModel -> [BL.ByteString]+summarizePM (P.MixtureModel mm) = summarizeMM mm+summarizePM (P.SubstitutionModel sm) = summarizeSM sm+ -- | Simulate sequences. simulateCmd :: ELynx SimulateArguments () simulateCmd = do@@ -139,6 +218,7 @@ $(logInfo) $ T.pack $ "Read tree from file '" ++ treeFile ++ "'." tree <- liftIO $ parseFileWith (newick Standard) treeFile let t' = either error id $ phyloToLengthTree tree+ $(logInfo) $ T.pack $ "Number of leaves: " ++ show (length $ leaves t') $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ summarizeBranchLengths t' let edmFile = argsEDMFile l let sProfileFiles = argsSiteprofilesFiles l@@ -185,21 +265,21 @@ $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $- LC.unlines $- P.summarize+ BL.unlines $+ summarizePM phyloModel' return phyloModel' Just (n, alpha) -> do $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $- LC.intercalate "\n" $- P.summarize phyloModel'+ BL.intercalate "\n" $+ summarizePM phyloModel' $(logInfo) "" $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $- LC.intercalate "\n" $+ BL.intercalate "\n" $ summarizeGammaRateHeterogeneity n alpha return $ expand n alpha phyloModel' -- -- XXX: Do not report possibly huge empirical distribution mixture models
src/SLynx/Tools.hs view
@@ -26,9 +26,7 @@ import qualified Data.Text as T import ELynx.Data.Alphabet.Alphabet import ELynx.Data.Sequence.Sequence-import ELynx.Import.Sequence.Fasta hiding- ( Parser,- )+import ELynx.Import.Sequence.Fasta import ELynx.Tools import Options.Applicative