From 38dc74d72ea09e5a2c9acc3fd72c231849c82166 Mon Sep 17 00:00:00 2001 From: Diane Trout Date: Thu, 27 Jul 2006 02:13:31 +0000 Subject: [PATCH] add annot and motif classes to python interface this also involved renaming annot.start to annot.begin to be a bit more consistent with the begin/end convention used by C++. I also added some more of the sequence class api to the python layer. (so there's some hope that one could add annotations) --- alg/glseqbrowser.cpp | 6 +++--- alg/glsequence.cpp | 8 ++++---- alg/glsequence.hpp | 4 ++-- alg/sequence.cpp | 28 ++++++++++++++-------------- alg/sequence.hpp | 6 +++--- alg/test/test_annotation_color.cpp | 2 +- alg/test/test_sequence.cpp | 12 ++++++------ py/CMakeLists.txt | 1 + py/annot.cpp | 19 +++++++++++++++++++ py/glsequence.cpp | 2 +- py/module.cpp | 2 ++ py/sequence.cpp | 12 ++++++++---- py/test/TestSequence.py | 22 +++++++++++++++++++++- 13 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 py/annot.cpp diff --git a/alg/glseqbrowser.cpp b/alg/glseqbrowser.cpp index 919508b..d7d60aa 100644 --- a/alg/glseqbrowser.cpp +++ b/alg/glseqbrowser.cpp @@ -563,15 +563,15 @@ void GlSeqBrowser::update_layout() { seq_i->setX(0); seq_i->setY(y); - if (seq_i->length() > max_base_pairs) - max_base_pairs = seq_i->length(); + if (seq_i->size() > max_base_pairs) + max_base_pairs = seq_i->size(); } } else if (track_count == 1) { // center the single track glseq_itor_type seq_i = track_container.begin(); seq_i->setX(0); seq_i->setY(viewport_size.x /2); - max_base_pairs = seq_i->length(); + max_base_pairs = seq_i->size(); } else { // nothing to do as we're empty return; diff --git a/alg/glsequence.cpp b/alg/glsequence.cpp index 54a13fa..de262d4 100644 --- a/alg/glsequence.cpp +++ b/alg/glsequence.cpp @@ -63,7 +63,7 @@ GLfloat GlSequence::x() const GLfloat GlSequence::right() const { - return length()+seq_x; + return size()+seq_x; } void GlSequence::setY(GLfloat value) @@ -81,7 +81,7 @@ GLfloat GlSequence::height() const return seq_height; } -GLfloat GlSequence::length() const +GLfloat GlSequence::size() const { return seq->size(); } @@ -236,7 +236,7 @@ void GlSequence::draw_annotations(GLfloat left, GLfloat right) const ++annot_itor) { glColor3f(0.0, 0.8, 0.0); - draw_box(left, right, seq_x+annot_itor->start, seq_x+annot_itor->end, + draw_box(left, right, seq_x+annot_itor->begin, seq_x+annot_itor->end, seq_height, annotation_z); } // if motifs? @@ -245,7 +245,7 @@ void GlSequence::draw_annotations(GLfloat left, GLfloat right) const ++motifs_itor) { glColor3fv(color_mapper->lookup("motif", motifs_itor->sequence).get()); - draw_box(left, right, seq_x+motifs_itor->start, seq_x+motifs_itor->end, + draw_box(left, right, seq_x+motifs_itor->begin, seq_x+motifs_itor->end, seq_height, annotation_z+1.0); } diff --git a/alg/glsequence.hpp b/alg/glsequence.hpp index 5b08fb3..31e282e 100644 --- a/alg/glsequence.hpp +++ b/alg/glsequence.hpp @@ -35,7 +35,7 @@ public: void setX(GLfloat); //! get our starting x (horizontal) coordinate GLfloat x() const; - //! get our right (horizontal) coordinate (length-x) + //! get our right (horizontal) coordinate (size-x) GLfloat right() const; //! set our current y (vertical) position void setY(GLfloat); @@ -44,7 +44,7 @@ public: //! how thick (high) the track we're drawing is GLfloat height() const; //! how long is our sequence track? (computed from the sequence) - GLfloat length() const; + GLfloat size() const; //! return the left (lowest) base index that is fully visible Sequence::size_type leftbase(GLfloat left) const; diff --git a/alg/sequence.cpp b/alg/sequence.cpp index 65ff57d..b2f76c7 100644 --- a/alg/sequence.cpp +++ b/alg/sequence.cpp @@ -47,15 +47,15 @@ static const char* rna_alphabet = "AaCcGgNnUu\012\015"; static const char* iupac_alphabet = "AaCcGgTtUuRrYyMmKkSsWwBbDdHhVvNn\012\015"; annot::annot() - : start(0), + : begin(0), end(0), type(""), name("") { } -annot::annot(int start, int end, std::string type, std::string name) - : start(start), +annot::annot(int begin, int end, std::string type, std::string name) + : begin(begin), end(end), type(type), name(name) @@ -68,14 +68,14 @@ annot::~annot() bool operator==(const annot& left, const annot& right) { - return ((left.start == right.start) and + return ((left.begin== right.begin) and (left.end == right.end) and (left.type == right.type) and (left.name == right.name)); } -motif::motif(int start, std::string motif) - : annot(start, start+motif.size(), "motif", motif), +motif::motif(int begin, std::string motif) + : annot(begin, begin+motif.size(), "motif", motif), sequence(motif) { } @@ -467,14 +467,14 @@ Sequence::subseq(int start, int count) const annot_i != annots.end(); ++annot_i) { - int annot_start = annot_i->start; + int annot_begin= annot_i->begin; int annot_end = annot_i->end; - if (annot_start < end) { - if (annot_start >=start) { - annot_start -= start; + if (annot_begin < end) { + if (annot_begin >= start) { + annot_begin -= start; } else { - annot_start = 0; + annot_begin = 0; } if (annot_end < end) { @@ -483,7 +483,7 @@ Sequence::subseq(int start, int count) const annot_end = count; } - annot new_annot(annot_start, annot_end, annot_i->type, annot_i->name); + annot new_annot(annot_begin, annot_end, annot_i->type, annot_i->name); new_seq.annots.push_back(new_annot); } } @@ -593,7 +593,7 @@ Sequence::save(fs::fstream &save_file) save_file << species << std::endl; for (annots_i = annots.begin(); annots_i != annots.end(); ++annots_i) { - save_file << annots_i->start << " " << annots_i->end << " " ; + save_file << annots_i->begin << " " << annots_i->end << " " ; save_file << annots_i->name << " " << annots_i->type << std::endl; } save_file << "" << std::endl; @@ -638,7 +638,7 @@ Sequence::load_museq(fs::path load_file_path, int seq_num) // get annot start index space_split_i = file_data_line.find(" "); annot_value = file_data_line.substr(0,space_split_i); - an_annot.start = atoi (annot_value.c_str()); + an_annot.begin = atoi (annot_value.c_str()); file_data_line = file_data_line.substr(space_split_i+1); // get annot end index space_split_i = file_data_line.find(" "); diff --git a/alg/sequence.hpp b/alg/sequence.hpp index eceb961..c576c3e 100644 --- a/alg/sequence.hpp +++ b/alg/sequence.hpp @@ -27,10 +27,10 @@ struct annot { annot(); - annot(int start, int end, std::string type, std::string name); + annot(int begin, int end, std::string type, std::string name); ~annot(); - int start; + int begin; int end; std::string type; std::string name; @@ -46,7 +46,7 @@ struct motif : public annot std::string sequence; //! this constructor is for when we're adding motifs to our annotations - motif(int start, std::string motif); + motif(int begin, std::string motif); ~motif(); }; diff --git a/alg/test/test_annotation_color.cpp b/alg/test/test_annotation_color.cpp index 4cde0dd..2e907e9 100644 --- a/alg/test/test_annotation_color.cpp +++ b/alg/test/test_annotation_color.cpp @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE( simple_annot_colors ) BOOST_CHECK_EQUAL( ac.lookup("venchent", "a"), white ); annot a; - a.start = 30; + a.begin = 30; a.end = 45; a.type = "bleem"; a.name = "a"; diff --git a/alg/test/test_sequence.cpp b/alg/test/test_sequence.cpp index b331bfa..990e193 100644 --- a/alg/test/test_sequence.cpp +++ b/alg/test/test_sequence.cpp @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE( annotation_load ) std::list annots_list = seq.annotations(); std::vector annots(annots_list.begin(), annots_list.end()); BOOST_REQUIRE_EQUAL( annots.size(), 8); - BOOST_CHECK_EQUAL( annots[0].start, 0 ); + BOOST_CHECK_EQUAL( annots[0].begin, 0 ); BOOST_CHECK_EQUAL( annots[0].end, 10 ); BOOST_CHECK_EQUAL( annots[0].type, "type"); BOOST_CHECK_EQUAL( annots[0].name, "name"); @@ -138,14 +138,14 @@ BOOST_AUTO_TEST_CASE( annotation_load ) BOOST_CHECK_EQUAL( annots[4].name, "backward"); BOOST_CHECK_EQUAL( annots[5].name, "name2"); BOOST_CHECK_EQUAL( annots[5].end, 90); - BOOST_CHECK_EQUAL( annots[6].start, 100); + BOOST_CHECK_EQUAL( annots[6].begin, 100); BOOST_CHECK_EQUAL( annots[6].end, 120); BOOST_CHECK_EQUAL( annots[6].name, "name-asdf"); BOOST_CHECK_EQUAL( annots[6].type, "type!@#$%"); // sequence defined annotations will always be after the // absolute positions BOOST_CHECK_EQUAL( annots[7].name, "ident3 asdf"); - BOOST_CHECK_EQUAL( annots[7].start, 100); + BOOST_CHECK_EQUAL( annots[7].begin, 100); //BOOST_CHECK_EQUAL( annots } @@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE( annotation_load_no_species_name ) std::list annots_list = seq.annotations(); std::vector annots(annots_list.begin(), annots_list.end()); BOOST_REQUIRE_EQUAL( annots.size(), 8); - BOOST_CHECK_EQUAL( annots[0].start, 0 ); + BOOST_CHECK_EQUAL( annots[0].begin, 0 ); BOOST_CHECK_EQUAL( annots[0].end, 10 ); BOOST_CHECK_EQUAL( annots[0].type, "type"); } @@ -280,13 +280,13 @@ BOOST_AUTO_TEST_CASE( annot_test ) { annot a(0, 10, "test", "thing"); - BOOST_CHECK_EQUAL( a.start, 0 ); + BOOST_CHECK_EQUAL( a.begin, 0 ); BOOST_CHECK_EQUAL( a.end, 10 ); BOOST_CHECK_EQUAL( a.type, "test" ); BOOST_CHECK_EQUAL( a.name, "thing" ); motif m(10, "AAGGCC"); - BOOST_CHECK_EQUAL( m.start, 10 ); + BOOST_CHECK_EQUAL( m.begin, 10 ); BOOST_CHECK_EQUAL( m.type, "motif" ); BOOST_CHECK_EQUAL( m.name, "AAGGCC" ); BOOST_CHECK_EQUAL( m.end, 10+6 ); diff --git a/py/CMakeLists.txt b/py/CMakeLists.txt index 58a3f60..7f6577c 100644 --- a/py/CMakeLists.txt +++ b/py/CMakeLists.txt @@ -12,6 +12,7 @@ INCLUDE( ${QT_USE_FILE} ) IF(BOOST_PYTHON_LIBRARY) INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH} ${QT_INCLUDES}) SET(SOURCES + annot.cpp annotation_colors.cpp conserved_path.cpp glsequence.cpp diff --git a/py/annot.cpp b/py/annot.cpp new file mode 100644 index 0000000..7b06fb8 --- /dev/null +++ b/py/annot.cpp @@ -0,0 +1,19 @@ +#include +using namespace boost::python; + +#include "alg/sequence.hpp" + +void export_annot() +{ + class_("annot") + .def(init()) + .def_readwrite("begin", &annot::begin) + .def_readwrite("end", &annot::end) + .def_readwrite("type", &annot::type) + .def_readwrite("name", &annot::name) + ; + + class_ >("motif", init()) + .def_readwrite("sequence", &motif::sequence) + ; +} diff --git a/py/glsequence.cpp b/py/glsequence.cpp index f40efa3..d736920 100644 --- a/py/glsequence.cpp +++ b/py/glsequence.cpp @@ -19,6 +19,6 @@ void export_glsequence() return_internal_reference<>()) .add_property("x", &GlSequence::x, &GlSequence::setX) .add_property("y", &GlSequence::y, &GlSequence::setY) - .add_property("length", &GlSequence::length) + .add_property("__len__", &GlSequence::size) ; } diff --git a/py/module.cpp b/py/module.cpp index 632b117..91bdd11 100644 --- a/py/module.cpp +++ b/py/module.cpp @@ -1,6 +1,7 @@ #include using namespace boost::python; +void export_annot(); void export_annotation_colors(); void export_conserved_path(); void export_glsequence(); @@ -11,6 +12,7 @@ void export_mussa_window(); BOOST_PYTHON_MODULE(mussa) { + export_annot(); export_annotation_colors(); export_conserved_path(); export_glsequence(); diff --git a/py/sequence.cpp b/py/sequence.cpp index 2bb10ab..494690c 100644 --- a/py/sequence.cpp +++ b/py/sequence.cpp @@ -19,11 +19,15 @@ void export_sequence() { class_("Sequence") .def(init()) - .def("__str__", &seq_to_string) - .def("size", &Sequence::size) - .def("__len__", &Sequence::size) - .add_property("header", &Sequence::get_fasta_header, &Sequence::set_fasta_header) + .def("__str__", &seq_to_string, "cast to string") + .def("__repr__", &seq_to_string, "display as string") + .def("size", &Sequence::size, "return the length of the sequence") + .def("__len__", &Sequence::size, "return the length of the sequence") + .def("clear", &Sequence::clear, "clear the sequence and its annotations") + .add_property("header", &Sequence::get_fasta_header, &Sequence::set_fasta_header, "the fasta header") .add_property("species", &Sequence::get_species, &Sequence::set_species) + .def("add_annotation", &Sequence::add_annotation, "append an annotation") + //.def("annotations", &Sequence::annotations, "return list of annotations") .def("rcseq", &Sequence::rev_comp, return_value_policy()) ; diff --git a/py/test/TestSequence.py b/py/test/TestSequence.py index 274fbdb..5fcc362 100644 --- a/py/test/TestSequence.py +++ b/py/test/TestSequence.py @@ -27,7 +27,27 @@ class TestSequence(unittest.TestCase): s.species = species self.failUnless(s.header == header_text) self.failUnless(s.species == species) - + + def testAnnotations(self): + annot = mussa.annot() + annot.begin = 0 + annot.end = 10 + annot.name = "foo" + annot.type = "utr" + + seq = mussa.Sequence("AAGGCCTTAATTGGCCTT") + seq.add_annotation(annot) + + def notestFile(self): + # remove no prefix once we have sequence loading from a stream + seq_text = "AAGGCCTT" + from StringIO import StringIO + s = StringIO(seq_text) + + seq = mussa.Sequence(s) + + self.failUnless(seq == seq_text) + def suite(): return unittest.makeSuite(TestSequence, 'test') -- 2.30.2