tlynx-0.6.1.0: src/TLynx/Examine/Examine.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
-- |
-- Description : Analyze trees
-- Copyright : (c) Dominik Schrempf 2021
-- License : GPL-3.0-or-later
--
-- Maintainer : dominik.schrempf@gmail.com
-- Stability : unstable
-- Portability : portable
--
-- Creation date: Fri May 24 13:47:56 2019.
module TLynx.Examine.Examine
( examine,
)
where
import Control.Monad (unless)
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader (ask)
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Containers.ListUtils (nubOrd)
import Data.List ((\\))
import ELynx.Tools.ByteString
import ELynx.Tools.ELynx
import ELynx.Tools.Environment
import ELynx.Tools.Logger
import ELynx.Tree
import System.IO
( Handle,
hPutStrLn,
)
import TLynx.Examine.Options
import TLynx.Parsers
import Text.Printf
pretty :: Length -> String
pretty = printf "%.5f" . fromLength
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.
summarizeLengths :: HasLength e => Tree e a -> BL.ByteString
summarizeLengths t =
BL.intercalate
"\n"
[ prettyRow "Origin height: " $ pretty h,
prettyRow "Mean distance origin 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
readTrees :: FilePath -> ELynx ExamineArguments (Forest Phylo Name)
readTrees fp = do
logInfoS $ "Read tree(s) from file " <> fp <> "."
nf <- argsNewickFormat . localArguments <$> ask
liftIO $ parseTrees nf fp
examineTree :: HasName a => Handle -> Tree Phylo a -> IO ()
examineTree h t = do
hPutStrLn h $ "Number of leaves: " ++ show (length lvs)
let l = toLengthTree t
case l of
Left _ -> hPutStrLn h "Branch lengths not available."
Right t' -> BL.hPutStrLn h $ summarizeLengths t'
unless (null dups) $ do
hPutStrLn h ""
hPutStrLn h ("Duplicate leaves: " ++ show dups)
BL.hPutStrLn h $ "Leave names: " <> BL.intercalate " " lvs
where
lvs = map (fromName . getName) $ leaves t
dups = lvs \\ nubOrd lvs
-- | Examine phylogenetic trees.
examine :: ELynx ExamineArguments ()
examine = do
l <- localArguments <$> ask
let inFn = argsInFile l
trs <- readTrees inFn
outH <- outHandle "results" ".out"
liftIO $ mapM_ (examineTree outH) trs