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