Mussa aligned sequence view seems to work
authorDiane Trout <diane@caltech.edu>
Mon, 20 Mar 2006 08:58:30 +0000 (08:58 +0000)
committerDiane Trout <diane@caltech.edu>
Mon, 20 Mar 2006 08:58:30 +0000 (08:58 +0000)
I added a "normalizedIndexes" to the ConservedPath classes to return
vectors which don't have any negative path values.

I also think the use of menu entries is a bit annoying as it wont extend
well to large numbers of selected paths. Additionally, deselecting an
alignment doesnt seem to do much as I suspect there's a fair amount of
overlap betwen the various alignments.

But i was eventually able to make them all go away.

alg/conserved_path.cpp
alg/conserved_path.hpp
alg/glseqbrowser.cpp
alg/test/test_conserved_path.cpp
alg/test/test_glseqbrowser.cpp
mussagl.pro
qui/IntAction.cpp [new file with mode: 0644]
qui/IntAction.hpp [new file with mode: 0644]
qui/MussaAlignedWindow.cpp
qui/MussaAlignedWindow.hpp

index af8af7d4ba5ae356b8775330b38d5e3ce64d1a43..a3778daae38edec6b5cc3b21139d56b3b4b80151 100644 (file)
@@ -142,6 +142,23 @@ vector<bool> ConservedPath::reverseComplimented() const
 
 }
 
+std::vector<ConservedPath::path_element> ConservedPath::normalizedIndexes() const
+{
+  vector<path_element> paths;
+  for (ConservedPath::const_iterator this_itor = begin(); 
+       this_itor != end(); 
+       ++this_itor)
+  {
+    if (*this_itor < 0) {
+      paths.push_back(-*this_itor);
+    } else {
+      paths.push_back(*this_itor);
+    }
+  }
+  return paths;
+}
+
+
 /////////////////////
 ExtendedConservedPath::ExtendedConservedPath()
   : ConservedPath(),
@@ -169,6 +186,22 @@ ExtendedConservedPath::ExtendedConservedPath(int win_size,
 {
 }
 
+std::vector<ConservedPath::path_element> ExtendedConservedPath::normalizedIndexes() const
+{
+  vector<path_element> paths;
+  for (ConservedPath::const_iterator this_itor = begin(); 
+       this_itor != end(); 
+       ++this_itor)
+  {
+    if (*this_itor < 0) {
+      paths.push_back(-(*this_itor) - window_size);
+    } else {
+      paths.push_back((*this_itor));
+    }
+  }
+  return paths;
+}
+
 ExtendedConservedPath& ExtendedConservedPath::extend(int growth)
 {
   window_size += growth;
index cc2dda1736a9a6b326dfd14ac1153c907de010db..6217474c9bd4a9dade4988ae6fedee6eef741bb4 100644 (file)
@@ -38,6 +38,8 @@ struct ConservedPath
   bool nextTo(const ConservedPath& next) const;
   //! indicate which elements of the path are reversed
   std::vector<bool> reverseComplimented() const;
+  //! return the list of indexes normalized (to the left)
+  std::vector<path_element> normalizedIndexes() const;
 
   //! either number of conserved bases or average entropy
   double score;
@@ -52,6 +54,7 @@ struct ExtendedConservedPath : public ConservedPath
   ExtendedConservedPath(int win_size, ConservedPath conserved_path);
   ExtendedConservedPath(int win_size, double score, std::vector<int> path);
 
+  std::vector<ConservedPath::path_element> ExtendedConservedPath::normalizedIndexes() const;
   //! extend our current path
   /*! (aka increment our window size  by growth)
    */
index ea5dc2e3f4f6475b000ca032241ac84088da09ae..0b85cb80ac5c64aba6c37448276e75cbdd441b75 100644 (file)
@@ -314,12 +314,10 @@ const std::vector<GlSequence>& GlSeqBrowser::sequences() const
 
 void GlSeqBrowser::clear_links()
 {
-  path_segment_map_vector::iterator psmv_i;
-  for(psmv_i = path_segments.begin();
-      psmv_i != path_segments.end();
-      ++psmv_i)
+  path_segments.clear();
+  for (int i = track_container.size()-1; i > 0; --i)
   {
-    psmv_i->clear();
+    path_segments.push_back(pair_segment_map());
   }
 }
 
@@ -379,7 +377,8 @@ void GlSeqBrowser::centerOnPath(const vector<int>& paths)
 
   for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
   {
-    track_container[track_i].setX(viewport_center - paths[track_i]);
+    // -15 = shift more to the left
+    track_container[track_i].setX((viewport_center-15) - paths[track_i]);
   }
 }
 
index ec1b54cde5fec5a872ea2819d10d7539e31045a6..7050a73a11bfc5b4e625d4cc76c22fcda51ac5a5 100644 (file)
@@ -137,3 +137,25 @@ BOOST_AUTO_TEST_CASE ( extended_conserved_path_growth )
   ecp_base.extend(growth);
   BOOST_CHECK_EQUAL( ecp_base.window_size, window_size + growth );
 }
