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;
}
@Override
- public int[] getVisibleStartAndEndIndex(List<int[]> 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<int[]> 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<Object, ContactMatrixI> contactmaps = new HashMap<Object, ContactMatrixI>();
++ Map<Object, ContactMatrixI> 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;
+ }
}
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<int[]> 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);
}
--- /dev/null
+ /**
+ *
+ */
+ 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());
+ }
+
+ }