2c91da7410babc1d1f56742e77aace0590ca9d6e
[mussa.git] / mussa_gui_conn_view.cc
1 //  This file is part of the Mussa source distribution.
2 //  http://mussa.caltech.edu/
3 //  Contact author: Tristan  De Buysscher, tristan@caltech.edu
4
5 // This program and all associated source code files are Copyright (C) 2005
6 // the California Institute of Technology, Pasadena, CA, 91125 USA.  It is
7 // under the GNU Public License; please see the included LICENSE.txt
8 // file for more information, or contact Tristan directly.
9
10
11 #include "mussa_gui_conn_view.hh"
12
13 #include <iomanip>
14 #include <math.h>
15 using namespace std;
16
17 void
18 ConnView::setup(string name, int sq_num, int win_len,
19                 vector<Sequence> *some_seqs,
20                 Nway_Paths *some_paths)
21 {
22   int i, i2, seq_length;
23   Sequence a_seq;
24   motif blank_motif;
25   annot_color new_annot;
26
27
28   ana_name = name;
29   seq_num = sq_num;
30   window = win_len;
31   S = some_seqs;
32   P = some_paths;
33
34   cout << "num of paths = " << some_paths->refined_pathz.size() << endl;
35
36   cout << "x()=" << x() << " y()=" << y() << " w()=" << w() << " h()=" << h();
37   cout << endl;
38
39   max_seq_len = 0;
40   for(i = 0; i < seq_num; ++i)
41   {
42     a_seq = (*S)[i];
43     cout << a_seq.len() << endl;
44     seq_length = a_seq.len();
45     seq_lens.push_back(seq_length);
46     if (seq_length > max_seq_len)
47       max_seq_len = seq_length;
48     if (seq_length < 1000)
49       seq_scales.push_back(1);
50     else if (seq_length < 1000000)
51       seq_scales.push_back(2);
52     else
53       seq_scales.push_back(3);
54   }
55
56   name_pad = 80;
57   y_pad = 20;
58
59   x_scale_factor = (float) max_seq_len / (w() - name_pad);
60   cout << "scale factor is " << x_scale_factor << endl;
61   y_seq_incre = (h()-(y_pad*2)) / (seq_num - 1);
62
63
64   drag_start = -1000;
65   drag_end = -1000;
66   ref_seq_num = 0;
67
68   dragging = false;
69   selected = false;
70
71   highlight.clear();
72   show_bars = false;
73   show_lines = false;
74   bar_interval = max_seq_len / 20;
75   line_interval = max_seq_len / 20;
76   ref_seq_num = 0;
77
78
79   some_motifs.clear();
80   for(i = 0; i < 5; ++i)
81   {
82     blank_motif = new_blank_motif();
83     some_motifs.push_back(blank_motif);
84   }
85
86   // find all unique annotation type ids
87   some_annots.clear();
88   vector<annot_color>::iterator annot_type_i;
89   list<annot>::iterator annot_i;
90
91   // loop thru all sequences
92   for(i2 = 0; i2 < seq_num; i2++)
93   {
94     cout << "ConnView: annotation loop\n";
95     // loop thru all annotation entries in this sequence
96     for(annot_i = (*S)[i2].annots.begin(); annot_i != (*S)[i2].annots.end(); ++annot_i)
97     {
98       cout << annot_i->start << ", " << annot_i->end << " : ";
99       cout << annot_i->name << "  " << annot_i->type << endl;
100       // loop thru annotation types
101       annot_type_i = some_annots.begin();
102       bool type_unfound = true;
103       while ((annot_type_i != some_annots.end()) && type_unfound)
104       {
105         if (annot_i->type == annot_type_i->type)
106           type_unfound = false;  // stop search if found
107         ++annot_type_i;
108       }
109       //if unfound, then add to list
110       if (type_unfound)
111       {
112         new_annot = new_blank_annot();
113         new_annot.type = annot_i->type;
114         some_annots.push_back(new_annot);
115       } 
116     }
117   }
118 }
119
120
121 void
122 ConnView::scale_paths()
123 {
124   vector<int> a_path;
125   list<vector<int> >::iterator pathz_i;
126   int i2;
127
128
129   scaled_pathz.clear();
130
131   for(pathz_i = P->refined_pathz.begin(); pathz_i != P->refined_pathz.end(); ++pathz_i)
132   {
133     a_path = *pathz_i;
134     for(i2 = 0; i2 <= seq_num; i2++)
135       a_path[i2] = (int) (a_path[i2] / x_scale_factor);
136     scaled_pathz.push_back(a_path);
137   }
138 }
139
140 void
141 ConnView::toggle_bars()
142 {
143   show_bars = !show_bars;
144   redraw();
145 }
146
147 void
148 ConnView::set_bar_interval(int new_bar_len)
149 {
150   bar_interval = new_bar_len;
151   cout << "bar interval = " << bar_interval << endl;
152   redraw();
153 }
154
155 void
156 ConnView::toggle_lines()
157 {
158   show_lines = !show_lines;
159   redraw();
160 }
161
162 void
163 ConnView::set_line_interval(int new_line_len)
164 {
165   line_interval = new_line_len;
166   cout << "line interval = " << line_interval << endl;
167   redraw();
168 }
169
170
171 void
172 ConnView::draw()
173 {
174   // this is temporary - check if new motifs have been added
175   check_new_motifs();
176
177   // clear drawing area and set background to white
178   fl_color(FL_WHITE);
179   fl_rectf(x(), y(), w(), h());
180
181
182   // draw the scale indicators if they are on
183   // put into own method soon...
184   int i, div_num, x_loc; 
185   float div_len_scaled;
186
187   if (show_bars)
188   {
189     div_num = max_seq_len / bar_interval;
190     div_len_scaled = ((float) bar_interval) / x_scale_factor;
191     fl_color(230,230,230);
192     for(i = 0; i <= div_num; i+=2)
193     {
194       x_loc = (int)(i * div_len_scaled+x());
195       fl_rectf(x_loc, y(), (int) div_len_scaled, h());
196     }
197   }
198
199   if (show_lines)
200   {  
201     div_num = max_seq_len / line_interval;
202     div_len_scaled = ((float) line_interval) / x_scale_factor;
203     fl_color(0,0,0);
204     fl_line_style(FL_SOLID, 1, NULL);
205     for(i = 0; i <= div_num; i++)
206     {
207       x_loc = (int)(i * div_len_scaled+x());
208       fl_line(x_loc, y(), x_loc, h()+y());
209     }
210   }
211
212
213   // divide up the space with some light blue lines
214   fl_color(150,200,255);
215   fl_line_style(FL_SOLID, 2, NULL);
216   fl_rect(x(), y(), w(), h());
217   fl_line(w()+x()-name_pad, y(), w()+x()-name_pad, h()+y());
218
219   draw_paths();
220
221   // white out any overdraw from path area into name/info area
222   fl_color(FL_WHITE);
223   fl_rectf(w()+x()-name_pad, y(), w()+x(), h());
224
225   draw_sequence_stuff();
226
227   // draw selection box
228   /*
229   if (selected)
230   {
231     fl_color(FL_BLACK);
232     fl_line_style(FL_SOLID, 1, NULL);
233     fl_rect(drag_start,(ref_seq_num*y_seq_incre)+y(),drag_end-drag_start,
234             16);
235   }
236   */
237 }
238
239
240 void
241 ConnView::draw_paths()
242 {
243   list<vector<int> >::iterator i;
244   int i2, i3, y_loc, x_loc, x_start, x_end;
245   vector<int> a_path;
246   list<bool>::iterator highlight_i;
247   int window_size;
248   bool rc_color;
249   int path_start, path_end;
250   //Sequence a_seq;
251
252
253   // determine which paths to highlight
254   highlight.clear();
255   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
256   {
257     a_path = *i;
258     // determine if path falls within the selected region and mark it for
259     // highlighted color
260     path_start = abs(a_path[ref_seq_num+1]);
261     path_end = path_start + a_path[0];
262     if ( ( (path_start >= drag_start-x()) && (path_end <= drag_end-x())  ) ||
263          ( (path_start < drag_start-x())  && (path_end > drag_end-x())   ) ||
264          ( (path_start < drag_start-x())  && (path_end > drag_start-x()) ) ||
265          ( (path_start < drag_end-x())    && (path_end > drag_end-x())   )    )
266       highlight.push_back(true);
267     else
268       highlight.push_back(false);
269   }
270
271   fl_line_style(FL_SOLID, 1, NULL);
272   // draw non-highlight paths (ie not in the selection box)
273   highlight_i = highlight.begin();
274   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
275   {
276     a_path = *i;
277     y_loc = y()+y_pad;
278
279     // get window size to determine line width
280     window_size = a_path[0];
281     // make sure width is at least 1  - might be zero to my slack rounding
282     if (window_size == 0)
283       window_size = 1;
284
285     if (!(*highlight_i))
286       for(i2 = 1; i2 < seq_num; i2++)
287       {
288         // RC case handling
289         // ugh, an xor...only want blue if one of the nodes is rc
290         if ( ((a_path[i2] < 0) || (a_path[i2+1] < 0)) &&
291              !((a_path[i2] < 0) && (a_path[i2+1] < 0)) )
292           fl_color(200,200,255);
293         else
294           fl_color(255,200,200);
295           
296         fl_line_style(FL_SOLID, 1, NULL);
297         fl_polygon((int)abs(a_path[i2])+x(), y_loc + 3,
298                    (int)abs(a_path[i2])+window_size+x(), y_loc + 3,
299                    (int)abs(a_path[i2+1])+window_size+x(), y_loc + y_seq_incre - 3,
300                    (int)abs(a_path[i2+1])+x(), y_loc + y_seq_incre - 3);
301
302         y_loc += y_seq_incre;
303       }
304     ++highlight_i;
305   }
306
307   // draw highlighted paths (ie in or partially in selection)
308   // drawing these separately and after other paths so they are on top
309   highlight_i = highlight.begin();
310   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
311   {
312     a_path = *i;
313     y_loc = y()+y_pad;
314
315     // get window size to determine line width
316     window_size = a_path[0];
317     // make sure width is at least 1  - might be zero to my slack rounding
318     if (window_size == 0)
319       window_size = 1;
320
321     if (*highlight_i)
322       for(i2 = 1; i2 < seq_num; i2++)
323       {
324         // RC case handling
325         // ugh, an xor...only want blue if one of the nodes is rc
326         if ( ((a_path[i2] < 0) || (a_path[i2+1] < 0)) &&
327              !((a_path[i2] < 0) && (a_path[i2+1] < 0)) )
328           fl_color(FL_BLUE);
329         else
330           fl_color(FL_RED);
331           
332         fl_polygon((int)abs(a_path[i2])+x(), y_loc + 3,
333                    (int)abs(a_path[i2])+window_size+x(), y_loc + 3,
334                    (int)abs(a_path[i2+1])+window_size+x(), y_loc + y_seq_incre - 3,
335                    (int)abs(a_path[i2+1])+x(), y_loc + y_seq_incre - 3);
336
337         y_loc += y_seq_incre;
338       }
339     ++highlight_i;
340   }
341 }
342
343 /*
344   list<vector<int> >::iterator i;
345   int window_size;
346   bool rc_color;
347   int path_start, path_end;
348   Sequence a_seq;
349   vector<int> a_path;
350 */
351
352 void
353 ConnView::draw_sequence_stuff()
354 {
355   int i2, i3, y_loc, y_offset, x_loc, x_start, x_end, mv_offset;
356   list<annot>::iterator annot_i;
357   string species_name, seq_length;
358   stringstream raw_length;
359
360
361   // draw sequence representation lines
362   fl_font(FL_COURIER, 14);
363   //fl_color(FL_BLACK);
364   fl_color(100,100,100);
365   // normally size 7, adjust for various screenshotage
366   fl_line_style(FL_SOLID, 11, NULL);
367   y_loc = y()+y_pad;
368   y_offset = 5;
369   for(i2 = 0; i2 < seq_num; i2++)
370   {
371     if (i2 == seq_num - 1)
372       y_offset = -10;
373     x_loc = (int)(seq_lens[i2] / x_scale_factor) + x();
374     //report_float("seq scaled len", x_loc);
375     fl_line(x(),y_loc,x_loc,y_loc);
376
377     species_name = (*S)[i2].species;
378     fl_draw(species_name.c_str(), x()+w()-name_pad+5, y_loc+y_offset);
379
380     // funkiness to figure out which genomic scale to report size in
381     if (seq_scales[i2] == 1)
382       raw_length << setprecision(3) << seq_lens[i2] << " bp";
383     else if (seq_scales[i2] == 2)
384       raw_length << setprecision(3) << seq_lens[i2] / 1000.0 << " Kb";
385     else if (seq_scales[i2] == 3)
386       raw_length << setprecision(3) << seq_lens[i2] /1000000.0<< " Mb";
387     seq_length = raw_length.str();
388     fl_draw(seq_length.c_str(), x()+w()-name_pad+5, y_loc+y_offset+15);
389     raw_length.str("");
390
391     y_loc += y_seq_incre;
392   }
393
394   //fl_line(x(),y()+y_pad/2,w()-name_pad,y()+y_pad/2);
395   //fl_line(x(),y()+h()-y_pad/2,w()-name_pad,y()+h()-y_pad/2);
396
397   // draw annotations
398   vector<annot_color>::iterator annot_type_i;
399
400   fl_color(FL_GREEN);
401   fl_line_style(FL_SOLID, 3, NULL);
402   y_loc = y()+y_pad;
403   for(i2 = 0; i2 < seq_num; i2++)
404   {
405     // loop thru all annotation entries
406     for(annot_i = (*S)[i2].annots.begin(); annot_i != (*S)[i2].annots.end(); ++annot_i)
407     {
408       fl_line_style(FL_SOLID, 7, NULL);
409       mv_offset = 0;
410
411       // loop thru annotation types to determine color
412       annot_type_i = some_annots.begin();
413       bool type_unfound = true;
414       while ((annot_type_i != some_annots.end()) && type_unfound)
415       {
416         if (annot_i->type == annot_type_i->type)
417         {  
418           fl_color(annot_type_i->color);
419           type_unfound = false;
420         }
421         else
422           fl_color(FL_GREEN);
423         ++annot_type_i;
424       }
425
426       // calculate scaled start and end, and draw
427       x_start = (int)(annot_i->start / x_scale_factor) + x();
428       x_end = (int)(annot_i->end / x_scale_factor) + x();
429       fl_line(x_start,y_loc+mv_offset,x_end,y_loc+mv_offset);
430     }
431     y_loc += y_seq_incre;
432   }
433
434
435   // draw motifs found
436   vector<motif>::iterator motif_i;
437   vector<int> some_motif_locs;
438   vector<int>::iterator i_locs;
439   int scale_len, motif_len;
440
441   fl_color(255,0,255);
442   fl_line_style(FL_SOLID, 9, NULL);
443   motif_i = some_motifs.begin();
444   while (motif_i != some_motifs.end())
445   {
446     fl_color(motif_i->color);
447     motif_len = motif_i->seq.length();
448     scale_len = (int) (motif_len / x_scale_factor);
449     if (scale_len == 0)
450       scale_len = 1;
451     y_loc = y()+y_pad;
452     if (!motif_i->locations.empty())
453     for(i2 = 0; i2 < seq_num; i2++)
454     {
455       some_motif_locs = (*motif_i).locations[i2];
456
457       i_locs = some_motif_locs.begin();
458       while (i_locs != some_motif_locs.end())
459       {
460         x_start = (int)(*i_locs / x_scale_factor) + x();
461         fl_line(x_start,y_loc,x_start+scale_len,y_loc);
462         ++i_locs;
463       }
464     y_loc += y_seq_incre;      
465     }
466     ++motif_i;
467   }
468 }
469
470
471 void
472 ConnView::resize(int new_x, int new_y, int new_w, int new_h)
473 {
474
475   x(new_x);
476   y(new_y);
477   w(new_w);
478   h(new_h);
479
480   x_scale_factor = (float) max_seq_len / (w() - name_pad);
481   cout << "scale factor is " << x_scale_factor << endl;
482   y_seq_incre = (h()-(2*y_pad)) / (seq_num - 1);
483
484   scale_paths();
485 }
486
487
488 void
489 ConnView::reporter(string var, int value)
490 {
491   cout << var << " : " << value << endl;
492 }
493
494
495 void
496 ConnView::report_float(string var, float value)
497 {
498   cout << var << " : " << value << endl;
499 }
500
501 int
502 ConnView::handle(int e)
503 {
504   int return_value;
505   float y_calc_tmp;
506
507   // this empty string needs to be put on cout, otherwise the -O optimize
508   // compile option seems to throw this function away with the following:
509   // gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
510   cout << "";
511
512   // why do I need a -O for this module?  Well, originally I just used the 
513   // same compile flags for all modules.  I changed that.  However, on debian
514   // systems I need the -O otherwise the behavior I observe on redhat machines
515   // with above compiler happens if I don't have that empty cout.  WTF
516
517   switch(e)
518   {
519   case FL_PUSH:
520     if (Fl::event_button3())
521     {
522       spawnSeq();
523       return_value = 1;
524     }
525     else if (Fl::event_button2())
526     {
527       find_motifs();
528       return_value = 1;
529     }
530     break;
531   case FL_DRAG:
532     if (!dragging)
533     {
534       drag_start = Fl::event_x();
535       y_drag_start = (float) Fl::event_y();
536       ref_seq_num = (int) (round ( (y_drag_start/y_seq_incre) ) ); 
537       dragging = true;
538       selected = false;
539       return_value = 1;
540     }
541     fl_line_style(FL_SOLID, 1, NULL);
542     fl_overlay_rect(drag_start, (ref_seq_num*y_seq_incre)+y(),
543                     Fl::event_x()-drag_start, 16);
544     
545     break;
546   case FL_RELEASE:
547     if (dragging)
548     {
549       drag_end = Fl::event_x();
550       dragging = false;
551       selected = true;
552       redraw();
553       return_value = 1;
554     }
555     break;
556   default:
557     return_value = Fl_Widget::handle(e);
558   }
559
560   return return_value;
561 }
562
563
564
565 void
566 ConnView::check_new_motifs()
567 {
568   vector<motif>::iterator i;
569   int i2;
570   vector<int> some_motif_locs;
571   vector<int>::iterator i_locs;
572
573   i = some_motifs.begin();
574   while (i != some_motifs.end())
575   {
576     if (i->dirty)
577     {
578       cout << i->seq << " is new\n";
579       i->locations.clear();
580       //i_locs = i->locations;
581       for(i2 = 0; i2 < seq_num; i2++)
582       {
583         some_motif_locs = (*S)[i2].find_motif(i->seq);
584         (*i).locations.push_back(some_motif_locs);
585
586         
587         i_locs = some_motif_locs.begin();
588         while (i_locs != some_motif_locs.end())
589         {
590           cout << *i_locs << " ";
591           ++i_locs;
592         }
593         cout << endl;
594         
595       }
596
597       i->dirty = false;
598     }
599     ++i;
600   }
601 }
602
603
604 void
605 ConnView::spawnSeq()
606 {
607   list<vector<int> > selected_paths;
608   list<vector<int> >::iterator pathz_i;
609   int i2, i3, y_loc, x_loc, x_start, x_end;
610   vector<int> a_path;
611   list<bool>::iterator highlight_i;
612   int y_max;
613   string window_name;
614
615
616   if (selected)
617   {
618     // make new list of connections that are highlighted
619     selected_paths.clear();
620     highlight_i = highlight.begin();
621     for(pathz_i = P->refined_pathz.begin(); pathz_i != P->refined_pathz.end(); ++pathz_i)
622     {
623       if (*highlight_i)
624       {
625         a_path = *pathz_i;
626         selected_paths.push_back(a_path);
627       }
628       ++highlight_i;
629     }
630
631     // give 50 pixels of height per sequence
632     y_max = seq_num * 50;
633     window_name = "Mussa Sequence: " + ana_name;
634
635     a_seq_win = new SeqWindow(800, y_max, (const char*) window_name.c_str(),
636                               seq_num,
637                               S, selected_paths, seq_lens, &some_motifs);
638   }
639 }
640
641
642 void
643 ConnView::find_motifs()
644 {
645   motif_find_window = new MotifWindow(300, 300, "Motifs", &some_motifs);
646 }
647
648 void
649 ConnView::annot_win()
650 {
651   annot_color_window = new AnnotWindow(300, 300, "Annotations", &some_annots);
652 }
653
654 // @!@! special hacked in color coding for the myf5/6 region annots
655
656 /*
657       if (annot_i->type == "mvista")
658       {
659         fl_color(255,230,0);
660         fl_line_style(FL_SOLID, 8, NULL);
661         mv_offset = -4;
662       }
663       else if (annot_i->type == "reg")
664       {
665         fl_line_style(FL_SOLID, 10, NULL);
666         mv_offset = -8;
667
668         if (annot_i->name == "CNS")
669           fl_color(255,150,0);
670         else if (annot_i->name == "ELA")
671           fl_color(0,200,120);
672         else if (annot_i->name == "ES")
673           fl_color(0,200,200);
674         else if (annot_i->name == "NA")
675           fl_color(120,120,120);
676         else if (annot_i->name == "EA")
677         {
678           fl_line_style(FL_SOLID, 7, NULL);
679           mv_offset = -13;
680           fl_color(0,200,120);
681         }
682         else if (annot_i->name == "VS")
683         {
684           fl_line_style(FL_SOLID, 7, NULL);
685           mv_offset = -6;
686           fl_color(255,255,0);
687         }
688         else if (annot_i->name == "SP")
689         {
690           fl_line_style(FL_SOLID, 7, NULL);
691           mv_offset = -13;
692           fl_color(255,230,150);
693         }
694         else if (annot_i->name == "L")
695         {
696           fl_line_style(FL_SOLID, 7, NULL);
697           mv_offset = -6;
698           fl_color(0,0,100);
699         }
700         else if (annot_i->name == "TCM")
701           fl_color(0,130,230);
702       }
703 */