+
+BOOST_AUTO_TEST_CASE ( extended_conserved_normalized ) 
+{
+  vector<int> path;
+  path += 3,-14,5,-19; // magic from boost assign
+  vector<int> normalized_path;
+  normalized_path += 3,4, 5,9;
+
+  ExtendedConservedPath ecp1;
+  ecp1.window_size = 10;
+  ecp1.score = 18;
+  ecp1.track_indexes = path;
+  BOOST_CHECK_EQUAL ( ecp1.size(), path.size() );
+
+  vector<ConservedPath::path_element> normalized_index(ecp1.normalizedIndexes());
+  for(int i=0; i != ecp1.size(); ++i)
+  {
+    BOOST_CHECK_EQUAL(normalized_index[i], normalized_path[i]);
+  }
+}
+
index 3641d086c842e391b8403f2e2b64d326836f7738..0a3f8c976204f5313d8e1dd2a5123034ba9256b2 100644 (file)
@@ -74,13 +74,13 @@ BOOST_AUTO_TEST_CASE( glseqbrowser_center )
   // I didn't bother to compute how the path should shift things
   // by the magic number 3, i just ran the test and saw how it failed
   // and hard coded this in.
-  BOOST_CHECK_EQUAL( gt.left(), -3-gt.border() );
-  BOOST_CHECK_EQUAL( gt.right(), 3 + s0.size() + gt.border() );
+  BOOST_CHECK_EQUAL( gt.left(), -18-gt.border() );
+  BOOST_CHECK_EQUAL( gt.right(), s0.size() + gt.border()-11 );
 
   // aparently we end up with a different glsequence in the seqbrowser
   BOOST_CHECK( glseq1.x() != gt.sequences()[1].x() );
 
-  BOOST_CHECK_EQUAL( gt.sequences()[0].x(), gt.viewportCenter()-path[0] );
-  BOOST_CHECK_EQUAL( gt.sequences()[1].x(), gt.viewportCenter()-path[1] );
-  BOOST_CHECK_EQUAL( gt.sequences()[2].x(), gt.viewportCenter()-path[2] );
+  BOOST_CHECK_EQUAL( gt.sequences()[0].x(), (gt.viewportCenter()-15)-path[0] );
+  BOOST_CHECK_EQUAL( gt.sequences()[1].x(), (gt.viewportCenter()-15)-path[1] );
+  BOOST_CHECK_EQUAL( gt.sequences()[2].x(), (gt.viewportCenter()-15)-path[2] );
 }
index 72286856245026240aa8838e7bfdd01a8c761f89..c7e5aeab432978c34764ce11d12f39f7feffcfb9 100644 (file)
@@ -17,6 +17,7 @@ HEADERS += mussa_exceptions.hpp \
            qui/ThresholdWidget.hpp \
            qui/ImageScaler.hpp \
            qui/ImageSaveDialog.hpp \
+           qui/IntAction.hpp \
            qui/seqbrowser/SequenceBrowserWidget.hpp \
            qui/seqbrowser/SequenceBrowser.hpp \
            qui/seqbrowser/SequenceBrowserSidebar.hpp \
@@ -38,6 +39,7 @@ SOURCES += mussagl.cpp \
            qui/ThresholdWidget.cpp \
            qui/ImageScaler.cpp \
            qui/ImageSaveDialog.cpp \
