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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: cav_alndisplay.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:41:15  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.5
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: cav_alndisplay.cpp,v 1000.3 2004/06/01 19:41:15 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. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      Classes to hold alignment display
  38. *
  39. * ===========================================================================
  40. */
  41. #include <ncbi_pch.hpp>
  42. #include <corelib/ncbistl.hpp>
  43. #include <corelib/ncbiobj.hpp>
  44. #include <map>
  45. #include <deque>
  46. #include <memory>
  47. #include <iomanip>
  48. #include <math.h>
  49. #include <objtools/cddalignview/cav_alndisplay.hpp>
  50. #include <objtools/cddalignview/cav_seqset.hpp>
  51. #include <objtools/cddalignview/cav_alignset.hpp>
  52. #include <objtools/cddalignview/cddalignview.h>
  53. BEGIN_NCBI_SCOPE
  54. const double AlignmentDisplay::SHOW_IDENTITY = 100000.0;
  55. // HTML colors
  56. static const int nBlockColors = 2;
  57. static const string
  58.     bgColor("#FFFFFF"), blockBGColors[nBlockColors] = { "#FFFFE0", "#FFE8FF" },
  59.     rulerColor("#700777"), numColor("#229922"), featColor("#888811"),
  60.     plainColor("#888888"), blockColor("#2233CC"), conservedColor("#FF4466");
  61. #define LEFT_JUSTIFY resetiosflags(IOS_BASE::right) << setiosflags(IOS_BASE::left)
  62. #define RIGHT_JUSTIFY resetiosflags(IOS_BASE::left) << setiosflags(IOS_BASE::right)
  63. static string StrToLower(const string& str)
  64. {
  65.     string newStr(str);
  66.     for (int i=0; i<newStr.size(); ++i) newStr[i] = tolower(newStr[i]);
  67.     return newStr;
  68. }
  69. class UnalignedInterval
  70. {
  71. public:
  72.     int alnLocBefore, alnLocAfter, seqLocFrom, seqLocTo;
  73. };
  74. typedef list < UnalignedInterval > IntervalList;
  75. AlignmentDisplay::AlignmentDisplay(const SequenceSet *sequenceSet, const AlignmentSet *alignmentSet) :
  76.     status(CAV_ERROR_DISPLAY)
  77. {
  78.     // start with master row at top, all in lowercase - will be capitalized as things are
  79.     // aligned to it. Also, add an IndexAlnLocToSeqLocRow for the master (only).
  80.     if (!sequenceSet->master) {
  81.         ERR_POST(Error << "Need to know master sequence of SequenceSet for AlignmentDisplay construction");
  82.         return;
  83.     }
  84.     textRows.push_back(new TextRow(StrToLower(sequenceSet->master->sequenceString)));
  85.     // initialize the master index row
  86.     indexAlnLocToSeqLocRows.push_back(
  87.         new IndexAlnLocToSeqLocRow(sequenceSet->master, sequenceSet->master->sequenceString.size()));
  88.     int l;
  89.     for (l=0; l<sequenceSet->master->sequenceString.size(); ++l)
  90.         indexAlnLocToSeqLocRows[0]->SetSeqLocAt(l, l);
  91.     // loop through alignments - one new row for each alignment
  92.     AlignmentSet::AlignmentList::const_iterator a, ae = alignmentSet->alignments.end();
  93.     for (a=alignmentSet->alignments.begin(); a!=ae; ++a) {
  94.         // add index row for each slave that contains only Sequence* for now
  95.         indexAlnLocToSeqLocRows.push_back(new IndexAlnLocToSeqLocRow((*a)->slave));
  96.         // first add blank row that will be filled in with slave
  97.         textRows.push_back(new TextRow(GetWidth()));
  98.         // during this pass through the master, do several things:
  99.         //  - change aligned master residues to uppercase
  100.         //  - fill in aligned slave residues with uppercase
  101.         //  - make a list of all unaligned slave regions, and the current display
  102.         //      coordinates of the aligned slave residues on either side
  103.         int prevAlignedSlaveSeqLoc = -1, prevAlignedSlaveAlnLoc = -1;
  104.         IntervalList intervalList;
  105.         for (int alnLoc=0; alnLoc<=GetWidth(); ++alnLoc) {
  106.             int masterSeqLoc = -1, alignedSlaveSeqLoc = -1;
  107.             if (alnLoc < GetWidth()) {
  108.                 masterSeqLoc = indexAlnLocToSeqLocRows.front()->GetSeqLocAt(alnLoc);
  109.                 if (masterSeqLoc >= 0) {
  110.                     alignedSlaveSeqLoc = (*a)->masterToSlave[masterSeqLoc];
  111.                     if (alignedSlaveSeqLoc >= 0) {
  112.                         textRows.front()->SetCharAt(alnLoc,
  113.                             toupper(textRows.front()->GetCharAt(alnLoc)));
  114.                         textRows.back()->SetCharAt(alnLoc,
  115.                             toupper((*a)->slave->sequenceString[alignedSlaveSeqLoc]));
  116.                     }
  117.                 }
  118.             } else {
  119.                 masterSeqLoc = (*a)->master->sequenceString.size();
  120.                 alignedSlaveSeqLoc = (*a)->slave->sequenceString.size();
  121.             }
  122.             if (alignedSlaveSeqLoc >= 0) {
  123.                 if (alignedSlaveSeqLoc - prevAlignedSlaveSeqLoc > 1) {
  124.                     intervalList.resize(intervalList.size() + 1);
  125.                     intervalList.back().alnLocBefore = prevAlignedSlaveAlnLoc;
  126.                     intervalList.back().alnLocAfter = alnLoc;
  127.                     intervalList.back().seqLocFrom = prevAlignedSlaveSeqLoc + 1;
  128.                     intervalList.back().seqLocTo = alignedSlaveSeqLoc - 1;
  129.                 }
  130.                 prevAlignedSlaveSeqLoc = alignedSlaveSeqLoc;
  131.                 prevAlignedSlaveAlnLoc = alnLoc;
  132.             }
  133.         }
  134.         // now, put in the unaligned regions of the slave. If there is more space
  135.         // than residues, then pad with spaces as necessary. If
  136.         // there isn't enough space, then add gaps to all prior alignments.
  137.         IntervalList::iterator i, ie = intervalList.end();
  138.         int alnLocOffset = 0;   // to track # inserted columns
  139.         for (i=intervalList.begin(); i!=ie; ++i) {
  140.             // compensate for inserted columns in display
  141.             i->alnLocBefore += alnLocOffset;
  142.             i->alnLocAfter += alnLocOffset;
  143.             int
  144.                 displaySpace = i->alnLocAfter - i->alnLocBefore - 1,
  145.                 unalignedLength = i->seqLocTo - i->seqLocFrom + 1,
  146.                 extraSpace = displaySpace - unalignedLength;
  147.             // add gaps to make space
  148.             if (extraSpace < 0) {
  149.                 // where to insert gaps if display space is too small
  150.                 int insertPos;
  151.                 if (i->seqLocFrom == 0) {   // left tail
  152.                     insertPos = 0;
  153.                 } else if (i->seqLocTo == (*a)->slave->sequenceString.size() - 1) { // right tail
  154.                     insertPos = GetWidth();
  155.                 } else {    // between aligned blocks
  156.                     insertPos = i->alnLocAfter - displaySpace / 2;
  157.                 }
  158.                 InsertGaps(-extraSpace, insertPos);
  159.                 alnLocOffset -= extraSpace;
  160.                 extraSpace = 0;
  161.             }
  162.             // fill in unaligned regions with lowercase, right-justifying only for left tail
  163.             for (l=0; l<unalignedLength; ++l) {
  164.                 textRows.back()->SetCharAt(
  165.                     i->alnLocBefore + 1 + ((i->seqLocFrom == 0) ? l + extraSpace : l),
  166.                     tolower((*a)->slave->sequenceString[i->seqLocFrom + l]));
  167.             }
  168.         }
  169.     }
  170.     ERR_POST(Info << "initial alignment display size: " << GetWidth() << " x " << GetNRows());
  171.     // the above algorithm introduces more gaps than are strictly necessary. This
  172.     // will "squeeze" the alignment, deleting gaps wherever possible
  173.     Squeeze();
  174.     // finally, redistribute unaligned residues so that they are split equally between
  175.     // flanking aligned residues
  176.     SplitUnaligned();
  177.     // The Squeeze and SplitUnaligned leave the master index row out of sync, so reindex it
  178.     indexAlnLocToSeqLocRows[0]->ReIndex(*(textRows[0]));
  179.     // find first and last aligned master residues (in alignment coords)
  180.     firstAlnLoc = GetWidth();
  181.     lastAlnLoc = -1;
  182.     for (l=0; l<GetWidth(); ++l)
  183.         if (IsAligned(textRows[0]->GetCharAt(l))) {
  184.             firstAlnLoc = l;
  185.             break;
  186.         }
  187.     for (l=GetWidth()-1; l>=0; --l)
  188.         if (IsAligned(textRows[0]->GetCharAt(l))) {
  189.             lastAlnLoc = l;
  190.             break;
  191.         }
  192.     ERR_POST(Info << "final alignment display size: " << GetWidth() << " x " << GetNRows());
  193.     ERR_POST(Info << "aligned region: " << firstAlnLoc << " through " << lastAlnLoc);
  194.     status = CAV_SUCCESS;
  195. }
  196. AlignmentDisplay::~AlignmentDisplay()
  197. {
  198.     int i;
  199.     for (i=0; i<indexAlnLocToSeqLocRows.size(); ++i) delete indexAlnLocToSeqLocRows[i];
  200.     for (i=0; i<textRows.size(); ++i) delete textRows[i];
  201. }
  202. // shift unaligned residues as far as possible to the left
  203. void AlignmentDisplay::ShiftUnalignedLeft(void)
  204. {
  205.     int gapLoc, resLoc;
  206.     for (int row=0; row<GetNRows(); ++row) {
  207.         gapLoc = 0;
  208.         while (gapLoc < GetWidth()) {
  209.             // find a gap
  210.             while (gapLoc < GetWidth() && !IsGap(textRows[row]->GetCharAt(gapLoc))) ++gapLoc;
  211.             if (gapLoc == GetWidth()) break;
  212.             // find the next unaligned residue
  213.             resLoc = gapLoc + 1;
  214.             while (resLoc < GetWidth() && IsGap(textRows[row]->GetCharAt(resLoc))) ++resLoc;
  215.             if (resLoc == GetWidth()) break;
  216.             if (!IsUnaligned(textRows[row]->GetCharAt(resLoc))) {
  217.                 gapLoc = resLoc + 1;
  218.                 continue;
  219.             }
  220.             // shift unaligned residues over
  221.             while (resLoc < GetWidth() && IsUnaligned(textRows[row]->GetCharAt(resLoc))) {
  222.                 textRows[row]->SetCharAt(gapLoc++, textRows[row]->GetCharAt(resLoc));
  223.                 textRows[row]->SetCharAt(resLoc++, '-');
  224.             }
  225.         }
  226.     }
  227. }
  228. void AlignmentDisplay::Squeeze(void)
  229. {
  230.     // move all unaligned residues as far left as possible - makes it much simpler
  231.     // to identify squeezable regions
  232.     ShiftUnalignedLeft();
  233.     typedef vector < int > SqueezeLocs;
  234.     SqueezeLocs squeezeLocs(GetNRows());
  235.     // find last aligned residue; stop search one after that
  236.     int alnLoc, lastAlignedLoc;
  237.     for (lastAlignedLoc=GetWidth()-2;
  238.          lastAlignedLoc>=0 && !IsAligned(textRows[0]->GetCharAt(lastAlignedLoc));
  239.          --lastAlignedLoc) ;
  240.     ERR_POST(Info << "checking for squeeze up to " << (lastAlignedLoc+1));
  241.     for (alnLoc=0; alnLoc<=lastAlignedLoc+1; ++alnLoc) {
  242.         // check to see whether each row is squeezable at this location
  243.         int row, nGaps, minNGaps = GetWidth();
  244.         for (row=0; row<GetNRows(); ++row) {
  245.             if (!textRows[row]->IsSqueezable(alnLoc, &nGaps, &(squeezeLocs[row]), minNGaps))
  246.                 break;
  247.             if (nGaps < minNGaps) minNGaps = nGaps;
  248.         }
  249.         // if all rows are squeezable, then do the squeeze
  250.         if (row == GetNRows()) {
  251.             ERR_POST(Info << "squeezing " << minNGaps << " gaps at loc " << alnLoc);
  252.             for (row=0; row<GetNRows(); ++row)
  253.                 textRows[row]->DeleteGaps(minNGaps, squeezeLocs[row]);
  254.             lastAlignedLoc -= minNGaps; // account for shift of lastAlignedLoc
  255.         }
  256.         // after checking very first column, skip to first aligned loc to save time
  257.         if (alnLoc == 0)
  258.             while (alnLoc<=lastAlignedLoc && !IsAligned(textRows[0]->GetCharAt(alnLoc))) ++alnLoc;
  259.     }
  260. }
  261. // redistribute unaligned residues so they're split left/right between aligned residues.
  262. // This assumes ShiftUnalignedLeft() has already been called, so that all unaligned
  263. // residues are on the left of the gaps.
  264. void AlignmentDisplay::SplitUnaligned(void)
  265. {
  266.     // alnLocs of various key residues
  267.     int firstAligned, prevAligned, nextAligned, firstUnaligned, lastUnaligned;
  268.     int nGaps, nShift, shiftRes, shiftGap, i;
  269.     for (int row=0; row<GetNRows(); ++row) {
  270.         // find first aligned loc; count gaps up to there
  271.         nGaps = 0;
  272.         for (i=0; i<GetWidth()-2 && !IsAligned(textRows[row]->GetCharAt(i)); ++i)
  273.              if (IsGap(textRows[row]->GetCharAt(i))) ++nGaps;
  274.         firstAligned = i;
  275.         // right-shift left tails
  276.         if (nGaps > 0) {
  277.             for (i=0; i<firstAligned-nGaps; ++i) {
  278.                 textRows[row]->SetCharAt(firstAligned-1-i, textRows[row]->GetCharAt(firstAligned-1-nGaps-i));
  279.                 textRows[row]->SetCharAt(firstAligned-1-nGaps-i, '-');
  280.             }
  281.         }
  282.         prevAligned = firstAligned;
  283.         while (prevAligned < GetWidth()-2) {
  284.             // find aligned res immediately followed by unaligned
  285.             if (!(IsAligned(textRows[row]->GetCharAt(prevAligned)) &&
  286.                   IsUnaligned(textRows[row]->GetCharAt(prevAligned + 1)))) {
  287.                 ++prevAligned;
  288.                 continue;
  289.             }
  290.             firstUnaligned = prevAligned + 1;
  291.             // find last unaligned residue
  292.             for (lastUnaligned = firstUnaligned;
  293.                  lastUnaligned < GetWidth()-1 &&
  294.                     IsUnaligned(textRows[row]->GetCharAt(lastUnaligned + 1));
  295.                  ++lastUnaligned) ;
  296.             // find next aligned after this
  297.             for (nextAligned = lastUnaligned + 1;
  298.                  nextAligned < GetWidth() &&
  299.                     !IsAligned(textRows[row]->GetCharAt(nextAligned));
  300.                  ++nextAligned) ;
  301.             if (nextAligned == GetWidth()) break;
  302.             // shift over the right half of the unaligned stretch
  303.             nGaps = nextAligned - lastUnaligned - 1;
  304.             nShift = (lastUnaligned - firstUnaligned + 1) / 2;
  305.             if (nGaps > 0 && nShift > 0) {
  306.                 shiftRes = lastUnaligned;
  307.                 shiftGap = nextAligned - 1;
  308.                 for (i=0; i<nShift; ++i) {
  309.                     textRows[row]->SetCharAt(shiftGap - i, textRows[row]->GetCharAt(shiftRes - i));
  310.                     textRows[row]->SetCharAt(shiftRes - i, '-');
  311.                 }
  312.             }
  313.             prevAligned = nextAligned;
  314.         }
  315.     }
  316. }
  317. void AlignmentDisplay::InsertGaps(int nGaps, int beforePos)
  318. {
  319.     int i;
  320.     for (i=0; i<indexAlnLocToSeqLocRows.size(); ++i)
  321.         indexAlnLocToSeqLocRows[i]->InsertGaps(nGaps, beforePos);
  322.     for (i=0; i<textRows.size(); ++i)
  323.         textRows[i]->InsertGaps(nGaps, beforePos);
  324. }
  325. char AlignmentDisplay::GetCharAt(int alnLoc, int row) const
  326. {
  327.     if (alnLoc < 0 || alnLoc >= GetWidth() || row < 0 || row >= GetNRows()) {
  328.         ERR_POST(Error << "AlignmentDisplay::GetCharAt() - coordinate out of range");
  329.         return '?';
  330.     }
  331.     return textRows[row]->GetCharAt(alnLoc);
  332. }
  333. class CondensedColumn : public CObject
  334. {
  335. protected:
  336.     const string color;
  337.     vector < int > info;
  338.     CondensedColumn(int nRows, string columnColor) : color(columnColor) { info.resize(nRows, 0); }
  339. public:
  340.     virtual ~CondensedColumn(void) { }
  341.     string GetColor(void) const { return color; }
  342.     virtual int GetDisplayWidth(void) const = 0;
  343.     virtual int GetNResidues(int row) const = 0;
  344.     virtual void DumpRow(CNcbiOstream& os, int row) const = 0;
  345.     virtual void AddRowChar(int row, char ch) = 0;
  346. };
  347. class CondensedColumnAligned : public CondensedColumn
  348. {
  349. public:
  350.     CondensedColumnAligned(int nRows, string color) : CondensedColumn(nRows, color) { }
  351.     int GetDisplayWidth(void) const { return 1; }
  352.     int GetNResidues(int row) const { return 1; }
  353.     void DumpRow(CNcbiOstream& os, int row) const;
  354.     void AddRowChar(int row, char ch);
  355. };
  356. void CondensedColumnAligned::DumpRow(CNcbiOstream& os, int row) const
  357. {
  358.     os << ((char) info[row]);
  359. }
  360. void CondensedColumnAligned::AddRowChar(int row, char ch)
  361. {
  362.     info[row] = (int) ch;
  363. }
  364. class CondensedColumnUnaligned : public CondensedColumn
  365. {
  366. private:
  367.     static const string prefix, postfix;
  368.     int nDigits;
  369. public:
  370.     CondensedColumnUnaligned(int nRows, string color) : CondensedColumn(nRows, color) { nDigits = 1; }
  371.     int GetDisplayWidth(void) const { return prefix.size() + nDigits + postfix.size(); }
  372.     int GetNResidues(int row) const { return info[row]; }
  373.     void DumpRow(CNcbiOstream& os, int row) const;
  374.     void AddRowChar(int row, char ch);
  375. };
  376. const string CondensedColumnUnaligned::prefix = ".[";
  377. const string CondensedColumnUnaligned::postfix = "].";
  378. void CondensedColumnUnaligned::DumpRow(CNcbiOstream& os, int row) const
  379. {
  380.     if (info[row] > 0)
  381.         os << prefix << RIGHT_JUSTIFY << setw(nDigits) << info[row] << postfix;
  382.     else
  383.         os << setw(GetDisplayWidth()) << ' ';
  384. }
  385. void CondensedColumnUnaligned::AddRowChar(int row, char ch)
  386. {
  387.     if (!IsGap(ch)) {
  388.         (info[row])++;
  389.         int digits = ((int) log10((double) info[row])) + 1;
  390.         if (digits > nDigits)
  391.             nDigits = digits;
  392.     }
  393. }
  394. int AlignmentDisplay::DumpCondensed(CNcbiOstream& os, unsigned int options,
  395.     int firstCol, int lastCol, int nColumns, double conservationThreshhold,
  396.     const char *titleHTML, int nFeatures, const AlignmentFeature *alnFeatures) const
  397. {
  398.     bool doHTML = ((options & CAV_HTML) > 0), doHTMLHeader = ((options & CAV_HTML_HEADER) > 0);
  399.     if (firstCol < 0 || lastCol >= GetWidth() || firstCol > lastCol || nColumns < 1) {
  400.         ERR_POST(Error << "AlignmentDisplay::DumpText() - nonsensical display region parameters");
  401.         return CAV_ERROR_BAD_PARAMS;
  402.     }
  403.     // how many rows in the display, including annotations?
  404.     int nDisplayRows = GetNRows();
  405.     if (!alnFeatures) nFeatures = 0;
  406.     if (nFeatures > 0) nDisplayRows += nFeatures;
  407.     // do make look-up location index for each feature
  408.     vector < vector < bool > > annotLocsByIndex;
  409.     int i, featIndex, masterIndex;
  410.     if (nFeatures > 0) {
  411.         annotLocsByIndex.resize(nFeatures);
  412.         for (featIndex=0; featIndex<nFeatures; ++featIndex) {
  413.             annotLocsByIndex[featIndex].resize(indexAlnLocToSeqLocRows[0]->sequence->Length(), false);
  414.             for (i=0; i<alnFeatures[featIndex].nLocations; ++i) {
  415.                 masterIndex = alnFeatures[featIndex].locations[i];
  416.                 if (masterIndex >= 0 && masterIndex < indexAlnLocToSeqLocRows[0]->sequence->Length())
  417.                     annotLocsByIndex[featIndex][masterIndex] = true;
  418.             }
  419.         }
  420.     }
  421.     // condense the display into CondensedColumn list
  422.     deque < CRef < CondensedColumn > > condensedColumns;
  423.     int alnLoc, alnRow, row;
  424.     bool isAlnRow;
  425.     for (alnLoc=firstCol; alnLoc<=lastCol; ++alnLoc) {
  426.         for (alnRow=0; alnRow<GetNRows(); ++alnRow)
  427.             if (!IsAligned(textRows[alnRow]->GetCharAt(alnLoc))) break;
  428.         bool alignedColumn = (alnRow == GetNRows());
  429.         if (alignedColumn) {
  430.             condensedColumns.resize(condensedColumns.size() + 1);
  431.             condensedColumns.back().Reset(
  432.                 new CondensedColumnAligned(nDisplayRows, GetColumnColor(alnLoc, conservationThreshhold)));
  433.         } else {
  434.             if (condensedColumns.size() == 0 ||
  435.                 !(dynamic_cast<CondensedColumnUnaligned*>(condensedColumns.back().GetPointer()))) {
  436.                 condensedColumns.resize(condensedColumns.size() + 1);
  437.                 condensedColumns.back().Reset(
  438.                     new CondensedColumnUnaligned(nDisplayRows, GetColumnColor(alnLoc, conservationThreshhold)));
  439.             }
  440.         }
  441.         for (row=0; row<nDisplayRows; ++row) {
  442.             if (options & CAV_ANNOT_BOTTOM) {
  443.                 alnRow = row;
  444.                 featIndex = row - GetNRows();
  445.             } else {
  446.                 featIndex = row;
  447.                 alnRow = row - nFeatures;
  448.             }
  449.             isAlnRow = (alnRow >= 0 && alnRow < GetNRows());
  450.             if (isAlnRow) {
  451.                 condensedColumns.back()->AddRowChar(row, textRows[alnRow]->GetCharAt(alnLoc));
  452.             } else if (alignedColumn) {
  453.                 // display feature characters only in aligned columns
  454.                 masterIndex = indexAlnLocToSeqLocRows[0]->GetSeqLocAt(alnLoc);
  455.                 if (masterIndex >= 0 && annotLocsByIndex[featIndex][masterIndex])
  456.                     condensedColumns.back()->AddRowChar(row, alnFeatures[featIndex].featChar);
  457.                 else
  458.                     condensedColumns.back()->AddRowChar(row, ' ');
  459.             }
  460.         }
  461.     }
  462.     // set up the titles and uids, figure out how much space any seqLoc string will take
  463.     vector < string > titles(nDisplayRows), uids(doHTML ? GetNRows() : 0);
  464.     int maxTitleLength = 0, maxSeqLocStrLength = 0, leftMargin, decimalLength;
  465.     for (row=0; row<nDisplayRows; ++row) {
  466.         if (options & CAV_ANNOT_BOTTOM) {
  467.             alnRow = row;
  468.             featIndex = row - GetNRows();
  469.         } else {
  470.             featIndex = row;
  471.             alnRow = row - nFeatures;
  472.         }
  473.         isAlnRow = (alnRow >= 0 && alnRow < GetNRows());
  474.         // title
  475.         titles[row] = isAlnRow ?
  476.             indexAlnLocToSeqLocRows[alnRow]->sequence->GetTitle() :
  477.             string(alnFeatures[featIndex].shortName);
  478.         if (titles[row].size() > maxTitleLength) maxTitleLength = titles[row].size();
  479.         if (isAlnRow) {
  480.             decimalLength = ((int) log10((double)
  481.                 indexAlnLocToSeqLocRows[alnRow]->sequence->sequenceString.size())) + 1;
  482.             if (decimalLength > maxSeqLocStrLength) maxSeqLocStrLength = decimalLength;
  483.         }
  484.         // uid for link to entrez
  485.         if (doHTML && isAlnRow) {
  486.             if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID.size() > 0) {
  487.                 if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID != "query" &&
  488.                     indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID != "consensus") {
  489.                     uids[alnRow] = indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID;
  490.                     if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbChain != ' ')
  491.                         uids[alnRow] += (char) indexAlnLocToSeqLocRows[alnRow]->sequence->pdbChain;
  492.                 }
  493.             } else if (indexAlnLocToSeqLocRows[alnRow]->sequence->gi != Sequence::NOT_SET) {
  494.                 CNcbiOstrstream uidoss;
  495.                 uidoss << indexAlnLocToSeqLocRows[alnRow]->sequence->gi << '';
  496.                 uids[alnRow] = uidoss.str();
  497.                 delete uidoss.str();
  498.             } else if (indexAlnLocToSeqLocRows[alnRow]->sequence->accession.size() > 0) {
  499.                 uids[alnRow] = indexAlnLocToSeqLocRows[alnRow]->sequence->accession;
  500.             }
  501.         }
  502.     }
  503.     leftMargin = maxTitleLength + maxSeqLocStrLength + 2;
  504.     // need to keep track of first, last seqLocs for each row in each paragraph;
  505.     // find seqLoc of first residue >= firstCol
  506.     vector < int > lastShownSeqLocs(GetNRows());
  507.     for (alnRow=0; alnRow<GetNRows(); ++alnRow) {
  508.         lastShownSeqLocs[alnRow] = -1;
  509.         for (alnLoc=0; alnLoc<firstCol; ++alnLoc)
  510.             if (!IsGap(textRows[alnRow]->GetCharAt(alnLoc))) lastShownSeqLocs[alnRow]++;
  511.     }
  512.     // header
  513.     if (doHTML && doHTMLHeader)
  514.         os << "<HTML><TITLE>" << (titleHTML ? titleHTML : "CDDAlignView HTML Display") <<
  515.             "</TITLE><BODY BGCOLOR=" << bgColor << ">n";;
  516.     // split alignment up into "paragraphs", each with <= nColumns
  517.     if (doHTML) os << "<TABLE>n";
  518.     int paragraphStart, nParags = 0, nCondensedColumns;
  519.     ERR_POST(Info << "paragraph width: " << nColumns);
  520.     for (paragraphStart=0;
  521.          paragraphStart<condensedColumns.size();
  522.          paragraphStart+=nCondensedColumns, ++nParags) {
  523.         // figure out how many condensed columns will fit in this paragraph
  524.         int displayWidth = condensedColumns[paragraphStart]->GetDisplayWidth();
  525.         nCondensedColumns = 1;
  526.         while (paragraphStart+nCondensedColumns < condensedColumns.size()) {
  527.             int columnWidth = condensedColumns[paragraphStart+nCondensedColumns]->GetDisplayWidth();
  528.             if (displayWidth + columnWidth <= nColumns) {
  529.                 displayWidth += columnWidth;
  530.                 ++nCondensedColumns;
  531.             } else
  532.                 break;
  533.         }
  534.         // start table row
  535.         if (doHTML)
  536.             os << "<tr><td bgcolor=" << blockBGColors[nParags % nBlockColors] << "><pre>nn";
  537.         else
  538.             if (paragraphStart > 0) os << 'n';
  539.         // output each alignment row
  540.         for (row=0; row<nDisplayRows; ++row) {
  541.             if (options & CAV_ANNOT_BOTTOM) {
  542.                 alnRow = row;
  543.                 featIndex = row - GetNRows();
  544.             } else {
  545.                 featIndex = row;
  546.                 alnRow = row - nFeatures;
  547.             }
  548.             isAlnRow = (alnRow >= 0 && alnRow < GetNRows());
  549.             // title
  550.             if (isAlnRow && doHTML && uids[alnRow].size() > 0) {
  551.                 os << "<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi"
  552.                     << "?cmd=Search&doptcmdl=GenPept&db=Protein&term="
  553.                     << uids[alnRow] << "" onMouseOut="window.status=''"n"
  554.                     << "onMouseOver="window.status='"
  555.                     << ((indexAlnLocToSeqLocRows[alnRow]->sequence->description.size() > 0) ?
  556.                             indexAlnLocToSeqLocRows[alnRow]->sequence->description : titles[row])
  557.                     << "';return true">"
  558.                     << setw(0) << titles[row] << "</a>";
  559.             } else {
  560.                 if (doHTML && !isAlnRow) os << "<font color=" << featColor << '>';
  561.                 os << setw(0) << titles[row];
  562.             }
  563.             os << setw(maxTitleLength+1-titles[row].size()) << ' ';
  564.             if (isAlnRow) {
  565.                 // count displayed residues
  566.                 int nDisplayedResidues = 0;
  567.                 for (i=0; i<nCondensedColumns; ++i)
  568.                     nDisplayedResidues += condensedColumns[paragraphStart+i]->GetNResidues(row);
  569.                 // left start pos (output 1-numbered for humans...)
  570.                 if (doHTML) os << "<font color=" << numColor << '>';
  571.                 if (nDisplayedResidues > 0)
  572.                     os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << (lastShownSeqLocs[alnRow]+2) << ' ';
  573.                 else
  574.                     os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << ' ' << ' ';
  575.                 // dump sequence, applying color changes only when necessary
  576.                 if (doHTML) {
  577.                     string prevColor;
  578.                     for (i=0; i<nCondensedColumns; ++i) {
  579.                         string color = condensedColumns[paragraphStart+i]->GetColor();
  580.                         if (color != prevColor) {
  581.                             os << "</font><font color=" << color << '>';
  582.                             prevColor = color;
  583.                         }
  584.                         condensedColumns[paragraphStart+i]->DumpRow(os, row);
  585.                     }
  586.                     os << "</font>";
  587.                 } else {
  588.                     for (i=0; i<nCondensedColumns; ++i) {
  589.                         condensedColumns[paragraphStart+i]->DumpRow(os, row);
  590.                     }
  591.                 }
  592.                 // right end pos
  593.                 if (nDisplayedResidues > 0) {
  594.                     os << ' ';
  595.                     if (doHTML) os << "<font color=" << numColor << '>';
  596.                     os << LEFT_JUSTIFY << setw(0) << (lastShownSeqLocs[alnRow]+nDisplayedResidues+1);
  597.                     if (doHTML) os << "</font>";
  598.                 }
  599.                 os << 'n';
  600.                 // setup to begin next parag
  601.                 lastShownSeqLocs[alnRow] += nDisplayedResidues;
  602.             }
  603.             // print alignment annotation characters
  604.             else {
  605.                 // skip number
  606.                 os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << ' ' << ' ';
  607.                 // do characters
  608.                 for (i=0; i<nCondensedColumns; ++i)
  609.                     condensedColumns[paragraphStart+i]->DumpRow(os, row);
  610.                 os << (doHTML ? "</font>n" : "n");
  611.             }
  612.         }
  613.         // end table row
  614.         if (doHTML) os << "</pre></td></tr>n";
  615.     }
  616.     if (doHTML) os << "</TABLE>n";
  617.     // add feature legend
  618.     if (nFeatures > 0) {
  619.         os << (doHTML ? "<BR>n" : "n");
  620.         for (featIndex=0; featIndex<nFeatures; ++featIndex)
  621.             if (alnFeatures[featIndex].description)
  622.                 os << alnFeatures[featIndex].shortName << ": " << alnFeatures[featIndex].description
  623.                    << (doHTML ? "<BR>n" : "n");
  624.     }
  625.     if (doHTML && doHTMLHeader) os << "</BODY></HTML>n";
  626.     // additional sanity check on seqloc markers
  627.     if (firstCol == 0 && lastCol == GetWidth()-1) {
  628.         for (alnRow=0; alnRow<GetNRows(); ++alnRow) {
  629.             if (lastShownSeqLocs[alnRow] !=
  630.                     indexAlnLocToSeqLocRows[alnRow]->sequence->sequenceString.size()-1) {
  631.                 ERR_POST(Error << "full display - seqloc markers don't add up");
  632.                 break;
  633.             }
  634.         }
  635.         if (alnRow == GetNRows())
  636.             ERR_POST(Info << "full display - seqloc markers add up correctly");
  637.     }
  638.     return CAV_SUCCESS;
  639. }
  640. int AlignmentDisplay::DumpText(CNcbiOstream& os, unsigned int options,
  641.     int firstCol, int lastCol, int nColumns, double conservationThreshhold,
  642.     const char *titleHTML, int nFeatures, const AlignmentFeature *alnFeatures) const
  643. {
  644.     bool doHTML = ((options & CAV_HTML) > 0), doHTMLHeader = ((options & CAV_HTML_HEADER) > 0);
  645.     if (firstCol < 0 || lastCol >= GetWidth() || firstCol > lastCol || nColumns < 1) {
  646.         ERR_POST(Error << "AlignmentDisplay::DumpText() - nonsensical display region parameters");
  647.         return CAV_ERROR_BAD_PARAMS;
  648.     }
  649.     // how many rows in the display, including annotations?
  650.     int nDisplayRows = GetNRows();
  651.     if (!alnFeatures) nFeatures = 0;
  652.     if (nFeatures > 0) nDisplayRows += nFeatures;
  653.     // set up the titles and uids, figure out how much space any seqLoc string will take
  654.     vector < string > titles(nDisplayRows), uids(doHTML ? GetNRows() : 0);
  655.     int row, featIndex, alnRow, maxTitleLength = 0, maxSeqLocStrLength = 0, leftMargin, decimalLength;
  656.     bool isAlnRow;
  657.     for (row=0; row<nDisplayRows; ++row) {
  658.         if (options & CAV_ANNOT_BOTTOM) {
  659.             alnRow = row;
  660.             featIndex = row - GetNRows();
  661.         } else {
  662.             featIndex = row;
  663.             alnRow = row - nFeatures;
  664.         }
  665.         isAlnRow = (alnRow >= 0 && alnRow < GetNRows());
  666.         // title
  667.         titles[row] = isAlnRow ?
  668.             indexAlnLocToSeqLocRows[alnRow]->sequence->GetTitle() :
  669.             string(alnFeatures[featIndex].shortName);
  670.         if (titles[row].size() > maxTitleLength) maxTitleLength = titles[row].size();
  671.         if (isAlnRow) {
  672.             decimalLength = ((int) log10((double)
  673.                 indexAlnLocToSeqLocRows[alnRow]->sequence->sequenceString.size())) + 1;
  674.             if (decimalLength > maxSeqLocStrLength) maxSeqLocStrLength = decimalLength;
  675.         }
  676.         // uid for link to entrez
  677.         if (doHTML && isAlnRow) {
  678.             if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID.size() > 0) {
  679.                 if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID != "query" &&
  680.                     indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID != "consensus") {
  681.                     uids[alnRow] = indexAlnLocToSeqLocRows[alnRow]->sequence->pdbID;
  682.                     if (indexAlnLocToSeqLocRows[alnRow]->sequence->pdbChain != ' ')
  683.                         uids[alnRow] += (char) indexAlnLocToSeqLocRows[alnRow]->sequence->pdbChain;
  684.                 }
  685.             } else if (indexAlnLocToSeqLocRows[alnRow]->sequence->gi != Sequence::NOT_SET) {
  686.                 CNcbiOstrstream uidoss;
  687.                 uidoss << indexAlnLocToSeqLocRows[alnRow]->sequence->gi << '';
  688.                 uids[alnRow] = uidoss.str();
  689.                 delete uidoss.str();
  690.             } else if (indexAlnLocToSeqLocRows[alnRow]->sequence->accession.size() > 0) {
  691.                 uids[alnRow] = indexAlnLocToSeqLocRows[alnRow]->sequence->accession;
  692.             }
  693.         }
  694.     }
  695.     leftMargin = maxTitleLength + maxSeqLocStrLength + 2;
  696.     // need to keep track of first, last seqLocs for each row in each paragraph;
  697.     // find seqLoc of first residue >= firstCol
  698.     vector < int > lastShownSeqLocs(GetNRows());
  699.     int alnLoc;
  700.     for (alnRow=0; alnRow<GetNRows(); ++alnRow) {
  701.         lastShownSeqLocs[alnRow] = -1;
  702.         for (alnLoc=0; alnLoc<firstCol; ++alnLoc)
  703.             if (!IsGap(textRows[alnRow]->GetCharAt(alnLoc))) lastShownSeqLocs[alnRow]++;
  704.     }
  705.     // header
  706.     if (doHTML && doHTMLHeader)
  707.         os << "<HTML><TITLE>" << (titleHTML ? titleHTML : "CDDAlignView HTML Display") <<
  708.             "</TITLE><BODY BGCOLOR=" << bgColor << ">n";;
  709.     // do make look-up location index for each feature
  710.     vector < vector < bool > > annotLocsByIndex;
  711.     int i, masterIndex;
  712.     if (nFeatures > 0) {
  713.         annotLocsByIndex.resize(nFeatures);
  714.         for (featIndex=0; featIndex<nFeatures; ++featIndex) {
  715.             annotLocsByIndex[featIndex].resize(indexAlnLocToSeqLocRows[0]->sequence->Length(), false);
  716.             for (i=0; i<alnFeatures[featIndex].nLocations; ++i) {
  717.                 masterIndex = alnFeatures[featIndex].locations[i];
  718.                 if (masterIndex >= 0 && masterIndex < indexAlnLocToSeqLocRows[0]->sequence->Length())
  719.                     annotLocsByIndex[featIndex][masterIndex] = true;
  720.             }
  721.         }
  722.     }
  723.     // split alignment up into "paragraphs", each with nColumns
  724.     if (doHTML) os << "<TABLE>n";
  725.     int paragraphStart, nParags = 0;
  726.     for (paragraphStart=0; (firstCol+paragraphStart)<=lastCol; paragraphStart+=nColumns, ++nParags) {
  727.         // start table row
  728.         if (doHTML)
  729.             os << "<tr><td bgcolor=" << blockBGColors[nParags % nBlockColors] << "><pre>n";
  730.         else
  731.             if (paragraphStart > 0) os << 'n';
  732.         // do ruler
  733.         int nMarkers = 0, width;
  734.         if (doHTML) os << "<font color=" << rulerColor << '>';
  735.         for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i) {
  736.             if ((paragraphStart+i+1)%10 == 0) {
  737.                 if (nMarkers == 0)
  738.                     width = leftMargin + i + 1;
  739.                 else
  740.                     width = 10;
  741.                 os << RIGHT_JUSTIFY << setw(width) << (paragraphStart+i+1);
  742.                 ++nMarkers;
  743.             }
  744.         }
  745.         if (doHTML) os << "</font>";
  746.         os << 'n';
  747.         if (doHTML) os << "<font color=" << rulerColor << '>';
  748.         for (i=0; i<leftMargin; ++i) os << ' ';
  749.         for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i) {
  750.             if ((paragraphStart+i+1)%10 == 0)
  751.                 os << '|';
  752.             else if ((paragraphStart+i+1)%5 == 0)
  753.                 os << '*';
  754.             else
  755.                 os << '.';
  756.         }
  757.         if (doHTML) os << "</font>";
  758.         os << 'n';
  759.         // get column colors
  760.         vector < string > columnColors;
  761.         if (doHTML)
  762.             for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i)
  763.                 columnColors.resize(columnColors.size()+1,
  764.                     GetColumnColor(firstCol+paragraphStart+i, conservationThreshhold));
  765.         // output each alignment row
  766.         int nDisplayedResidues;
  767.         for (row=0; row<nDisplayRows; ++row) {
  768.             if (options & CAV_ANNOT_BOTTOM) {
  769.                 alnRow = row;
  770.                 featIndex = row - GetNRows();
  771.             } else {
  772.                 featIndex = row;
  773.                 alnRow = row - nFeatures;
  774.             }
  775.             isAlnRow = (alnRow >= 0 && alnRow < GetNRows());
  776.             // actual sequence characters; count how many non-gaps in each row
  777.             nDisplayedResidues = 0;
  778.             string rowChars;
  779.             if (isAlnRow) {
  780.                 for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i) {
  781.                     char ch = textRows[alnRow]->GetCharAt(firstCol+paragraphStart+i);
  782.                     rowChars += ch;
  783.                     if (!IsGap(ch)) ++nDisplayedResidues;
  784.                 }
  785.             }
  786.             // title
  787.             if (isAlnRow && doHTML && uids[alnRow].size() > 0) {
  788.                 os << "<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi"
  789.                     << "?cmd=Search&doptcmdl=GenPept&db=Protein&term="
  790.                     << uids[alnRow] << "" onMouseOut="window.status=''"n"
  791.                     << "onMouseOver="window.status='"
  792.                     << ((indexAlnLocToSeqLocRows[alnRow]->sequence->description.size() > 0) ?
  793.                             indexAlnLocToSeqLocRows[alnRow]->sequence->description : titles[row])
  794.                     << "';return true">"
  795.                     << setw(0) << titles[row] << "</a>";
  796.             } else {
  797.                 if (doHTML && !isAlnRow) os << "<font color=" << featColor << '>';
  798.                 os << setw(0) << titles[row];
  799.             }
  800.             os << setw(maxTitleLength+1-titles[row].size()) << ' ';
  801.             if (isAlnRow) {
  802.                 // left start pos (output 1-numbered for humans...)
  803.                 if (doHTML) os << "<font color=" << numColor << '>';
  804.                 if (nDisplayedResidues > 0)
  805.                     os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << (lastShownSeqLocs[alnRow]+2) << ' ';
  806.                 else
  807.                     os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << ' ' << ' ';
  808.                 // dump sequence, applying color changes only when necessary
  809.                 if (doHTML) {
  810.                     string prevColor;
  811.                     for (i=0; i<rowChars.size(); ++i) {
  812.                         if (columnColors[i] != prevColor) {
  813.                             os << "</font><font color=" << columnColors[i] << '>';
  814.                             prevColor = columnColors[i];
  815.                         }
  816.                         os << rowChars[i];
  817.                     }
  818.                     os << "</font>";
  819.                 } else
  820.                     os << rowChars;
  821.                 // right end pos
  822.                 if (nDisplayedResidues > 0) {
  823.                     os << ' ';
  824.                     if (doHTML) os << "<font color=" << numColor << '>';
  825.                     os << LEFT_JUSTIFY << setw(0) << (lastShownSeqLocs[alnRow]+nDisplayedResidues+1);
  826.                     if (doHTML) os << "</font>";
  827.                 }
  828.                 os << 'n';
  829.                 // setup to begin next parag
  830.                 lastShownSeqLocs[alnRow] += nDisplayedResidues;
  831.             }
  832.             // print alignment annotation characters
  833.             else {
  834.                 // skip number
  835.                 os << RIGHT_JUSTIFY << setw(maxSeqLocStrLength) << ' ' << ' ';
  836.                 // do characters, but only allow annot where master residue is aligned to something
  837.                 for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i) {
  838.                     if (IsAligned(textRows[0]->GetCharAt(firstCol+paragraphStart+i))) {
  839.                         masterIndex = indexAlnLocToSeqLocRows[0]->GetSeqLocAt(firstCol+paragraphStart+i);
  840.                         os << ((masterIndex >= 0 && annotLocsByIndex[featIndex][masterIndex])
  841.                             ? alnFeatures[featIndex].featChar : ' ');
  842.                     } else
  843.                         os << ' ';
  844.                 }
  845.                 os << (doHTML ? "</font>n" : "n");
  846.             }
  847.         }
  848.         // end table row
  849.         if (doHTML) os << "</pre></td></tr>n";
  850.     }
  851.     if (doHTML) os << "</TABLE>n";
  852.     // add feature legend
  853.     if (nFeatures > 0) {
  854.         os << (doHTML ? "<BR>n" : "n");
  855.         for (featIndex=0; featIndex<nFeatures; ++featIndex)
  856.             if (alnFeatures[featIndex].description)
  857.                 os << alnFeatures[featIndex].shortName << ": " << alnFeatures[featIndex].description
  858.                    << (doHTML ? "<BR>n" : "n");
  859.     }
  860.     if (doHTML && doHTMLHeader) os << "</BODY></HTML>n";
  861.     // additional sanity check on seqloc markers
  862.     if (firstCol == 0 && lastCol == GetWidth()-1) {
  863.         for (alnRow=0; alnRow<GetNRows(); ++alnRow) {
  864.             if (lastShownSeqLocs[alnRow] !=
  865.                     indexAlnLocToSeqLocRows[alnRow]->sequence->sequenceString.size()-1) {
  866.                 ERR_POST(Error << "full display - seqloc markers don't add up");
  867.                 break;
  868.             }
  869.         }
  870.         if (alnRow == GetNRows())
  871.             ERR_POST(Info << "full display - seqloc markers add up correctly");
  872.     }
  873.     return CAV_SUCCESS;
  874. }
  875. int AlignmentDisplay::DumpFASTA(int firstCol, int lastCol, int nColumns,
  876.     bool doLowercase, CNcbiOstream& os) const
  877. {
  878.     if (firstCol < 0 || lastCol >= GetWidth() || firstCol > lastCol || nColumns < 1) {
  879.         ERR_POST(Error << "AlignmentDisplay::DumpFASTA() - nonsensical display region parameters");
  880.         return CAV_ERROR_BAD_PARAMS;
  881.     }
  882.     // output each alignment row
  883.     for (int row=0; row<GetNRows(); ++row) {
  884.         // create title line
  885.         os << '>';
  886.         const Sequence *seq = indexAlnLocToSeqLocRows[row]->sequence;
  887.         bool prevID = false;
  888.         if (seq->gi != Sequence::NOT_SET) {
  889.             os << "gi|" << seq->gi;
  890.             prevID = true;
  891.         }
  892.         if (seq->pdbID.size() > 0) {
  893.             if (prevID) os << '|';
  894.             if (seq->pdbID == "query" || seq->pdbID == "consensus") {
  895.                 os << "lcl|" << seq->pdbID;
  896.             } else {
  897.                 os << "pdb|" << seq->pdbID;
  898.                 if (seq->pdbChain != ' ')
  899.                     os << '|' << (char) seq->pdbChain << " Chain "
  900.                        << (char) seq->pdbChain << ',';
  901.             }
  902.             prevID = true;
  903.         }
  904.         if (seq->accession.size() > 0) {
  905.             if (prevID) os << '|';
  906.             os << seq->accession;
  907.             prevID = true;
  908.         }
  909.         if (seq->description.size() > 0)
  910.             os << ' ' << seq->description;
  911.         os << 'n';
  912.         // split alignment up into "paragraphs", each with nColumns
  913.         int paragraphStart, nParags = 0, i;
  914.         for (paragraphStart=0; (firstCol+paragraphStart)<=lastCol; paragraphStart+=nColumns, ++nParags) {
  915.             for (i=0; i<nColumns && (firstCol+paragraphStart+i)<=lastCol; ++i) {
  916.                 char ch = textRows[row]->GetCharAt(firstCol+paragraphStart+i);
  917.                 if (!doLowercase) ch = toupper(ch);
  918.                 os << ch;
  919.             }
  920.             os << 'n';
  921.         }
  922.     }
  923.     return CAV_SUCCESS;
  924. }
  925. const string& AlignmentDisplay::GetColumnColor(int alnLoc, double conservationThreshhold) const
  926. {
  927.     // standard probabilities (calculated by BLAST using BLOSUM62 - see conservation_colorer.cpp in Cn3D++)
  928.     typedef map < char , double > Char2Double;
  929.     static Char2Double StandardProbabilities;
  930.     if (StandardProbabilities.size() == 0) {
  931.         StandardProbabilities['A'] = 0.07805;
  932.         StandardProbabilities['C'] = 0.01925;
  933.         StandardProbabilities['D'] = 0.05364;
  934.         StandardProbabilities['E'] = 0.06295;
  935.         StandardProbabilities['F'] = 0.03856;
  936.         StandardProbabilities['G'] = 0.07377;
  937.         StandardProbabilities['H'] = 0.02199;
  938.         StandardProbabilities['I'] = 0.05142;
  939.         StandardProbabilities['K'] = 0.05744;
  940.         StandardProbabilities['L'] = 0.09019;
  941.         StandardProbabilities['M'] = 0.02243;
  942.         StandardProbabilities['N'] = 0.04487;
  943.         StandardProbabilities['P'] = 0.05203;
  944.         StandardProbabilities['Q'] = 0.04264;
  945.         StandardProbabilities['R'] = 0.05129;
  946.         StandardProbabilities['S'] = 0.07120;
  947.         StandardProbabilities['T'] = 0.05841;
  948.         StandardProbabilities['V'] = 0.06441;
  949.         StandardProbabilities['W'] = 0.01330;
  950.         StandardProbabilities['X'] = 0;
  951.         StandardProbabilities['Y'] = 0.03216;
  952.     }
  953.     // if this column isn't completely aligned, use plain color
  954.     int row;
  955.     for (row=0; row<GetNRows(); ++row)
  956.         if (!IsAligned(textRows[row]->GetCharAt(alnLoc))) return plainColor;
  957.     // create profile (residue frequencies) for this column
  958.     Char2Double profile;
  959.     Char2Double::iterator p, pe;
  960.     for (row=0; row<GetNRows(); ++row) {
  961.         char ch = toupper(textRows[row]->GetCharAt(alnLoc));
  962.         switch (ch) {
  963.             case 'A': case 'R': case 'N': case 'D': case 'C':
  964.             case 'Q': case 'E': case 'G': case 'H': case 'I':
  965.             case 'L': case 'K': case 'M': case 'F': case 'P':
  966.             case 'S': case 'T': case 'W': case 'Y': case 'V':
  967.                 break;
  968.             default:
  969.                 ch = 'X'; // make all but natural aa's just 'X'
  970.         }
  971.         if ((p=profile.find(ch)) != profile.end())
  972.             p->second += 1.0/GetNRows();
  973.         else
  974.             profile[ch] = 1.0/GetNRows();
  975.     }
  976.     // check for identity...
  977.     if (conservationThreshhold == SHOW_IDENTITY) {
  978.         if (profile.size() == 1 && profile.begin()->first != 'X')
  979.             return conservedColor;
  980.         else
  981.             return blockColor;
  982.     }
  983.     // ... or calculate information content for this column (calculated in bits -> logs of base 2)
  984.     double information = 0.0;
  985.     pe = profile.end();
  986.     for (p=profile.begin(); p!=pe; ++p) {
  987.         static const double ln2 = log(2.0), threshhold = 0.0001;
  988.         double expFreq = StandardProbabilities[p->first];
  989.         if (expFreq > threshhold) {
  990.             float freqRatio = p->second / expFreq;
  991.             if (freqRatio > threshhold)
  992.                 information += p->second * log(freqRatio) / ln2;
  993.         }
  994.     }
  995.     // if conserved, use conservation color
  996.     if (information > conservationThreshhold) return conservedColor;
  997.     // if is unconserved, use block color to show post-IBM block locations
  998.     return blockColor;
  999. }
  1000. ///// Row class methods /////
  1001. void TextRow::InsertGaps(int nGaps, int beforePos)
  1002. {
  1003.     if (beforePos < 0 || beforePos > Length()) {
  1004.         ERR_POST(Error << "TextRow::InsertGaps() - beforePos out of range");
  1005.         return;
  1006.     }
  1007.     chars.insert(beforePos, nGaps, '-');
  1008. }
  1009. void TextRow::DeleteGaps(int nGaps, int startPos)
  1010. {
  1011.     if (startPos < 0 || startPos+nGaps-1 > Length()) {
  1012.         ERR_POST(Error << "TextRow::DeleteGaps() - startPos out of range");
  1013.         return;
  1014.     }
  1015.     // check to make sure they're all gaps
  1016.     for (int i=0; i<nGaps; ++i) {
  1017.         if (!IsGap(chars[startPos + i])) {
  1018.             ERR_POST(Error << "TextRow::DeleteGaps() - trying to delete non-gap");
  1019.             return;
  1020.         }
  1021.     }
  1022.     chars.erase(startPos, nGaps);
  1023. }
  1024. // find out how many gaps (up to maxGaps) are present from alnLoc to the next aligned
  1025. // residue to the right; set startPos to the first gap, nGaps to # gaps starting at startPos
  1026. bool TextRow::IsSqueezable(int alnLoc, int *nGaps, int *startPos, int maxGaps) const
  1027. {
  1028.     if (alnLoc < 0 || alnLoc >= chars.size()) {
  1029.         ERR_POST(Error << "TextRow::IsSqueezable() - alnLoc out of range");
  1030.         return false;
  1031.     }
  1032.     // skip unaligned residues
  1033.     while (alnLoc < chars.size() && IsUnaligned(chars[alnLoc])) ++alnLoc;
  1034.     if (alnLoc == chars.size() || IsAligned(chars[alnLoc])) return false;
  1035.     // count gaps
  1036.     *startPos = alnLoc;
  1037.     for (*nGaps=1, ++alnLoc; alnLoc < chars.size() && IsGap(chars[alnLoc]); (*nGaps)++, ++alnLoc)
  1038.         if (*nGaps == maxGaps) break;
  1039.     return true;
  1040. }
  1041. IndexAlnLocToSeqLocRow::IndexAlnLocToSeqLocRow(const Sequence *seq, int length) :
  1042.     sequence(seq)
  1043. {
  1044.     if (length > 0) seqLocs.resize(length, -1);
  1045. }
  1046. void IndexAlnLocToSeqLocRow::InsertGaps(int nGaps, int beforePos)
  1047. {
  1048.     if (nGaps <= 0 || seqLocs.size() == 0) return;
  1049.     if (beforePos < 0 || beforePos > Length()) {
  1050.         ERR_POST(Error << "IndexAlnLocToSeqLocRow::InsertGaps() - beforePos out of range");
  1051.         return;
  1052.     }
  1053.     IntVec::iterator s = seqLocs.begin();
  1054.     for (int i=0; i<beforePos; ++i) ++s;
  1055.     seqLocs.insert(s, nGaps, -1);
  1056. }
  1057. void IndexAlnLocToSeqLocRow::ReIndex(const TextRow& textRow)
  1058. {
  1059.     seqLocs.resize(textRow.Length());
  1060.     int seqLoc = 0;
  1061.     for (int i=0; i<textRow.Length(); ++i) {
  1062.         if (IsGap(textRow.GetCharAt(i)))
  1063.             seqLocs[i] = -1;
  1064.         else
  1065.             seqLocs[i] = seqLoc++;
  1066.     }
  1067.     if (seqLoc != sequence->sequenceString.size())
  1068.         ERR_POST(Error << "IndexAlnLocToSeqLocRow::ReIndex() - wrong sequence length");
  1069. }
  1070. END_NCBI_SCOPE
  1071. /*
  1072. * ---------------------------------------------------------------------------
  1073. * $Log: cav_alndisplay.cpp,v $
  1074. * Revision 1000.3  2004/06/01 19:41:15  gouriano
  1075. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.5
  1076. *
  1077. * Revision 1.5  2004/05/21 21:42:51  gorelenk
  1078. * Added PCH ncbi_pch.hpp
  1079. *
  1080. * Revision 1.4  2004/03/15 18:51:27  thiessen
  1081. * prefer prefix vs. postfix ++/-- operators
  1082. *
  1083. * Revision 1.3  2003/11/15 13:16:04  thiessen
  1084. * fix uid link urls
  1085. *
  1086. * Revision 1.2  2003/06/02 16:06:41  dicuccio
  1087. * Rearranged src/objects/ subtree.  This includes the following shifts:
  1088. *     - src/objects/asn2asn --> arc/app/asn2asn
  1089. *     - src/objects/testmedline --> src/objects/ncbimime/test
  1090. *     - src/objects/objmgr --> src/objmgr
  1091. *     - src/objects/util --> src/objmgr/util
  1092. *     - src/objects/alnmgr --> src/objtools/alnmgr
  1093. *     - src/objects/flat --> src/objtools/flat
  1094. *     - src/objects/validator --> src/objtools/validator
  1095. *     - src/objects/cddalignview --> src/objtools/cddalignview
  1096. * In addition, libseq now includes six of the objects/seq... libs, and libmmdb
  1097. * replaces the three libmmdb? libs.
  1098. *
  1099. * Revision 1.1  2003/03/19 19:04:12  thiessen
  1100. * move again
  1101. *
  1102. * Revision 1.2  2003/03/19 13:25:09  thiessen
  1103. * fix log ambiguity
  1104. *
  1105. * Revision 1.1  2003/03/19 05:33:43  thiessen
  1106. * move to src/app/cddalignview
  1107. *
  1108. * Revision 1.23  2003/02/03 17:52:03  thiessen
  1109. * move CVS Log to end of file
  1110. *
  1111. * Revision 1.22  2003/01/21 18:01:07  thiessen
  1112. * add condensed alignment display
  1113. *
  1114. * Revision 1.21  2002/12/09 13:31:04  thiessen
  1115. * use new query.fcgi for genpept links
  1116. *
  1117. * Revision 1.20  2002/11/08 19:38:11  thiessen
  1118. * add option for lowercase unaligned in FASTA
  1119. *
  1120. * Revision 1.19  2002/04/25 13:14:55  thiessen
  1121. * fix range test
  1122. *
  1123. * Revision 1.18  2002/02/12 13:08:20  thiessen
  1124. * annot description optional
  1125. *
  1126. * Revision 1.17  2002/02/12 12:54:10  thiessen
  1127. * feature legend at bottom; annot only where aligned
  1128. *
  1129. * Revision 1.16  2002/02/08 19:53:17  thiessen
  1130. * add annotation to text/HTML displays
  1131. *
  1132. * Revision 1.15  2001/03/02 01:19:24  thiessen
  1133. * add FASTA output
  1134. *
  1135. * Revision 1.14  2001/02/16 19:18:47  thiessen
  1136. * change color scheme again
  1137. *
  1138. * Revision 1.13  2001/02/15 19:23:44  thiessen
  1139. * add identity coloring
  1140. *
  1141. * Revision 1.12  2001/02/15 18:08:15  thiessen
  1142. * change color scheme
  1143. *
  1144. * Revision 1.11  2001/02/14 16:06:09  thiessen
  1145. * add block and conservation coloring to HTML display
  1146. *
  1147. * Revision 1.10  2001/02/14 03:16:27  thiessen
  1148. * fix seqloc markers and right-justification of left tails
  1149. *
  1150. * Revision 1.9  2001/02/14 00:06:49  thiessen
  1151. * filter out consensus
  1152. *
  1153. * Revision 1.8  2001/01/29 23:55:09  thiessen
  1154. * add AlignmentDisplay verification
  1155. *
  1156. * Revision 1.7  2001/01/29 18:13:33  thiessen
  1157. * split into C-callable library + main
  1158. *
  1159. * Revision 1.6  2001/01/25 00:51:20  thiessen
  1160. * add command-line args; can read asn data from stdin
  1161. *
  1162. * Revision 1.5  2001/01/23 23:17:48  thiessen
  1163. * fix uid link problems
  1164. *
  1165. * Revision 1.4  2001/01/23 20:42:00  thiessen
  1166. * add description
  1167. *
  1168. * Revision 1.3  2001/01/23 17:34:12  thiessen
  1169. * add HTML output
  1170. *
  1171. * Revision 1.2  2001/01/22 15:55:11  thiessen
  1172. * correctly set up ncbi namespacing
  1173. *
  1174. * Revision 1.1  2001/01/22 13:15:23  thiessen
  1175. * initial checkin
  1176. *
  1177. */