packages feed

slynx-0.7.1.0: src/SLynx/Filter/Filter.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      :  Analyze.Analyze
-- Description :  Parse sequence file formats and analyze them
-- Copyright   :  2021 Dominik Schrempf
-- License     :  GPL-3.0-or-later
--
-- Maintainer  :  dominik.schrempf@gmail.com
-- Stability   :  unstable
-- Portability :  portable
--
-- Creation date: Fri Oct  5 08:41:05 2018.
module SLynx.Filter.Filter
  ( filterRowsCmd,
    filterColsCmd,
  )
where

import Control.Monad (when)
import Control.Monad.Trans.Reader
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Maybe (fromMaybe)
import qualified ELynx.Sequence.Alignment as M
import ELynx.Sequence.Export.Fasta
import qualified ELynx.Sequence.Sequence as S
import ELynx.Tools.ELynx
import ELynx.Tools.Environment
import ELynx.Tools.Logger
import SLynx.Filter.Options
import SLynx.Tools

-- Chain a list of functions together. See https://wiki.haskell.org/Compose.
compose :: [a -> a] -> a -> a
compose = foldl (flip (.)) id

filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> BL.ByteString
filterRows ml ms std ss = sequencesToFasta $ compose filters ss
  where
    filters' =
      map (fromMaybe id) [S.filterLongerThan <$> ml, S.filterShorterThan <$> ms]
    filters = if std then S.filterStandard : filters' else filters'

-- | Filter sequences.
filterRowsCmd :: ELynx FilterRowsArguments ()
filterRowsCmd = do
  (FilterRowsArguments al inFile long short std) <- localArguments <$> ask
  maybe
    (return ())
    ( \val ->
        logInfoS $ "  Keep sequences longer than " <> show val <> "."
    )
    long
  maybe
    (return ())
    ( \val ->
        logInfoS $ "  Keep sequences shorter than " <> show val <> "."
    )
    short
  when std $
    logInfoS
      "  Keep sequences containing at least one standard (i.e., non-IUPAC) character."
  ss <- readSeqs al inFile
  let result = filterRows long short std ss
  out "filtered sequences" result ".fasta"

filterCols :: Maybe Double -> [S.Sequence] -> BL.ByteString
filterCols ms ss = sequencesToFasta . M.toSequences $ compose filters a
  where
    a = either error id (M.fromSequences ss)
    filters = map (fromMaybe id) [M.filterColsStd <$> ms]

-- | Filter columns.
filterColsCmd :: ELynx FilterColsArguments ()
filterColsCmd = do
  (FilterColsArguments al inFile standard) <- localArguments <$> ask
  case standard of
    Nothing -> return ()
    Just p ->
      logInfoS $
        "  Keep columns with a proportion of standard (non-IUPAC) characters larger than "
          ++ show p
          ++ "."
  ss <- readSeqs al inFile
  let result = filterCols standard ss
  out "filtered sequences" result ".fasta"