From: Jim Procter Date: Tue, 18 Jun 2019 09:19:49 +0000 (+0100) Subject: Merge branch 'features/JAL-2349_matrixvis' into merge/develop_JAL-2340_matrixvis X-Git-Tag: Release_2_11_4_0~562^2~9^2^2 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=f14071cd4c32feeacdb6d4638ef4e3b52071f2f3;p=jalview.git Merge branch 'features/JAL-2349_matrixvis' into merge/develop_JAL-2340_matrixvis Conflicts: src/jalview/datamodel/Alignment.java src/jalview/datamodel/AlignmentI.java --- f14071cd4c32feeacdb6d4638ef4e3b52071f2f3 diff --cc src/jalview/api/AlignViewportI.java index 389d9cf,2870373..29e82cd --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@@ -25,7 -24,9 +25,8 @@@ import jalview.analysis.TreeModel import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; -import jalview.datamodel.CigarArray; import jalview.datamodel.ColumnSelection; + import jalview.datamodel.ContactListI; import jalview.datamodel.ProfilesI; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceCollectionI; diff --cc src/jalview/datamodel/Alignment.java index 3b0ca46,25d770d..1f0e1c2 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@@ -28,13 -28,11 +28,14 @@@ import jalview.util.LinkedIdentityHashS import jalview.util.MessageManager; import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.Enumeration; + import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@@ -1909,124 -1917,77 +1910,156 @@@ public class Alignment implements Align } @Override - public int[] getVisibleStartAndEndIndex(List hiddenCols) + public boolean setHiddenColumns(HiddenColumns cols) { - boolean changed = cols == null ? hiddenCols != null - : !cols.equals(hiddenCols); - hiddenCols = cols; - return changed; - int[] alignmentStartEnd = new int[] { 0, getWidth() - 1 }; - int startPos = alignmentStartEnd[0]; - int endPos = alignmentStartEnd[1]; ++ boolean changed = cols == null ? hiddenCols != null ++ : !cols.equals(hiddenCols); ++ hiddenCols = cols; ++ return changed; + } - + @Override + public void setupJPredAlignment() + { + SequenceI repseq = getSequenceAt(0); + setSeqrep(repseq); + HiddenColumns cs = new HiddenColumns(); + cs.hideList(repseq.getInsertions()); + setHiddenColumns(cs); + } - int[] lowestRange = new int[] { -1, -1 }; - int[] higestRange = new int[] { -1, -1 }; + @Override + public HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentView input) + { + int profsqpos = 0; - for (int[] hiddenCol : hiddenCols) - { - lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange; - higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange; - } + char gc = getGapCharacter(); + Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); + HiddenColumns nview = (HiddenColumns) alandhidden[1]; + SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; + return propagateInsertions(profileseq, origseq, nview); + } - if (lowestRange[0] == -1 && lowestRange[1] == -1) - { - startPos = alignmentStartEnd[0]; - } - else + /** + * + * @param profileseq + * sequence in al which corresponds to origseq + * @param al + * alignment which is to have gaps inserted into it + * @param origseq + * sequence corresponding to profileseq which defines gap map for + * modifying al + */ + private HiddenColumns propagateInsertions(SequenceI profileseq, + SequenceI origseq, HiddenColumns hc) + { + // take the set of hidden columns, and the set of gaps in origseq, + // and remove all the hidden gaps from hiddenColumns + + // first get the gaps as a Bitset + // then calculate hidden ^ not(gap) + BitSet gaps = origseq.gapBitset(); + hc.andNot(gaps); + + // for each sequence in the alignment, except the profile sequence, + // insert gaps corresponding to each hidden region but where each hidden + // column region is shifted backwards by the number of preceding visible + // gaps update hidden columns at the same time + HiddenColumns newhidden = new HiddenColumns(); + + int numGapsBefore = 0; + int gapPosition = 0; + Iterator it = hc.iterator(); + while (it.hasNext()) { - startPos = lowestRange[1] + 1; + int[] region = it.next(); + + // get region coordinates accounting for gaps + // we can rely on gaps not being *in* hidden regions because we already + // removed those + while (gapPosition < region[0]) + { + gapPosition++; + if (gaps.get(gapPosition)) + { + numGapsBefore++; + } + } + + int left = region[0] - numGapsBefore; + int right = region[1] - numGapsBefore; + + newhidden.hideColumns(left, right); + padGaps(left, right, profileseq); } + return newhidden; + } + + /** + * Pad gaps in all sequences in alignment except profileseq + * + * @param left + * position of first gap to insert + * @param right + * position of last gap to insert + * @param profileseq + * sequence not to pad + */ + private void padGaps(int left, int right, SequenceI profileseq) + { + char gc = getGapCharacter(); - if (higestRange[0] == -1 && higestRange[1] == -1) + // make a string with number of gaps = length of hidden region + StringBuilder sb = new StringBuilder(); + for (int g = 0; g < right - left + 1; g++) { - endPos = alignmentStartEnd[1]; + sb.append(gc); } - else + + // loop over the sequences and pad with gaps where required + for (int s = 0, ns = getHeight(); s < ns; s++) { - endPos = higestRange[0] - 1; + SequenceI sqobj = getSequenceAt(s); + if ((sqobj != profileseq) && (sqobj.getLength() >= left)) + { + String sq = sqobj.getSequenceAsString(); + sqobj.setSequence( + sq.substring(0, left) + sb.toString() + sq.substring(left)); + } } - return new int[] { startPos, endPos }; - } - @Override - public void setHiddenColumns(HiddenColumns cols) - { - hiddenCols = cols; } - Map contactmaps = new HashMap(); ++ Map contactmaps = new HashMap<>(); + @Override + public + ContactListI getContactListFor(AlignmentAnnotation _aa, int column) + { + ContactMatrixI cm = contactmaps.get(_aa.annotationId); + if (cm == null) + { + return null; + } + return cm.getContactList(column); + } + + @Override + public AlignmentAnnotation addContactList(ContactMatrixI cm) + { + Annotation _aa[] = new Annotation[getWidth()]; + Annotation dummy = new Annotation(0.0f); + for (int i = 0; i < _aa.length; _aa[i++] = dummy) + { + ; + } + AlignmentAnnotation aa = new AlignmentAnnotation("Contact Matrix", + "Contact Matrix", _aa); + aa.graph = AlignmentAnnotation.CUSTOMRENDERER; + aa.graphMin = cm.getMin(); + aa.graphMax = cm.getMax(); + aa.editable = false; + // aa.autoCalculated = true; + contactmaps.put(aa.annotationId, cm); + addAnnotation(aa); + return aa; + } } diff --cc src/jalview/datamodel/AlignmentI.java index 93a2456,cfc45ae..862a2bf --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@@ -595,33 -581,25 +595,44 @@@ public interface AlignmentI extends Ann AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo); /** - * Calculate the visible start and end index of an alignment. The result is - * returned an int array where: int[0] = startIndex, and int[1] = endIndex. + * Set the hidden columns collection on the alignment. Answers true if the + * hidden column selection changed, else false. * - * @param hiddenCols + * @param cols * @return */ - public int[] getVisibleStartAndEndIndex(List hiddenCols); + public boolean setHiddenColumns(HiddenColumns cols); + + /** + * Set the first sequence as representative and hide its insertions. Typically + * used when loading JPred files. + */ + public void setupJPredAlignment(); + + /** + * Add gaps into the sequences aligned to profileseq under the given + * AlignmentView + * + * @param profileseq + * sequence in al which sequences are aligned to + * @param input + * alignment view where sequence corresponding to profileseq is first + * entry + * @return new HiddenColumns for new alignment view, with insertions into + * profileseq marked as hidden. + */ + public HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentView input); + /** + * resolve a contact list instance (if any) associated with the annotation row + * and column position + * + * @param _aa + * @param column + * @return + */ + ContactListI getContactListFor(AlignmentAnnotation _aa, int column); + + AlignmentAnnotation addContactList(ContactMatrixI cm); - - public void setHiddenColumns(HiddenColumns cols); } diff --cc src/jalview/gui/AnnotationPanel.java index 16db94c,302c770..c179343 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@@ -544,13 -527,13 +544,13 @@@ public class AnnotationPanel extends JP { activeRow = i; } - else if (aa[i].graph > 0) + else if (aa[i].graph != 0) { - // Stretch Graph + /* + * we have clicked on a resizable graph annotation + */ graphStretch = i; - graphStretchY = y; } - break; } } diff --cc src/jalview/renderer/ContactMapRenderer.java index 0000000,bed54e8..7413e65 mode 000000,100644..100644 --- a/src/jalview/renderer/ContactMapRenderer.java +++ b/src/jalview/renderer/ContactMapRenderer.java @@@ -1,0 -1,118 +1,118 @@@ + /** + * + */ + package jalview.renderer; + + import jalview.api.AlignViewportI; + import jalview.datamodel.AlignmentAnnotation; + import jalview.datamodel.Annotation; + import jalview.datamodel.ColumnSelection; + import jalview.datamodel.ContactListI; + import jalview.datamodel.ContactRange; + import jalview.datamodel.HiddenColumns; + import jalview.renderer.api.AnnotationRowRendererI; + + import java.awt.Color; + import java.awt.Graphics; + + /** + * @author jprocter + * + */ + public class ContactMapRenderer implements AnnotationRowRendererI + { + + @Override + public void renderRow(Graphics g, int charWidth, int charHeight, + boolean hasHiddenColumns, AlignViewportI viewport, 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; + } + eRes = Math.min(eRes, aa_annotations.length); + + int x = 0, y2 = y; + + g.setColor(Color.pink); + + g.drawLine(x, y2, (eRes - sRes) * charWidth, y2); + + int column; + int aaMax = aa_annotations.length - 1; + while (x < eRes - sRes) + { + column = sRes + x; + if (hasHiddenColumns) + { - column = hiddenColumns.adjustForHiddenColumns(column); ++ column = hiddenColumns.visibleToAbsoluteColumn(column); + } + + if (column > aaMax) + { + break; + } + + if (aa_annotations[column] == null) + { + x++; + continue; + } + /* + * {profile type, #values, total count, char1, pct1, char2, pct2...} + */ + ContactListI contacts = viewport.getContactList(_aa, column); + if (contacts == null) + { + return; + } + + // cell height to render + double scale = (_aa.graphHeight < contacts.getContactHeight()) ? 1 + : ((double) _aa.graphHeight) + / (double) contacts.getContactHeight(); + int cstart, cend = -1; + for (int ht = y2, eht = y2 - _aa.graphHeight; ht >= eht; ht -= scale) + { + cstart = cend + 1; + cend = Math.max(cstart + 1, contacts.getContactHeight() + * ((ht - y2) / _aa.graphHeight)); + // TODO show maximum colour for range - sort of done + // also need a 'getMaxPosForRange(start,end)' + g.setColor(getColorForRange(min, max, contacts, cstart, cend)); + + if (scale > 1) + { + g.fillRect(x * charWidth, ht, charWidth, 1 + (int) scale); + } + else + { + g.drawLine(x * charWidth, ht, (x + 1) * charWidth, ht); + } + } + x++; + } + + } + + Color minColor = Color.white, maxColor = Color.magenta; + + + Color shadeFor(float min, float max, float value) + { + return jalview.util.ColorUtils.getGraduatedColour(value, 0, minColor, + max, 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()); + } + + } diff --cc src/jalview/viewmodel/AlignmentViewport.java index 148ea16,39820c8..3378192 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@@ -34,7 -33,9 +34,8 @@@ import jalview.datamodel.AlignmentAnnot import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.Annotation; -import jalview.datamodel.CigarArray; import jalview.datamodel.ColumnSelection; + import jalview.datamodel.ContactListI; import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.ProfilesI;