Use annotation colour for graph
[jalview.git] / src / jalview / appletgui / AnnotationPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 import jalview.datamodel.*;\r
28 \r
29 public class AnnotationPanel\r
30     extends Panel implements AdjustmentListener\r
31 {\r
32   AlignViewport av;\r
33   AlignmentPanel ap;\r
34   int activeRow = -1;\r
35 \r
36   Vector activeRes;\r
37   static String HELIX = "Helix";\r
38   static String SHEET = "Sheet";\r
39   static String LABEL = "Label";\r
40   static String REMOVE = "Remove Annotation";\r
41   static String COLOUR = "Colour";\r
42   static Color HELIX_COLOUR = Color.red.darker();\r
43   static Color SHEET_COLOUR = Color.green.darker().darker();\r
44 \r
45   Image image;\r
46   Graphics gg;\r
47   FontMetrics fm;\r
48   int imgWidth = 0;\r
49 \r
50   boolean fastPaint = false;\r
51 \r
52   public static int GRAPH_HEIGHT = 40;\r
53 \r
54   public AnnotationPanel(AlignmentPanel ap)\r
55   {\r
56     this.ap = ap;\r
57     av = ap.av;\r
58     this.setLayout(null);\r
59     adjustPanelHeight();\r
60 \r
61     addMouseMotionListener(new MouseMotionAdapter()\r
62     {\r
63       public void mouseMoved(MouseEvent evt)\r
64       {\r
65         doMouseMoved(evt);\r
66       }\r
67     });\r
68 \r
69     // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );\r
70   }\r
71 \r
72 \r
73   public AnnotationPanel(AlignViewport av)\r
74   {\r
75     this.av = av;\r
76   }\r
77 \r
78 \r
79   public void adjustmentValueChanged(AdjustmentEvent evt)\r
80   {\r
81     ap.alabels.setScrollOffset( -evt.getValue());\r
82   }\r
83 \r
84   public int adjustPanelHeight()\r
85   {\r
86     // setHeight of panels\r
87     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
88 \r
89 \r
90     int height = 0;\r
91     if (aa != null)\r
92     {\r
93       for (int i = 0; i < aa.length; i++)\r
94       {\r
95         if (!aa[i].visible)\r
96         {\r
97           continue;\r
98         }\r
99 \r
100         aa[i].height = 0;\r
101 \r
102         if (aa[i].hasText)\r
103         {\r
104           aa[i].height += av.charHeight;\r
105         }\r
106         if (aa[i].hasIcons)\r
107         {\r
108           aa[i].height += 16;\r
109         }\r
110 \r
111         if (aa[i].graph>0)\r
112         {\r
113           aa[i].height += GRAPH_HEIGHT;\r
114         }\r
115 \r
116         if (aa[i].height == 0)\r
117         {\r
118           aa[i].height = 20;\r
119         }\r
120         height += aa[i].height;\r
121       }\r
122     }\r
123     else\r
124     {\r
125       height = 20;\r
126     }\r
127 \r
128     this.setSize(getSize().width, height);\r
129     if(ap!=null)\r
130        ap.annotationScroller.setSize(getSize().width, height);\r
131 \r
132 \r
133     repaint();\r
134 \r
135     return height;\r
136 \r
137   }\r
138 \r
139   public void addEditableColumn(int i)\r
140   {\r
141     if (activeRow == -1)\r
142     {\r
143       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
144       if(aa ==null)\r
145         return;\r
146 \r
147       for (int j = 0; j < aa.length; j++)\r
148       {\r
149         if (aa[j].editable)\r
150         {\r
151           activeRow = j;\r
152           break;\r
153         }\r
154       }\r
155     }\r
156 \r
157     if (activeRes == null)\r
158     {\r
159       activeRes = new Vector();\r
160       activeRes.addElement(String.valueOf(i));\r
161       return;\r
162     }\r
163 \r
164     activeRes.addElement(String.valueOf(i));\r
165   }\r
166 \r
167   public void doMouseMoved(MouseEvent evt)\r
168   {\r
169     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
170     if (aa == null)\r
171     {\r
172       return;\r
173     }\r
174 \r
175     int row = -1;\r
176     int height = 0;\r
177     for (int i = 0; i < aa.length; i++)\r
178     {\r
179 \r
180       if (aa[i].visible)\r
181       {\r
182         height += aa[i].height;\r
183       }\r
184 \r
185       if (evt.getY() < height)\r
186       {\r
187         row = i;\r
188         break;\r
189       }\r
190     }\r
191 \r
192     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
193     if (row > -1 && res < aa[row].annotations.length && aa[row].annotations[res] != null)\r
194     {\r
195       StringBuffer text = new StringBuffer("Sequence position " + (res + 1) +\r
196                                            "  " +\r
197                                            aa[row].annotations[res].description);\r
198       ap.alignFrame.statusBar.setText(text.toString());\r
199     }\r
200   }\r
201 \r
202   public void update(Graphics g)\r
203   {\r
204     paint(g);\r
205   }\r
206 \r
207   public void paint(Graphics g)\r
208   {\r
209     g.setColor(Color.white);\r
210     g.fillRect(0,0, getSize().width, getSize().height);\r
211     imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
212 \r
213     if (image == null || imgWidth != image.getWidth(this))\r
214     {\r
215       image = createImage(imgWidth, ap.annotationPanel.getSize().height);\r
216       gg = image.getGraphics();\r
217       gg.setFont(av.getFont());\r
218       fm = gg.getFontMetrics();\r
219       fastPaint = false;\r
220     }\r
221 \r
222     if (fastPaint)\r
223     {\r
224       g.drawImage(image, 0, 0, this);\r
225       fastPaint = false;\r
226       return;\r
227     }\r
228 \r
229     drawComponent(gg, av.startRes, av.endRes + 1);\r
230     g.drawImage(image, 0, 0, this);\r
231   }\r
232 \r
233   public void fastPaint(int horizontal)\r
234   {\r
235     if (horizontal == 0\r
236         || av.alignment.getAlignmentAnnotation() == null\r
237         || av.alignment.getAlignmentAnnotation().length < 1\r
238         )\r
239     {\r
240       repaint();\r
241       return;\r
242     }\r
243 \r
244     gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.charWidth, 0);\r
245     int sr = av.startRes, er = av.endRes + 1, transX = 0;\r
246 \r
247     if (horizontal > 0) // scrollbar pulled right, image to the left\r
248     {\r
249       transX = (er - sr - horizontal) * av.charWidth;\r
250       sr = er - horizontal;\r
251     }\r
252     else if (horizontal < 0)\r
253     {\r
254       er = sr - horizontal;\r
255     }\r
256 \r
257     gg.translate(transX, 0);\r
258 \r
259     drawComponent(gg, sr, er);\r
260 \r
261     gg.translate( -transX, 0);\r
262 \r
263     fastPaint = true;\r
264     repaint();\r
265   }\r
266 \r
267   /**\r
268    * DOCUMENT ME!\r
269    *\r
270    * @param g DOCUMENT ME!\r
271    * @param startRes DOCUMENT ME!\r
272    * @param endRes DOCUMENT ME!\r
273    */\r
274   public void drawComponent(Graphics g, int startRes, int endRes)\r
275   {\r
276     g.setFont(av.getFont());\r
277 \r
278     if (fm == null)\r
279       fm = g.getFontMetrics();\r
280 \r
281 \r
282       g.setColor(Color.white);\r
283       g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);\r
284 \r
285       if ((av.alignment.getAlignmentAnnotation() == null) ||\r
286               (av.alignment.getAlignmentAnnotation().length < 1))\r
287       {\r
288           g.setColor(Color.white);\r
289           g.fillRect(0, 0, getSize().width, getSize().height);\r
290           g.setColor(Color.black);\r
291           g.drawString("Alignment has no annotations", 20, 15);\r
292 \r
293           return;\r
294       }\r
295 \r
296       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
297 \r
298       int j;\r
299       int x = 0;\r
300       int y = 0;\r
301       char[] lastSS = new char[aa.length];\r
302       int[] lastSSX = new int[aa.length];\r
303       int iconOffset = av.charHeight / 2;\r
304       boolean validRes = false;\r
305 \r
306       boolean [] graphGroupDrawn = new boolean[aa.length];\r
307 \r
308 \r
309       //\u03B2 \u03B1\r
310       for (int i = 0; i < aa.length; i++)\r
311       {\r
312           AlignmentAnnotation row = aa[i];\r
313 \r
314           if (!row.visible)\r
315           {\r
316               continue;\r
317           }\r
318 \r
319 \r
320 \r
321           if (row.graph>0)\r
322           {\r
323               if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
324                 continue;\r
325 \r
326               // this is so that we draw the characters below the graph\r
327               y += row.height;\r
328 \r
329               if (row.hasText)\r
330               {\r
331                   y -= av.charHeight;\r
332               }\r
333           }\r
334 \r
335           if (row.hasText)\r
336           {\r
337               iconOffset = av.charHeight / 2;\r
338           }\r
339           else\r
340           {\r
341               iconOffset = 0;\r
342           }\r
343 \r
344           for (j = startRes; j < endRes; j++)\r
345           {\r
346               if ((row.annotations.length <= j) ||\r
347                       (row.annotations[j] == null))\r
348               {\r
349                   validRes = false;\r
350               }\r
351               else\r
352               {\r
353                   validRes = true;\r
354               }\r
355 \r
356               x = (j - startRes) * av.charWidth;\r
357 \r
358               if (activeRow == i)\r
359               {\r
360                   g.setColor(Color.red);\r
361 \r
362                   if (activeRes != null)\r
363                   {\r
364                       for (int n = 0; n < activeRes.size(); n++)\r
365                       {\r
366                           int v = Integer.parseInt(activeRes.elementAt(n).toString());\r
367 \r
368                           if (v == j)\r
369                           {\r
370                               g.fillRect((j - startRes) * av.charWidth, y,\r
371                                   av.charWidth, row.height);\r
372                           }\r
373                       }\r
374                   }\r
375               }\r
376 \r
377               if (validRes &&\r
378                       (row.annotations[j].displayCharacter.length() > 0))\r
379               {\r
380 \r
381                   int charOffset = (av.charWidth -\r
382                       fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
383                               0))) / 2;\r
384                   g.setColor(row.annotations[j].colour);\r
385 \r
386                   if (j == 0 || row.graph>0)\r
387                   {\r
388                       g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
389                           y + iconOffset + 3);\r
390                   }\r
391                   else if (((row.annotations[j - 1] == null) ||\r
392                           (row.annotations[j].displayCharacter != row.annotations[j -\r
393                           1].displayCharacter)))\r
394                   {\r
395                       g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
396                           y + iconOffset + 3);\r
397                   }\r
398               }\r
399 \r
400               if (row.hasIcons)\r
401               {\r
402                   if (!validRes ||\r
403                           (row.annotations[j].secondaryStructure != lastSS[i]))\r
404                   {\r
405                       switch (lastSS[i])\r
406                       {\r
407                       case 'H':\r
408                           g.setColor(HELIX_COLOUR);\r
409                           g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
410                               x - lastSSX[i], 7, 8, 8);\r
411 \r
412                           break;\r
413 \r
414                       case 'E':\r
415                           g.setColor(SHEET_COLOUR);\r
416                           g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
417                               x - lastSSX[i] - 4, 7);\r
418                           g.fillPolygon(new int[] { x - 4, x - 4, x },\r
419                               new int[]\r
420                               {\r
421                                   y + iconOffset, y + 14 + iconOffset,\r
422                                   y + 8 + iconOffset\r
423                               }, 3);\r
424 \r
425                           break;\r
426 \r
427 \r
428                       default:\r
429                           g.setColor(Color.gray);\r
430                           g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
431                               x - lastSSX[i], 2);\r
432 \r
433                           break;\r
434                       }\r
435 \r
436                       if (validRes)\r
437                       {\r
438                           lastSS[i] = row.annotations[j].secondaryStructure;\r
439                       }\r
440                       else\r
441                       {\r
442                           lastSS[i] = ' ';\r
443                       }\r
444 \r
445                       lastSSX[i] = x;\r
446                   }\r
447               }\r
448           }\r
449 \r
450           x += av.charWidth;\r
451 \r
452           if (row.hasIcons)\r
453           {\r
454               switch (lastSS[i])\r
455               {\r
456               case 'H':\r
457                   g.setColor(HELIX_COLOUR);\r
458                   g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
459                       x - lastSSX[i], 7, 8, 8);\r
460 \r
461                   break;\r
462 \r
463               case 'E':\r
464                   g.setColor(SHEET_COLOUR);\r
465 \r
466                   if (row.annotations.length > endRes\r
467                       && row.annotations[endRes].secondaryStructure != 'E')\r
468                   {\r
469                     g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
470                                x - lastSSX[i] - 4, 7);\r
471                     g.fillPolygon(new int[]\r
472                                   {x - 4, x - 4, x},\r
473                                   new int[]\r
474                                   {\r
475                                   y + iconOffset, y + 14 + iconOffset,\r
476                                   y + 7 + iconOffset\r
477                     }, 3);\r
478                   }\r
479                   else\r
480                     g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
481                                x - lastSSX[i], 7);\r
482 \r
483                   break;\r
484 \r
485               case 'C':\r
486                   break;\r
487 \r
488               default:\r
489                   g.setColor(Color.gray);\r
490                   g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
491 \r
492                   break;\r
493               }\r
494           }\r
495 \r
496           if (row.graph>0)\r
497           {\r
498               if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
499               {\r
500                 if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
501                  {\r
502                    float groupmax=-999999, groupmin=9999999;\r
503                    for(int gg=0; gg<aa.length; gg++)\r
504                    {\r
505                      if(aa[gg].graphGroup!=row.graphGroup)\r
506                        continue;\r
507 \r
508                      if(aa[gg]!=row)\r
509                        aa[gg].visible = false;\r
510 \r
511                      if(aa[gg].graphMax>groupmax)\r
512                        groupmax = aa[gg].graphMax;\r
513                      if(aa[gg].graphMin<groupmin)\r
514                        groupmin = aa[gg].graphMin;\r
515                    }\r
516 \r
517                    for (int gg = 0; gg < aa.length; gg++)\r
518                    {\r
519                      if (aa[gg].graphGroup == row.graphGroup)\r
520                      {\r
521                        drawLineGraph(g, aa[gg], startRes, endRes, y,\r
522                                      groupmin, groupmax,\r
523                                      row.graphHeight);\r
524                      }\r
525                    }\r
526 \r
527                    graphGroupDrawn[ row.graphGroup ] = true;\r
528                  }\r
529                  else\r
530                    drawLineGraph(g, row, startRes, endRes,\r
531                                  y, row.graphMin, row.graphMax, row.graphHeight  );\r
532               }\r
533               else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
534                  drawBarGraph(g, row, startRes, endRes,\r
535                               row.graphMin, row.graphMax, y);\r
536           }\r
537 \r
538           if (row.graph>0 && row.hasText)\r
539           {\r
540               y += av.charHeight;\r
541           }\r
542 \r
543           if (row.graph==0)\r
544           {\r
545               y += aa[i].height;\r
546           }\r
547       }\r
548   }\r
549 \r
550   public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
551                             int sRes, int eRes,\r
552                             int y,\r
553                             float min, float max,\r
554                             int graphHeight)\r
555   {\r
556     if(sRes>aa.annotations.length)\r
557       return;\r
558 \r
559     int x = 0;\r
560 \r
561     //Adjustment for fastpaint to left\r
562     if(eRes<av.endRes)\r
563       eRes++;\r
564 \r
565     if(sRes==0)\r
566     {\r
567       sRes++;\r
568       x+=av.charWidth;\r
569     }\r
570 \r
571     int y1=y, y2=y;\r
572     float range = max - min;\r
573 \r
574     ////Draw origin\r
575     if(min<0)\r
576       y2 = (int)(y - (0-min / range)*graphHeight);\r
577 \r
578     g.setColor(Color.gray);\r
579     g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
580 \r
581 \r
582     if(aa.threshold!=null)\r
583     {\r
584         g.setColor(aa.threshold.colour);\r
585         y2 = (int)(y - ((aa.threshold.value-min) / range)*graphHeight);\r
586         g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
587     }\r
588 \r
589     eRes = Math.min(eRes, aa.annotations.length);\r
590     for (int j = sRes; j < eRes; j++)\r
591     {\r
592       if(aa.annotations[j]==null || aa.annotations[j-1]==null)\r
593       {\r
594         x+=av.charWidth;\r
595         continue;\r
596       }\r
597         g.setColor(aa.annotations[j].colour);\r
598         y1 = y - (int) (((aa.annotations[j-1].value-min) / range) * graphHeight);\r
599         y2 = y - (int) (((aa.annotations[j].value-min) / range) * graphHeight);\r
600         g.drawLine(x-av.charWidth/2, y1, x+av.charWidth/2, y2);\r
601         x += av.charWidth;\r
602      }\r
603   }\r
604 \r
605   public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
606                            int sRes, int eRes,\r
607                            float min, float max,\r
608                            int y)\r
609   {\r
610     if(sRes>aa.annotations.length)\r
611       return;\r
612 \r
613     int x=0, y1, y2;\r
614 \r
615     float range = max - min;\r
616 \r
617     if(aa.threshold!=null)\r
618     {\r
619         g.setColor(aa.threshold.colour);\r
620         y2 = (int)(y - ((aa.threshold.value-min) / range)*aa.graphHeight);\r
621         g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
622     }\r
623 \r
624     y1 = y2 = y;\r
625 \r
626     if(min<0)\r
627       y2 = (int)(y - (0-min / (range))*aa.graphHeight);\r
628 \r
629     g.setColor(Color.gray);\r
630 \r
631     g.drawLine(x,y2,(eRes-sRes+1)*av.charWidth,y2);\r
632 \r
633     eRes = Math.min(eRes, aa.annotations.length-1);\r
634 \r
635 \r
636     for (int j = sRes; j < eRes; j++)\r
637     {\r
638 \r
639       if (aa.annotations[j] == null)\r
640       {\r
641         x += av.charWidth;\r
642         continue;\r
643       }\r
644 \r
645         g.setColor(aa.annotations[j].colour);\r
646         y1 = y - (int) (((aa.annotations[j].value-min) / (range)) * aa.graphHeight);\r
647 \r
648         if(y1-y2>0)\r
649           g.fillRect(x, y2, av.charWidth, y1-y2 );\r
650         else\r
651           g.fillRect(x, y1, av.charWidth, y2-y1 );\r
652 \r
653         x += av.charWidth;\r
654     }\r
655 \r
656   }\r
657 \r
658   // used by overview window\r
659   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
660   {\r
661       g.setColor(Color.white);\r
662       g.fillRect(0, 0, width, y);\r
663       g.setColor(new Color(0, 0, 180));\r
664 \r
665       int x = 0, height;\r
666 \r
667       for (int j = sRes; j < eRes; j++)\r
668       {\r
669           g.setColor(aa.annotations[j].colour);\r
670 \r
671           height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
672           if(height>y)\r
673               height = y;\r
674           g.fillRect(x, y - height, av.charWidth, height);\r
675           x += av.charWidth;\r
676       }\r
677     }\r
678 }\r