flat_gff_formatter.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:15k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: flat_gff_formatter.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:43:14  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: flat_gff_formatter.cpp,v 1000.3 2004/06/01 19:43:14 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Author:  Aaron Ucko, Wratko Hlavina
  35. *
  36. * File Description:
  37. *   Flat formatter for Generic Feature Format (incl. Gene Transfer Format)
  38. *
  39. * ===========================================================================
  40. */
  41. #include <ncbi_pch.hpp>
  42. #include <objtools/flat/flat_gff_formatter.hpp>
  43. #include <objtools/flat/flat_head.hpp>
  44. #include <objtools/flat/flat_items.hpp>
  45. #include <objects/general/Dbtag.hpp>
  46. #include <objects/general/Int_fuzz.hpp>
  47. #include <objects/seqfeat/Cdregion.hpp>
  48. #include <objects/seqfeat/Gb_qual.hpp>
  49. #include <objects/seqfeat/Genetic_code_table.hpp>
  50. #include <objmgr/seq_vector.hpp>
  51. #include <objmgr/util/sequence.hpp>
  52. #include <algorithm>
  53. BEGIN_NCBI_SCOPE
  54. BEGIN_SCOPE(objects)
  55. CFlatGFFFormatter::CFlatGFFFormatter(IFlatTextOStream& stream, CScope& scope,
  56.                                      EMode mode, TGFFFlags gff_flags,
  57.                                      EStyle style, TFlags flags)
  58.     : IFlatFormatter(scope, mode, style, flags),
  59.       m_GFFFlags(gff_flags), m_Stream(&stream)
  60. {
  61.     list<string> header;
  62.     header.push_back("##gff-version 2");
  63.     header.push_back("##source-version NCBI C++ formatter 0.1");
  64.     header.push_back("##date " + CurrentTime().AsString("Y-M-D"));
  65.     stream.AddParagraph(header);
  66. }
  67. void CFlatGFFFormatter::FormatHead(const CFlatHead& head)
  68. {
  69.     m_Stream->NewSequence();
  70.     list<string> l;
  71.     switch (m_Context->GetMol()) {
  72.     case CSeq_inst::eMol_dna:  m_SeqType = "DNA";      break;
  73.     case CSeq_inst::eMol_rna:  m_SeqType = "RNA";      break;
  74.     case CSeq_inst::eMol_aa:   m_SeqType = "Protein";  break;
  75.     default:                   m_SeqType.erase();      break;
  76.     }
  77.     if ( !m_SeqType.empty() ) {
  78.         l.push_back("##Type " + m_SeqType + ' '
  79.                     + m_Context->GetAccession());
  80.     }
  81.     m_Date.erase();
  82.     head.GetUpdateDate().GetDate(&m_Date, "%4Y-%{%2M%|??%}-%{%2D%|??%}");
  83.     m_Strandedness = head.GetStrandedness();
  84.     m_EndSequence.erase();
  85.     m_Stream->AddParagraph(l, &head);
  86. }
  87. void CFlatGFFFormatter::FormatFeature(const IFlattishFeature& f)
  88. {
  89.     const CSeq_feat& seqfeat = f.GetFeat();
  90.     string           key(f.GetKey()), oldkey;
  91.     bool             gtf     = false;
  92.     // CSeq_loc         tentative_stop;
  93.     if ((m_GFFFlags & fGTFCompat)  &&  !m_Context->IsProt()
  94.         &&  (key == "CDS"  ||  key == "exon")) {
  95.         gtf = true;
  96.     } else if ((m_GFFFlags & fGTFCompat)
  97.                &&  m_Context->GetMol() == CSeq_inst::eMol_dna
  98.                &&  seqfeat.GetData().IsRna()) {
  99.         oldkey = key;
  100.         key    = "exon";
  101.         gtf    = true;
  102.     } else if ((m_GFFFlags & fGTFOnly) == fGTFOnly) {
  103.         return;
  104.     }
  105.     CFlatFeature& feat = *f.Format();
  106.     list<string>  l;
  107.     list<string>  attr_list;
  108.     if ( !oldkey.empty() ) {
  109.         attr_list.push_back("gbkey "" + oldkey + "";");
  110.     }
  111.     ITERATE (CFlatFeature::TQuals, it, feat.GetQuals()) {
  112.         string name = (*it)->GetName();
  113.         if (name == "codon_start"  ||  name == "translation"
  114.             ||  name == "transcription") {
  115.             continue; // suppressed to reduce verbosity
  116.         } else if (name == "number"  &&  key == "exon") {
  117.             name = "exon_number";
  118.         } else if ((m_GFFFlags & fGTFCompat)  &&  !m_Context->IsProt()
  119.                    &&  name == "gene") {
  120.             string gene_id = x_GetGeneID(feat, (*it)->GetValue());
  121.             attr_list.push_front
  122.                 ("transcript_id "" + gene_id + '.' + m_Date + "";");
  123.             attr_list.push_front("gene_id "" + gene_id + "";");
  124.             continue;
  125.         }
  126.         string value;
  127.         NStr::Replace((*it)->GetValue(), " b", kEmptyStr, value);
  128.         string value2(NStr::PrintableString(value));
  129.         // some parsers may be dumb, so quote further
  130.         value.erase();
  131.         ITERATE (string, c, value2) {
  132.             switch (*c) {
  133.             case ' ':  value += "\x20"; break;
  134.             case '"': value += "x22";   break; // already backslashed
  135.             case '#':  value += "\x23"; break;
  136.             default:   value += *c;
  137.             }
  138.         }
  139.         attr_list.push_back(name + " "" + value + "";");
  140.     }
  141.     string attrs(NStr::Join(attr_list, " "));
  142.     string source = x_GetSourceName(f);
  143.     int frame = -1;
  144.     if (seqfeat.GetData().IsCdregion()  &&  !m_Context->IsProt() ) {
  145.         const CCdregion& cds = seqfeat.GetData().GetCdregion();
  146.         frame = max(cds.GetFrame() - 1, 0);
  147.     }
  148.     x_AddFeature(l, f.GetLoc(), source, key, "." /*score*/, frame, attrs, gtf);
  149.     if (gtf  &&  seqfeat.GetData().IsCdregion()) {
  150.         const CCdregion& cds = seqfeat.GetData().GetCdregion();
  151.         if ( !f.GetLoc().IsPartialLeft() ) {
  152.             CRef<CSeq_loc> tentative_start;
  153.             {{
  154.                 CRef<SRelLoc::TRange> range(new SRelLoc::TRange);
  155.                 SRelLoc::TRanges      ranges;
  156.                 range->SetFrom(frame);
  157.                 range->SetTo(frame + 2);
  158.                 ranges.push_back(range);
  159.                 tentative_start = SRelLoc(f.GetLoc(), ranges).Resolve(m_Scope);
  160.             }}
  161.             string s;
  162.             m_Context->GetHandle().GetSequenceView
  163.                 (*tentative_start, CBioseq_Handle::eViewConstructed)
  164.                 .GetSeqData(0, 3, s);
  165.             const CTrans_table* tt;
  166.             if (cds.IsSetCode()) {
  167.                 tt = &CGen_code_table::GetTransTable(cds.GetCode());
  168.             } else {
  169.                 tt = &CGen_code_table::GetTransTable(1);
  170.             }
  171.             if (s.size() == 3
  172.                 &&  tt->IsAnyStart(tt->SetCodonState(s[0], s[1], s[2]))) {
  173.                 x_AddFeature(l, *tentative_start, source, "start_codon",
  174.                              "." /* score */, 0, attrs, gtf);
  175.             }
  176.         }
  177.         if ( !f.GetLoc().IsPartialRight()  &&  seqfeat.IsSetProduct() ) {
  178.             TSeqPos loc_len = sequence::GetLength(f.GetLoc(), m_Scope);
  179.             TSeqPos prod_len = sequence::GetLength(seqfeat.GetProduct(),
  180.                                                    m_Scope);
  181.             CRef<CSeq_loc> tentative_stop;
  182.             if (loc_len >= frame + 3 * prod_len + 3) {
  183.                 SRelLoc::TRange range;
  184.                 range.SetFrom(frame + 3 * prod_len);
  185.                 range.SetTo  (frame + 3 * prod_len + 2);
  186.                 // needs to be partial for TranslateCdregion to DTRT
  187.                 range.SetFuzz_from().SetLim(CInt_fuzz::eLim_lt);
  188.                 SRelLoc::TRanges ranges;
  189.                 ranges.push_back(CRef<SRelLoc::TRange>(&range));
  190.                 tentative_stop = SRelLoc(f.GetLoc(), ranges).Resolve(m_Scope);
  191.             }
  192.             if (tentative_stop.NotEmpty()  &&  !tentative_stop->IsNull()) {
  193.                 string s;
  194.                 CCdregion_translate::TranslateCdregion
  195.                     (s, m_Context->GetHandle(), *tentative_stop, cds);
  196.                 if (s == "*") {
  197.                     x_AddFeature(l, *tentative_stop, source, "stop_codon",
  198.                                  "." /* score */, 0, attrs, gtf);
  199.                 }
  200.             }
  201.         }
  202.     }
  203.     m_Stream->AddParagraph(l, &f, &seqfeat);
  204. }
  205. void CFlatGFFFormatter::FormatDataHeader(const CFlatDataHeader& dh)
  206. {
  207.     if ( !(m_GFFFlags & fShowSeq) )
  208.         return;
  209.     list<string> l;
  210.     l.push_back("##" + m_SeqType + ' ' + m_Context->GetAccession());
  211.     m_Stream->AddParagraph(l, &dh);
  212.     m_EndSequence = "##end-" + m_SeqType;
  213. }
  214. void CFlatGFFFormatter::FormatData(const CFlatData& data)
  215. {
  216.     if ( !(m_GFFFlags & fShowSeq) )
  217.         return;
  218.     list<string> l;
  219.     CSeqVector v = m_Context->GetHandle().GetSequenceView
  220.         (data.GetLoc(), CBioseq_Handle::eViewConstructed,
  221.          CBioseq_Handle::eCoding_Iupac);
  222.     CSeqVector_CI vi(v);
  223.     while (vi) {
  224.         string s;
  225.         vi.GetSeqData(s, 70);
  226.         l.push_back("##" + s);
  227.     }
  228.     m_Stream->AddParagraph(l, &data, &data.GetLoc());
  229. }
  230. void CFlatGFFFormatter::EndSequence(void)
  231. {
  232.     if ( !m_EndSequence.empty() ) {
  233.         list<string> l;
  234.         l.push_back(m_EndSequence);
  235.         m_Stream->AddParagraph(l);
  236.     }
  237. }
  238. string CFlatGFFFormatter::x_GetGeneID(const CFlatFeature& feat,
  239.                                       const string& gene)
  240. {
  241.     const CSeq_feat& seqfeat = feat.GetFeat();
  242.     string               main_acc;
  243.     if (m_Context->InSegSet()) {
  244.         const CSeq_id& id = *m_Context->GetSegMaster()->GetId().front();
  245.         main_acc = m_Context->GetPreferredSynonym(id).GetSeqIdString(true);
  246.     } else {
  247.         main_acc = m_Context->GetAccession();
  248.     }
  249.     string               gene_id   = main_acc + ':' + gene;
  250.     CConstRef<CSeq_feat> gene_feat = sequence::GetBestOverlappingFeat
  251.         (seqfeat.GetLocation(), CSeqFeatData::e_Gene,
  252.          sequence::eOverlap_Interval, *m_Scope);
  253.     
  254.     TFeatVec&                v  = m_Genes[gene_id];
  255.     TFeatVec::const_iterator it = find(v.begin(), v.end(), gene_feat);
  256.     int                      n;
  257.     if (it == v.end()) {
  258.         n = v.size();
  259.         v.push_back(gene_feat);
  260.     } else {
  261.         n = it - v.begin();
  262.     }
  263.     if (n > 0) {
  264.         gene_id += '.' + NStr::IntToString(n + 1);
  265.     }
  266.     return gene_id;
  267. }
  268. string CFlatGFFFormatter::x_GetSourceName(const IFlattishFeature&)
  269. {
  270.     // XXX - get from annot name (not presently available from IFF)?
  271.     switch (m_Context->GetPrimaryID().Which()) {
  272.     case CSeq_id::e_Local:                           return "Local";
  273.     case CSeq_id::e_Gibbsq: case CSeq_id::e_Gibbmt:
  274.     case CSeq_id::e_Giim:   case CSeq_id::e_Gi:      return "GenInfo";
  275.     case CSeq_id::e_Genbank:                         return "Genbank";
  276.     case CSeq_id::e_Swissprot:                       return "SwissProt";
  277.     case CSeq_id::e_Patent:                          return "Patent";
  278.     case CSeq_id::e_Other:                           return "RefSeq";
  279.     case CSeq_id::e_General:
  280.         return m_Context->GetPrimaryID().GetGeneral().GetDb();
  281.     default:
  282.     {
  283.         string source
  284.             (CSeq_id::SelectionName(m_Context->GetPrimaryID().Which()));
  285.         return NStr::ToUpper(source);
  286.     }
  287.     }
  288. }
  289. void CFlatGFFFormatter::x_AddFeature(list<string>& l, const CSeq_loc& loc,
  290.                                      const string& source, const string& key,
  291.                                      const string& score, int frame,
  292.                                      const string& attrs, bool gtf)
  293. {
  294.     int exon_number = 1;
  295.     for (CSeq_loc_CI it(loc);  it;  ++it) {
  296.         TSeqPos from   = it.GetRange().GetFrom(), to = it.GetRange().GetTo();
  297.         char    strand = '+';
  298.         if (IsReverse(it.GetStrand())) {
  299.             strand = '-';
  300.         } else if (it.GetRange().IsWhole()
  301.                    ||  (m_Strandedness <= CSeq_inst::eStrand_ss
  302.                         &&  m_Context->GetMol() != CSeq_inst::eMol_dna)) {
  303.             strand = '.'; // N/A
  304.         }
  305.         if (it.GetRange().IsWhole()) {
  306.             to = sequence::GetLength(it.GetSeq_id(), m_Scope) - 1;
  307.         }
  308.         string extra_attrs;
  309.         if (gtf  &&  attrs.find("exon_number ") == NPOS) {
  310.             CSeq_loc       loc2;
  311.             CSeq_interval& si = loc2.SetInt();
  312.             si.SetFrom(from);
  313.             si.SetTo(to);
  314.             si.SetStrand(it.GetStrand());
  315.             si.SetId(const_cast<CSeq_id&>(it.GetSeq_id()));
  316.             CConstRef<CSeq_feat> exon = sequence::GetBestOverlappingFeat
  317.                 (loc2, CSeqFeatData::eSubtype_exon,
  318.                  sequence::eOverlap_Contains, *m_Scope);
  319.             if (exon.NotEmpty()  &&  exon->IsSetQual()) {
  320.                 ITERATE (CSeq_feat::TQual, q, exon->GetQual()) {
  321.                     if ( !NStr::CompareNocase((*q)->GetQual(), "number") ) {
  322.                         int n = NStr::StringToNumeric((*q)->GetVal());
  323.                         if (n >= exon_number) {
  324.                             exon_number = n;
  325.                             break;
  326.                         }
  327.                     }
  328.                 }
  329.             }
  330.             extra_attrs = " exon_number "" + NStr::IntToString(exon_number)
  331.                 + "";";
  332.             ++exon_number;
  333.         }
  334.         if ( sequence::IsSameBioseq(it.GetSeq_id(), m_Context->GetPrimaryID(),
  335.                                     m_Scope) ) {
  336.             // conditionalize printing, but update state regardless
  337.             l.push_back(m_Context->GetAccession() + 't'
  338.                         + source + 't'
  339.                         + key + 't'
  340.                         + NStr::UIntToString(from + 1) + 't'
  341.                         + NStr::UIntToString(to + 1) + 't'
  342.                         + score + 't'
  343.                         + strand + 't'
  344.                         + (frame >= 0 ? char(frame + '0') : '.') + "t"
  345.                         + attrs + extra_attrs);
  346.         }
  347.         if (frame >= 0) {
  348.             frame = (frame + to - from + 1) % 3;
  349.         }
  350.     }
  351. }
  352. END_SCOPE(objects)
  353. END_NCBI_SCOPE
  354. /*
  355. * ===========================================================================
  356. *
  357. * $Log: flat_gff_formatter.cpp,v $
  358. * Revision 1000.3  2004/06/01 19:43:14  gouriano
  359. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  360. *
  361. * Revision 1.6  2004/05/21 21:42:53  gorelenk
  362. * Added PCH ncbi_pch.hpp
  363. *
  364. * Revision 1.5  2003/12/03 20:53:53  ucko
  365. * Also quote #s in values to avoid trouble with naive comment recognizers.
  366. *
  367. * Revision 1.4  2003/11/04 20:00:28  ucko
  368. * Edit " b" sequences (used as hints for wrapping) out from qualifier values
  369. *
  370. * Revision 1.3  2003/10/18 01:36:34  ucko
  371. * Tweak to work around MSVC stupidity.
  372. *
  373. * Revision 1.2  2003/10/17 21:06:35  ucko
  374. * Reworked GTF mode per Wratko's critique:
  375. *  - Now handles multi-exonic(!) start and stop codons.
  376. *  - Treats all RNA features on DNA as exons.
  377. *  - Sets exon_number attribute for GTF 1 compatibility.
  378. *  - Quotes other attributes better.
  379. *
  380. * Revision 1.1  2003/10/08 21:11:45  ucko
  381. * New GFF/GTF formatter
  382. *
  383. *
  384. * ===========================================================================
  385. */