2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.renderer;
23 import java.awt.BasicStroke;
24 import java.awt.Color;
25 import java.awt.Graphics;
26 import java.awt.Graphics2D;
27 import java.awt.Stroke;
29 import jalview.api.AlignViewportI;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.Annotation;
32 import jalview.datamodel.ColumnSelection;
33 import jalview.datamodel.ContactListI;
34 import jalview.datamodel.ContactMatrixI;
35 import jalview.datamodel.ContactRange;
36 import jalview.datamodel.HiddenColumns;
37 import jalview.renderer.api.AnnotationRowRendererI;
43 public abstract class ContactMapRenderer implements AnnotationRowRendererI
46 * bean holding colours for shading
54 * shown when no data available from map
59 * shown for region not currently visible - should normally not see this
64 * linear shading scheme min/max
66 Color maxColor, minColor;
69 * linear shading scheme min/max for selected region
71 Color selMinColor, selMaxColor;
76 * - colour when no data available
78 * - colour if this row is hidden
80 * - colour for maximum value of contact
82 * - colour for minimum value of contact
84 * - min colour if the contact has been selected
86 * - max colour if contact is selected
88 public Shading(Color no_data, Color hidden, Color maxColor,
89 Color minColor, Color selMinColor, Color selMaxColor)
92 this.no_data = no_data;
94 this.maxColor = maxColor;
95 this.minColor = minColor;
96 this.selMinColor = selMinColor;
97 this.selMaxColor = selMaxColor;
105 * build an EBI-AlphaFold style renderer of PAE matrices
109 public static ContactMapRenderer newPAERenderer()
111 return new ContactMapRenderer()
114 public Shading getShade()
116 return new Shading(Color.pink, Color.red,
118 new Color(247, 252, 245), new Color(0, 68, 28),
119 new Color(28, 0, 68), new Color(245, 247, 252));
126 * @return instance of Shading used to initialise the renderer
128 public abstract Shading getShade();
130 public ContactMapRenderer()
132 this.shade = getShade();
136 public void renderRow(Graphics g, int charWidth, int charHeight,
137 boolean hasHiddenColumns, AlignViewportI viewport,
138 HiddenColumns hiddenColumns, ColumnSelection columnSelection,
139 AlignmentAnnotation _aa, Annotation[] aa_annotations, int sRes,
140 int eRes, float min, float max, int y, boolean isVectorRendering)
142 if (sRes > aa_annotations.length)
146 eRes = Math.min(eRes, aa_annotations.length);
150 // uncomment below to render whole area of matrix as pink
151 // g.setColor(shade.no_data);
152 // g.fillRect(x, topY-_aa.height, (eRes - sRes) * charWidth,
155 boolean showGroups = _aa.isShowGroupsForContactMatrix();
157 int aaMax = aa_annotations.length - 1;
158 ContactMatrixI cm = viewport.getContactMatrix(_aa);
163 Graphics2D g2d = (Graphics2D) g;
164 // Not sure turning off antialiasing is appropriate here
165 // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
166 // RenderingHints.VALUE_ANTIALIAS_OFF);
167 g2d.setStroke(thinRectangularLineStroke);
168 while (x < eRes - sRes)
171 if (hasHiddenColumns)
173 column = hiddenColumns.visibleToAbsoluteColumn(column);
175 // TODO: highlight columns selected
176 boolean colsel = false;
177 if (columnSelection != null)
179 colsel = columnSelection.contains(column);
187 if (aa_annotations[column] == null)
192 ContactListI contacts = viewport.getContactList(_aa, column);
193 if (contacts == null)
198 // ContactListI from viewport can map column -> group
199 Color gpcol = (cm == null) ? Color.white
200 : contacts.getColourForGroup(); // cm.getColourForGroup(cm.getGroupsFor(column));
201 // feature still in development - highlight or omit regions hidden in
202 // the alignment - currently marks them as red rows
203 boolean maskHiddenCols = false;
204 // TODO: optionally pass visible column mask to the ContactGeometry object
206 // only visible contacts to geometry
207 // Bean holding mapping from contact list to pixels
208 // TODO: allow bracketing/limiting of range on contacts to render (like
209 // visible column mask but more flexible?)
211 // COntactListI provides mapping for column -> cm-groupmapping
212 final ContactGeometry cgeom = new ContactGeometry(contacts,
215 for (int ht = 0, botY = topY
216 - _aa.height; ht < _aa.graphHeight; ht += cgeom.pixels_step)
218 ContactGeometry.contactInterval ci = cgeom.mapFor(ht);
219 // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
220 // cend = (int) Math.min(contact_height,
221 // Math.ceil(cstart + contacts_per_pixel * pixels_step));
224 boolean rowsel = false;
225 boolean containsHidden = false;
226 if (columnSelection != null)
228 rowsel = cgeom.intersects(ci, columnSelection, hiddenColumns,
231 // TODO: show selected region
232 if (colsel || rowsel)
235 col = getSelectedColorForRange(min, max, contacts, ci.cStart,
237 if (colsel && rowsel)
239 col = new Color(col.getBlue(), col.getGreen(), col.getRed());
243 col = new Color(col.getBlue(), col.getBlue(), col.getBlue());
248 col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd);
254 if (showGroups && gpcol != null && gpcol != Color.white)
256 // todo - could overlay group as a transparent rectangle ?
257 col = new Color((int) ((col.getRed() + gpcol.getRed()) / 2f),
258 (int) ((col.getGreen() + gpcol.getGreen()) / 2f),
259 (int) ((col.getBlue() + gpcol.getBlue()) / 2f));
262 if (isVectorRendering || cgeom.pixels_step > 1)
264 g2d.fillRect(x * charWidth, botY + ht, charWidth,
269 g2d.drawLine(x * charWidth, botY + ht, (x + 1) * charWidth - 1,
278 private static Stroke thinRectangularLineStroke = new BasicStroke(1,
279 BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
281 Color shadeFor(float min, float max, float value)
283 return jalview.util.ColorUtils.getGraduatedColour(value, 0,
284 shade.minColor, max, shade.maxColor);
287 public Color getColorForRange(float min, float max, ContactListI cl,
290 ContactRange cr = cl.getRangeFor(i, j);
291 // average for moment - probably more interested in maxIntProj though
292 return shadeFor(min, max, (float) cr.getMean());
295 public Color getSelectedColorForRange(float min, float max,
296 ContactListI cl, int i, int j)
298 ContactRange cr = cl.getRangeFor(i, j);
299 // average for moment - probably more interested in maxIntProj though
300 return jalview.util.ColorUtils.getGraduatedColour((float) cr.getMin(),
301 0, shade.selMinColor, max, shade.selMaxColor);