//the_paths.save("tmp.save");
}
+void Mussa::add_motifs(const vector<string>& motifs,
+ const vector<Color>& colors)
+{
+ if (motifs.size() != colors.size()) {
+ throw mussa_error("motif and color vectors must be the same size");
+ }
+
+ for(size_t i = 0; i != motifs.size(); ++i)
+ {
+ motif_sequences.insert(motifs[i]);
+ color_mapper.appendInstanceColor("motif", motifs[i], colors[i]);
+ }
+ update_sequences_motifs();
+}
+
// I mostly split the ifstream out so I can use a stringstream to test it.
void Mussa::load_motifs(std::istream &in)
{
continue;
}
}
+ update_sequences_motifs();
+}
+
+void Mussa::load_motifs(string filename)
+{
+ ifstream f;
+ f.open(filename.c_str(), ifstream::in);
+ load_motifs(f);
+}
+
+void Mussa::update_sequences_motifs()
+{
// once we've loaded all the motifs from the file,
// lets attach them to the sequences
for(vector<Sequence>::iterator seq_i = the_seqs.begin();
}
}
-void Mussa::load_motifs(string filename)
+const set<string>& Mussa::motifs() const
{
- ifstream f;
- f.open(filename.c_str(), ifstream::in);
- load_motifs(f);
+ return motif_sequences;
}
AnnotationColors& Mussa::colorMapper()
void load_old(char * load_file_path, int s_num);
// manage motif lists
+ //! add vector of motifs and colors to our motif collection
+ /*! this depends on sets and color maps being unique
+ * (aka if you add the same item more than once it doesn't
+ * increase the size of the data structure
+ */
+ void add_motifs(const std::vector<std::string>& motifs,
+ const std::vector<Color>& colors);
//! load motifs from an ifstream
/*! The file should look something like
* <sequence> <red> <green> <blue>
void load_motifs(std::istream &);
//! load a list of motifs from a file named filename
void load_motifs(std::string filename);
+ //! return our motifs;
+ const std::set<std::string>& motifs() const;
//! return color mapper
AnnotationColors& colorMapper();
private:
+ //! push motifs to our attached sequences
+ void update_sequences_motifs();
+
// Private variables
// parameters needed for a mussa analysis
//! name of this analysis. (will also be used when saving an analysis)
BOOST_CHECK( seq_i->motifs().size() > 0 );
}
}
+
+BOOST_AUTO_TEST_CASE( mussa_add_motif )
+{
+ vector<string> motifs;
+ motifs.push_back("AAGG");
+ vector<Color> colors;
+ colors.push_back(Color(1.0, 0.0, 0.0));
+
+ Mussa m1;
+ m1.add_a_seq("AAAAGGGGTTTT");
+ m1.add_a_seq("GGGCCCCTTGGTT");
+ m1.add_motifs(motifs, colors);
+ int first_size = m1.motifs().size();
+ BOOST_CHECK_EQUAL( first_size, 1 );
+ m1.add_motifs(motifs, colors);
+ BOOST_CHECK_EQUAL( first_size, m1.motifs().size() );
+}
qui/ImageScaler.hpp \
qui/ImageSaveDialog.hpp \
qui/IntAction.hpp \
+ qui/motif_editor/MotifDetail.hpp \
+ qui/motif_editor/MotifEditor.hpp \
qui/seqbrowser/SequenceBrowserWidget.hpp \
qui/seqbrowser/SequenceBrowser.hpp \
qui/seqbrowser/SequenceBrowserSidebar.hpp \
qui/ImageScaler.cpp \
qui/ImageSaveDialog.cpp \
qui/IntAction.cpp \
+ qui/motif_editor/MotifDetail.cpp \
+ qui/motif_editor/MotifEditor.cpp \
qui/seqbrowser/SequenceBrowserWidget.cpp \
qui/seqbrowser/SequenceBrowser.cpp \
qui/seqbrowser/SequenceBrowserSidebar.cpp \
computeMatchLines();
}
+void MussaAlignedWindow::update()
+{
+ browser.update();
+}
+
void MussaAlignedWindow::computeMatchLines()
{
const vector<Sequence>& raw_sequence = analysis.sequences();
//! toggle whether or not to show the aligned basepairs of a window
void toggleViewAlignment(size_t alignment_index);
+ //! just force updating the window
+ void update();
+
protected:
void setSelectedPaths(Mussa &m, const std::set<int>& sel_paths);
//! set menus (must be called after setSelectedPaths)
MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) :
QMainWindow(parent),
analysis(analysis_),
+ motif_editor(0),
browser(this),
mussaViewTB("Path Views"),
zoomBox(),
// opengl widget.
//scene->setWhatsThis(tr("Mussa in OpenGL!"));
setCentralWidget(&browser);
+ // well updatePosition isn't quite right as we really just need
+ // to call update()
+ connect(this, SIGNAL(changedAnnotations()), &browser, SLOT(update()));
mussaViewTB.addAction(toggleMotifsAction);
connect(createSubAnalysisAction, SIGNAL(triggered()),
this, SLOT(createSubAnalysis()));
+ editMotifsAction = new QAction(tr("Edit Motifs"), this);;
+ connect(editMotifsAction, SIGNAL(triggered()), this, SLOT(editMotifs()));
+
loadMotifListAction = new QAction(tr("Load Motif List"), this);
connect(loadMotifListAction, SIGNAL(triggered()),
this, SLOT(loadMotifList()));
newMenu->addAction(closeAction);
newMenu = menuBar()->addMenu(tr("&View"));
+ newMenu->addAction(editMotifsAction);
newMenu->addAction(viewMussaAlignmentAction);
newMenu->addAction(showMussaViewToolbarAction);
NotImplementedBox();
}
+void MussaWindow::editMotifs()
+{
+ if (motif_editor != 0) {
+ motif_editor->hide();
+ delete motif_editor;
+ }
+ motif_editor = new MotifEditor(analysis);
+ connect(motif_editor, SIGNAL(changedMotifs()),
+ this, SLOT(updateAnnotations()));
+ motif_editor->show();
+}
void MussaWindow::loadMotifList()
{
QObject::tr("you should probably select some paths "
"first"));
} else {
- MussaAlignedWindow *ma_win = new MussaAlignedWindow(*analysis, selected_paths);
+ MussaAlignedWindow *ma_win = new MussaAlignedWindow(*analysis,
+ selected_paths);
+ connect(this, SIGNAL(changedAnnotations()),
+ ma_win, SLOT(update()));
aligned_windows.push_back(ma_win);
ma_win->show();
}
zoomBox.setValue(browser.zoom());
}
+void MussaWindow::updateAnnotations()
+{
+ // motifs were changed in the sequences by
+ // Mussa::update_sequences_motifs
+ emit changedAnnotations();
+ browser.update();
+}
+
void MussaWindow::updateLinks()
{
browser.clear_links();
#include <QToolBar>
#include "qui/MussaAlignedWindow.hpp"
+#include "qui/motif_editor/MotifEditor.hpp"
#include "qui/seqbrowser/SequenceBrowserWidget.hpp"
#include "qui/ThresholdWidget.hpp"
//! \defgroup MotifHandling Handling of motif lists
//\@{
//! load motifs
+ void editMotifs();
void loadMotifList();
void saveMotifList();
void toggleMotifs();
//! open new window showing our alignment
void viewMussaAlignment();
-
+
+signals:
+ void changedAnnotations();
+
protected:
Mussa *analysis;
std::list<MussaAlignedWindow *> aligned_windows;
+ MotifEditor *motif_editor;
// display our wonderful mussa output
SequenceBrowserWidget browser;
QSpinBox zoomBox;
ThresholdWidget threshold;
QLabel zoomLabel;
+
QAction *aboutAction;
QAction *closeAction;
QAction *createNewAnalysisAction;
QAction *createSubAnalysisAction;
+ QAction *editMotifsAction;
QAction *loadMotifListAction;
QAction *loadMupaAction;
QAction *loadSavedAnalysisAction;
void setupMainMenu();
//! stub function to fill in QActions
void NotImplementedBox();
+
+protected slots:
//! update the SequenceBrowser with our analysis
void updateAnalysis();
//! update the view of conserved windows
void updateLinks();
+ //! update annotations?
+ void updateAnnotations();
};
#endif
--- /dev/null
+#include <QColorDialog>
+#include <QHBoxLayout>
+#include <QRegExp>
+
+#include "qui/motif_editor/MotifDetail.hpp"
+
+#include <iostream>
+using namespace std;
+
+static const QRegExp iupacAlphabet("[ACTGUWRKYSMBHDVN]*", Qt::CaseInsensitive);
+static const QRegExpValidator iupacValidator(iupacAlphabet, 0);
+
+MotifDetail::MotifDetail(QWidget *parent)
+ : QWidget(parent),
+ motif_color(1.0, 1.0, 1.0)
+{
+ setupWidget();
+}
+
+MotifDetail::MotifDetail(const MotifDetail &md)
+ : QWidget((QWidget *)md.parent()),
+ motif_color(md.motif_color),
+ motifText(md.motifText.displayText())
+{
+}
+
+MotifDetail::MotifDetail(std::string& m, Color& c, QWidget *parent)
+ : QWidget(parent),
+ motif_color(c),
+ motifText(m.c_str())
+{
+ setupWidget();
+}
+
+void MotifDetail::setupWidget()
+{
+ QHBoxLayout *layout = new QHBoxLayout;
+
+ colorButton.setFlat(true);
+
+ colorButton.setPalette(QPalette(qcolor()));
+ colorButton.setAutoFillBackground(true);
+ connect(&colorButton, SIGNAL(clicked()), this, SLOT(promptColor()));
+ layout->addWidget(&colorButton);
+ motifText.setValidator(&iupacValidator);
+ layout->addWidget(&motifText);
+
+ setLayout(layout);
+}
+
+void MotifDetail::setMotif(const string &m)
+{
+ motifText.setText(m.c_str());
+}
+
+string MotifDetail::motif() const
+{
+ return motifText.text().toStdString();
+}
+
+void MotifDetail::setColor(const Color &c)
+{
+ motif_color = c;
+ colorButton.setPalette(QPalette(qcolor()));
+}
+
+Color MotifDetail::color() const
+{
+ return motif_color;
+}
+
+QColor MotifDetail::qcolor() const
+{
+ QColor qc;
+ qc.setRedF(motif_color.r());
+ qc.setGreenF(motif_color.g());
+ qc.setBlueF(motif_color.b());
+ return qc;
+}
+
+void MotifDetail::promptColor()
+{
+ QColor new_qcolor = QColorDialog::getColor(qcolor(), this);
+ Color new_color(new_qcolor.redF(), new_qcolor.greenF(), new_qcolor.blueF());
+ setColor(new_color);
+}
--- /dev/null
+#ifndef _MOTIF_DETAIL_H
+#define _MOTIF_DETAIL_H
+
+#include <string>
+
+#include <QColor>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRegExpValidator>
+#include <QWidget>
+
+//#include "alg/sequence.hpp"
+#include "alg/color.hpp"
+
+class MotifDetail : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MotifDetail(QWidget *parent=0);
+ MotifDetail(const MotifDetail &);
+ MotifDetail(std::string& m, Color& c, QWidget *parent=0);
+
+ void setMotif(const std::string& m);
+ std::string motif() const;
+
+ void setColor(const Color&);
+ Color color() const;
+ QColor qcolor() const;
+
+public slots:
+ void promptColor();
+
+private:
+ void setupWidget();
+
+ Color motif_color;
+
+ // widgets
+ QPushButton colorButton;
+ QLineEdit motifText;
+};
+#endif
--- /dev/null
+#include "qui/motif_editor/MotifEditor.hpp"
+#include "alg/sequence.hpp"
+
+#include <set>
+#include <string>
+
+using namespace std;
+
+MotifEditor::MotifEditor(Mussa *m, QWidget *parent)
+ : QWidget(parent),
+ analysis(m),
+ applyButton("set motifs")
+{
+ assert (m != 0);
+ const set<string> &motif = analysis->motifs();
+ vector<string> motif_seq(motif.begin(), motif.end());
+
+ connect(&applyButton, SIGNAL(clicked()), this, SLOT(updateMotifs()));
+ layout.addWidget(&applyButton);
+
+ for(size_t i=0; i != 10; ++i)
+ {
+ MotifDetail *detail = new MotifDetail;
+ if (i < motif_seq.size()) {
+ detail->setMotif(motif_seq[i]);
+ detail->setColor(analysis->colorMapper().lookup("motif", motif_seq[i]));
+ }
+ motif_details.push_back(detail);
+ layout.addWidget(detail);
+ }
+ setLayout(&layout);
+}
+
+MotifEditor::MotifEditor(const MotifEditor& me)
+ : QWidget((QWidget*)me.parent()),
+ analysis(me.analysis),
+ applyButton(me.applyButton.text())
+{
+}
+
+void MotifEditor::updateMotifs()
+{
+ // This function is _sooo_ not thread safe
+ // erase motifs
+ Color motif_default = analysis->colorMapper().typeColor("motif");
+ analysis->colorMapper().erase("motif");
+ analysis->colorMapper().appendTypeColor("motif", motif_default);
+
+ // add our motifs back
+ vector<string> motifs;
+ vector<Color> colors;
+
+ for(std::vector<MotifDetail *>::iterator md_i = motif_details.begin();
+ md_i != motif_details.end();
+ ++md_i)
+ {
+ if ((*md_i)->motif().size() > 0) {
+ motifs.push_back((*md_i)->motif());
+ colors.push_back((*md_i)->color());
+ }
+ }
+ analysis->add_motifs(motifs, colors);
+
+ emit changedMotifs();
+}
+
+//MotifEditor::
+
--- /dev/null
+#ifndef MOTIF_EDITOR_H
+#define MOTIF_EDITOR_H
+
+#include <vector>
+
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "alg/mussa.hpp"
+#include "qui/motif_editor/MotifDetail.hpp"
+
+class MotifEditor : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MotifEditor(Mussa* m, QWidget *parent=0);
+ MotifEditor(const MotifEditor&);
+
+public slots:
+ // called to apply motif changes
+ void updateMotifs();
+
+signals:
+ // emitted when the use has applied the motif changes
+ void changedMotifs();
+
+private:
+ Mussa* analysis;
+
+ QPushButton applyButton;
+ QVBoxLayout layout;
+
+ std::vector<MotifDetail *> motif_details;
+};
+#endif
{
scrollable_browser.browser().setZoom(z);
}
+
+void SequenceBrowserWidget::update()
+{
+ scrollable_browser.browser().update();
+}
//! ask the user where to save an image of the current browser view
void promptSaveBrowserPixmap();
+ void update();
+
private:
ScrollableSequenceBrowser scrollable_browser;
SequenceBrowserSidebar left_sidebar;