+           qui/IntAction.cpp \
            qui/seqbrowser/SequenceBrowserWidget.cpp \
            qui/seqbrowser/SequenceBrowser.cpp \
            qui/seqbrowser/SequenceBrowserSidebar.cpp \
diff --git a/qui/IntAction.cpp b/qui/IntAction.cpp
new file mode 100644 (file)
index 0000000..f2c5ff4
--- /dev/null
@@ -0,0 +1,16 @@
+#include "qui/IntAction.hpp"
+
+#include <iostream>
+using namespace std;
+
+IntAction::IntAction(const QString &text, int value, QObject*parent)
+  : QAction(text, parent),
+    val(value)
+{
+  connect(this, SIGNAL(triggered()), this, SLOT(triggerWithValue()));
+}
+
+void IntAction::triggerWithValue()
+{
+  emit triggered(val);
+}
diff --git a/qui/IntAction.hpp b/qui/IntAction.hpp
new file mode 100644 (file)
index 0000000..38dac89
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _INT_ACTION_H
+#define _INT_ACTION_H
+
+#include <QAction>
+#include <QString>
+
+class IntAction : public QAction
+{
+  Q_OBJECT
+
+public:
+  IntAction(const QString &text, int value, QObject*parent=0);
+
+  int value() const { return val; }
+
+public slots:
+  void triggerWithValue();
+
+signals:
+  void triggered(int);
+
+private:
+  int val;
+};
+#endif
+
index e54f099cef78a941739ab46d354ac687c066fda4..e3735bd2282245a0a6d7313a23cf7f33ea747bf5 100644 (file)
@@ -2,7 +2,9 @@
 #include <vector>
 #include <sstream>
 
-#include <QVBoxLayout>
+#include <QStatusBar>
+#include <QString>
+#include <QMenuBar>
 
 #include "qui/MussaAlignedWindow.hpp"
 #include "alg/sequence.hpp"
@@ -12,25 +14,25 @@ using namespace std;
 MussaAlignedWindow::MussaAlignedWindow(Mussa& m, 
                                        const set<int>& sel_paths, 
                                        QWidget *parent)
-  : QWidget(parent),
-    analysis(m)//,
-    //selected_paths(sel_paths)
-    
+  : QMainWindow(parent),
+    analysis(m),
+    pick_align_menu(tr("Choose Alignment")),
+    view_align_menu(tr("View Alignment"))
 {
   browser.setSequences(analysis.sequences(), analysis.colorMapper());
   setSelectedPaths(m, sel_paths);
   setAlignment(0);
   browser.zoomToSequence();
   computeMatchLines();
+  setupMenus();
 
-  QVBoxLayout *layout = new QVBoxLayout;
-  layout->addWidget(&browser);
-  layout->addWidget(&status);
-  setLayout(layout);
+  setCentralWidget(&browser);
+  menuBar()->addMenu(&pick_align_menu);
+  menuBar()->addMenu(&view_align_menu);
 
   ostringstream message;
   message << "Selected " << selected_paths.size() << " paths";
-  status.showMessage(message.str().c_str(), 5000);
+  statusBar()->showMessage(message.str().c_str(), 5000);
 }
 
 
@@ -44,13 +46,14 @@ void MussaAlignedWindow::setSelectedPaths(Mussa &m, const set<int>& sel_paths)
   size_t pathid=0;
 
   selected_paths.reserve(sel_paths.size());
+  view_paths.reserve(sel_paths.size());
   while (pathid != path_size and sel_i != sel_paths.end())
   {
     assert (*sel_i >= 0);
     size_t sel_pathid = (size_t)(*sel_i);
     if (pathid == sel_pathid) {
-      cout << "found one " << *path_i << endl;
       selected_paths.push_back(*path_i);
+      view_paths.push_back(true);
       ++pathid;
       ++path_i;
       ++sel_i;
@@ -63,13 +66,59 @@ void MussaAlignedWindow::setSelectedPaths(Mussa &m, const set<int>& sel_paths)
   }
 }
 
