*/
package jalview.analysis;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import jalview.bin.Cache;
import jalview.commands.RemoveGapColCommand;
import jalview.datamodel.AlignedCodon;
import jalview.datamodel.AlignedCodonFrame;
import jalview.util.MapList;
import jalview.util.MappingUtils;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
/**
* grab bag of useful alignment manipulation operations Expect these to be
* refactored elsewhere at some point.
.findMappingsForSequence(cdsSeq, mappings);
for (AlignedCodonFrame mapping : dnaMappings)
{
- SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein);
+ List<SequenceToSequenceMapping> foundMap=new ArrayList<>();
+ SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein,foundMap);
if (peptide != null)
{
final int peptideLength = peptide.getLength();
- Mapping map = mapping.getMappingBetween(cdsSeq, peptide);
+ Mapping map = foundMap.get(0).getMapping();
if (map != null)
{
MapList mapList = map.getMap();
.getFromRanges());
int mappedToLength = MappingUtils
.getLength(mapList.getToRanges());
- boolean addStopCodon = (cdsLength == mappedFromLength
+ boolean addStopCodon = peptide.getDatasetSequence().getEnd()==peptide.getEnd() && ((cdsLength == mappedFromLength
* CODON_LENGTH + CODON_LENGTH)
|| (peptide.getDatasetSequence()
- .getLength() == mappedFromLength - 1);
+ .getLength() == mappedFromLength - 1));
if (cdsLength != mappedToLength && !addStopCodon)
{
System.err.println(String.format(
SequenceI newSeq = null;
- final MapList maplist = mapping.getMap();
- if (maplist.isContiguous() && maplist.isFromForwardStrand())
- {
- /*
- * just a subsequence, keep same dataset sequence
- */
- int start = maplist.getFromLowest();
- int end = maplist.getFromHighest();
- newSeq = seq.getSubSequence(start - 1, end);
- newSeq.setName(seqId);
- }
- else
- {
- /*
- * construct by splicing mapped from ranges
- */
- char[] seqChars = seq.getSequence();
- List<int[]> fromRanges = maplist.getFromRanges();
- int cdsWidth = MappingUtils.getLength(fromRanges);
- char[] newSeqChars = new char[cdsWidth];
+ /*
+ * construct CDS sequence by splicing mapped from ranges
+ */
+ char[] seqChars = seq.getSequence();
+ List<int[]> fromRanges = mapping.getMap().getFromRanges();
+ int cdsWidth = MappingUtils.getLength(fromRanges);
+ char[] newSeqChars = new char[cdsWidth];
- int newPos = 0;
- for (int[] range : fromRanges)
+ int newPos = 0;
+ for (int[] range : fromRanges)
+ {
+ if (range[0] <= range[1])
{
- if (range[0] <= range[1])
- {
- // forward strand mapping - just copy the range
- int length = range[1] - range[0] + 1;
- System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
- length);
- newPos += length;
- }
- else
+ // forward strand mapping - just copy the range
+ int length = range[1] - range[0] + 1;
+ System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
+ length);
+ newPos += length;
+ }
+ else
+ {
+ // reverse strand mapping - copy and complement one by one
+ for (int i = range[0]; i >= range[1]; i--)
{
- // reverse strand mapping - copy and complement one by one
- for (int i = range[0]; i >= range[1]; i--)
- {
- newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
- }
+ newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
}
}
}
else
{
- System.err.println(
- "JAL-2154 regression: warning - found (and ignnored a duplicate CDS sequence):"
- + mtch.toString());
+ Cache.log.error(
+ "JAL-2154 regression: warning - found (and ignored) a duplicate CDS sequence:" + mtch.toString());
}
}
}
*/
public static boolean SeqCharacterUnhash(SequenceI sq, Hashtable sqinfo)
{
+ return SeqCharacterUnhash(sq, sqinfo, false, false);
+ }
+
+ /**
+ * restore some characteristics for a sequence from its hash
+ * @param sq
+ * @param sqinfo
+ * @param excludeLimits - when true, start/end is left unmodified
+ * @param excludeFeatures - when true, features are not restored from stashed vector
+ * @return true if sequence's name was modified
+ */
+
+ public static boolean SeqCharacterUnhash(SequenceI sq, Hashtable sqinfo, boolean excludeLimits,boolean excludeFeatures)
+ {
boolean namePresent = true;
if (sqinfo == null)
{
sq.setPDBId(pdbid);
}
- if ((start != null) && (end != null))
+ if (!excludeLimits && (start != null) && (end != null))
{
sq.setStart(start.intValue());
sq.setEnd(end.intValue());
}
-
- if (sfeatures != null && !sfeatures.isEmpty())
+ // TODO: drop this completely since we should not manipulate sequenceFeatures as a vector any more
+ if (!excludeFeatures && sfeatures != null && !sfeatures.isEmpty())
{
sq.setSequenceFeatures(sfeatures);
}
AlignmentView getAlignmentView(boolean selectedOnly, boolean markGroups);
/**
+ * @return an alignment view, optionally without a complement view
+ * @param selectedOnly
+ * @param markGroups
+ * @param withComplement - false if no complement view required
+ */
+ AlignmentView getAlignmentViewWithComplement(boolean selectedOnly,
+ boolean markGroups, boolean withComplement);
+
+ /**
* This method returns the visible alignment as text, as seen on the GUI, ie
* if columns are hidden they will not be returned in the result. Use this for
* calculating trees, PCA, redundancy etc on views which contain hidden
*/
package jalview.datamodel;
-import jalview.util.MapList;
-import jalview.util.MappingUtils;
-
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+
/**
* Stores mapping between the columns of a protein alignment and a DNA alignment
* and a list of individual codon to amino acid mappings between sequences.
{
return mapping;
}
+
+ /**
+ * Returns true if the mapping covers the full length of the given sequence.
+ * This allows us to distinguish the CDS that codes for a protein from
+ * another overlapping CDS in the parent dna sequence.
+ *
+ * @param seq
+ * @return
+ */
+ public boolean covers(SequenceI seq)
+ {
+ return covers(seq,false,false);
+ }
+ /**
+ *
+ * @param seq
+ * @param localCover - when true - compare extent of seq's dataset sequence rather than the local extent
+ * @param either - when true coverage is required for either seq or the mapped sequence
+ * @return true if mapping covers full length of given sequence (or the other if either==true)
+ */
+ public boolean covers(SequenceI seq, boolean localCover,boolean either)
+ {
+ List<int[]> mappedRanges = null,otherRanges=null;
+ MapList mapList = mapping.getMap();
+ int mstart=seq.getStart(),mend=seq.getEnd(),ostart,oend;
+ ;
+ if (fromSeq == seq || fromSeq == seq.getDatasetSequence())
+ {
+ if (localCover && fromSeq !=seq)
+ {
+ mstart=fromSeq.getStart();
+ mend=fromSeq.getEnd();
+ }
+ mappedRanges = mapList.getFromRanges();
+ otherRanges=mapList.getToRanges();
+ ostart=mapping.to.getStart();
+ oend=mapping.to.getEnd();
+ }
+ else if (mapping.to == seq || mapping.to == seq.getDatasetSequence())
+ {
+ if (localCover && mapping.to !=seq)
+ {
+ mstart=mapping.to.getStart();
+ mend=mapping.to.getEnd();
+ }
+ mappedRanges = mapList.getToRanges();
+ otherRanges=mapList.getFromRanges();
+ ostart=fromSeq.getStart();
+ oend=fromSeq.getEnd();
+ }
+ else
+ {
+ return false;
+ }
+
+ /*
+ * check that each mapped range lies within the sequence range
+ * (necessary for circular CDS - example EMBL:J03321:AAA91567)
+ * and mapped length covers (at least) sequence length
+ */
+ int length = countRange(mappedRanges,mstart,mend);
+
+ if (length != -1)
+ {
+ // add 1 to mapped length to allow for a mapped stop codon
+ if (length + 1 >= (mend - mstart + 1))
+ {
+ return true;
+ }
+ }
+ if (either)
+ {
+ // also check coverage of the other range
+ length = countRange(otherRanges, ostart, oend);
+ if (length != -1)
+ {
+ if (length + 1 >= (oend - ostart + 1))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ private int countRange(List<int[]> mappedRanges,int mstart,int mend)
+ {
+ int length=0;
+ for (int[] range : mappedRanges)
+ {
+ int from = Math.min(range[0], range[1]);
+ int to = Math.max(range[0], range[1]);
+ if (from < mstart || to > mend)
+ {
+ return -1;
+ }
+ length += (to - from + 1);
+ }
+ return length;
+ }
+
+ /**
+ * Adds any regions mapped to or from position {@code pos} in sequence
+ * {@code seq} to the given search results
+ *
+ * @param seq
+ * @param pos
+ * @param sr
+ */
+ public void markMappedRegion(SequenceI seq, int pos, SearchResultsI sr)
+ {
+ int[] codon = null;
+ SequenceI mappedSeq = null;
+ SequenceI ds = seq.getDatasetSequence();
+ if (ds == null)
+ {
+ ds = seq;
+ }
+
+ if (this.fromSeq == seq || this.fromSeq == ds)
+ {
+ codon = this.mapping.map.locateInTo(pos, pos);
+ mappedSeq = this.mapping.to;
+ }
+ else if (this.mapping.to == seq || this.mapping.to == ds)
+ {
+ codon = this.mapping.map.locateInFrom(pos, pos);
+ mappedSeq = this.fromSeq;
+ }
+
+ if (codon != null)
+ {
+ for (int i = 0; i < codon.length; i += 2)
+ {
+ sr.addResult(mappedSeq, codon[i], codon[i + 1]);
+ }
+ }
+ }
}
private List<SequenceToSequenceMapping> mappings;
}
/**
+ * Return the corresponding aligned or dataset dna sequence for given amino
+ * acid sequence, or null if not found. returns the sequence from the first
+ * mapping found that involves the protein sequence.
*
- * @param sequenceRef
- * @return null or corresponding aaSeq entry for dnaSeq entry
+ * @param aaSeqRef
+ * @return
*/
public SequenceI getDnaForAaSeq(SequenceI aaSeqRef)
{
/**
* Add search results for regions in other sequences that translate or are
- * translated from a particular position in seq
+ * translated from a particular position in seq (which may be an aligned or
+ * dataset sequence)
*
* @param seq
* @param index
public void markMappedRegion(SequenceI seq, int index,
SearchResultsI results)
{
- int[] codon;
SequenceI ds = seq.getDatasetSequence();
+ if (ds == null)
+ {
+ ds = seq;
+ }
for (SequenceToSequenceMapping ssm : mappings)
{
- if (ssm.fromSeq == seq || ssm.fromSeq == ds)
- {
- codon = ssm.mapping.map.locateInTo(index, index);
- if (codon != null)
- {
- for (int i = 0; i < codon.length; i += 2)
- {
- results.addResult(ssm.mapping.to, codon[i], codon[i + 1]);
- }
- }
- }
- else if (ssm.mapping.to == seq || ssm.mapping.to == ds)
- {
- {
- codon = ssm.mapping.map.locateInFrom(index, index);
- if (codon != null)
- {
- for (int i = 0; i < codon.length; i += 2)
- {
- results.addResult(ssm.fromSeq, codon[i], codon[i + 1]);
- }
- }
- }
- }
+ ssm.markMappedRegion(ds, index, results);
}
}
*/
public SequenceI findAlignedSequence(SequenceI seq, AlignmentI al)
{
+ return findAlignedSequence(seq, al, null);
+ }
+ /**
+ * Convenience method to return the first aligned sequence in the given
+ * alignment whose dataset has a mapping with the given (aligned or dataset)
+ * sequence, and optionally the mapping that relates them
+ *
+ * @param seq
+ * @param al
+ * @param map - list to add the mapping to
+ * @return sequence from al that maps to seq
+ */
+ public SequenceI findAlignedSequence(SequenceI seq, AlignmentI al,List<SequenceToSequenceMapping> map)
+ {
/*
* Search mapped protein ('to') sequences first.
*/
for (SequenceToSequenceMapping ssm : mappings)
{
- if (ssm.fromSeq == seq || ssm.fromSeq == seq.getDatasetSequence())
+ int mStart=ssm.getMapping().getMap().getFromLowest(),mEnd=ssm.getMapping().map.getFromHighest();
+ if ((ssm.fromSeq == seq || ssm.fromSeq == seq.getDatasetSequence())
+ // here AlignmentUtilsTest. testAlignProteinAsDna_incompleteStartCodon fails because mStart/mEnd is contained by seq
+ // without this filter, we don't get the correct mapping, however
+ )// && seq.getStart()>=mStart && seq.getEnd()<=mEnd)
{
for (SequenceI sourceAligned : al.getSequences())
{
- if (ssm.mapping.to == sourceAligned.getDatasetSequence()
- || ssm.mapping.to == sourceAligned)
+ if (ssm.covers(sourceAligned,true,false))
{
+ if (map != null)
+ {
+ map.add(ssm);
+ }
return sourceAligned;
}
}
*/
for (SequenceToSequenceMapping ssm : mappings)
{
- if (ssm.mapping.to == seq
+ int mStart=ssm.getMapping().getMap().getToLowest(),mEnd=ssm.getMapping().map.getToHighest();
+ if ((ssm.mapping.to == seq
|| ssm.mapping.to == seq.getDatasetSequence())
+ && seq.getStart()>=mStart && seq.getEnd()<=mEnd)
{
for (SequenceI sourceAligned : al.getSequences())
{
- if (ssm.fromSeq == sourceAligned.getDatasetSequence())
+ if (ssm.covers(sourceAligned,true,true))
{
+ if (map != null)
+ {
+ map.add(ssm);
+ }
return sourceAligned;
}
}
* Two AlignedCodonFrame objects are equal if they hold the same ordered list
* of mappings
*
- * @see SequenceToSequenceMapping#
+ * @see SequenceToSequenceMapping#equals
*/
@Override
public boolean equals(Object obj)
{
return mappings;
}
+
+ /**
+ * Returns the first mapping found which is between the two given sequences,
+ * and covers the full extent of both.
+ *
+ * @param seq1
+ * @param seq2
+ * @return
+ */
+ public SequenceToSequenceMapping getCoveringMapping(SequenceI seq1,
+ SequenceI seq2)
+ {
+ for (SequenceToSequenceMapping mapping : mappings)
+ {
+ if (mapping.covers(seq2) && mapping.covers(seq1))
+ {
+ return mapping;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first mapping found which is between the given dataset sequence
+ * and another, is a triplet mapping (3:1 or 1:3), and covers the full extent
+ * of both sequences involved
+ *
+ * @param seq
+ * @return
+ */
+ public SequenceToSequenceMapping getCoveringCodonMapping(SequenceI seq)
+ {
+ for (SequenceToSequenceMapping mapping : mappings)
+ {
+ if (mapping.getMapping().getMap().isTripletMap()
+ && mapping.covers(seq))
+ {
+ if (mapping.fromSeq == seq
+ && mapping.covers(mapping.getMapping().getTo()))
+ {
+ return mapping;
+ }
+ else if (mapping.getMapping().getTo() == seq
+ && mapping.covers(mapping.fromSeq))
+ {
+ return mapping;
+ }
+ }
+ }
+ return null;
+ }
}
private boolean isNa = false;
/**
+ * reference to the complementary CDS/Protein alignment for this alignment, if available
+ */
+ private AlignmentView complementView=null;
+
+ /**
+ * setter for
+ * @param complementView
+ */
+ public void setComplement(AlignmentView complementView)
+ {
+ this.complementView = complementView;
+
+ }
+ /**
+ *
+ * @return true if a complement is available
+ */
+ public boolean hasComplementView()
+ {
+ return complementView!=null;
+ }
+ /**
+ *
+ * @return the complement view or null
+ */
+ public AlignmentView getComplementView()
+ {
+ return complementView;
+ }
+
+ /**
* false if the view concerns peptides
*
* @return
public int[] getMappedPositions(int begin, int end)
{
MapList map = mapping.getMap();
- return mapping.to == featureSequence ? map.locateInFrom(begin, end)
- : map.locateInTo(begin, end);
+ return mapping.to == featureSequence ? map.getOverlapsInFrom(begin, end)
+ : map.getOverlapsInTo(begin, end);
}
/**
}
/**
- * Two SearchResults are considered equal if they contain the same matches in
- * the same order.
+ * Two SearchResults are considered equal if they contain the same matches
+ * (Sequence, start position, end position) in the same order
+ *
+ * @see Match#equals(Object)
*/
@Override
public boolean equals(Object obj)
+ (bounds[2] == 0 ? -1 : bounds[2]));
seqs[i].setDatasetSequence(ref);
seqs[i].setDescription(ref.getDescription());
+ SeqsetUtils.SeqCharacterUnhash(seqs[i],alseqs[i].seqProps,true,true);
}
if (segments != null)
{
String consequence = "";
if (mf != null)
{
- int[] beginRange = mf.getMappedPositions(begin, begin);
- int[] endRange = mf.getMappedPositions(end, end);
- int from = beginRange[0];
- int to = endRange[endRange.length - 1];
+ int[] localRange = mf.getMappedPositions(begin, end);
+ int from = localRange[0];
+ int to = localRange[localRange.length - 1];
String s = mf.isFromCds() ? "Peptide Location" : "Coding location";
sb.append(String.format(ROW_DATA, s, seqName, from == to ? from
: from + (isContactFeature() ? ":" : "-") + to));
* show local rather than linked feature coordinates
*/
int[] beginRange = mf.getMappedPositions(start, start);
- start = beginRange[0];
int[] endRange = mf.getMappedPositions(end, end);
+ if (beginRange == null || endRange == null)
+ {
+ // e.g. variant extending to stop codon so not mappable
+ return;
+ }
+ start = beginRange[0];
end = endRange[endRange.length - 1];
+ int[] localRange = mf.getMappedPositions(start, end);
+ if (localRange == null)
+ {
+ return;
+ }
+ start = localRange[0];
+ end = localRange[localRange.length - 1];
}
StringBuilder desc = new StringBuilder();
desc.append(sf.getType()).append(" ").append(String.valueOf(start));
int exonLength = MappingUtils.getLength(Arrays.asList(exon));
/*
- * if exon length matches protein, or is shorter, or longer by the
- * length of a stop codon (3 bases), then leave it unchanged
+ * if exon length matches protein, or is shorter, then leave it unchanged
*/
- if (expectedCdsLength >= exonLength
- || expectedCdsLength == exonLength - 3)
+ if (expectedCdsLength >= exonLength)
{
return exon;
}
* if this is a virtual features, convert begin/end to the
* coordinates of the sequence it is mapped to
*/
- int[] beginRange = null;
- int[] endRange = null;
+ int[] beginRange = null; // feature start in local coordinates
+ int[] endRange = null; // feature end in local coordinates
if (mf != null)
{
- beginRange = mf.getMappedPositions(begin, begin);
- endRange = mf.getMappedPositions(end, end);
+ if (feature.isContactFeature())
+ {
+ /*
+ * map start and end points individually
+ */
+ beginRange = mf.getMappedPositions(begin, begin);
+ endRange = begin == end ? beginRange
+ : mf.getMappedPositions(end, end);
+ }
+ else
+ {
+ /*
+ * map the feature extent
+ */
+ beginRange = mf.getMappedPositions(begin, end);
+ endRange = beginRange;
+ }
if (beginRange == null || endRange == null)
{
// something went wrong
import java.util.Arrays;
import java.util.List;
+import jalview.bin.Cache;
+
/**
* A simple way of bijectively mapping a non-contiguous linear range to another
* non-contiguous linear range.
/**
* Constructor given from and to ranges as [start1, end1, start2, end2,...].
- * If any end is equal to the next start, the ranges will be merged. There is
- * no validation check that the ranges do not overlap each other.
+ * There is no validation check that the ranges do not overlap each other.
*
* @param from
* contiguous regions as [start1, end1, start2, end2, ...]
this.toRatio = toRatio;
fromLowest = Integer.MAX_VALUE;
fromHighest = Integer.MIN_VALUE;
- int added = 0;
for (int i = 0; i < from.length; i += 2)
{
*/
fromLowest = Math.min(fromLowest, Math.min(from[i], from[i + 1]));
fromHighest = Math.max(fromHighest, Math.max(from[i], from[i + 1]));
- if (added > 0 && from[i] == fromShifts.get(added - 1)[1])
- {
- /*
- * this range starts where the last ended - just extend it
- */
- fromShifts.get(added - 1)[1] = from[i + 1];
- }
- else
- {
- fromShifts.add(new int[] { from[i], from[i + 1] });
- added++;
- }
+ fromShifts.add(new int[] { from[i], from[i + 1] });
}
toLowest = Integer.MAX_VALUE;
toHighest = Integer.MIN_VALUE;
- added = 0;
for (int i = 0; i < to.length; i += 2)
{
toLowest = Math.min(toLowest, Math.min(to[i], to[i + 1]));
toHighest = Math.max(toHighest, Math.max(to[i], to[i + 1]));
- if (added > 0 && to[i] == toShifts.get(added - 1)[1])
- {
- toShifts.get(added - 1)[1] = to[i + 1];
- }
- else
- {
- toShifts.add(new int[] { to[i], to[i + 1] });
- added++;
- }
+ toShifts.add(new int[] { to[i], to[i + 1] });
}
}
if (range.length != 2)
{
// throw new IllegalArgumentException(range);
- System.err.println(
- "Invalid format for fromRange " + Arrays.toString(range)
- + " may cause errors");
+ Cache.log.error("Invalid format for fromRange "
+ + Arrays.toString(range) + " may cause errors");
}
fromLowest = Math.min(fromLowest, Math.min(range[0], range[1]));
fromHighest = Math.max(fromHighest, Math.max(range[0], range[1]));
if (range.length != 2)
{
// throw new IllegalArgumentException(range);
- System.err.println("Invalid format for toRange "
- + Arrays.toString(range)
- + " may cause errors");
+ Cache.log.error("Invalid format for toRange "
+ + Arrays.toString(range) + " may cause errors");
}
toLowest = Math.min(toLowest, Math.min(range[0], range[1]));
toHighest = Math.max(toHighest, Math.max(range[0], range[1]));
/**
* Consolidates a list of ranges so that any contiguous ranges are merged.
* This assumes the ranges are already in start order (does not sort them).
+ * <p>
+ * The main use case for this method is when mapping cDNA sequence to its
+ * protein product, based on CDS feature ranges which derive from spliced
+ * exons, but are contiguous on the cDNA sequence. For example
+ * <pre>
+ * CDS 1-20 // from exon1
+ * CDS 21-35 // from exon2
+ * CDS 36-71 // from exon3
+ * 'coalesce' to range 1-71
+ * </pre>
*
* @param ranges
* @return the same list (if unchanged), else a new merged list, leaving the
first = false;
continue;
}
- if (range[0] == lastRange[0] && range[1] == lastRange[1])
- {
- // drop duplicate range
- changed = true;
- continue;
- }
-
- /*
- * drop this range if it lies within the last range
- */
- if ((lastDirection == 1 && range[0] >= lastRange[0]
- && range[0] <= lastRange[1] && range[1] >= lastRange[0]
- && range[1] <= lastRange[1])
- || (lastDirection == -1 && range[0] <= lastRange[0]
- && range[0] >= lastRange[1]
- && range[1] <= lastRange[0]
- && range[1] >= lastRange[1]))
- {
- changed = true;
- continue;
- }
int direction = range[1] >= range[0] ? 1 : -1;
boolean sameDirection = range[1] == range[0]
|| direction == lastDirection;
boolean extending = range[0] == lastRange[1] + lastDirection;
- boolean overlapping = (lastDirection == 1 && range[0] >= lastRange[0]
- && range[0] <= lastRange[1])
- || (lastDirection == -1 && range[0] <= lastRange[0]
- && range[0] >= lastRange[1]);
- if (sameDirection && (overlapping || extending))
+ if (sameDirection && extending)
{
lastRange[1] = range[1];
changed = true;
}
/**
- * A helper method that returns true unless at least one range has start > end.
- * Behaviour is undefined for a mixture of forward and reverse ranges.
+ * A helper method that returns true unless at least one range has start >
+ * end. Behaviour is undefined for a mixture of forward and reverse ranges.
*
* @param ranges
* @return
{
return fromShifts.size() == 1 && toShifts.size() == 1;
}
+
+ /**
+ * Returns the [start, end...] positions in the range mapped from, that are
+ * mapped to by part or all of the given begin-end of the range mapped to.
+ * Returns null if begin-end does not overlap any position mapped to.
+ *
+ * @param begin
+ * @param end
+ * @return
+ */
+ public int[] getOverlapsInFrom(final int begin, final int end)
+ {
+ int[] overlaps = MappingUtils.findOverlap(toShifts, begin, end);
+
+ return overlaps == null ? null : locateInFrom(overlaps[0], overlaps[1]);
+ }
+
+ /**
+ * Returns the [start, end...] positions in the range mapped to, that are
+ * mapped to by part or all of the given begin-end of the range mapped from.
+ * Returns null if begin-end does not overlap any position mapped from.
+ *
+ * @param begin
+ * @param end
+ * @return
+ */
+ public int[] getOverlapsInTo(final int begin, final int end)
+ {
+ int[] overlaps = MappingUtils.findOverlap(fromShifts, begin, end);
+
+ return overlaps == null ? null : locateInTo(overlaps[0], overlaps[1]);
+ }
}
*/
package jalview.util;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
import jalview.analysis.AlignmentSorter;
import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
import jalview.commands.CommandI;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.commands.EditCommand.Edit;
import jalview.commands.OrderCommand;
import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
/**
* Helper methods for manipulations involving sequence mappings.
*
action = action.getUndoAction();
}
// TODO write this
- System.err.println("MappingUtils.mapCutOrPaste not yet implemented");
+ Cache.log.error("MappingUtils.mapCutOrPaste not yet implemented");
}
/**
firstUngappedPos++;
}
- /*
- * If this sequence is only gaps in the selected range, skip it
- */
- if (firstUngappedPos > selectionEndRes)
- {
- continue;
- }
+ boolean allGapped = (firstUngappedPos > selectionEndRes);
int lastUngappedPos = selectionEndRes;
- while (lastUngappedPos >= selectionStartRes
- && Comparison.isGap(selected.getCharAt(lastUngappedPos)))
+ if (!allGapped)
{
- lastUngappedPos--;
+ while (lastUngappedPos >= selectionStartRes
+ && Comparison.isGap(selected.getCharAt(lastUngappedPos)))
+ {
+ lastUngappedPos--;
+ }
}
/*
* Find the selected start/end residue positions in sequence
*/
- int startResiduePos = selected.findPosition(firstUngappedPos);
- int endResiduePos = selected.findPosition(lastUngappedPos);
+ int startResiduePos = allGapped ? 0 : selected.findPosition(firstUngappedPos);
+ int endResiduePos = allGapped ? 0 : selected.findPosition(lastUngappedPos);
for (AlignedCodonFrame acf : codonFrames)
{
- SequenceI mappedSequence = targetIsNucleotide
- ? acf.getDnaForAaSeq(selected)
- : acf.getAaForDnaSeq(selected);
- if (mappedSequence != null)
+ for (SequenceI seq : mapTo.getAlignment().getSequences())
{
- for (SequenceI seq : mapTo.getAlignment().getSequences())
+ SequenceI peptide = targetIsNucleotide ? selected : seq;
+ SequenceI cds = targetIsNucleotide ? seq : selected;
+ SequenceToSequenceMapping s2s = acf.getCoveringMapping(cds,
+ peptide);
+ if (s2s == null)
{
- int mappedStartResidue = 0;
- int mappedEndResidue = 0;
- if (seq.getDatasetSequence() == mappedSequence)
- {
- /*
- * Found a sequence mapping. Locate the start/end mapped residues.
- */
- List<AlignedCodonFrame> mapping = Arrays
- .asList(new AlignedCodonFrame[]
- { acf });
- SearchResultsI sr = buildSearchResults(selected,
- startResiduePos, mapping);
- for (SearchResultMatchI m : sr.getResults())
- {
- mappedStartResidue = m.getStart();
- mappedEndResidue = m.getEnd();
- }
- sr = buildSearchResults(selected, endResiduePos, mapping);
- for (SearchResultMatchI m : sr.getResults())
- {
- mappedStartResidue = Math.min(mappedStartResidue,
- m.getStart());
- mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
- }
-
- /*
- * Find the mapped aligned columns, save the range. Note findIndex
- * returns a base 1 position, SequenceGroup uses base 0
- */
- int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
- minStartCol = minStartCol == -1 ? mappedStartCol
- : Math.min(minStartCol, mappedStartCol);
- int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
- maxEndCol = maxEndCol == -1 ? mappedEndCol
- : Math.max(maxEndCol, mappedEndCol);
- mappedGroup.addSequence(seq, false);
- break;
- }
+ continue;
}
+ mappedGroup.addSequence(seq, false);
+ if (allGapped)
+ {
+ /*
+ * sequence is mapped but includes no mapped residues
+ */
+ continue;
+ }
+ int mappedStartResidue = 0;
+ int mappedEndResidue = 0;
+ List<AlignedCodonFrame> mapping = Arrays.asList(acf);
+ SearchResultsI sr = buildSearchResults(selected, startResiduePos,
+ mapping);
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ mappedStartResidue = m.getStart();
+ mappedEndResidue = m.getEnd();
+ }
+ sr = buildSearchResults(selected, endResiduePos, mapping);
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ mappedStartResidue = Math.min(mappedStartResidue, m.getStart());
+ mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
+ }
+
+ /*
+ * Find the mapped aligned columns, save the range. Note findIndex
+ * returns a base 1 position, SequenceGroup uses base 0
+ */
+ int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
+ minStartCol = minStartCol == -1 ? mappedStartCol
+ : Math.min(minStartCol, mappedStartCol);
+ int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
+ maxEndCol = maxEndCol == -1 ? mappedEndCol
+ : Math.max(maxEndCol, mappedEndCol);
+ break;
}
}
}
{
for (AlignedCodonFrame acf : mappings)
{
- SequenceI mappedSeq = mappingToNucleotide ? acf.getDnaForAaSeq(seq)
- : acf.getAaForDnaSeq(seq);
- if (mappedSeq != null)
- {
for (SequenceI seq2 : mapTo.getSequences())
{
- if (seq2.getDatasetSequence() == mappedSeq)
+ /*
+ * the corresponding peptide / CDS is the one for which there is
+ * a complete ('covering') mapping to 'seq'
+ */
+ SequenceI peptide = mappingToNucleotide ? seq2 : seq;
+ SequenceI cds = mappingToNucleotide ? seq : seq2;
+ SequenceToSequenceMapping s2s = acf.getCoveringMapping(cds,
+ peptide);
+ if (s2s != null)
{
mappedOrder.add(seq2);
j++;
break;
}
}
- }
}
}
if (colsel == null)
{
- return; // mappedColumns;
+ return;
}
char fromGapChar = mapFrom.getAlignment().getGapCharacter();
while (regions.hasNext())
{
mapHiddenColumns(regions.next(), codonFrames, newHidden,
- fromSequences,
- toSequences, fromGapChar);
+ fromSequences, toSequences, fromGapChar);
}
- return; // mappedColumns;
+ return;
}
/**
*/
for (SequenceI toSeq : toSequences)
{
- if (toSeq.getDatasetSequence() == mappedSeq)
+ if (toSeq.getDatasetSequence() == mappedSeq
+ && mappedStartResidue >= toSeq.getStart()
+ && mappedEndResidue <= toSeq.getEnd())
{
int mappedStartCol = toSeq.findIndex(mappedStartResidue);
int mappedEndCol = toSeq.findIndex(mappedEndResidue);
{
if (range.length % 2 != 0)
{
- System.err.println(
+ Cache.log.error(
"Error unbalance start/end ranges: " + ranges.toString());
return 0;
}
int min = Math.min(range[0], range[1]);
int max = Math.max(range[0], range[1]);
-
+
return (min <= queryRange[0] && max >= queryRange[0]
&& min <= queryRange[1] && max >= queryRange[1]);
}
* a list of (single) [start, end] ranges
* @return
*/
- public static void removeEndPositions(int positions,
- List<int[]> ranges)
+ public static void removeEndPositions(int positions, List<int[]> ranges)
{
int toRemove = positions;
Iterator<int[]> it = new ReverseListIterator<>(ranges);
/*
* not coded for [start1, end1, start2, end2, ...]
*/
- System.err
- .println("MappingUtils.removeEndPositions doesn't handle multiple ranges");
+ Cache.log.error(
+ "MappingUtils.removeEndPositions doesn't handle multiple ranges");
return;
}
/*
* not coded for a reverse strand range (end < start)
*/
- System.err
- .println("MappingUtils.removeEndPositions doesn't handle reverse strand");
+ Cache.log.error(
+ "MappingUtils.removeEndPositions doesn't handle reverse strand");
return;
}
if (length > toRemove)
}
return result;
}
+
+ /**
+ * Returns the maximal start-end positions in the given (ordered) list of
+ * ranges which is overlapped by the given begin-end range, or null if there
+ * is no overlap.
+ *
+ * <pre>
+ * Examples:
+ * if ranges is {[4, 8], [10, 12], [16, 19]}
+ * then
+ * findOverlap(ranges, 1, 20) == [4, 19]
+ * findOverlap(ranges, 6, 11) == [6, 11]
+ * findOverlap(ranges, 9, 15) == [10, 12]
+ * findOverlap(ranges, 13, 15) == null
+ * </pre>
+ *
+ * @param ranges
+ * @param begin
+ * @param end
+ * @return
+ */
+ protected static int[] findOverlap(List<int[]> ranges, final int begin,
+ final int end)
+ {
+ boolean foundStart = false;
+ int from = 0;
+ int to = 0;
+
+ /*
+ * traverse the ranges to find the first position (if any) >= begin,
+ * and the last position (if any) <= end
+ */
+ for (int[] range : ranges)
+ {
+ if (!foundStart)
+ {
+ if (range[0] >= begin)
+ {
+ /*
+ * first range that starts with, or follows, begin
+ */
+ foundStart = true;
+ from = Math.max(range[0], begin);
+ }
+ else if (range[1] >= begin)
+ {
+ /*
+ * first range that contains begin
+ */
+ foundStart = true;
+ from = begin;
+ }
+ }
+
+ if (range[0] <= end)
+ {
+ to = Math.min(end, range[1]);
+ }
+ }
+
+ return foundStart && to >= from ? new int[] { from, to } : null;
+ }
}
public jalview.datamodel.AlignmentView getAlignmentView(
boolean selectedOnly, boolean markGroups)
{
- return new AlignmentView(alignment, alignment.getHiddenColumns(),
- selectionGroup,
+ return getAlignmentViewWithComplement(selectedOnly,markGroups,true);
+ }
+
+ @Override
+ public jalview.datamodel.AlignmentView getAlignmentViewWithComplement(
+ boolean selectedOnly, boolean markGroups,boolean withComplment)
+ {
+ AlignmentView complementView = null;
+ if (withComplment)
+ {
+ if (codingComplement != null)
+ {
+ complementView = codingComplement.getAlignmentViewWithComplement(
+ selectedOnly, markGroups, false);
+ }
+ }
+ AlignmentView thisView = new AlignmentView(alignment,
+ alignment.getHiddenColumns(), selectionGroup,
alignment.getHiddenColumns() != null
&& alignment.getHiddenColumns().hasHiddenColumns(),
selectedOnly, markGroups);
+ thisView.setComplement(complementView);
+ return thisView;
}
@Override
import jalview.api.FeatureColourI;
import jalview.api.FeaturesDisplayedI;
import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.MappedFeatures;
-import jalview.datamodel.Mapping;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
* todo: direct lookup of CDS for peptide and vice-versa; for now,
* have to search through an unordered list of mappings for a candidate
*/
- Mapping mapping = null;
+ SequenceToSequenceMapping mapping = null;
SequenceI mapFrom = null;
for (AlignedCodonFrame acf : mappings)
{
- mapping = acf.getMappingForSequence(sequence);
- if (mapping == null || !mapping.getMap().isTripletMap())
+ mapping = acf.getCoveringCodonMapping(ds);
+ if (mapping == null)
{
- continue; // we are only looking for 3:1 or 1:3 mappings
+ continue;
}
SearchResultsI sr = new SearchResults();
- acf.markMappedRegion(ds, pos, sr);
+ mapping.markMappedRegion(ds, pos, sr);
for (SearchResultMatchI match : sr.getResults())
{
int fromRes = match.getStart();
}
}
- return new MappedFeatures(mapping, mapFrom, pos, residue, result);
+ return new MappedFeatures(mapping.getMapping(), mapFrom, pos, residue, result);
}
@Override
*
* @deprecated endpoint withdrawn August 2020 (JAL-3692), use EmblFlatfileSource
*/
+
public abstract class EmblXmlSource extends EbiFileRetrievedProxy
{
private static final Regex ACCESSION_REGEX = new Regex("^[A-Z]+[0-9]+");
else
{
// final product length truncation check
- int[] cdsRanges = adjustForProteinLength(translationLength,
+ int [] exons2 = adjustForProteinLength(translationLength,
exons);
- dnaToProteinMapping = new Mapping(product, cdsRanges,
+ dnaToProteinMapping = new Mapping(product, exons2,
new int[]
{ 1, translationLength }, 3, 1);
if (product != null)
/**
* Truncates (if necessary) the exon intervals to match 3 times the length of
- * the protein; also accepts 3 bases longer (for stop codon not included in
- * protein)
+ * the protein (including truncation for stop codon included in exon)
*
* @param proteinLength
* @param exon
int exonLength = MappingUtils.getLength(Arrays.asList(exon));
/*
- * if exon length matches protein, or is shorter, or longer by the
- * length of a stop codon (3 bases), then leave it unchanged
+ * if exon length matches protein, or is shorter, then leave it unchanged
*/
- if (expectedCdsLength >= exonLength
- || expectedCdsLength == exonLength - 3)
+ if (expectedCdsLength >= exonLength)
{
return exon;
}
{
al.setDataset(dataset);
}
-
propagateDatasetMappings(al);
+ Alignment complement=null;
+ if (input.hasComplementView())
+ {
+ Object[] newcompl = input
+ .getComplementView()
+ .getAlignmentAndHiddenColumns(getRequestingAlignFrame()
+ .getViewport().getCodingComplement().getGapCharacter());
+ complement = new Alignment((SequenceI[])newcompl[0]);
+ complement.setHiddenColumns((HiddenColumns) newcompl[1]);
+ complement.setDataset(dataset);
+ complement.alignAs(al);
+ }
// JBNote- TODO: warn user if a block is input rather than aligned data ?
if (newFrame)
{
- displayInNewFrame(al, alorders, hidden);
+ displayInNewFrame(al, alorders, hidden, complement);
}
else
*
* @param al
* @param alorders
+ * @param complement2
* @param columnselection
*/
protected void displayInNewFrame(AlignmentI al,
- List<AlignmentOrder> alorders, HiddenColumns hidden)
+ List<AlignmentOrder> alorders, HiddenColumns hidden, AlignmentI complement)
{
AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
* SplitFrame with the other pane similarly aligned.
*/
AlignFrame requestedBy = getRequestingAlignFrame();
- if (requestedBy != null && requestedBy.getSplitViewContainer() != null
+ if (complement!=null && requestedBy != null && requestedBy.getSplitViewContainer() != null
&& requestedBy.getSplitViewContainer()
.getComplement(requestedBy) != null)
{
- AlignmentI complement = requestedBy.getSplitViewContainer()
- .getComplement(requestedBy);
String complementTitle = requestedBy.getSplitViewContainer()
.getComplementTitle(requestedBy);
// becomes null if the alignment window was closed before the alignment
// job finished.
- AlignmentI copyComplement = new Alignment(complement);
- // todo should this be done by copy constructor?
- copyComplement.setGapCharacter(complement.getGapCharacter());
- // share the same dataset (and the mappings it holds)
- copyComplement.setDataset(complement.getDataset());
- copyComplement.alignAs(al);
- if (copyComplement.getHeight() > 0)
+ if (complement.getHeight() > 0)
{
af.setTitle(alTitle);
- AlignFrame af2 = new AlignFrame(copyComplement,
+ AlignFrame af2 = new AlignFrame(complement,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
af2.setTitle(complementTitle);
String linkedTitle = MessageManager
*/
package jalview.analysis;
+import static org.junit.Assert.assertNotEquals;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.datamodel.features.SequenceFeatures;
import jalview.gui.JvOptionPane;
import jalview.io.AppletFormatAdapter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
ArrayList<AlignedCodonFrame> acfs = new ArrayList<>();
acfs.add(acf);
protein.setCodonFrames(acfs);
-
+ Iterator<SequenceI> protseq = protein.getSequences().iterator();
+ for (SequenceI dnaseq:dna.getSequences()) {
+ assertCanResolveProteinCDS(dnaseq,protseq.next(),protein);
+ }
/*
* verify X is included in the aligned proteins, and placed just
* before the first mapped residue
}
/**
+ * assert that we can resolve the protein product in the given alignment given a DNA sequence with CDS mapping
+ * @param dnaseq
+ * @param protein
+ */
+ private void assertCanResolveProteinCDS(SequenceI dnaseq, SequenceI expProtein, AlignmentI protein)
+ {
+ // try a few different methods to check all work
+ SequenceI aprot=null;
+ for (AlignedCodonFrame cf:protein.getCodonFrame(dnaseq))
+ {
+ aprot=cf.getAaForDnaSeq(dnaseq);
+ if (aprot!=null)
+ {
+ assertTrue("getAaForDnaSeq didn't return expected protein sequence",aprot!=expProtein);
+ break;
+ }
+ }
+ assertNotNull("Didn't locate any proteins via AlignmentI.getCodonFrame .. AlignCodonFrame.getAaForDnaSeq", aprot);
+ // try mapping utils -
+ List<AlignedCodonFrame> mu_mappings=MappingUtils.findMappingsForSequence(dnaseq, protein.getCodonFrames());
+ assertNotNull("No mappings found for dnaseq in protein alignment via MappingUtils.findMappingsForSequence",mu_mappings);
+ assertNotEquals("No mappings found for dnaseq in protein alignment via MappingUtils.findMappingsForSequence",0,mu_mappings.size());
+ SequenceI mu_alignedprot=null;
+ List<SequenceToSequenceMapping> foundMap=null;
+ for (AlignedCodonFrame cf:mu_mappings)
+ {
+ foundMap=new ArrayList<>();
+ mu_alignedprot = cf.findAlignedSequence(dnaseq, protein,foundMap);
+ if (mu_alignedprot!=null) {
+ break;
+ }
+ }
+ assertNotNull("Didn't locate proteins via MappingUtils.findMappingsForSequence",mu_alignedprot);
+ assertTrue("findAlignedSequence didn't return expected protein sequence",mu_alignedprot==expProtein);
+ }
+
+ /**
* Tests for the method that maps the subset of a dna sequence that has CDS
* (or subtype) feature - case where the start codon is incomplete.
*/
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
-import jalview.gui.JvOptionPane;
-import jalview.util.MapList;
-
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
+import jalview.gui.JvOptionPane;
+import jalview.util.MapList;
+
public class AlignedCodonFrameTest
{
public void testGetMappedRegion()
{
// introns lower case, exons upper case
- final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
- seq1.createDatasetSequence();
- final Sequence seq2 = new Sequence("Seq2", "-TA-gG-Gg-CG-a");
- seq2.createDatasetSequence();
+ final Sequence dna1 = new Sequence("Seq1/10-18", "c-G-TA-gC-gT-T");
+ dna1.createDatasetSequence();
+ final Sequence dna2 = new Sequence("Seq2/20-28", "-TA-gG-Gg-CG-a");
+ dna2.createDatasetSequence();
- final Sequence aseq1 = new Sequence("Seq1", "-P-R");
- aseq1.createDatasetSequence();
- final Sequence aseq2 = new Sequence("Seq2", "-LY-Q");
- aseq2.createDatasetSequence();
+ final Sequence pep1 = new Sequence("Seq1/3-4", "-P-R");
+ pep1.createDatasetSequence();
+ final Sequence pep2 = new Sequence("Seq2/7-9", "-LY-Q");
+ pep2.createDatasetSequence();
/*
* First with no mappings
*/
AlignedCodonFrame acf = new AlignedCodonFrame();
- assertNull(acf.getMappedRegion(seq1, aseq1, 1));
+ assertNull(acf.getMappedRegion(dna1, pep1, 3));
/*
* Set up the mappings for the exons (upper-case bases)
* Note residue Q is unmapped
*/
- MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
- 1, 2 }, 3, 1);
- acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
- map = new MapList(new int[] { 1, 2, 4, 5, 7, 8 }, new int[] { 1, 2 },
+ MapList map1 = new MapList(new int[] { 11, 13, 15, 15, 17, 18 }, new int[] {
+ 3, 4 }, 3, 1);
+ acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map1);
+ MapList map2 = new MapList(new int[] { 20, 21, 23, 24, 26, 27 }, new int[] { 7, 9 },
3, 1);
- acf.addMap(seq2.getDatasetSequence(), aseq2.getDatasetSequence(), map);
+ acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map2);
- assertArrayEquals(new int[] { 2, 4 },
- acf.getMappedRegion(seq1, aseq1, 1));
- assertArrayEquals(new int[] { 6, 6, 8, 9 },
- acf.getMappedRegion(seq1, aseq1, 2));
- assertArrayEquals(new int[] { 1, 2, 4, 4 },
- acf.getMappedRegion(seq2, aseq2, 1));
- assertArrayEquals(new int[] { 5, 5, 7, 8 },
- acf.getMappedRegion(seq2, aseq2, 2));
+ /*
+ * get codon positions for peptide position
+ */
+ assertArrayEquals(new int[] { 11, 13 },
+ acf.getMappedRegion(dna1, pep1, 3));
+ assertArrayEquals(new int[] { 15, 15, 17, 18 },
+ acf.getMappedRegion(dna1, pep1, 4));
+ assertArrayEquals(new int[] { 20, 21, 23, 23 },
+ acf.getMappedRegion(dna2, pep2, 7));
+ assertArrayEquals(new int[] { 24, 24, 26, 27 },
+ acf.getMappedRegion(dna2, pep2, 8));
/*
- * No mapping from seq2 to Q
+ * No mapping from dna2 to Q
*/
- assertNull(acf.getMappedRegion(seq2, aseq2, 3));
+ assertNull(acf.getMappedRegion(dna2, pep2, 9));
/*
- * No mapping from sequence 1 to sequence 2
+ * No mapping from dna1 to pep2
*/
- assertNull(acf.getMappedRegion(seq1, aseq2, 1));
+ assertNull(acf.getMappedRegion(dna1, pep2, 7));
+
+ /*
+ * get peptide position for codon position
+ */
+ assertArrayEquals(new int[] { 3, 3 },
+ acf.getMappedRegion(pep1, dna1, 11));
+ assertArrayEquals(new int[] { 3, 3 },
+ acf.getMappedRegion(pep1, dna1, 12));
+ assertArrayEquals(new int[] { 3, 3 },
+ acf.getMappedRegion(pep1, dna1, 13));
+ assertNull(acf.getMappedRegion(pep1, dna1, 14)); // intron base, not mapped
+
}
@Test(groups = { "Functional" })
assertEquals(1, acf.getMappingsFromSequence(seq1).size());
assertSame(before, acf.getMappingsFromSequence(seq1).get(0));
}
+
+ @Test(groups = { "Functional" })
+ public void testGetCoveringMapping()
+ {
+ SequenceI dna = new Sequence("dna", "acttcaATGGCGGACtaattt");
+ SequenceI cds = new Sequence("cds/7-15", "ATGGCGGAC");
+ cds.setDatasetSequence(dna);
+ SequenceI pep = new Sequence("pep", "MAD");
+
+ /*
+ * with null argument or no mappings
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ assertNull(acf.getCoveringMapping(null, null));
+ assertNull(acf.getCoveringMapping(dna, null));
+ assertNull(acf.getCoveringMapping(null, pep));
+ assertNull(acf.getCoveringMapping(dna, pep));
+
+ /*
+ * with a non-covering mapping e.g. overlapping exon
+ */
+ MapList map = new MapList(new int[] { 7, 9 }, new int[] {
+ 1, 1 }, 3, 1);
+ acf.addMap(dna, pep, map);
+ assertNull(acf.getCoveringMapping(dna, pep));
+
+ acf = new AlignedCodonFrame();
+ MapList map2 = new MapList(new int[] { 13, 18 }, new int[] {
+ 2, 2 }, 3, 1);
+ acf.addMap(dna, pep, map2);
+ assertNull(acf.getCoveringMapping(dna, pep));
+
+ /*
+ * with a covering mapping from CDS (dataset) to protein
+ */
+ acf = new AlignedCodonFrame();
+ MapList map3 = new MapList(new int[] { 7, 15 }, new int[] {
+ 1, 3 }, 3, 1);
+ acf.addMap(dna, pep, map3);
+ assertNull(acf.getCoveringMapping(dna, pep));
+ SequenceToSequenceMapping mapping = acf.getCoveringMapping(cds, pep);
+ assertNotNull(mapping);
+
+ /*
+ * with a mapping that extends to stop codon
+ */
+ acf = new AlignedCodonFrame();
+ MapList map4 = new MapList(new int[] { 7, 18 }, new int[] {
+ 1, 3 }, 3, 1);
+ acf.addMap(dna, pep, map4);
+ assertNull(acf.getCoveringMapping(dna, pep));
+ assertNull(acf.getCoveringMapping(cds, pep));
+ SequenceI cds2 = new Sequence("cds/7-18", "ATGGCGGACtaa");
+ cds2.setDatasetSequence(dna);
+ mapping = acf.getCoveringMapping(cds2, pep);
+ assertNotNull(mapping);
+ }
+
+ /**
+ * Test the method that adds mapped positions to SearchResults
+ */
+ @Test(groups = { "Functional" })
+ public void testMarkMappedRegion()
+ {
+ // introns lower case, exons upper case
+ final Sequence dna1 = new Sequence("Seq1/10-18", "c-G-TA-gC-gT-T");
+ dna1.createDatasetSequence();
+ final Sequence dna2 = new Sequence("Seq2/20-28", "-TA-gG-Gg-CG-a");
+ dna2.createDatasetSequence();
+
+ final Sequence pep1 = new Sequence("Seq1/3-4", "-P-R");
+ pep1.createDatasetSequence();
+ final Sequence pep2 = new Sequence("Seq2/7-9", "-LY-Q");
+ pep2.createDatasetSequence();
+
+ /*
+ * First with no mappings
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ SearchResults sr = new SearchResults();
+ acf.markMappedRegion(dna1, 12, sr);
+ assertTrue(sr.isEmpty());
+
+ /*
+ * Set up the mappings for the exons (upper-case bases)
+ * Note residue Q is unmapped
+ */
+ MapList map1 = new MapList(new int[] { 11, 13, 15, 15, 17, 18 }, new int[] {
+ 3, 4 }, 3, 1);
+ acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map1);
+ MapList map2 = new MapList(new int[] { 20, 21, 23, 24, 26, 27 }, new int[] { 7, 8 },
+ 3, 1);
+ acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map2);
+
+ /*
+ * intron bases are not mapped
+ */
+ acf.markMappedRegion(dna1, 10, sr);
+ assertTrue(sr.isEmpty());
+
+ /*
+ * Q is not mapped
+ */
+ acf.markMappedRegion(pep2, 9, sr);
+ assertTrue(sr.isEmpty());
+
+ /*
+ * mark peptide position for exon position (of aligned sequence)
+ */
+ acf.markMappedRegion(dna1, 11, sr);
+ SearchResults expected = new SearchResults();
+ expected.addResult(pep1.getDatasetSequence(), 3, 3);
+ assertEquals(sr, expected);
+
+ /*
+ * mark peptide position for exon position of dataset sequence - same result
+ */
+ sr = new SearchResults();
+ acf.markMappedRegion(dna1.getDatasetSequence(), 11, sr);
+ assertEquals(sr, expected);
+
+ /*
+ * marking the same position a second time should not create a duplicate match
+ */
+ acf.markMappedRegion(dna1.getDatasetSequence(), 12, sr);
+ assertEquals(sr, expected);
+
+ /*
+ * mark exon positions for peptide position (of aligned sequence)
+ */
+ sr = new SearchResults();
+ acf.markMappedRegion(pep2, 7, sr); // codon positions 20, 21, 23
+ expected = new SearchResults();
+ expected.addResult(dna2.getDatasetSequence(), 20, 21);
+ expected.addResult(dna2.getDatasetSequence(), 23, 23);
+ assertEquals(sr, expected);
+
+ /*
+ * add another codon to the same SearchResults
+ */
+ acf.markMappedRegion(pep1.getDatasetSequence(), 4, sr); // codon positions 15, 17, 18
+ expected.addResult(dna1.getDatasetSequence(), 15, 15);
+ expected.addResult(dna1.getDatasetSequence(), 17, 18);
+ assertEquals(sr, expected);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetCoveringCodonMapping()
+ {
+ SequenceI dna = new Sequence("dna/10-30", "acttcaATGGCGGACtaattt");
+ // CDS sequence with its own dataset sequence (JAL-3763)
+ SequenceI cds = new Sequence("cds/1-9", "-A--TGGC-GGAC");
+ cds.createDatasetSequence();
+ SequenceI pep = new Sequence("pep/1-3", "MAD");
+
+ /*
+ * with null argument or no mappings
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ assertNull(acf.getCoveringCodonMapping(null));
+ assertNull(acf.getCoveringCodonMapping(dna));
+ assertNull(acf.getCoveringCodonMapping(pep));
+
+ /*
+ * with a non-covering mapping e.g. overlapping exon
+ */
+ MapList map = new MapList(new int[] { 16, 18 }, new int[] {
+ 1, 1 }, 3, 1);
+ acf.addMap(dna, pep, map);
+ assertNull(acf.getCoveringCodonMapping(dna));
+ assertNull(acf.getCoveringCodonMapping(pep));
+
+ acf = new AlignedCodonFrame();
+ MapList map2 = new MapList(new int[] { 13, 18 }, new int[] {
+ 2, 2 }, 3, 1);
+ acf.addMap(dna, pep, map2);
+ assertNull(acf.getCoveringCodonMapping(dna));
+ assertNull(acf.getCoveringCodonMapping(pep));
+
+ /*
+ * with a covering mapping from CDS (dataset) to protein
+ */
+ acf = new AlignedCodonFrame();
+ MapList map3 = new MapList(new int[] { 1, 9 }, new int[] {
+ 1, 3 }, 3, 1);
+ acf.addMap(cds.getDatasetSequence(), pep, map3);
+ assertNull(acf.getCoveringCodonMapping(dna));
+ SequenceToSequenceMapping mapping = acf.getCoveringCodonMapping(pep);
+ assertNotNull(mapping);
+ SequenceToSequenceMapping mapping2 = acf.getCoveringCodonMapping(cds.getDatasetSequence());
+ assertSame(mapping, mapping2);
+
+ /*
+ * with a mapping that extends to stop codon
+ * (EMBL CDS location often includes the stop codon)
+ * - getCoveringCodonMapping is lenient (doesn't require exact length match)
+ */
+ SequenceI cds2 = new Sequence("cds/1-12", "-A--TGGC-GGACTAA");
+ cds2.createDatasetSequence();
+ acf = new AlignedCodonFrame();
+ MapList map4 = new MapList(new int[] { 1, 12 }, new int[] {
+ 1, 3 }, 3, 1);
+ acf.addMap(cds2, pep, map4);
+ mapping = acf.getCoveringCodonMapping(cds2.getDatasetSequence());
+ assertNotNull(mapping);
+ mapping2 = acf.getCoveringCodonMapping(pep);
+ assertSame(mapping, mapping2);
+ }
}
*/
package jalview.datamodel;
+import static org.testng.Assert.assertTrue;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
}
}
+ @Test(groups= {"Functional"})
+ public void testReconstructSeq()
+ {
+ String o_seq = "asdfktryasdtqwrtsaslldddptyipqqwaslchvhttt";
+ SequenceI s = new Sequence("MySeq", o_seq, 39, 80);
+ String orig_gapped = "----asdf------ktryas---dtqwrtsasll----dddptyipqqwa----slchvhttt";
+ // name of sequence in a particular alignment should be recovered
+ SequenceI s_gapped = new Sequence("MySeqAlign", orig_gapped, 39, 80);
+ s_gapped.setDatasetSequence(s);
+ SeqCigar cg_sgapped = new SeqCigar(s_gapped);
+ assertTrue(testSeqRecovery(cg_sgapped,s_gapped,true));
+ SequenceI subseq_gapped = s_gapped.getSubSequence(44, 60);
+ SeqCigar subseq_cg_range=new SeqCigar(s_gapped,44,59);
+ assertTrue(testSeqRecovery(subseq_cg_range, subseq_gapped, true),"SeqCigar created on range of sequence failed");
+
+ // test another way of reconstructing a sequence from seqCigar
+ SequenceI[] sqs=SeqCigar.createAlignmentSequences(new SeqCigar[] {subseq_cg_range}, '-', new HiddenColumns(), null);
+ assertTrue(testSeqRecovery(subseq_cg_range, sqs[0], true),"createAlignmentSequences didn't reconstruct same sequence as for SeqCigar created on range of sequence failed (used by AlignmentView for selections)");
+
+ subseq_gapped.setName("SubSeqMySeqAlign"); // name of sequence in a particular alignment should be recovered
+ SeqCigar subseq_cg = new SeqCigar(subseq_gapped);
+ assertTrue(testSeqRecovery(subseq_cg,subseq_gapped,true));
+ }
/*
* refactored 'as is' from main method
*
assertEquals("Failed parseCigar", ex_cs_gapped,
gen_sgapped.getCigarstring());
- testSeqRecovery(gen_sgapped, s_gapped);
+ assertTrue(testSeqRecovery(gen_sgapped, s_gapped,true));
/*
* Test dataset resolution
*/
SeqCigar sub_gapped = new SeqCigar(s_subsequence_gapped);
- testSeqRecovery(sub_gapped, s_subsequence_gapped);
+ assertTrue(testSeqRecovery(sub_gapped, s_subsequence_gapped,true));
/*
* Test width functions
assertEquals("Failed getCigarstring", ex_cs_gapped, cs_gapped);
}
- protected void testSeqRecovery(SeqCigar gen_sgapped, SequenceI s_gapped)
+ protected boolean testSeqRecovery(SeqCigar gen_sgapped, SequenceI s_gapped,boolean startEndCheck)
{
// this is non-rigorous - start and end recovery is not tested.
SequenceI gen_sgapped_s = gen_sgapped.getSeq('-');
System.err.println("Couldn't reconstruct sequence.\n"
+ gen_sgapped_s.getSequenceAsString() + "\n"
+ s_gapped.getSequenceAsString());
+ return false;
+ }
+ if (startEndCheck)
+ {
+ assertEquals("Start not conserved in reconstructed sequence",s_gapped.getStart(),gen_sgapped_s.getStart());
+ assertEquals("End not conserved in reconstructed sequence",s_gapped.getEnd(),gen_sgapped_s.getEnd());
}
+ return true;
}
}
@Test(groups = { "Functional" })
public void testCopyConstructors()
{
- SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
- 12.5f, "group");
+ SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+ "group");
sf1.setValue("STRAND", "+");
sf1.setValue("Note", "Testing");
Integer count = Integer.valueOf(7);
/*
* copy constructor modifying type/begin/end/group/score
*/
- SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12,
- 15, "group3", -9.1f);
+ SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12, 15,
+ "group3", -9.1f);
assertEquals("Disulfide bond", sf4.getType());
assertTrue(sf4.isContactFeature());
assertEquals("desc", sf4.getDescription());
@Test(groups = { "Functional" })
public void testGetValue()
{
- SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
- 12.5f, "group");
+ SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+ "group");
sf1.setValue("STRAND", "+");
assertEquals("+", sf1.getValue("STRAND"));
assertNull(sf1.getValue("strand")); // case-sensitive
@Test(groups = { "Functional" })
public void testEqualsAndHashCode()
{
- SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
- 12.5f, "group");
+ SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+ "group");
sf1.setValue("ID", "id");
sf1.setValue("Name", "name");
sf1.setValue("Parent", "parent");
sf1.setStrand("+");
sf1.setPhase("1");
- SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33,
- 12.5f, "group");
+ SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+ "group");
sf2.setValue("ID", "id");
sf2.setValue("Name", "name");
sf2.setValue("Parent", "parent");
assertEquals(sf1.hashCode(), sf2.hashCode());
// changing type breaks equals:
- SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33,
- 12.5f, "group");
- SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33,
- 12.5f, "group");
+ SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+ "group");
+ SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33, 12.5f,
+ "group");
assertFalse(sf3.equals(sf4));
// changing description breaks equals:
// changing start position breaks equals:
int restorei = sf2.getBegin();
- sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(), sf2.getScore());
+ sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(),
+ sf2.getScore());
assertFalse(sf1.equals(sf2));
sf2 = new SequenceFeature(sf2, restorei, sf2.getEnd(),
sf2.getFeatureGroup(), sf2.getScore());
// changing feature group breaks equals:
restores = sf2.getFeatureGroup();
- sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group", sf2.getScore());
+ sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group",
+ sf2.getScore());
assertFalse(sf1.equals(sf2));
- sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores, sf2.getScore());
+ sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores,
+ sf2.getScore());
// changing ID breaks equals:
restores = (String) sf2.getValue("ID");
String seqName = seq.getName();
// single locus, no group, no score
- SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22, null);
+ SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22,
+ null);
String expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22</td></tr>"
+ "<tr><td>Type</td><td>variant</td><td></td></tr>"
+ "<tr><td>Description</td><td>G,C</td><td></td></tr></table>";
+ "<tr><td>Description</td><td>a description</td><td></td></tr></table>";
assertEquals(expected, sf.getDetailsReport(seqName, null));
- sf = new SequenceFeature("variant", "G,C", 22, 33,
- 12.5f, "group");
+ sf = new SequenceFeature("variant", "G,C", 22, 33, 12.5f, "group");
sf.setValue("Parent", "ENSG001");
sf.setValue("Child", "ENSP002");
expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22-33</td></tr>"
+ "<tr><td>Type</td><td>variant</td><td></td></tr>"
+ "<tr><td>Description</td><td>G,C</td><td></td></tr>"
+ "<tr><td>Consequence</td><td><i>Translated by Jalview</i></td><td>p.Leu9Phe</td></tr>"
- + "<tr><td>alleles</td><td></td><td>G,C</td></tr>"
+ + "<tr><td>alleles</td><td></td><td>G,C</td></tr>"
+ "</table>";
assertEquals(expected, sf.getDetailsReport(seq.getName(), mf));
+
+
+ /*
+ * exon feature extending beyond mapped range; mapped location should be
+ * restricted to peptide mapped range limit i.e. 10-13
+ */
+ SequenceFeature sf2 = new SequenceFeature("exon", "exon 1", 109, 230, null);
+ features.add(sf2);
+ expected = "<br><table><tr><td>Location</td><td>Cds</td><td>109-230</td></tr>"
+ + "<tr><td>Peptide Location</td><td>TestSeq</td><td>10-13</td></tr>"
+ + "<tr><td>Type</td><td>exon</td><td></td></tr>"
+ + "<tr><td>Description</td><td>exon 1</td><td></td></tr>"
+ + "</table>";
+ assertEquals(expected, sf2.getDetailsReport(seq.getName(), mf));
}
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.FeatureColourI;
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.project.Jalview2xmlTests;
+import jalview.renderer.ResidueShaderI;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.JalviewColourScheme;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.util.MessageManager;
+
+import java.awt.Color;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class SplitFrameTest
+{
+ AlignFrame dnaAf, proteinAf;
+
+ SplitFrame testSplitFrame;
+
+ @BeforeClass(alwaysRun = true)
+ public static void setUpBeforeClass() throws Exception
+ {
+ setUpJvOptionPane();
+ /*
+ * use read-only test properties file
+ */
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ Jalview.main(new String[] { "-nonews" });
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown()
+ {
+ Desktop.instance.closeAll_actionPerformed(null);
+ }
+
+ /**
+ * configure (read-only) properties for test to ensure Consensus is computed
+ * for colour Above PID testing
+ */
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+ Boolean.TRUE.toString());
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/testdata/MN908947.jvp", DataSourceType.FILE);
+
+ /*
+ * wait for Consensus thread to complete
+ */
+ synchronized (this)
+ {
+ while (af.getViewport().getConsensusSeq() == null)
+ {
+ try
+ {
+ wait(50);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ testSplitFrame = (SplitFrame) af.getSplitViewContainer();
+ proteinAf=af.getViewport().getAlignment().isNucleotide() ? testSplitFrame.getComplementAlignFrame(af) : af;
+ dnaAf=testSplitFrame.getComplementAlignFrame(proteinAf);
+ }
+
+ public static void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ @Test(groups= {"Functional"})
+ public void testAlignAsSplitFrame()
+ {
+
+ /*
+ * If alignment was requested from one half of a SplitFrame, show in a
+ * SplitFrame with the other pane similarly aligned.
+ */
+ AlignFrame requestedBy = proteinAf;
+ AlignmentI wholeProteinAl = proteinAf.getViewport().getAlignment();
+ SequenceI[] sel = wholeProteinAl.getSequencesArray();
+ // Select 3 sequences, from columns 3-7 inclusive
+ SequenceGroup selRegion = new SequenceGroup(
+ Arrays.asList(sel[0], sel[1], sel[3]));
+ selRegion.setStartRes(3);
+ selRegion.setEndRes(7);
+ proteinAf.getViewport().setSelectionGroup(selRegion);
+ proteinAf.getViewport().sendSelection();
+ assertNotNull(dnaAf.getViewport().getSelectionGroup());
+ AlignmentView inputView = proteinAf.gatherSequencesForAlignment();
+ assertEquals(inputView.getSequences().length, 3);
+ assertEquals(inputView.getWidth(), 5);
+ assertNotNull(inputView.getComplementView());
+
+ Object alAndHidden[] = inputView.getAlignmentAndHiddenColumns(
+ proteinAf.getViewport().getGapCharacter());
+ AlignmentI result = new Alignment((SequenceI[]) alAndHidden[0]);
+ result.setHiddenColumns((HiddenColumns) alAndHidden[1]);
+ // check we are referring to the expected alignment
+ assertEquals(
+ requestedBy.getSplitViewContainer().getComplement(requestedBy),
+ dnaAf.getCurrentView().getAlignment());
+ // and that datasets are consistent (if not, there's a problem elsewhere in
+ // splitframe construction
+ AlignmentI complementDs = requestedBy.getSplitViewContainer()
+ .getComplement(requestedBy).getDataset();
+ assertTrue(complementDs == dnaAf
+ .getViewport().getAlignment().getDataset());
+ assertTrue(complementDs == proteinAf.getViewport().getAlignment()
+ .getDataset());
+
+ char gc = requestedBy.getSplitViewContainer().getComplement(requestedBy)
+ .getGapCharacter();
+
+ AlignmentI complement = inputView.getComplementView()
+ .getVisibleAlignment(gc);
+ String complementTitle = requestedBy.getSplitViewContainer()
+ .getComplementTitle(requestedBy);
+ // becomes null if the alignment window was closed before the alignment
+ // job finished.
+ AlignmentI copyComplement = new Alignment(complement);
+ // todo should this be done by copy constructor?
+ copyComplement.setGapCharacter(complement.getGapCharacter());
+ // share the same dataset (and the mappings it holds)
+ copyComplement.setDataset(complementDs);
+ copyComplement.alignAs(result);
+ // check shape is as expected
+ assertEquals(copyComplement.getWidth(), result.getWidth() * 3);
+ assertEquals(copyComplement.getHeight(), result.getHeight());
+ // specific bug with this set - see same CDS for all distinct products
+ assertTrue(
+ !copyComplement.getSequenceAt(0).getSequenceAsString().equals(
+ copyComplement.getSequenceAt(1).getSequenceAsString()),
+ "Didn't reconstruct CDS correctly");
+ // now get the result again, do some edits and reconstruct again
+ alAndHidden = inputView.getAlignmentAndHiddenColumns(
+ proteinAf.getViewport().getGapCharacter());
+ AlignmentI newresult = new Alignment((SequenceI[]) alAndHidden[0]);
+ newresult.setHiddenColumns((HiddenColumns) alAndHidden[1]);
+ newresult.setDataset(complementDs);
+ newresult.getSequenceAt(0).insertCharAt(3, 3, '-');
+ newresult.getSequenceAt(1).insertCharAt(0, 3, '-');
+ newresult.padGaps();
+ AlignmentI newcomplement = inputView.getComplementView()
+ .getVisibleAlignment('-');
+ newcomplement.alignAs(newresult);
+ assertEquals(newcomplement.getWidth(), newresult.getWidth() * 3);
+ assertEquals(newcomplement.getHeight(), newresult.getHeight());
+ // if reconstruction worked, the first sequence should not equal the first
+ // sequence in the original CDS 'alignAs'
+ for (int sq = 0; sq < 3; sq++)
+ {
+ // check same CDS in same position
+ assertTrue(newcomplement.getSequenceAt(sq)
+ .getDatasetSequence() == newcomplement.getSequenceAt(sq)
+ .getDatasetSequence());
+ // verify that sequence strings are different
+ assertTrue(!newcomplement.getSequenceAt(sq).getSequenceAsString()
+ .equals(copyComplement.getSequenceAt(sq)
+ .getSequenceAsString()));
+ }
+ // JAL-3748 bug manifests as duplicated CDS sequence content, so need to
+ // also check each CDS is distinct.
+ assertTrue(
+ !newcomplement.getSequenceAt(0).getSequenceAsString().equals(
+ newcomplement.getSequenceAt(1).getSequenceAsString()),
+ "Didn't reconstruct CDS correctly");
+
+ }
+}
{
assertEquals((ranges = map.getFromRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1579);
- assertEquals(ranges.get(0)[1], 2934);
+ assertEquals(ranges.get(0)[1], 2931);
assertEquals((ranges = map.getToRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1);
assertEquals(ranges.get(0)[1], 451);
{
assertEquals((ranges = map.getFromRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 2928);
- assertEquals(ranges.get(0)[1], 3992);
+ assertEquals(ranges.get(0)[1], 3989);
assertEquals((ranges = map.getToRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1);
assertEquals(ranges.get(0)[1], 354);
{
assertEquals((ranges = map.getFromRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 4054);
- assertEquals(ranges.get(0)[1], 4848);
+ assertEquals(ranges.get(0)[1], 4845);
assertEquals((ranges = map.getToRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1);
assertEquals(ranges.get(0)[1], 264);
assertEquals(ranges.get(0)[0], 7022);
assertEquals(ranges.get(0)[1], 7502);
assertEquals(ranges.get(1)[0], 1);
- assertEquals(ranges.get(1)[1], 437);
+ assertEquals(ranges.get(1)[1], 434);
assertEquals((ranges = map.getToRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1);
assertEquals(ranges.get(0)[1], 305);
// complement(488..1480)
assertEquals((ranges = map.getFromRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1480);
- assertEquals(ranges.get(0)[1], 488);
+ assertEquals(ranges.get(0)[1], 491);
assertEquals((ranges = map.getToRanges()).size(), 1);
assertEquals(ranges.get(0)[0], 1);
assertEquals(ranges.get(0)[1], 330);
{
int[] exons = new int[] { 11, 15, 21, 25, 31, 38 }; // 18 bp
+ int[] exons_nostop = new int[] { 11, 15, 21, 25, 31, 35 }; // 15 bp
// exact length match:
assertSame(exons, EmblFlatFile.adjustForProteinLength(6, exons));
- // match if we assume exons include stop codon not in protein:
- assertSame(exons, EmblFlatFile.adjustForProteinLength(5, exons));
+ // trimmed if we assume exons include stop codon not in protein:
+ assertEquals(Arrays.toString(exons_nostop), Arrays.toString(EmblFlatFile.adjustForProteinLength(5, exons)));
// truncate last exon by 6bp
int[] truncated = EmblFlatFile.adjustForProteinLength(4, exons);
@Test(groups = { "Functional" })
public void compareTransferredToRefPDBAnnot() throws Exception
{
+ // JBPNote this has failed when run on OSX via gradle clean test
+ // possible race condition ?
StructureImportSettings.setProcessSecondaryStructure(true);
StructureImportSettings.setVisibleChainAnnotation(true);
StructureImportSettings.setShowSeqFeatures(true);
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
-import jalview.gui.JvOptionPane;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import jalview.bin.Cache;
+import jalview.gui.JvOptionPane;
+
public class MapListTest
{
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.initLogger();
+ }
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
@Test(groups = { "Functional" })
public void testSomething()
{
- MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
- 51, 1 }, 1, 3);
+ MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+ new int[]
+ { 51, 1 }, 1, 3);
MapList ml1 = new MapList(new int[] { 1, 3, 17, 4 },
- new int[] { 51, 1 }, 1, 3);
+ new int[]
+ { 51, 1 }, 1, 3);
MapList ml2 = new MapList(new int[] { 1, 60 }, new int[] { 1, 20 }, 3,
1);
// test internal consistency
int to[] = new int[51];
testMap(ml, 1, 60);
- MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 }, new int[]
- { 1, 3 }, 3, 1);
+ MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 },
+ new int[]
+ { 1, 3 }, 3, 1);
int[] frm = mldna.locateInFrom(1, 1);
testLocateFrom(mldna, 1, 1, new int[] { 2, 2, 6, 7 });
testMap(mldna, 1, 3);
}
/**
+ * Tests for method that locates the overlap of the ranges in the 'from' map
+ * for given range in the 'to' map
+ */
+ @Test(groups = { "Functional" })
+ public void testGetOverlapsInFrom_withIntrons()
+ {
+ /*
+ * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [16, 17, 18] i.e.
+ * 2-3, 5-7, 9-10, 12-12, 14-14, 16-18
+ */
+ int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
+ int[] protein = { 11, 14 };
+ MapList ml = new MapList(codons, protein, 3, 1);
+
+ assertEquals("[2, 3, 5, 5]",
+ Arrays.toString(ml.getOverlapsInFrom(11, 11)));
+ assertEquals("[2, 3, 5, 7, 9, 9]",
+ Arrays.toString(ml.getOverlapsInFrom(11, 12)));
+ // out of range 5' :
+ assertEquals("[2, 3, 5, 7, 9, 9]",
+ Arrays.toString(ml.getOverlapsInFrom(8, 12)));
+ // out of range 3' :
+ assertEquals("[10, 10, 12, 12, 14, 14, 16, 18]",
+ Arrays.toString(ml.getOverlapsInFrom(13, 16)));
+ // out of range both :
+ assertEquals("[2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18]",
+ Arrays.toString(ml.getOverlapsInFrom(1, 16)));
+ // no overlap:
+ assertNull(ml.getOverlapsInFrom(20, 25));
+ }
+
+ /**
+ * Tests for method that locates the overlap of the ranges in the 'to' map
+ * for given range in the 'from' map
+ */
+ @Test(groups = { "Functional" })
+ public void testGetOverlapsInTo_withIntrons()
+ {
+ /*
+ * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [17, 18, 19] i.e.
+ * 2-3, 5-7, 9-10, 12-12, 14-14, 17-19
+ */
+ int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 17, 19 };
+ /*
+ * Mapped proteins at positions 1, 3, 4, 6 in the sequence
+ */
+ int[] protein = { 1, 1, 3, 4, 6, 6 };
+ MapList ml = new MapList(codons, protein, 3, 1);
+
+ /*
+ * Can't map from an unmapped position
+ */
+ assertNull(ml.getOverlapsInTo(1, 1));
+ assertNull(ml.getOverlapsInTo(4, 4));
+ assertNull(ml.getOverlapsInTo(15, 16));
+
+ /*
+ * nor from a range that includes no mapped position (exon)
+ */
+ assertNull(ml.getOverlapsInTo(15, 16));
+
+ // end of codon 1 maps to first peptide
+ assertEquals("[1, 1]", Arrays.toString(ml.getOverlapsInTo(2, 2)));
+ // end of codon 1 and start of codon 2 maps to first 2 peptides
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(3, 7)));
+
+ // range overlaps 5' end of dna:
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 6)));
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 8)));
+
+ // range overlaps 3' end of dna:
+ assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(17, 24)));
+ assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(16, 24)));
+
+ // dna positions 8, 11 are intron but include end of exon 2 and start of exon 3
+ assertEquals("[3, 4]", Arrays.toString(ml.getOverlapsInTo(8, 11)));
+ }
+
+ /**
* Tests for method that locates ranges in the 'to' map for given range in the
* 'from' map.
*/
List<int[]> ranges = new ArrayList<>();
ranges.add(new int[] { 2, 3 });
ranges.add(new int[] { 5, 6 });
- assertEquals("[2, 3, 5, 6]", Arrays.toString(MapList.getRanges(ranges)));
+ assertEquals("[2, 3, 5, 6]",
+ Arrays.toString(MapList.getRanges(ranges)));
}
/**
assertEquals(6, ml2.getToHighest());
assertEquals("{[2, 3], [5, 7], [9, 10], [12, 12], [14, 14], [16, 18]}",
prettyPrint(ml2.getFromRanges()));
- assertEquals("{[1, 1], [3, 4], [6, 6]}", prettyPrint(ml2.getToRanges()));
+ assertEquals("{[1, 1], [3, 4], [6, 6]}",
+ prettyPrint(ml2.getToRanges()));
/*
* reverse direction
}
/**
- * Test constructor can merge consecutive ranges
+ * Test constructor used to merge consecutive ranges but now just leaves them
+ * as supplied (JAL-3751)
*/
@Test(groups = { "Functional" })
public void testConstructor_mergeRanges()
{
- int[] codons = { 2, 3, 3, 7, 9, 10, 12, 12, 14, 14, 16, 17 };
- int[] protein = { 1, 1, 1, 3, 6, 6 };
+ int[] codons = { 2, 3, 3, 7, 9, 10, 12, 12, 13, 14, 16, 17 };
+ int[] protein = { 1, 1, 2, 3, 6, 6 };
MapList ml = new MapList(codons, protein, 3, 1);
assertEquals(3, ml.getFromRatio());
assertEquals(2, ml.getFromLowest());
assertEquals(17, ml.getFromHighest());
assertEquals(1, ml.getToLowest());
assertEquals(6, ml.getToHighest());
- assertEquals("{[2, 7], [9, 10], [12, 12], [14, 14], [16, 17]}",
+ assertEquals("{[2, 3], [3, 7], [9, 10], [12, 12], [13, 14], [16, 17]}",
prettyPrint(ml.getFromRanges()));
- assertEquals("{[1, 3], [6, 6]}", prettyPrint(ml.getToRanges()));
+ assertEquals("{[1, 1], [2, 3], [6, 6]}", prettyPrint(ml.getToRanges()));
}
/**
@Test(groups = { "Functional" })
public void testToString()
{
- MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
- 51, 1 }, 1, 3);
+ MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+ new int[]
+ { 51, 1 }, 1, 3);
String s = ml.toString();
assertEquals("[ [1, 5] [10, 15] [25, 20] ] 1:3 to [ [51, 1] ]", s);
}
public void testAddMapList()
{
MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
- new int[] { 72, 22 }, 1, 3);
+ new int[]
+ { 72, 22 }, 1, 3);
assertEquals(11, ml.getFromLowest());
assertEquals(35, ml.getFromHighest());
assertEquals(22, ml.getToLowest());
assertEquals(72, ml.getToHighest());
- MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 }, new int[] { 12,
- 17, 78, 83, 88, 96 }, 1, 3);
+ MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 },
+ new int[]
+ { 12, 17, 78, 83, 88, 96 }, 1, 3);
ml.addMapList(ml2);
assertEquals(2, ml.getFromLowest());
assertEquals(40, ml.getFromHighest());
public void testAddMapList_sameMap()
{
MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
- new int[] { 72, 22 }, 1, 3);
+ new int[]
+ { 72, 22 }, 1, 3);
String before = ml.toString();
ml.addMapList(ml);
assertEquals(before, ml.toString());
MapList ml = new MapList(new int[] { 11, 15 }, new int[] { 72, 58 }, 1,
3);
- MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 },
- 1, 3);
+ MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 }, 1,
+ 3);
ml.addMapList(ml2);
assertEquals("[ [11, 16] ] 1:3 to [ [72, 53] ]", ml.toString());
}
public void testIsFromForwardStrand()
{
// [3-9] declares forward strand
- MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 }, new int[] {
- 20, 11 }, 1, 1);
+ MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 },
+ new int[]
+ { 20, 11 }, 1, 1);
assertTrue(ml.isFromForwardStrand());
// [11-5] declares reverse strand ([13-14] is ignored)
ml = new MapList(new int[] { 2, 2, 11, 5, 13, 14 },
- new int[] { 20, 11 }, 1, 1);
+ new int[]
+ { 20, 11 }, 1, 1);
assertFalse(ml.isFromForwardStrand());
// all single position ranges - defaults to forward strand
}
/**
- * Test the method that merges a list of ranges where possible
+ * Test the method that merges contiguous ranges
*/
@Test(groups = { "Functional" })
public void testCoalesceRanges()
// merging in forward direction:
ranges.clear();
ranges.add(new int[] { 1, 3 });
- ranges.add(new int[] { 4, 5 });
- ranges.add(new int[] { 5, 5 });
- ranges.add(new int[] { 5, 7 });
+ ranges.add(new int[] { 4, 5 }); // contiguous
+ ranges.add(new int[] { 5, 5 }); // overlap!
+ ranges.add(new int[] { 6, 7 }); // contiguous
List<int[]> merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 1, 7 }, merged.get(0));
+ assertEquals(2, merged.size());
+ assertArrayEquals(new int[] { 1, 5 }, merged.get(0));
+ assertArrayEquals(new int[] { 5, 7 }, merged.get(1));
// verify input list is unchanged
assertEquals(4, ranges.size());
assertArrayEquals(new int[] { 1, 3 }, ranges.get(0));
assertArrayEquals(new int[] { 4, 5 }, ranges.get(1));
assertArrayEquals(new int[] { 5, 5 }, ranges.get(2));
- assertArrayEquals(new int[] { 5, 7 }, ranges.get(3));
+ assertArrayEquals(new int[] { 6, 7 }, ranges.get(3));
// merging in reverse direction:
ranges.clear();
ranges.add(new int[] { 7, 5 });
- ranges.add(new int[] { 5, 4 });
- ranges.add(new int[] { 4, 4 });
- ranges.add(new int[] { 3, 1 });
+ ranges.add(new int[] { 5, 4 }); // overlap
+ ranges.add(new int[] { 4, 4 }); // overlap
+ ranges.add(new int[] { 3, 1 }); // contiguous
merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 7, 1 }, merged.get(0));
+ assertEquals(3, merged.size());
+ assertArrayEquals(new int[] { 7, 5 }, merged.get(0));
+ assertArrayEquals(new int[] { 5, 4 }, merged.get(1));
+ assertArrayEquals(new int[] { 4, 1 }, merged.get(2));
// merging with switches of direction:
ranges.clear();
ranges.add(new int[] { 1, 3 });
- ranges.add(new int[] { 4, 5 });
- ranges.add(new int[] { 5, 5 });
- ranges.add(new int[] { 6, 6 });
+ ranges.add(new int[] { 4, 5 }); // contiguous
+ ranges.add(new int[] { 5, 5 }); // overlap
+ ranges.add(new int[] { 6, 6 }); // contiguous
ranges.add(new int[] { 12, 10 });
- ranges.add(new int[] { 9, 8 });
- ranges.add(new int[] { 8, 8 });
- ranges.add(new int[] { 7, 7 });
+ ranges.add(new int[] { 9, 8 }); // contiguous
+ ranges.add(new int[] { 8, 8 }); // overlap
+ ranges.add(new int[] { 7, 7 }); // contiguous
merged = MapList.coalesceRanges(ranges);
- assertEquals(2, merged.size());
- assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
- assertArrayEquals(new int[] { 12, 7 }, merged.get(1));
- }
-
- /**
- * Test the method that merges a list of ranges where possible
- */
- @Test(groups = { "Functional" })
- public void testCoalesceRanges_withOverlap()
- {
- List<int[]> ranges = new ArrayList<>();
- ranges.add(new int[] { 1, 3 });
- ranges.add(new int[] { 2, 5 });
-
- /*
- * [2, 5] should extend [1, 3]
- */
- List<int[]> merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
+ assertEquals(4, merged.size());
assertArrayEquals(new int[] { 1, 5 }, merged.get(0));
-
- /*
- * a subsumed interval should be dropped
- */
- ranges.clear();
- ranges.add(new int[] { 1, 6 });
- ranges.add(new int[] { 2, 4 });
- merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
-
- ranges.clear();
- ranges.add(new int[] { 1, 5 });
- ranges.add(new int[] { 1, 6 });
- merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
-
- /*
- * merge duplicate ranges
- */
+ assertArrayEquals(new int[] { 5, 6 }, merged.get(1));
+ assertArrayEquals(new int[] { 12, 8 }, merged.get(2));
+ assertArrayEquals(new int[] { 8, 7 }, merged.get(3));
+
+ // 'subsumed' ranges are preserved
ranges.clear();
- ranges.add(new int[] { 1, 3 });
- ranges.add(new int[] { 1, 3 });
+ ranges.add(new int[] { 10, 30 });
+ ranges.add(new int[] { 15, 25 });
merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 1, 3 }, merged.get(0));
-
- /*
- * reverse direction
- */
- ranges.clear();
- ranges.add(new int[] { 9, 5 });
- ranges.add(new int[] { 9, 4 });
- ranges.add(new int[] { 8, 3 });
- ranges.add(new int[] { 3, 2 });
- ranges.add(new int[] { 1, 0 });
- merged = MapList.coalesceRanges(ranges);
- assertEquals(1, merged.size());
- assertArrayEquals(new int[] { 9, 0 }, merged.get(0));
+ assertEquals(2, merged.size());
+ assertArrayEquals(new int[] { 10, 30 }, merged.get(0));
+ assertArrayEquals(new int[] { 15, 25 }, merged.get(1));
}
/**
/*
* simple 1:1 plus 1:1 forwards
*/
- MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 }, new int[] { 5, 8,
- 11, 13 }, 1, 1);
+ MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 },
+ new int[]
+ { 5, 8, 11, 13 }, 1, 1);
assertEquals("{[3, 4], [8, 12]}", prettyPrint(ml1.getFromRanges()));
assertEquals("{[5, 8], [11, 13]}", prettyPrint(ml1.getToRanges()));
- MapList ml2 = new MapList(new int[] { 1, 50 }, new int[] { 40, 45, 70,
- 75, 90, 127 }, 1, 1);
+ MapList ml2 = new MapList(new int[] { 1, 50 },
+ new int[]
+ { 40, 45, 70, 75, 90, 127 }, 1, 1);
assertEquals("{[1, 50]}", prettyPrint(ml2.getFromRanges()));
assertEquals("{[40, 45], [70, 75], [90, 127]}",
prettyPrint(ml2.getToRanges()));
*/
ml1 = new MapList(new int[] { 1, 50 }, new int[] { 70, 119 }, 1, 1);
ml2 = new MapList(new int[] { 1, 500 },
- new int[] { 1000, 901, 600, 201 }, 1, 1);
+ new int[]
+ { 1000, 901, 600, 201 }, 1, 1);
compound = ml1.traverse(ml2);
assertEquals(1, compound.getFromRatio());
* 1:1 plus 1:3 should result in 1:3
*/
ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 40 }, 1, 1);
- ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 },
- 1, 3);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 }, 1,
+ 3);
compound = ml1.traverse(ml2);
assertEquals(1, compound.getFromRatio());
* 3:1 plus 1:1 should result in 3:1
*/
ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 20 }, 3, 1);
- ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 },
- 1, 1);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 }, 1,
+ 1);
compound = ml1.traverse(ml2);
assertEquals(3, compound.getFromRatio());
}
/**
- * Test that method that inspects for the (first) forward or reverse 'to' range.
- * Single position ranges are ignored.
+ * Test that method that inspects for the (first) forward or reverse 'to'
+ * range. Single position ranges are ignored.
*/
@Test(groups = { "Functional" })
public void testIsToForwardsStrand()
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.AssertJUnit.fail;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.commands.EditCommand.Edit;
import jalview.io.FileFormatI;
import jalview.io.FormatAdapter;
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
public class MappingUtilsTest
{
-
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.initLogger();
+ }
+
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
{
MapList map = new MapList(new int[] { 5, 10 }, new int[] { 12, 13 }, 3,
1);
acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
/*
* Check protein residue 12 maps to codon 5-7, 13 to codon 8-10
* Map dna bases [6, 8, 9], [11, 13, 115] to protein residues 8 and 9
*/
AlignedCodonFrame acf = new AlignedCodonFrame();
- MapList map = new MapList(new int[] { 6, 6, 8, 9, 11, 11, 13, 13, 15,
- 15 }, new int[] { 8, 9 }, 3, 1);
+ MapList map = new MapList(
+ new int[]
+ { 6, 6, 8, 9, 11, 11, 13, 13, 15, 15 }, new int[] { 8, 9 }, 3,
+ 1);
acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
/*
* Check protein residue 8 maps to [6, 8, 9]
for (int i = 5; i < 18; i++)
{
sr = MappingUtils.buildSearchResults(seq1, i, acfList);
- int residue = (i == 6 || i == 8 || i == 9) ? 8 : (i == 11 || i == 13
- || i == 15 ? 9 : 0);
+ int residue = (i == 6 || i == 8 || i == 9) ? 8
+ : (i == 11 || i == 13 || i == 15 ? 9 : 0);
if (residue == 0)
{
assertEquals(0, sr.getResults().size());
MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
for (int seq = 0; seq < 3; seq++)
{
- acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
- .getSequenceAt(seq).getDatasetSequence(), map);
+ acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+ protein.getSequenceAt(seq).getDatasetSequence(), map);
}
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
- AlignViewportI dnaView = new AlignViewport(cdna);
- AlignViewportI proteinView = new AlignViewport(protein);
+ AlignViewportI theDnaView = new AlignViewport(cdna);
+ AlignViewportI theProteinView = new AlignViewport(protein);
protein.setCodonFrames(acfList);
/*
- * Select Seq1 and Seq3 in the protein (startRes=endRes=0)
+ * Select Seq1 and Seq3 in the protein
*/
SequenceGroup sg = new SequenceGroup();
sg.setColourText(true);
sg.setOutlineColour(Color.LIGHT_GRAY);
sg.addSequence(protein.getSequenceAt(0), false);
sg.addSequence(protein.getSequenceAt(2), false);
+ sg.setEndRes(protein.getWidth() - 1);
/*
* Verify the mapped sequence group in dna
*/
SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
- proteinView, dnaView);
+ theProteinView, theDnaView);
assertTrue(mappedGroup.getColourText());
assertSame(sg.getIdColour(), mappedGroup.getIdColour());
assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
assertEquals(0, mappedGroup.getStartRes());
- assertEquals(2, mappedGroup.getEndRes());
+ assertEquals(2, mappedGroup.getEndRes()); // 3 columns (1 codon)
/*
* Verify mapping sequence group from dna to protein
sg.addSequence(cdna.getSequenceAt(0), false);
sg.setStartRes(0);
sg.setEndRes(2);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theDnaView, theProteinView);
assertTrue(mappedGroup.getColourText());
assertSame(sg.getIdColour(), mappedGroup.getIdColour());
assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
protected AlignmentI loadAlignment(final String data, FileFormatI format)
throws IOException
{
- AlignmentI a = new FormatAdapter().readFile(data,
- DataSourceType.PASTE, format);
+ AlignmentI a = new FormatAdapter().readFile(data, DataSourceType.PASTE,
+ format);
a.setDataset(null);
return a;
}
cs.clear();
colsel.clear();
colsel.addElement(2);
- MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
- dnaView, cs, hs);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+ cs, hs);
assertEquals("[]", cs.getSelected().toString());
/*
cs.clear();
colsel.clear();
colsel.addElement(3);
- MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
- dnaView, cs, hs);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+ cs, hs);
assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
/*
colsel.clear();
colsel.addElement(1);
colsel.addElement(3);
- MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
- dnaView, cs, hs);
- assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
- .toString());
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+ cs, hs);
+ assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]",
+ cs.getSelected().toString());
}
/**
// map first dna to first protein seq
AlignedCodonFrame acf = new AlignedCodonFrame();
MapList map = new MapList(new int[] { 10, 12, 15, 15, 17, 18 },
- new int[] { 40, 41 }, 3, 1);
- acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
- .getSequenceAt(0).getDatasetSequence(), map);
+ new int[]
+ { 40, 41 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(),
+ protein.getSequenceAt(0).getDatasetSequence(), map);
// map second dna to second protein seq
- map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 }, new int[] { 50,
- 51 }, 3, 1);
- acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
- .getSequenceAt(1).getDatasetSequence(), map);
+ map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 },
+ new int[]
+ { 50, 51 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(),
+ protein.getSequenceAt(1).getDatasetSequence(), map);
// map third dna to third protein seq
- map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 }, new int[] { 60,
- 61 }, 3, 1);
- acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
- .getSequenceAt(2).getDatasetSequence(), map);
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 },
+ new int[]
+ { 60, 61 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(),
+ protein.getSequenceAt(2).getDatasetSequence(), map);
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
dnaView = new AlignViewport(cdna);
proteinView = new AlignViewport(protein);
public void testFlattenRanges()
{
assertEquals("[1, 2, 3, 4]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4 })));
- assertEquals(
- "[1, 2, 3, 4]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 2, 3,
- 4 })));
- assertEquals(
- "[1, 2, 3, 4]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 1, 2,
- 2, 3, 3, 4, 4 })));
- assertEquals(
- "[1, 2, 3, 4, 7, 8, 9, 12]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
- 9, 12, 12 })));
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4 })));
+ assertEquals("[1, 2, 3, 4]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 2, 3, 4 })));
+ assertEquals("[1, 2, 3, 4]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 1, 2, 2, 3, 3, 4, 4 })));
+ assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4, 7, 9, 12, 12 })));
// trailing unpaired start position is ignored:
- assertEquals(
- "[1, 2, 3, 4, 7, 8, 9, 12]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
- 9, 12, 12, 15 })));
+ assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4, 7, 9, 12, 12, 15 })));
}
/**
MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
for (int seq = 0; seq < 3; seq++)
{
- acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
- .getSequenceAt(seq).getDatasetSequence(), map);
+ acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+ protein.getSequenceAt(seq).getDatasetSequence(), map);
}
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
- AlignViewportI dnaView = new AlignViewport(cdna);
- AlignViewportI proteinView = new AlignViewport(protein);
+ AlignViewportI theDnaView = new AlignViewport(cdna);
+ AlignViewportI theProteinView = new AlignViewport(protein);
protein.setCodonFrames(acfList);
/*
* Verify the mapped sequence group in dna
*/
SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
- proteinView, dnaView);
+ theProteinView, theDnaView);
assertTrue(mappedGroup.getColourText());
assertSame(sg.getIdColour(), mappedGroup.getIdColour());
assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
// select columns 2 and 3 in DNA which span protein columns 0 and 1
sg.setStartRes(2);
sg.setEndRes(3);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theDnaView, theProteinView);
assertTrue(mappedGroup.getColourText());
assertSame(sg.getIdColour(), mappedGroup.getIdColour());
assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
* viewport).
*/
AlignmentI cdna = loadAlignment(
- ">Seq1\nA-CG-GC--AT-CA\n>Seq2\n-TG-AC-AG-T-AT\n>Seq3\n-T--ACG-TAAT-G\n",
+ ">Cds11\nA-CG-GC--AT-CA\n>Cds2\n-TG-AC-AG-T-AT\n>Cds3\n-T--ACG-TAAT-G\n",
FileFormat.Fasta);
cdna.setDataset(null);
AlignmentI protein = loadAlignment(
- ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n", FileFormat.Fasta);
+ ">Pep1\n-KA-S\n>Pep2\n--L-QY\n>Pep3\nQ-V-M\n",
+ FileFormat.Fasta);
protein.setDataset(null);
AlignedCodonFrame acf = new AlignedCodonFrame();
MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
for (int seq = 0; seq < 3; seq++)
{
- acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
- .getSequenceAt(seq).getDatasetSequence(), map);
+ acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+ protein.getSequenceAt(seq).getDatasetSequence(), map);
}
- List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
- { acf });
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
- AlignViewportI dnaView = new AlignViewport(cdna);
- AlignViewportI proteinView = new AlignViewport(protein);
+ AlignViewportI theDnaView = new AlignViewport(cdna);
+ AlignViewportI theProteinView = new AlignViewport(protein);
protein.setCodonFrames(acfList);
/*
- * Select Seq1 and Seq2 in the protein, column 1 (K/-). Expect mapped
- * sequence group to cover Seq1, columns 0-3 (ACG). Because the selection
- * only includes a gap in Seq2 there is no mappable selection region in the
- * corresponding DNA.
+ * Select Pep1 and Pep2 in the protein, column 1 (K/-). Expect mapped
+ * sequence group to cover Cds1, columns 0-3 (ACG). Although the selection
+ * only includes a gap in Cds2, mapped Cds2 is included with 'no columns'
*/
SequenceGroup sg = new SequenceGroup();
sg.setColourText(true);
* Verify the mapped sequence group in dna
*/
SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
- proteinView, dnaView);
+ theProteinView, theDnaView);
assertTrue(mappedGroup.getColourText());
assertSame(sg.getIdColour(), mappedGroup.getIdColour());
assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
- assertEquals(1, mappedGroup.getSequences().size());
+ assertEquals(2, mappedGroup.getSequences().size());
assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
- // Seq2 in protein has a gap in column 1 - ignored
- // Seq1 has K which should map to columns 0-3 in Seq1
+ assertSame(cdna.getSequenceAt(1), mappedGroup.getSequences().get(1));
+ // Pep2 in protein has a gap in column 1 - doesn't map to any column
+ // Pep1 has K which should map to columns 0-3 in Cds1
assertEquals(0, mappedGroup.getStartRes());
assertEquals(3, mappedGroup.getEndRes());
*/
sg.setStartRes(2);
sg.setEndRes(4);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theProteinView, theDnaView);
assertEquals(1, mappedGroup.getStartRes());
assertEquals(13, mappedGroup.getEndRes());
// select columns 4,5 - includes Seq1:codon2 (A) only
sg.setStartRes(4);
sg.setEndRes(5);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theDnaView, theProteinView);
assertEquals(2, mappedGroup.getStartRes());
assertEquals(2, mappedGroup.getEndRes());
// add Seq2 to dna selection cols 4-5 include codons 1 and 2 (LQ)
sg.addSequence(cdna.getSequenceAt(1), false);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theDnaView, theProteinView);
assertEquals(2, mappedGroup.getStartRes());
assertEquals(4, mappedGroup.getEndRes());
// add Seq3 to dna selection cols 4-5 include codon 1 (Q)
sg.addSequence(cdna.getSequenceAt(2), false);
- mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, theDnaView, theProteinView);
assertEquals(0, mappedGroup.getStartRes());
assertEquals(4, mappedGroup.getEndRes());
}
/*
* Seq1 has three mappings
*/
- List<AlignedCodonFrame> result = MappingUtils.findMappingsForSequence(
- seq1, mappings);
+ List<AlignedCodonFrame> result = MappingUtils
+ .findMappingsForSequence(seq1, mappings);
assertEquals(3, result.size());
assertTrue(result.contains(acf1));
assertTrue(result.contains(acf2));
*/
List<AlignedCodonFrame> result = MappingUtils
.findMappingsForSequenceAndOthers(null, mappings,
- Arrays.asList(new SequenceI[] { seq1, seq2 }));
+ Arrays.asList(new SequenceI[]
+ { seq1, seq2 }));
assertTrue(result.isEmpty());
result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
- Arrays.asList(new SequenceI[] { seq1, seq2 }));
+ Arrays.asList(new SequenceI[]
+ { seq1, seq2 }));
assertTrue(result.isEmpty());
/*
* Seq1 has three mappings, but filter argument will only accept
* those to seq2
*/
- result = MappingUtils.findMappingsForSequenceAndOthers(
- seq1,
- mappings,
- Arrays.asList(new SequenceI[] { seq1, seq2,
- seq1.getDatasetSequence() }));
+ result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
+ Arrays.asList(new SequenceI[]
+ { seq1, seq2, seq1.getDatasetSequence() }));
assertEquals(2, result.size());
assertTrue(result.contains(acf1));
assertTrue(result.contains(acf2));
dna.createDatasetSequence();
protein.createDatasetSequence();
AlignedCodonFrame acf = new AlignedCodonFrame();
- MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3, 1);
+ MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3,
+ 1);
acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
List<AlignedCodonFrame> mappings = new ArrayList<>();
mappings.add(acf);
*/
EditCommand ec = new EditCommand();
final Edit edit = ec.new Edit(Action.INSERT_GAP,
- new SequenceI[] { protein }, 4, 2, '-');
+ new SequenceI[]
+ { protein }, 4, 2, '-');
ec.appendEdit(edit, prot, true, null);
/*
public void testFlattenRanges_reverseStrand()
{
assertEquals("[4, 3, 2, 1]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 1 })));
- assertEquals(
- "[4, 3, 2, 1]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 3, 2,
- 1 })));
- assertEquals(
- "[4, 3, 2, 1]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 4, 3,
- 3, 2, 2, 1, 1 })));
- assertEquals(
- "[12, 9, 8, 7, 4, 3, 2, 1]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
- 9, 7, 4, 1 })));
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 4, 1 })));
+ assertEquals("[4, 3, 2, 1]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 4, 3, 2, 1 })));
+ assertEquals("[4, 3, 2, 1]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 4, 4, 3, 3, 2, 2, 1, 1 })));
+ assertEquals("[12, 9, 8, 7, 4, 3, 2, 1]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 12, 12, 9, 7, 4, 1 })));
// forwards and backwards anyone?
- assertEquals(
- "[4, 5, 6, 3, 2, 1]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 6, 3,
- 1 })));
+ assertEquals("[4, 5, 6, 3, 2, 1]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 4, 6, 3, 1 })));
// backwards and forwards
- assertEquals(
- "[3, 2, 1, 4, 5, 6]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 3, 1, 4,
- 6 })));
+ assertEquals("[3, 2, 1, 4, 5, 6]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 3, 1, 4, 6 })));
// trailing unpaired start position is ignored:
- assertEquals(
- "[12, 9, 8, 7, 4, 3, 2]",
- Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
- 9, 7, 4, 2, 1 })));
+ assertEquals("[12, 9, 8, 7, 4, 3, 2]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 12, 12, 9, 7, 4, 2, 1 })));
}
/**
/*
* both forward ranges
*/
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 1, 10 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 2, 10 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 1, 9 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 4, 5 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 0, 9 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- -10, -9 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 1, 11 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 11, 12 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 1, 10 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 2, 10 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 1, 9 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 4, 5 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 0, 9 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { -10, -9 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 1, 11 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 11, 12 }));
/*
* forward range, reverse query
*/
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 10, 1 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 9, 1 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 10, 2 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 5, 5 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 11, 1 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
- 10, 0 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 10, 1 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 9, 1 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 10, 2 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 5, 5 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 11, 1 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 10, 0 }));
/*
* reverse range, forward query
*/
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 1, 10 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 1, 9 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 2, 10 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 6, 6 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 6, 11 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 11, 20 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- -3, -2 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 1, 10 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 1, 9 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 2, 10 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 6, 6 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 6, 11 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 11, 20 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { -3, -2 }));
/*
* both reverse
*/
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 10, 1 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 9, 1 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 10, 2 }));
- assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 3, 3 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 11, 1 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 10, 0 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- 12, 11 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
- -5, -8 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 10, 1 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 9, 1 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 10, 2 }));
+ assertTrue(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 3, 3 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 11, 1 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 10, 0 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { 12, 11 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 10, 1 }, new int[] { -5, -8 }));
/*
* bad arguments
*/
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10, 12 },
- new int[] {
- 1, 10 }));
- assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 },
- new int[] { 1 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10, 12 }, new int[] { 1, 10 }));
+ assertFalse(
+ MappingUtils.rangeContains(new int[]
+ { 1, 10 }, new int[] { 1 }));
assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, null));
assertFalse(MappingUtils.rangeContains(null, new int[] { 1, 10 }));
}
// expected
}
}
+
+ /**
+ * Test mapping a sequence group where sequences in and outside the group
+ * share a dataset sequence (e.g. alternative CDS for the same gene)
+ * <p>
+ * This scenario doesn't arise after JAL-3763 changes, but test left as still valid
+ * @throws IOException
+ */
+ @Test(groups = { "Functional" })
+ public void testMapSequenceGroup_sharedDataset() throws IOException
+ {
+ /*
+ * Set up dna and protein Seq1/2/3 with mappings (held on the protein
+ * viewport). CDS sequences share the same 'gene' dataset sequence.
+ */
+ SequenceI dna = new Sequence("dna", "aaatttgggcccaaatttgggccc");
+ SequenceI cds1 = new Sequence("cds1/1-6", "aaattt");
+ SequenceI cds2 = new Sequence("cds1/4-9", "tttggg");
+ SequenceI cds3 = new Sequence("cds1/19-24", "gggccc");
+
+ cds1.setDatasetSequence(dna);
+ cds2.setDatasetSequence(dna);
+ cds3.setDatasetSequence(dna);
+
+ SequenceI pep1 = new Sequence("pep1", "KF");
+ SequenceI pep2 = new Sequence("pep2", "FG");
+ SequenceI pep3 = new Sequence("pep3", "GP");
+ pep1.createDatasetSequence();
+ pep2.createDatasetSequence();
+ pep3.createDatasetSequence();
+
+ /*
+ * add mappings from coding positions of dna to respective peptides
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ acf.addMap(dna, pep1,
+ new MapList(new int[]
+ { 1, 6 }, new int[] { 1, 2 }, 3, 1));
+ acf.addMap(dna, pep2,
+ new MapList(new int[]
+ { 4, 9 }, new int[] { 1, 2 }, 3, 1));
+ acf.addMap(dna, pep3,
+ new MapList(new int[]
+ { 19, 24 }, new int[] { 1, 2 }, 3, 1));
+
+ List<AlignedCodonFrame> acfList = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
+
+ AlignmentI cdna = new Alignment(new SequenceI[] { cds1, cds2, cds3 });
+ AlignmentI protein = new Alignment(
+ new SequenceI[]
+ { pep1, pep2, pep3 });
+ AlignViewportI cdnaView = new AlignViewport(cdna);
+ AlignViewportI peptideView = new AlignViewport(protein);
+ protein.setCodonFrames(acfList);
+
+ /*
+ * Select pep1 and pep3 in the protein alignment
+ */
+ SequenceGroup sg = new SequenceGroup();
+ sg.setColourText(true);
+ sg.setIdColour(Color.GREEN);
+ sg.setOutlineColour(Color.LIGHT_GRAY);
+ sg.addSequence(pep1, false);
+ sg.addSequence(pep3, false);
+ sg.setEndRes(protein.getWidth() - 1);
+
+ /*
+ * Verify the mapped sequence group in dna is cds1 and cds3
+ */
+ SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
+ peptideView, cdnaView);
+ assertTrue(mappedGroup.getColourText());
+ assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+ assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+ assertEquals(2, mappedGroup.getSequences().size());
+ assertSame(cds1, mappedGroup.getSequences().get(0));
+ assertSame(cds3, mappedGroup.getSequences().get(1));
+ // columns 1-6 selected (0-5 base zero)
+ assertEquals(0, mappedGroup.getStartRes());
+ assertEquals(5, mappedGroup.getEndRes());
+
+ /*
+ * Select mapping sequence group from dna to protein
+ */
+ sg.clear();
+ sg.addSequence(cds2, false);
+ sg.addSequence(cds1, false);
+ sg.setStartRes(0);
+ sg.setEndRes(cdna.getWidth() - 1);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, cdnaView, peptideView);
+ assertTrue(mappedGroup.getColourText());
+ assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+ assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+ assertEquals(2, mappedGroup.getSequences().size());
+ assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
+ assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
+ assertEquals(0, mappedGroup.getStartRes());
+ assertEquals(1, mappedGroup.getEndRes()); // two columns
+ }
+
+ @Test(groups = "Functional")
+ public void testFindOverlap()
+ {
+ List<int[]> ranges = new ArrayList<>();
+ ranges.add(new int[] {4, 8});
+ ranges.add(new int[] {10, 12});
+ ranges.add(new int[] {16, 19});
+
+ int[] overlap = MappingUtils.findOverlap(ranges, 5, 13);
+ assertArrayEquals(overlap, new int[] {5, 12});
+ overlap = MappingUtils.findOverlap(ranges, -100, 100);
+ assertArrayEquals(overlap, new int[] {4, 19});
+ overlap = MappingUtils.findOverlap(ranges, 7, 17);
+ assertArrayEquals(overlap, new int[] {7, 17});
+ overlap = MappingUtils.findOverlap(ranges, 13, 15);
+ assertNull(overlap);
+ }
}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.xml.binding.embl.EntryType.Feature.Qualifier;
import jalview.xml.binding.embl.XrefType;
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
public class EmblXmlSourceTest
{
// exact length match:
assertSame(exons, EmblXmlSource.adjustForProteinLength(6, exons));
- // match if we assume exons include stop codon not in protein:
- assertSame(exons, EmblXmlSource.adjustForProteinLength(5, exons));
+ // truncate last exon by 3bp (e.g. stop codon)
+ int[] truncated = EmblXmlSource.adjustForProteinLength(5, exons);
+ assertEquals("[11, 15, 21, 25, 31, 35]", Arrays.toString(truncated));
// truncate last exon by 6bp
- int[] truncated = EmblXmlSource.adjustForProteinLength(4, exons);
+ truncated = EmblXmlSource.adjustForProteinLength(4, exons);
assertEquals("[11, 15, 21, 25, 31, 32]", Arrays.toString(truncated));
// remove last exon and truncate preceding by 1bp