import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.ColumnSelection;
import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResults.Match;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
*
* @param command
* @param undo
- * @param alignment
+ * @param mapTo
* @param gapChar
* @param mappings
* @return
*/
public static EditCommand mapEditCommand(EditCommand command,
- boolean undo, final AlignmentI alignment, char gapChar,
+ boolean undo, final AlignmentI mapTo, char gapChar,
Set<AlignedCodonFrame> mappings)
{
/*
+ * For now, only support mapping from protein edits to cDna
+ */
+ if (!mapTo.isNucleotide())
+ {
+ return null;
+ }
+
+ /*
* Cache a copy of the target sequences so we can mimic successive edits on
* them. This lets us compute mappings for all edits in the set.
*/
Map<SequenceI, SequenceI> targetCopies = new HashMap<SequenceI, SequenceI>();
- for (SequenceI seq : alignment.getSequences())
+ for (SequenceI seq : mapTo.getSequences())
{
SequenceI ds = seq.getDatasetSequence();
if (ds != null)
targetCopies.put(ds, copy);
}
}
-
+
/*
* Compute 'source' sequences as they were before applying edits:
*/
Map<SequenceI, SequenceI> originalSequences = command.priorState(undo);
-
+
EditCommand result = new EditCommand();
Iterator<Edit> edits = command.getEditIterator(!undo);
while (edits.hasNext())
if (edit.getAction() == Action.CUT
|| edit.getAction() == Action.PASTE)
{
- mapCutOrPaste(edit, undo, alignment.getSequences(), result,
- mappings);
+ mapCutOrPaste(edit, undo, mapTo.getSequences(), result, mappings);
}
else if (edit.getAction() == Action.INSERT_GAP
|| edit.getAction() == Action.DELETE_GAP)
{
mapInsertOrDelete(edit, undo, originalSequences,
- alignment.getSequences(),
- targetCopies, gapChar, result, mappings);
+ mapTo.getSequences(), targetCopies, gapChar, result,
+ mappings);
}
}
return result.getSize() > 0 ? result : null;
EditCommand result, Set<AlignedCodonFrame> mappings)
{
Action action = edit.getAction();
-
+
/*
* Invert sense of action if an Undo.
*/
}
final SequenceI actedOn = originalSequences.get(ds);
final int seqpos = actedOn.findPosition(editPos);
-
+
/*
* Determine all mappings from this position to mapped sequences.
*/
SearchResults sr = buildSearchResults(seq, seqpos, mappings);
-
+
if (!sr.isEmpty())
{
for (SequenceI targetSeq : targetSeqs)
{
final int ratio = 3; // TODO: compute this - how?
final int mappedCount = count * ratio;
-
+
/*
* Shift Delete start position left, as it acts on positions to its
* right.
Edit e = result.new Edit(action, new SequenceI[]
{ targetSeq }, mappedEditPos, mappedCount, gapChar);
result.addEdit(e);
-
+
/*
* and 'apply' the edit to our copy of its target sequence
*/
{
acf.markMappedRegion(seq, index, results);
}
- results.addResult(seq, index, index);
}
return results;
}
/**
- * Returns a (possibly empty) SequenceGroup containing any sequences the
+ * Returns a (possibly empty) SequenceGroup containing any sequences in the
* mapped viewport corresponding to the given group in the source viewport.
*
* @param sg
- * @param av
- * @param mapped
+ * @param mapFrom
+ * @param mapTo
* @return
*/
public static SequenceGroup mapSequenceGroup(SequenceGroup sg,
- AlignViewportI av, AlignViewportI mapped)
+ AlignViewportI mapFrom, AlignViewportI mapTo)
{
/*
- * Map sequence selection. Note the SequenceGroup holds aligned sequences,
- * the mappings hold dataset sequences.
+ * Note the SequenceGroup holds aligned sequences, the mappings hold dataset
+ * sequences.
*/
- AlignedCodonFrame[] codonFrames = av.getAlignment()
+ boolean targetIsNucleotide = mapTo.isNucleotide();
+ AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo;
+ Set<AlignedCodonFrame> codonFrames = protein.getAlignment()
.getCodonFrames();
/*
- * Copy group name, colours, but not sequences
+ * Copy group name, name colours, but not sequences or sequence colour
+ * scheme
*/
SequenceGroup mappedGroup = new SequenceGroup(sg);
+ mappedGroup.cs = mapTo.getGlobalColourScheme();
mappedGroup.clear();
// TODO set width of mapped group
{
for (AlignedCodonFrame acf : codonFrames)
{
- SequenceI dnaSeq = acf.getDnaForAaSeq(selected);
- if (dnaSeq != null)
+ SequenceI mappedSequence = targetIsNucleotide ? acf
+ .getDnaForAaSeq(selected) : acf.getAaForDnaSeq(selected);
+ if (mappedSequence != null)
{
- for (SequenceI seq : mapped.getAlignment().getSequences())
+ for (SequenceI seq : mapTo.getAlignment().getSequences())
{
- if (seq.getDatasetSequence() == dnaSeq)
+ if (seq.getDatasetSequence() == mappedSequence)
{
mappedGroup.addSequence(seq, false);
break;
* @return
*/
public static CommandI mapOrderCommand(OrderCommand command,
- boolean undo, AlignmentI mapTo,
- Set<AlignedCodonFrame> mappings)
+ boolean undo, AlignmentI mapTo, Set<AlignedCodonFrame> mappings)
{
SequenceI[] sortOrder = command.getSequenceOrder(undo);
List<SequenceI> mappedOrder = new ArrayList<SequenceI>();
{
for (AlignedCodonFrame acf : mappings)
{
- SequenceI dnaSeq = acf.getDnaForAaSeq(seq);
- if (dnaSeq != null)
+ /*
+ * Try protein-to-Dna, failing that try dna-to-protein
+ */
+ SequenceI mappedSeq = acf.getDnaForAaSeq(seq);
+ if (mappedSeq == null)
+ {
+ mappedSeq = acf.getAaForDnaSeq(seq);
+ }
+ if (mappedSeq != null)
{
for (SequenceI seq2 : mapTo.getSequences())
{
- if (seq2.getDatasetSequence() == dnaSeq)
+ if (seq2.getDatasetSequence() == mappedSeq)
{
mappedOrder.add(seq2);
j++;
}
/*
- * Have to align the sequences before constructing the OrderCommand - which
- * then realigns them?!?
+ * Have to sort the sequences before constructing the OrderCommand - which
+ * then resorts them?!?
*/
final SequenceI[] mappedOrderArray = mappedOrder
.toArray(new SequenceI[mappedOrder.size()]);
return result;
}
+ /**
+ * Returns a ColumnSelection in the 'mapTo' view which corresponds to the
+ * given selection in the 'mapFrom' view. We assume one is nucleotide, the
+ * other is protein (and holds the mappings from codons to protein residues).
+ *
+ * @param colsel
+ * @param mapFrom
+ * @param mapTo
+ * @return
+ */
+ public static ColumnSelection mapColumnSelection(ColumnSelection colsel,
+ AlignViewportI mapFrom, AlignViewportI mapTo)
+ {
+ boolean targetIsNucleotide = mapTo.isNucleotide();
+ AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo;
+ Set<AlignedCodonFrame> codonFrames = protein.getAlignment()
+ .getCodonFrames();
+ ColumnSelection mappedColumns = new ColumnSelection();
+ char fromGapChar = mapFrom.getAlignment().getGapCharacter();
+
+ // FIXME allow for hidden columns
+
+ /*
+ * For each mapped column, find the range of columns that residues in that
+ * column map to.
+ */
+ for (Object obj : colsel.getSelected())
+ {
+ int col = ((Integer) obj).intValue();
+ int mappedToMin = Integer.MAX_VALUE;
+ int mappedToMax = Integer.MIN_VALUE;
+
+ /*
+ * For each sequence in the 'from' alignment
+ */
+ for (SequenceI fromSeq : mapFrom.getAlignment().getSequences())
+ {
+ /*
+ * Ignore gaps (unmapped anyway)
+ */
+ if (fromSeq.getCharAt(col) == fromGapChar)
+ {
+ continue;
+ }
+
+ /*
+ * Get the residue position and find the mapped position.
+ */
+ int residuePos = fromSeq.findPosition(col);
+ SearchResults sr = buildSearchResults(fromSeq, residuePos,
+ codonFrames);
+ for (Match m : sr.getResults())
+ {
+ int mappedStartResidue = m.getStart();
+ int mappedEndResidue = m.getEnd();
+ SequenceI mappedSeq = m.getSequence();
+
+ /*
+ * Locate the aligned sequence whose dataset is mappedSeq. TODO a
+ * datamodel that can do this efficiently.
+ */
+ for (SequenceI toSeq : mapTo.getAlignment().getSequences())
+ {
+ if (toSeq.getDatasetSequence() == mappedSeq)
+ {
+ int mappedStartCol = toSeq.findIndex(mappedStartResidue);
+ int mappedEndCol = toSeq.findIndex(mappedEndResidue);
+ mappedToMin = Math.min(mappedToMin, mappedStartCol);
+ mappedToMax = Math.max(mappedToMax, mappedEndCol);
+ // System.out.println(fromSeq.getName() + " mapped to cols "
+ // + mappedStartCol + ":" + mappedEndCol);
+ break;
+ // note: remove break if we ever want to map one to many sequences
+ }
+ }
+ }
+ }
+ /*
+ * Add the range of mapped columns to the mapped selection (converting
+ * base 1 to base 0). Note that this may include intron-only regions which
+ * lie between the start and end ranges of the selection.
+ */
+ for (int i = mappedToMin; i <= mappedToMax; i++)
+ {
+ mappedColumns.addElement(i - 1);
+ }
+ }
+ return mappedColumns;
+ }
+
}