58e6ab15002d8bce407c61a9677e4304b2f1d2d0
[jalview.git] / src / jalview / renderer / ContactMapRenderer.java
1 /**
2  * 
3  */
4 package jalview.renderer;
5
6 import java.awt.Color;
7 import java.awt.Graphics;
8
9 import jalview.api.AlignViewportI;
10 import jalview.datamodel.AlignmentAnnotation;
11 import jalview.datamodel.Annotation;
12 import jalview.datamodel.ColumnSelection;
13 import jalview.datamodel.ContactListI;
14 import jalview.datamodel.ContactRange;
15 import jalview.datamodel.HiddenColumns;
16 import jalview.renderer.api.AnnotationRowRendererI;
17
18 /**
19  * @author jprocter
20  *
21  */
22 public class ContactMapRenderer implements AnnotationRowRendererI
23 {
24
25   @Override
26   public void renderRow(Graphics g, int charWidth, int charHeight,
27           boolean hasHiddenColumns, AlignViewportI viewport,
28           HiddenColumns hiddenColumns, ColumnSelection columnSelection,
29           AlignmentAnnotation _aa, Annotation[] aa_annotations, int sRes,
30           int eRes, float min, float max, int y)
31   {
32     if (sRes > aa_annotations.length)
33     {
34       return;
35     }
36     eRes = Math.min(eRes, aa_annotations.length);
37
38     int x = 0, y2 = y;
39
40     g.setColor(Color.pink);
41
42     g.drawLine(x, y2, (eRes - sRes) * charWidth, y2);
43
44     int column;
45     int aaMax = aa_annotations.length - 1;
46     while (x < eRes - sRes)
47     {
48       column = sRes + x;
49       if (hasHiddenColumns)
50       {
51         column = hiddenColumns.visibleToAbsoluteColumn(column);
52       }
53       // TODO: highlight columns selected
54       boolean colsel = false;
55       if (columnSelection != null)
56       {
57         colsel = columnSelection.contains(column);
58       }
59
60       if (column > aaMax)
61       {
62         break;
63       }
64
65       if (aa_annotations[column] == null)
66       {
67         x++;
68         continue;
69       }
70       ContactListI contacts = viewport.getContactList(_aa, column);
71       if (contacts == null)
72       {
73         x++;
74         continue;
75       }
76       // Bean holding mapping from contact list to pixels
77       final ContactGeometry cgeom = new ContactGeometry(contacts,
78               _aa.graphHeight);
79
80       for (int ht = y2, eht = y2
81               - _aa.graphHeight; ht >= eht; ht -= cgeom.pixels_step)
82       {
83         ContactGeometry.contactInterval ci = cgeom.mapFor(y2 - ht,
84                 y2 - ht + cgeom.pixels_step);
85         // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
86         // cend = (int) Math.min(contact_height,
87         // Math.ceil(cstart + contacts_per_pixel * pixels_step));
88
89         // TODO show maximum colour for range - sort of done
90         // also need a 'getMaxPosForRange(start,end)' to accurately render
91         Color col;
92         boolean rowsel = false;
93         if (columnSelection != null)
94         {
95           if (_aa.sequenceRef == null)
96           {
97             rowsel = columnSelection.intersects(ci.cStart, ci.cEnd);
98           }
99           else
100           {
101             // TODO check we have correctly mapped cstart to local sequence
102             // numbering
103             int s = _aa.sequenceRef.findIndex(ci.cStart);
104             int e = _aa.sequenceRef.findIndex(ci.cEnd);
105             if (s > 0 && s < _aa.sequenceRef.getLength())
106             {
107               rowsel = columnSelection.intersects(s, e);
108             }
109           }
110         }
111         // TODO: show selected region
112         if (colsel || rowsel)
113         {
114
115           col = getSelectedColorForRange(min, max, contacts, ci.cStart,
116                   ci.cEnd);
117           if (colsel && rowsel)
118           {
119             col = new Color(col.getBlue(), col.getGreen(), col.getRed());
120           }
121           else
122           {
123             col = new Color(col.getBlue(), col.getBlue(), col.getBlue());
124           }
125           g.setColor(col);
126         }
127         else
128         {
129           col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd);
130           g.setColor(col);
131         }
132         if (cgeom.pixels_step > 1)
133         {
134           g.fillRect(x * charWidth, ht, charWidth, 1 + cgeom.pixels_step);
135         }
136         else
137         {
138           g.drawLine(x * charWidth, ht, (x + 1) * charWidth, ht);
139         }
140       }
141       x++;
142     }
143
144   }
145
146   // Shading parameters
147   // currently hardwired for alphafold
148   Color maxColor = new Color(246, 252, 243),
149           minColor = new Color(0, 60, 26),
150           selMinColor = new Color(26, 0, 60),
151           selMaxColor = new Color(243, 246, 252);
152
153   Color shadeFor(float min, float max, float value)
154   {
155     return jalview.util.ColorUtils.getGraduatedColour(value, 0, minColor,
156             max, maxColor);
157   }
158
159   public Color getColorForRange(float min, float max, ContactListI cl,
160           int i, int j)
161   {
162     ContactRange cr = cl.getRangeFor(i, j);
163     // average for moment - probably more interested in maxIntProj though
164     return shadeFor(min, max, (float) cr.getMean());
165   }
166
167   public Color getSelectedColorForRange(float min, float max,
168           ContactListI cl, int i, int j)
169   {
170     ContactRange cr = cl.getRangeFor(i, j);
171     // average for moment - probably more interested in maxIntProj though
172     return jalview.util.ColorUtils.getGraduatedColour((float) cr.getMean(),
173             0, selMinColor, max, selMaxColor);
174   }
175
176 }