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);
126 while (x < eRes - sRes)
129 if (hasHiddenColumns)
131 column = hiddenColumns.visibleToAbsoluteColumn(column);
133 // TODO: highlight columns selected
134 boolean colsel = false;
135 if (columnSelection != null)
137 colsel = columnSelection.contains(column);
145 if (aa_annotations[column] == null)
150 ContactListI contacts = viewport.getContactList(_aa, column);
151 if (contacts == null)
156 // ContactListI from viewport can map column -> group
157 Color gpcol = (cm == null) ? Color.white
158 : contacts.getColourForGroup(); // cm.getColourForGroup(cm.getGroupsFor(column));
159 // feature still in development - highlight or omit regions hidden in
160 // the alignment - currently marks them as red rows
161 boolean maskHiddenCols = false;
162 // TODO: optionally pass visible column mask to the ContactGeometry object
164 // only visible contacts to geometry
165 // Bean holding mapping from contact list to pixels
166 // TODO: allow bracketing/limiting of range on contacts to render (like
167 // visible column mask but more flexible?)
169 // COntactListI provides mapping for column -> cm-groupmapping
170 final ContactGeometry cgeom = new ContactGeometry(contacts,
173 for (int ht = 0, botY = topY
174 - _aa.height; ht < _aa.graphHeight; ht += cgeom.pixels_step)
176 ContactGeometry.contactInterval ci = cgeom.mapFor(ht,
177 ht + cgeom.pixels_step);
178 // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
179 // cend = (int) Math.min(contact_height,
180 // Math.ceil(cstart + contacts_per_pixel * pixels_step));
183 boolean rowsel = false, containsHidden = false;
184 if (columnSelection != null)
186 rowsel = cgeom.intersects(ci, columnSelection, hiddenColumns,
189 // TODO: show selected region
190 if (colsel || rowsel)
193 col = getSelectedColorForRange(min, max, contacts, ci.cStart,
195 if (colsel && rowsel)
197 col = new Color(col.getBlue(), col.getGreen(), col.getRed());
201 col = new Color(col.getBlue(), col.getBlue(), col.getBlue());
206 col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd);
212 if (showGroups && gpcol != null && gpcol != Color.white)
214 // todo - could overlay group as a transparent rectangle ?
216 (int) (((float) (col.getRed() + gpcol.getRed())) / 2f),
217 (int) (((float) (col.getGreen() + gpcol.getGreen()))
219 (int) (((float) (col.getBlue() + gpcol.getBlue())) / 2f));
222 if (cgeom.pixels_step > 1)
224 g.fillRect(x * charWidth, botY+ht, charWidth, 1 + cgeom.pixels_step);
228 g.drawLine(x * charWidth, botY+ht, (x + 1) * charWidth, botY+ht);
236 Color shadeFor(float min, float max, float value)
238 return jalview.util.ColorUtils.getGraduatedColour(value, 0,
239 shade.minColor, max, shade.maxColor);
242 public Color getColorForRange(float min, float max, ContactListI cl,
245 ContactRange cr = cl.getRangeFor(i, j);
246 // average for moment - probably more interested in maxIntProj though
247 return shadeFor(min, max, (float) cr.getMean());
250 public Color getSelectedColorForRange(float min, float max,
251 ContactListI cl, int i, int j)
253 ContactRange cr = cl.getRangeFor(i, j);
254 // average for moment - probably more interested in maxIntProj though
255 return jalview.util.ColorUtils.getGraduatedColour((float) cr.getMean(),
256 0, shade.selMinColor, max, shade.selMaxColor);