convert-annotation 0.2.0.1 → 0.4.0.0
raw patch · 6 files changed
+247/−26 lines, 6 filesdep +inline-r
Dependencies added: inline-r
Files
- README.org +33/−0
- app/Main.hs +69/−22
- convert-annotation.cabal +7/−3
- src/MSigDBRDataConvert.hs +64/−0
- src/RGeneConvert.hs +57/−0
- src/Types.hs +17/−1
+ README.org view
@@ -0,0 +1,33 @@+* convert-annotation++Very early stages. Mix between =HTTP= and =wreq= libraries, need to fully+convert to =wreq= in the future.++Each mode, =info= or =annotation=, has its own help.++Main usage to convert, say, some unknown annotation to Ensembl annotation in a+=csv=:++#+BEGIN_SRC sh+cat input.csv | convert-annotation annotation --database "Ensembl" --column "gene"+#+END_SRC++#+BEGIN_SRC sh :exports results :results value code+convert-annotation -h+#+END_SRC++#+RESULTS:+#+BEGIN_SRC sh+convert-annotation, Gregory W. Schwartz. Converts an unknown annotation to some+other annotation.++Usage: convert-annotation (info | annotation)++Available options:+ -h,--help Show this help text++Available commands:+ info + annotation +#+END_SRC+
app/Main.hs view
@@ -4,6 +4,7 @@ Converts an unknown annotation to Ensembl's annotation, or other annotation. -} +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}@@ -17,6 +18,7 @@ import Data.List import Control.Monad import GHC.Generics+import Data.Semigroup -- Cabal import qualified Data.Text as T@@ -28,30 +30,42 @@ import Pipes.Csv import Options.Generic +import qualified Foreign.R as R+import Foreign.R (SEXP, SEXPTYPE)+import Language.R.Instance as R+import Language.R.QQ+import Language.R.Literal as R+ -- Local import Types import EnsemblConvert import HUGOConvert import UniProtConvert+import RGeneConvert+import MSigDBRDataConvert -- | Command line arguments data Options = Info { delimiter :: Maybe String <?> "([,] | CHAR) The delimiter of the CSV file." , database :: String- <?> "(Ensembl | HUGO TYPE | UniProt) Which database to convert with. TYPE is the type of the original gene symbol. The compatible list is in http://www.genenames.org/help/rest-web-service-help. HUGO is only supported for Annotation."- , descriptionField :: String+ <?> "(Ensembl | HUGO TYPE | UniProt | RGene (TYPE, TYPE) | MSigDBRdata (FILE, RDATA, TYPE)) Which database to convert with. TYPE is the type of the original gene symbol. The compatible list for TYPE with HUGO is in http://www.genenames.org/help/rest-web-service-help. HUGO is only supported for Annotation. RGene (Annotation only) takes in a type of (FROM, TO) for the gene symbol origin and destination. MSigDBRdata (Info only) takes an rdata file (tested with http://bioinf.wehi.edu.au/software/MSigDB/), the name of the rdata object containing the named list, and the TYPE of symbol (compatable list at http://bioconductor.org/packages/release/bioc/manuals/biomaRt/man/biomaRt.pdf in getGene) which returns pathways separated by \"/\"."+ , descriptionField :: Maybe String <?> "(Other TEXT | Description | Synonyms) The info to retrieve about the identifier. Description provides information about the identifier while synonyms provides alternate identifiers for the same entity. Returns a list of information (delimited by '/') for each match to Ensembl's cross references. For UniProt, enter a valid column (http://www.uniprot.org/help/programmatic_access)." , column :: T.Text <?> "(COLUMN) The column containing the identifier. Must be a valid id for info."+ , newColumn :: Maybe T.Text+ <?> "([Nothing] | COLUMN) The new column to put the results into. If unspecified, replaces the original column." , remove :: Bool <?> "Whether to remove empty results (no matches to the database)." } | Annotation { delimiter :: Maybe String <?> "([,] | CHAR) The delimiter of the CSV file." , database :: String- <?> "(Ensembl | HUGO TYPE | UniProt) Which database to convert with. TYPE is the type of the original gene symbol. The compatible list is in http://www.genenames.org/help/rest-web-service-help. HUGO is only supported for Annotation."+ <?> "(Ensembl | HUGO TYPE | UniProt | RGene (TYPE, TYPE) | MSigDBRdata (FILE, RDATA, TYPE)) Which database to convert with. TYPE is the type of the original gene symbol. The compatible list for TYPE with HUGO is in http://www.genenames.org/help/rest-web-service-help. HUGO is only supported for Annotation. RGene (Annotation only) takes in a type of (FROM, TO) for the gene symbol origin and destination. MSigDBRdata (Info only) takes an rdata file (tested with http://bioinf.wehi.edu.au/software/MSigDB/), the name of the rdata object containing the named list, and the TYPE of symbol (compatable list at http://bioconductor.org/packages/release/bioc/manuals/biomaRt/man/biomaRt.pdf in getGene) which returns pathways separated by \"/\"." , column :: T.Text <?> "(COLUMN) The column containing the identifier. Must be a valid id for info."+ , newColumn :: Maybe T.Text+ <?> "([Nothing] | COLUMN) The new column to put the results into. If unspecified, replaces the original column." , remove :: Bool <?> "Whether to remove empty results (no matches to the database)." }@@ -61,20 +75,25 @@ -- | Map the header column to the rest of the file for converting that -- column.-pipeConvert :: Options -> Pipe [T.Text] [T.Text] IO ()-pipeConvert opts = do+pipeConvert :: Options+ -> Maybe (RMart s)+ -> Maybe (RData s)+ -> Pipe [T.Text] [T.Text] IO ()+pipeConvert opts rMart rData = do h <- await - let c = col opts h+ let c = col opts h+ newCol = unHelpful . newColumn $ opts - yield h+ yield . maybe h (\x -> h <> [x]) $ newCol forever $ do x <- await- newX <- lift . convert opts . (!! c) $ x- unless- ((unHelpful . remove $ opts) && T.null newX)- (yield . L.set (L.ix c) newX $ x)+ newX <- lift . convert opts rMart rData . (!! c) $ x+ unless ((unHelpful . remove $ opts) && T.null newX)+ . maybe (yield . L.set (L.ix c) newX $ x)+ (const (yield (x <> [newX])))+ $ newCol return () return ()@@ -85,23 +104,41 @@ fromMaybe (error "Column not found.") . elemIndex (unHelpful $ column opts) -- | The conversion process.-convert :: Options -> T.Text -> IO T.Text-convert opts@(Info { descriptionField = df }) =+convert :: Options -> Maybe (RMart s) -> Maybe (RData s) -> T.Text -> IO T.Text+convert opts@(Info { descriptionField = df }) rMart rData = fmap (fromMaybe "" . fmap unDesc) . whichDesc (read . unHelpful . database $ opts) . UnknownAnn where- whichDesc Ensembl = toEnsemblDesc (read . unHelpful $ df)+ whichDesc Ensembl = toEnsemblDesc ( read+ . fromMaybe (error "Needs description field.")+ . unHelpful+ $ df+ ) whichDesc (HUGO _) = error "HUGO description not yet supported."- whichDesc UniProt = toUniProtDesc (read . unHelpful $ df)-convert opts@(Annotation {}) =+ whichDesc UniProt = toUniProtDesc ( read+ . fromMaybe (error "Needs description field.")+ . unHelpful+ $ df+ )+ whichDesc (RGene _) = error "RGene description not yet supported."+ whichDesc (MSigDBRData queryType) =+ toMSigDBPathways+ (fromJust rData)+ (fromJust rMart)+ (MSigDBType queryType)+convert opts@(Annotation {}) rMart rData = fmap (fromMaybe "" . fmap unAnn) . whichAnn (read . unHelpful . database $ opts) . UnknownAnn where- whichAnn Ensembl = toEnsemblAnn- whichAnn (HUGO queryType) = toHUGOAnn . HUGOType $ queryType- whichAnn UniProt = toUniProtAnn+ whichAnn Ensembl = toEnsemblAnn+ whichAnn (HUGO queryType) = toHUGOAnn . HUGOType $ queryType+ whichAnn UniProt = toUniProtAnn+ whichAnn (RGene queryType) =+ toRGeneAnn (fromJust rMart) (RType queryType)+ whichAnn (MSigDBRData _) =+ error "MSigDBRData annotation not yet supported." main :: IO () main = do@@ -118,10 +155,20 @@ csvOpts = CSV.defaultDecodeOptions { CSV.decDelimiter = fromIntegral (ord delim) } - runEffect $ decodeWith csvOpts NoHeader PB.stdin+ R.withEmbeddedR R.defaultConfig $ R.runRegion $ do+ rMart <- case read . unHelpful . database $ opts of+ (RGene _) -> fmap Just getRMart+ (MSigDBRData _) -> fmap Just getRMart+ _ -> return Nothing+ rData <- case read . unHelpful . database $ opts of+ (MSigDBRData (!file, !object, _)) ->+ fmap Just . getRData (File file) $ object+ _ -> return Nothing++ liftIO $ runEffect $ decodeWith csvOpts NoHeader PB.stdin >-> P.concat- >-> (pipeConvert opts)+ >-> (pipeConvert opts rMart rData) >-> encode >-> PB.stdout - return ()+ return ()
convert-annotation.cabal view
@@ -1,7 +1,7 @@ name: convert-annotation-version: 0.2.0.1+version: 0.4.0.0 synopsis: Convert the annotation of a gene to another in a delimited file using a variety of different databases.-description: Please see README.md+description: Please see README.org homepage: http://github.com/GregorySchwartz/convert-annotation#readme license: GPL-3 license-file: LICENSE@@ -10,7 +10,7 @@ copyright: Copyright: (c) 2016 Gregory W. Schwartz category: Bioinformatics build-type: Simple--- extra-source-files:+extra-source-files: README.org cabal-version: >=1.10 library@@ -19,6 +19,8 @@ , EnsemblConvert , HUGOConvert , UniProtConvert+ , RGeneConvert+ , MSigDBRDataConvert build-depends: base >= 4.7 && < 5 , containers , bytestring@@ -29,6 +31,7 @@ , wreq , HTTP , safe+ , inline-r ghc-options: -O2 default-language: Haskell2010@@ -47,6 +50,7 @@ , pipes-bytestring , pipes-csv , lens+ , inline-r default-language: Haskell2010 source-repository head
+ src/MSigDBRDataConvert.hs view
@@ -0,0 +1,64 @@+{- MSigDBRDataConvert+Gregory W. Schwartz++Collections the functions pertaining to converting certain annotations into+pathways using the MSigDB rdata files (tested with+http://bioinf.wehi.edu.au/software/MSigDB/).+-}++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module MSigDBRDataConvert+ ( getRData+ , toMSigDBPathways+ ) where++-- Standard++-- Cabal+import qualified Data.Text as T++import qualified Foreign.R as R+import Foreign.R (SEXP, SEXPTYPE)+import Language.R.Instance as R+import Language.R.QQ+import Language.R.Literal as R+import H.Prelude++-- Local+import Types+import RGeneConvert+ +-- | Get the RData object.+getRData :: File -> String -> R s (RData s)+getRData (File file) object = fmap RData+ $ [r| load(file_hs)+ res = get(object_hs)+ res+ |]++-- | Get the R mapping of gene to gene.+toMSigDBPathways+ :: RData s+ -> RMart s+ -> MSigDBType+ -> UnknownAnn+ -> IO (Maybe Desc)+toMSigDBPathways _ _ _ (UnknownAnn "") = return Nothing+toMSigDBPathways rData rMart (MSigDBType (_, _, !from)) query =+ (fmap . fmap) Desc $ R.runRegion $ do+ entrez <- io . toRGeneAnn rMart (RType (from, "entrezgene")) $ query+ let object = unRData rData++ case entrez of+ Nothing -> return Nothing+ (Just (Ann gText)) -> do+ let g = T.unpack gText+ res <- [r| pathNames = names(object_hs[unlist(lapply(object_hs, function(x) (g_hs %in% unlist(x))))]) |]+ let pathNames = R.fromSomeSEXP res :: [String]+ if null . drop 1 $ pathNames+ then return Nothing+ else+ return . Just . T.intercalate "/" . fmap T.pack $ pathNames
+ src/RGeneConvert.hs view
@@ -0,0 +1,57 @@+{- RGeneConvert+Gregory W. Schwartz++Collections the functions pertaining to converting certain annotations into+other annotations using biomart from R+(http://bioconductor.org/packages/release/bioc/html/biomaRt.html).+-}++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module RGeneConvert+ ( getRMart+ , toRGeneAnn+ ) where++-- Standard++-- Cabal+import qualified Data.Text as T++import qualified Foreign.R as R+import Foreign.R (SEXP, SEXPTYPE)+import Language.R.Instance as R+import Language.R.QQ+import Language.R.Literal as R++-- Local+import Types++-- | Get the R mapping of gene to gene.+getRMart :: R s (RMart s)+getRMart = fmap RMart+ $ [r| library(biomaRt)+ mart = useMart("ensembl", dataset="hsapiens_gene_ensembl")+ |]++-- | Get the R mapping of gene to gene.+toRGeneAnn :: RMart s -> RType -> UnknownAnn -> IO (Maybe Ann)+toRGeneAnn _ _ (UnknownAnn "") = return Nothing+toRGeneAnn rMart (RType (!from, !to)) (UnknownAnn textQuery) =+ (fmap . fmap) Ann $ R.runRegion $ do+ let query = T.unpack textQuery+ mart = unRMart rMart+ res <- [r| map = getBM( attributes = c(from_hs, to_hs)+ , filters = from_hs+ , values = c(query_hs)+ , mart = mart_hs+ , uniqueRows=FALSE+ )+ as.character(map[1,2])+ |]++ let naCheck "NA" = Nothing+ naCheck x = Just x+ return . fmap T.pack . naCheck $ (R.fromSomeSEXP res :: String)
src/Types.hs view
@@ -15,20 +15,36 @@ import qualified Data.Text as T import Data.Aeson +import qualified Foreign.R as R+import Foreign.R (SEXP, SEXPTYPE)+import Language.R.Instance as R+import Language.R.QQ+ -- Local -- Algebraic-data Database = Ensembl | HUGO T.Text | UniProt deriving (Read, Show)+data Database+ = Ensembl+ | HUGO T.Text+ | UniProt+ | RGene (String, String)+ | MSigDBRData (String, String, String)+ deriving (Read,Show) data DescFields = UniProtOther T.Text | Synonyms | Description deriving (Read,Show) -- Basic+newtype File = File String newtype UnknownAnn = UnknownAnn { unUnknownAnn :: T.Text } newtype Ann = Ann { unAnn :: T.Text } newtype Desc = Desc { unDesc :: T.Text } newtype HUGOType = HUGOType { unHUGOType :: T.Text }+newtype RType = RType { unRType :: (String, String) }+newtype MSigDBType = MSigDBType { unMSigDBType :: (String, String, String) }+newtype RMart s = RMart { unRMart :: (R.SomeSEXP s) }+newtype RData s = RData { unRData :: (R.SomeSEXP s) } -- Advanced