X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Frenderer%2FContactMapRenderer.java;h=a8f6c1b0644fbf4d2c5a1c96d0a7e6675cb8747f;hb=beb2fee66dde629e3bbb7febb38d0116e1a64df2;hp=313e3dbe07100eb921ed48a9ef30961a7f293761;hpb=6ac2062a667090f8e83082ba1ad2763b1b92c0e1;p=jalview.git diff --git a/src/jalview/renderer/ContactMapRenderer.java b/src/jalview/renderer/ContactMapRenderer.java index 313e3db..a8f6c1b 100644 --- a/src/jalview/renderer/ContactMapRenderer.java +++ b/src/jalview/renderer/ContactMapRenderer.java @@ -3,62 +3,133 @@ */ package jalview.renderer; +import java.awt.Color; +import java.awt.Graphics; +import java.util.Iterator; + import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.ContactListI; +import jalview.datamodel.ContactMatrixI; +import jalview.datamodel.ContactRange; +import jalview.datamodel.HiddenColumns; import jalview.renderer.api.AnnotationRowRendererI; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; - /** * @author jprocter * */ -public class ContactMapRenderer implements AnnotationRowRendererI +public abstract class ContactMapRenderer implements AnnotationRowRendererI { - /* + /** + * bean holding colours for shading * - * // TODO Auto-generated method stub - void drawProfileDensity(Graphics g, AlignmentAnnotation _aa, - Annotation[] aa_annotations, int sRes, int eRes, float min, - float max, int y) - { + * @author jprocter + * + */ + public class Shading + { + /** + * shown when no data available from map + */ + Color no_data; + /** + * shown for region not currently visible - should normally not see this + */ + Color hidden; + /** + * linear shading scheme min/max + */ + Color maxColor, minColor; + + /** + * linear shading scheme min/max for selected region + */ + Color selMinColor, selMaxColor; + + public Shading(Color no_data, Color hidden, Color maxColor, + Color minColor, Color selMinColor, Color selMaxColor) + { + super(); + this.no_data = no_data; + this.hidden = hidden; + this.maxColor = maxColor; + this.minColor = minColor; + this.selMinColor = selMinColor; + this.selMaxColor = selMaxColor; + } + + } + + final Shading shade; + /** + * build an EBI-AlphaFold style renderer of PAE matrices * + * @return + */ + public static ContactMapRenderer newPAERenderer() + { + return new ContactMapRenderer() + { + @Override + public Shading getShade() + { + return new Shading(Color.pink, Color.red, + + new Color(246, 252, 243), new Color(0, 60, 26), + new Color(26, 0, 60), new Color(243, 246, 252)); + } + }; + } + + /** * + * @return instance of Shading used to initialise the renderer */ + public abstract Shading getShade(); + + public ContactMapRenderer() + { + this.shade = getShade(); + } + @Override public void renderRow(Graphics g, int charWidth, int charHeight, boolean hasHiddenColumns, AlignViewportI viewport, - ColumnSelection columnSelection, AlignmentAnnotation _aa, - Annotation[] aa_annotations, int sRes, int eRes, float min, - float max, int y) + HiddenColumns hiddenColumns, ColumnSelection columnSelection, + AlignmentAnnotation _aa, Annotation[] aa_annotations, int sRes, + int eRes, float min, float max, int y) { if (sRes > aa_annotations.length) { return; } - Font ofont = g.getFont(); eRes = Math.min(eRes, aa_annotations.length); int x = 0, y2 = y; - g.setColor(Color.pink); + g.setColor(shade.no_data); g.drawLine(x, y2, (eRes - sRes) * charWidth, y2); int column; int aaMax = aa_annotations.length - 1; + ContactMatrixI cm = viewport.getContactMatrix(_aa); while (x < eRes - sRes) { column = sRes + x; if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); + } + // TODO: highlight columns selected + boolean colsel = false; + if (columnSelection != null) + { + colsel = columnSelection.contains(column); } if (column > aaMax) @@ -71,36 +142,113 @@ public class ContactMapRenderer implements AnnotationRowRendererI x++; continue; } - /* - * {profile type, #values, total count, char1, pct1, char2, pct2...} - */ ContactListI contacts = viewport.getContactList(_aa, column); - if (contacts == null) { - return; + x++; + continue; } + // ContactListI from viewport can map column -> group + Color gpcol = (cm == null) ? Color.white + : contacts.getColourForGroup(); // cm.getColourForGroup(cm.getGroupsFor(column)); + // feature still in development - highlight or omit regions hidden in + // the alignment - currently marks them as red rows + boolean maskHiddenCols = false; + // TODO: optionally pass visible column mask to the ContactGeometry object + // so it maps + // only visible contacts to geometry + // Bean holding mapping from contact list to pixels + // TODO: allow bracketing/limiting of range on contacts to render (like + // visible column mask but more flexible?) + // COntactListI provides mapping for column -> cm-groupmapping + final ContactGeometry cgeom = new ContactGeometry(contacts, + _aa.graphHeight); - int scale = Math - .max(1, _aa.graphHeight / contacts.getContactHeight()); - int step = _aa.graphHeight / scale; - int valuesProcessed = 0; - // profl[1] is the number of values in the profile - for (int stp = 0, ht = y2, eht = y2 + _aa.graphHeight; ht < eht; ht += scale, stp++) + for (int ht = y2, eht = y2 + - _aa.graphHeight; ht >= eht; ht -= cgeom.pixels_step) { - valuesProcessed = stp * step; - g.setColor(contacts.getColorForScore(stp * step)); + ContactGeometry.contactInterval ci = cgeom.mapFor(y2 - ht, + y2 - ht + cgeom.pixels_step); + // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel); + // cend = (int) Math.min(contact_height, + // Math.ceil(cstart + contacts_per_pixel * pixels_step)); + + Color col; + boolean rowsel = false, containsHidden = false; + if (columnSelection != null) + { + rowsel = cgeom.intersects(ci, columnSelection, hiddenColumns, + maskHiddenCols); + } + // TODO: show selected region + if (colsel || rowsel) + { - if (scale > 1) + col = getSelectedColorForRange(min, max, contacts, ci.cStart, + ci.cEnd); + if (colsel && rowsel) + { + col = new Color(col.getBlue(), col.getGreen(), col.getRed()); + } + else + { + col = new Color(col.getBlue(), col.getBlue(), col.getBlue()); + } + } + else + { + col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd); + } + if (containsHidden) + { + col = shade.hidden; + } + if (gpcol != null && gpcol != Color.white) + { + // todo - could overlay group as a transparent rectangle ? + col = new Color( + (int) (((float) (col.getRed() + gpcol.getRed())) / 2f), + (int) (((float) (col.getGreen() + gpcol.getGreen())) + / 2f), + (int) (((float) (col.getBlue() + gpcol.getBlue())) / 2f)); + } + g.setColor(col); + if (cgeom.pixels_step > 1) + { + g.fillRect(x * charWidth, ht, charWidth, 1 + cgeom.pixels_step); + } + else { - g.fillRect(x * charWidth, ht, charWidth, scale); - } else { g.drawLine(x * charWidth, ht, (x + 1) * charWidth, ht); } } + x++; } - x++; } + + Color shadeFor(float min, float max, float value) + { + return jalview.util.ColorUtils.getGraduatedColour(value, 0, + shade.minColor, max, shade.maxColor); + } + + public Color getColorForRange(float min, float max, ContactListI cl, + int i, int j) + { + ContactRange cr = cl.getRangeFor(i, j); + // average for moment - probably more interested in maxIntProj though + return shadeFor(min, max, (float) cr.getMean()); + } + + public Color getSelectedColorForRange(float min, float max, + ContactListI cl, int i, int j) + { + ContactRange cr = cl.getRangeFor(i, j); + // average for moment - probably more interested in maxIntProj though + return jalview.util.ColorUtils.getGraduatedColour((float) cr.getMean(), + 0, shade.selMinColor, max, shade.selMaxColor); + } + }