4 package jalview.renderer;
7 import java.awt.Graphics;
8 import java.util.Iterator;
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.ContactMatrixI;
16 import jalview.datamodel.ContactRange;
17 import jalview.datamodel.HiddenColumns;
18 import jalview.renderer.api.AnnotationRowRendererI;
24 public abstract class ContactMapRenderer implements AnnotationRowRendererI
27 * bean holding colours for shading
35 * shown when no data available from map
39 * shown for region not currently visible - should normally not see this
43 * linear shading scheme min/max
45 Color maxColor, minColor;
48 * linear shading scheme min/max for selected region
50 Color selMinColor, selMaxColor;
52 public Shading(Color no_data, Color hidden, Color maxColor,
53 Color minColor, Color selMinColor, Color selMaxColor)
56 this.no_data = no_data;
58 this.maxColor = maxColor;
59 this.minColor = minColor;
60 this.selMinColor = selMinColor;
61 this.selMaxColor = selMaxColor;
69 * build an EBI-AlphaFold style renderer of PAE matrices
73 public static ContactMapRenderer newPAERenderer()
75 return new ContactMapRenderer()
78 public Shading getShade()
80 return new Shading(Color.pink, Color.red,
82 new Color(246, 252, 243), new Color(0, 60, 26),
83 new Color(26, 0, 60), new Color(243, 246, 252));
90 * @return instance of Shading used to initialise the renderer
92 public abstract Shading getShade();
94 public ContactMapRenderer()
96 this.shade = getShade();
100 public void renderRow(Graphics g, int charWidth, int charHeight,
101 boolean hasHiddenColumns, AlignViewportI viewport,
102 HiddenColumns hiddenColumns, ColumnSelection columnSelection,
103 AlignmentAnnotation _aa, Annotation[] aa_annotations, int sRes,
104 int eRes, float min, float max, int y)
106 if (sRes > aa_annotations.length)
110 eRes = Math.min(eRes, aa_annotations.length);
114 // uncomment below to render whole area of matrix as pink
115 // g.setColor(shade.no_data);
116 // g.fillRect(x, topY-_aa.height, (eRes - sRes) * charWidth, _aa.graphHeight);
118 boolean showGroups = _aa.isShowGroupsForContactMatrix();
120 int aaMax = aa_annotations.length - 1;
121 ContactMatrixI cm = viewport.getContactMatrix(_aa);
122 while (x < eRes - sRes)
125 if (hasHiddenColumns)
127 column = hiddenColumns.visibleToAbsoluteColumn(column);
129 // TODO: highlight columns selected
130 boolean colsel = false;
131 if (columnSelection != null)
133 colsel = columnSelection.contains(column);
141 if (aa_annotations[column] == null)
146 ContactListI contacts = viewport.getContactList(_aa, column);
147 if (contacts == null)
152 // ContactListI from viewport can map column -> group
153 Color gpcol = (cm == null) ? Color.white
154 : contacts.getColourForGroup(); // cm.getColourForGroup(cm.getGroupsFor(column));
155 // feature still in development - highlight or omit regions hidden in
156 // the alignment - currently marks them as red rows
157 boolean maskHiddenCols = false;
158 // TODO: optionally pass visible column mask to the ContactGeometry object
160 // only visible contacts to geometry
161 // Bean holding mapping from contact list to pixels
162 // TODO: allow bracketing/limiting of range on contacts to render (like
163 // visible column mask but more flexible?)
165 // COntactListI provides mapping for column -> cm-groupmapping
166 final ContactGeometry cgeom = new ContactGeometry(contacts,
169 for (int ht = 0, botY = topY
170 - _aa.height; ht < _aa.graphHeight; ht += cgeom.pixels_step)
172 ContactGeometry.contactInterval ci = cgeom.mapFor(ht,
173 ht + cgeom.pixels_step);
174 // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
175 // cend = (int) Math.min(contact_height,
176 // Math.ceil(cstart + contacts_per_pixel * pixels_step));
179 boolean rowsel = false, containsHidden = false;
180 if (columnSelection != null)
182 rowsel = cgeom.intersects(ci, columnSelection, hiddenColumns,
185 // TODO: show selected region
186 if (colsel || rowsel)
189 col = getSelectedColorForRange(min, max, contacts, ci.cStart,
191 if (colsel && rowsel)
193 col = new Color(col.getBlue(), col.getGreen(), col.getRed());
197 col = new Color(col.getBlue(), col.getBlue(), col.getBlue());
202 col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd);
208 if (showGroups && gpcol != null && gpcol != Color.white)
210 // todo - could overlay group as a transparent rectangle ?
212 (int) (((float) (col.getRed() + gpcol.getRed())) / 2f),
213 (int) (((float) (col.getGreen() + gpcol.getGreen()))
215 (int) (((float) (col.getBlue() + gpcol.getBlue())) / 2f));
218 if (cgeom.pixels_step > 1)
220 g.fillRect(x * charWidth, botY+ht, charWidth, 1 + cgeom.pixels_step);
224 g.drawLine(x * charWidth, botY+ht, (x + 1) * charWidth, botY+ht);
232 Color shadeFor(float min, float max, float value)
234 return jalview.util.ColorUtils.getGraduatedColour(value, 0,
235 shade.minColor, max, shade.maxColor);
238 public Color getColorForRange(float min, float max, ContactListI cl,
241 ContactRange cr = cl.getRangeFor(i, j);
242 // average for moment - probably more interested in maxIntProj though
243 return shadeFor(min, max, (float) cr.getMean());
246 public Color getSelectedColorForRange(float min, float max,
247 ContactListI cl, int i, int j)
249 ContactRange cr = cl.getRangeFor(i, j);
250 // average for moment - probably more interested in maxIntProj though
251 return jalview.util.ColorUtils.getGraduatedColour((float) cr.getMean(),
252 0, shade.selMinColor, max, shade.selMaxColor);