+void MussaAlignedWindow::setupMenus()
+{
+  pick_align_menu.clear();
+  view_align_menu.clear();
+  pick_actions.clear();
+  view_actions.clear();
+
+  for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
+      pathz_i != selected_paths.end(); 
+      ++pathz_i)
+  {
+    ConservedPath::path_type normalized_path = pathz_i->normalizedIndexes();
+    ostringstream menu_text;
+    menu_text << pathz_i->window_size << ":";
+    ConservedPath::iterator element_i = normalized_path.begin();
+    menu_text << *element_i++;
+    for (;
+         element_i != normalized_path.end();
+         ++element_i)
+    {
+      menu_text << ", ";
+      menu_text << *element_i;
+    }
+    int index = pathz_i - selected_paths.begin();
+    IntAction *pick = new IntAction(QString(menu_text.str().c_str()), index, this);
+    connect(pick, SIGNAL(triggered(int)), this, SLOT(setAlignment(size_t)));
+    pick_actions.push_back(pick);
+    pick_align_menu.addAction(pick);
+    IntAction *view = new IntAction(QString(menu_text.str().c_str()), index, this);
+    connect(view, SIGNAL(triggered(int)), this, SLOT(toggleViewAlignment(size_t)));
+    view->setCheckable(true);
+    view->setChecked(true);
+    view_actions.push_back(view);
+    view_align_menu.addAction(view);
+  }
+}
+
 void MussaAlignedWindow::setAlignment(size_t alignment_index)
 {
   if (selected_paths.size() > 0) {
-    browser.centerOnPath(selected_paths[alignment_index].track_indexes);
+    browser.centerOnPath(selected_paths[alignment_index].normalizedIndexes());
   }
 }
 
+void MussaAlignedWindow::toggleViewAlignment(size_t alignment_index)
+{
+  view_paths[alignment_index]= not view_paths[alignment_index]; 
+  // perhaps it'd be better if we could erase specific sets
+  // of matches instead of erasing them all and recomputing them all
+  // but this is easier
+  computeMatchLines();
+}
+
 void MussaAlignedWindow::computeMatchLines()
 {
   const vector<Sequence>& raw_sequence = analysis.sequences();
@@ -85,12 +134,13 @@ void MussaAlignedWindow::computeMatchLines()
   vector<bool> matched;
   int align_counter;
 
+  browser.clear_links();
   align_counter = 0;
   for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
       pathz_i != selected_paths.end(); 
       ++pathz_i)
   {
-    if (true /* show_aligns[align_counter] */)
+    if (view_paths[align_counter])
     {
       ExtendedConservedPath& a_path = *pathz_i;
       window_length = a_path.window_size;
index 10f7d168ac28dd7dce1270846efc34af31d09a63..d7b642e1e42415ec337330cddca129732648388b 100644 (file)
@@ -3,14 +3,17 @@
 
 #include <set>
 
-#include <QStatusBar>
-#include <QWidget>
+#include <QMainWindow>
+#include <QMenu>
 #include "alg/mussa.hpp"
+#include "qui/IntAction.hpp"
 #include "qui/seqbrowser/SequenceBrowserWidget.hpp"
 
 //! Show sequence alignments
-class MussaAlignedWindow : public QWidget
+class MussaAlignedWindow : public QMainWindow
 {
+  Q_OBJECT 
+
 public:
   //! construct an aligned window for an analysis and selected paths
   MussaAlignedWindow(Mussa&, const std::set<int>&, QWidget *parent=0);
@@ -18,16 +21,24 @@ public:
 public slots:
   //! use selected_paths[pathid] to set the starting position of our sequence
   void setAlignment(size_t pathid);
+  //! toggle whether or not to show the aligned basepairs of a window
+  void toggleViewAlignment(size_t alignment_index);
 
 protected:
   void setSelectedPaths(Mussa &m, const std::set<int>& sel_paths);
+  //! set menus (must be called after setSelectedPaths)
+  void setupMenus();
   void computeMatchLines();
   
   Mussa& analysis;
   //std::vector<Sequence> sequences;
   //const std::set<int>& selected_paths;
   std::vector<ExtendedConservedPath> selected_paths;
+  std::vector<bool> view_paths;
   SequenceBrowserWidget browser;
-  QStatusBar status;
+  QMenu pick_align_menu;
+  QMenu view_align_menu;
+  std::vector <IntAction *> pick_actions;
+  std::vector <IntAction *> view_actions;
 };
 #endif