1 package jalview.analysis;
\r
3 import java.util.Enumeration;
\r
4 import java.util.Hashtable;
\r
5 import java.util.Vector;
\r
7 import jalview.datamodel.AlignedCodonFrame;
\r
8 import jalview.datamodel.Alignment;
\r
9 import jalview.datamodel.AlignmentAnnotation;
\r
10 import jalview.datamodel.AlignmentI;
\r
11 import jalview.datamodel.Annotation;
\r
12 import jalview.datamodel.ColumnSelection;
\r
13 import jalview.datamodel.DBRefEntry;
\r
14 import jalview.datamodel.FeatureProperties;
\r
15 import jalview.datamodel.Mapping;
\r
16 import jalview.datamodel.Sequence;
\r
17 import jalview.datamodel.SequenceFeature;
\r
18 import jalview.datamodel.SequenceI;
\r
19 import jalview.schemes.ResidueProperties;
\r
20 import jalview.util.MapList;
\r
21 import jalview.util.ShiftList;
\r
29 * @return -1 if cdp1 aligns before cdp2, 0 if in the same column or cdp2 is
\r
30 * null, +1 if after cdp2
\r
32 private static int compare_codonpos(int[] cdp1, int[] cdp2)
\r
35 || (cdp1[0] == cdp2[0] && cdp1[1] == cdp2[1] && cdp1[2] == cdp2[2]))
\r
37 if (cdp1[0] < cdp2[0] || cdp1[1] < cdp2[1] || cdp1[2] < cdp2[2])
\r
38 return -1; // one base in cdp1 precedes the corresponding base in the
\r
40 return 1; // one base in cdp1 appears after the corresponding base in the
\r
45 * DNA->mapped protein sequence alignment translation given set of sequences
\r
46 * 1. id distinct coding regions within selected region for each sequence 2.
\r
47 * generate peptides based on inframe (or given) translation or (optionally
\r
48 * and where specified) out of frame translations (annotated appropriately) 3.
\r
49 * align peptides based on codon alignment
\r
52 * id potential products from dna 1. search for distinct products within
\r
53 * selected region for each selected sequence 2. group by associated DB type.
\r
54 * 3. return as form for input into above function
\r
60 * create a new alignment of protein sequences by an inframe translation of
\r
61 * the provided NA sequences
\r
66 * @param gapCharacter
\r
67 * @param annotations
\r
69 * @param dataset destination dataset for translated sequences and mappings
\r
72 public static AlignmentI CdnaTranslate(SequenceI[] selection,
\r
73 String[] seqstring, int viscontigs[], char gapCharacter,
\r
74 AlignmentAnnotation[] annotations, int aWidth, Alignment dataset)
\r
76 return CdnaTranslate(selection, seqstring, null, viscontigs,
\r
77 gapCharacter, annotations, aWidth, dataset);
\r
84 * @param product - array of DbRefEntry objects from which exon map in seqstring is derived
\r
86 * @param gapCharacter
\r
87 * @param annotations
\r
92 public static AlignmentI CdnaTranslate(SequenceI[] selection,
\r
93 String[] seqstring, DBRefEntry[] product, int viscontigs[],
\r
94 char gapCharacter, AlignmentAnnotation[] annotations, int aWidth, Alignment dataset)
\r
96 AlignedCodonFrame codons = new AlignedCodonFrame(aWidth); // stores hash of
\r
102 int s, sSize = selection.length;
\r
103 Vector pepseqs = new Vector();
\r
104 for (s = 0; s < sSize; s++)
\r
106 SequenceI newseq = translateCodingRegion(selection[s], seqstring[s],
\r
107 viscontigs, codons, gapCharacter, (product!=null) ? product[s] : null); // possibly anonymous product
\r
108 if (newseq != null)
\r
110 pepseqs.addElement(newseq);
\r
111 SequenceI ds = newseq;
\r
112 while (ds.getDatasetSequence()!=null)
\r
114 ds = ds.getDatasetSequence();
\r
116 dataset.addSequence(ds);
\r
119 if (codons.aaWidth == 0)
\r
121 SequenceI[] newseqs = new SequenceI[pepseqs.size()];
\r
122 pepseqs.copyInto(newseqs);
\r
123 AlignmentI al = new Alignment(newseqs);
\r
124 al.padGaps(); // ensure we look aligned.
\r
125 al.setDataset(dataset);
\r
126 translateAlignedAnnotations(annotations, al, codons);
\r
127 al.addCodonFrame(codons);
\r
131 * fake the collection of DbRefs with associated exon mappings to identify
\r
132 * if a translation would generate distinct product in the currently selected region.
\r
134 * @param viscontigs
\r
137 public static boolean canTranslate(SequenceI[] selection, int viscontigs[])
\r
139 for (int gd=0; gd<selection.length; gd++)
\r
141 SequenceI dna = selection[gd];
\r
142 jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
\r
143 .selectRefs(dna.getDBRef(),
\r
144 jalview.datamodel.DBRefSource.DNACODINGDBS);
\r
145 if (dnarefs != null)
\r
147 // intersect with pep
\r
148 // intersect with pep
\r
149 Vector mappedrefs = new Vector();
\r
150 DBRefEntry[] refs=dna.getDBRef();
\r
151 for (int d=0; d<refs.length; d++)
\r
153 if (refs[d].getMap()!=null && refs[d].getMap().getMap()!=null && refs[d].getMap().getMap().getFromRatio()==3
\r
154 && refs[d].getMap().getMap().getToRatio()==1)
\r
156 mappedrefs.addElement(refs[d]); // add translated protein maps
\r
159 dnarefs = new DBRefEntry[mappedrefs.size()];
\r
160 mappedrefs.copyInto(dnarefs);
\r
161 for (int d = 0; d < dnarefs.length; d++)
\r
163 Mapping mp = dnarefs[d].getMap();
\r
166 for (int vc=0; vc<viscontigs.length; vc+=2)
\r
168 int[] mpr=mp.locateMappedRange(viscontigs[vc], viscontigs[vc+1]);
\r
180 * generate a set of translated protein products from annotated sequenceI
\r
182 * @param viscontigs
\r
183 * @param gapCharacter
\r
184 * @param dataset destination dataset for translated sequences
\r
185 * @param annotations
\r
189 public static AlignmentI CdnaTranslate(SequenceI[] selection,
\r
190 int viscontigs[], char gapCharacter, Alignment dataset)
\r
193 Vector cdnasqs=new Vector();
\r
194 Vector cdnasqi=new Vector();
\r
195 Vector cdnaprod=new Vector();
\r
196 for (int gd=0; gd<selection.length; gd++)
\r
198 SequenceI dna = selection[gd];
\r
199 jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
\r
200 .selectRefs(dna.getDBRef(),
\r
201 jalview.datamodel.DBRefSource.DNACODINGDBS);
\r
202 if (dnarefs != null)
\r
204 // intersect with pep
\r
205 Vector mappedrefs = new Vector();
\r
206 DBRefEntry[] refs=dna.getDBRef();
\r
207 for (int d=0; d<refs.length; d++)
\r
209 if (refs[d].getMap()!=null && refs[d].getMap().getMap()!=null && refs[d].getMap().getMap().getFromRatio()==3
\r
210 && refs[d].getMap().getMap().getToRatio()==1)
\r
212 mappedrefs.addElement(refs[d]); // add translated protein maps
\r
215 dnarefs = new DBRefEntry[mappedrefs.size()];
\r
216 mappedrefs.copyInto(dnarefs);
\r
217 for (int d = 0; d < dnarefs.length; d++)
\r
219 Mapping mp = dnarefs[d].getMap();
\r
220 StringBuffer sqstr=new StringBuffer();
\r
223 Mapping intersect = mp.intersectVisContigs(viscontigs);
\r
224 // generate seqstring for this sequence based on mapping
\r
226 if (sqstr.length()>alwidth)
\r
227 alwidth = sqstr.length();
\r
228 cdnasqs.addElement(sqstr.toString());
\r
229 cdnasqi.addElement(dna);
\r
230 cdnaprod.addElement(intersect);
\r
234 SequenceI[] cdna = new SequenceI[cdnasqs.size()];
\r
235 DBRefEntry[] prods = new DBRefEntry[cdnaprod.size()];
\r
236 String[] xons = new String[cdnasqs.size()];
\r
237 cdnasqs.copyInto(xons);
\r
238 cdnaprod.copyInto(prods);
\r
239 cdnasqi.copyInto(cdna);
\r
240 return CdnaTranslate(cdna, xons, prods, viscontigs, gapCharacter, null, alwidth, dataset);
\r
246 * translate na alignment annotations onto translated amino acid alignment al
\r
247 * using codon mapping codons
\r
249 * @param annotations
\r
253 public static void translateAlignedAnnotations(
\r
254 AlignmentAnnotation[] annotations, AlignmentI al,
\r
255 AlignedCodonFrame codons)
\r
257 // //////////////////////////////
\r
258 // Copy annotations across
\r
260 // Can only do this for columns with consecutive codons, or where
\r
261 // annotation is sequence associated.
\r
264 if (annotations != null)
\r
266 for (int i = 0; i < annotations.length; i++)
\r
268 // Skip any autogenerated annotation
\r
269 if (annotations[i].autoCalculated)
\r
274 aSize = codons.getaaWidth(); // aa alignment width.
\r
275 jalview.datamodel.Annotation[] anots = (annotations[i].annotations == null) ? null
\r
276 : new jalview.datamodel.Annotation[aSize];
\r
279 for (a = 0; a < aSize; a++)
\r
281 // process through codon map.
\r
282 if (codons.codons[a] != null
\r
283 && codons.codons[a][0] == (codons.codons[a][2] - 2))
\r
285 anots[a] = getCodonAnnotation(codons.codons[a], annotations[i].annotations);
\r
290 jalview.datamodel.AlignmentAnnotation aa = new jalview.datamodel.AlignmentAnnotation(
\r
291 annotations[i].label, annotations[i].description, anots);
\r
292 aa.graph = annotations[i].graph;
\r
293 aa.graphGroup = annotations[i].graphGroup;
\r
294 aa.graphHeight = annotations[i].graphHeight;
\r
295 if (annotations[i].getThreshold()!=null)
\r
297 aa.setThreshold(new jalview.datamodel.GraphLine(annotations[i].getThreshold()));
\r
299 if (annotations[i].hasScore)
\r
301 aa.setScore(annotations[i].getScore());
\r
303 if (annotations[i].sequenceRef != null)
\r
305 SequenceI aaSeq = codons
\r
306 .getAaForDnaSeq(annotations[i].sequenceRef);
\r
309 // aa.compactAnnotationArray(); // throw away alignment annotation
\r
311 aa.setSequenceRef(aaSeq);
\r
312 aa.createSequenceMapping(aaSeq, aaSeq.getStart(), true); // rebuild
\r
314 aa.adjustForAlignment();
\r
315 aaSeq.addAlignmentAnnotation(aa);
\r
319 al.addAnnotation(aa);
\r
324 private static Annotation getCodonAnnotation(int[] is, Annotation[] annotations)
\r
326 // Have a look at all the codon positions for annotation and put the first
\r
327 // one found into the translated annotation pos.
\r
328 for (int p=0; p<3; p++)
\r
330 if (annotations[is[p]]!=null)
\r
332 return new Annotation(annotations[is[p]]);
\r
339 * Translate a na sequence
\r
341 * @param selection sequence displayed under viscontigs visible columns
\r
342 * @param seqstring ORF read in some global alignment reference frame
\r
343 * @param viscontigs mapping from global reference frame to visible seqstring ORF read
\r
344 * @param codons Definition of global ORF alignment reference frame
\r
345 * @param gapCharacter
\r
347 * @return sequence ready to be added to alignment.
\r
349 public static SequenceI translateCodingRegion(SequenceI selection,
\r
350 String seqstring, int[] viscontigs, AlignedCodonFrame codons,
\r
351 char gapCharacter, DBRefEntry product)
\r
353 Vector skip=new Vector();
\r
354 int skipint[]=null;
\r
355 ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring
\r
357 int vc, scontigs[] = new int[viscontigs.length];
\r
359 for (vc = 0; vc < viscontigs.length; vc += 2)
\r
362 vismapping.addShift(npos, viscontigs[vc]);
\r
365 vismapping.addShift(npos, viscontigs[vc]-viscontigs[vc-1]+1);
\r
367 scontigs[vc] = viscontigs[vc];
\r
368 scontigs[vc + 1] = viscontigs[vc+1];
\r
371 StringBuffer protein = new StringBuffer();
\r
372 String seq = seqstring.replace('U', 'T');
\r
373 char codon[] = new char[3];
\r
374 int cdp[] = new int[3], rf = 0, lastnpos = 0, nend;
\r
377 for (npos = 0, nend = seq.length(); npos < nend; npos++)
\r
379 if (!jalview.util.Comparison.isGap(seq.charAt(npos)))
\r
381 cdp[rf] = npos; // store position
\r
382 codon[rf++] = seq.charAt(npos); // store base
\r
384 // filled an RF yet ?
\r
387 String aa = ResidueProperties.codonTranslate(new String(codon));
\r
391 aa = String.valueOf(gapCharacter);
\r
394 skipint = new int[] { cdp[0],cdp[2] };
\r
396 skipint[1] = cdp[2];
\r
401 skipint[0] = vismapping.shift(skipint[0]);
\r
402 skipint[1] = vismapping.shift(skipint[1]);
\r
403 for (vc=0; vc<scontigs.length; vc+=2)
\r
405 if (scontigs[vc+1]<skipint[0])
\r
409 if (scontigs[vc]<=skipint[0])
\r
411 if (skipint[0]==scontigs[vc])
\r
415 int[] t = new int[scontigs.length+2];
\r
416 System.arraycopy(scontigs, 0, t, 0, vc-1);
\r
417 // scontigs[vc]; //
\r
421 skip.addElement(skipint);
\r
424 if (aa.equals("STOP"))
\r
430 // insert/delete gaps prior to this codon - if necessary
\r
431 boolean findpos = true;
\r
434 // first ensure that the codons array is long enough.
\r
435 codons.checkCodonFrameWidth(aspos);
\r
436 // now check to see if we place the aa at the current aspos in the
\r
437 // protein alignment
\r
438 switch (Dna.compare_codonpos(cdp, codons.codons[aspos]))
\r
441 codons.insertAAGap(aspos, gapCharacter);
\r
445 // this aa appears after the aligned codons at aspos, so prefix it
\r
447 aa = "" + gapCharacter + aa;
\r
449 //if (aspos >= codons.aaWidth)
\r
450 // codons.aaWidth = aspos + 1;
\r
451 break; // check the next position for alignment
\r
453 // codon aligns at aspos position.
\r
457 // codon aligns with all other sequence residues found at aspos
\r
458 protein.append(aa);
\r
460 if (codons.codons[aspos] == null)
\r
462 // mark this column as aligning to this aligned reading frame
\r
463 codons.codons[aspos] = new int[]
\r
464 { cdp[0], cdp[1], cdp[2] };
\r
467 if (aspos >= codons.aaWidth)
\r
469 codons.aaWidth = aspos + 1;
\r
475 SequenceI newseq = new Sequence(selection.getName(), protein
\r
479 jalview.bin.Cache.log
\r
480 .debug("trimming contigs for incomplete terminal codon.");
\r
481 // map and trim contigs to ORF region
\r
482 vc = scontigs.length - 1;
\r
483 lastnpos = vismapping.shift(lastnpos); // place npos in context of
\r
484 // whole dna alignment (rather
\r
485 // than visible contigs)
\r
486 // incomplete ORF could be broken over one or two visible contig
\r
488 while (vc >= 0 && scontigs[vc] > lastnpos)
\r
490 if (vc > 0 && scontigs[vc - 1] > lastnpos)
\r
496 // correct last interval in list.
\r
497 scontigs[vc] = lastnpos;
\r
501 if (vc > 0 && (vc + 1) < scontigs.length)
\r
503 // truncate map list to just vc elements
\r
504 int t[] = new int[vc + 1];
\r
505 System.arraycopy(scontigs, 0, t, 0, vc + 1);
\r
511 if (scontigs != null)
\r
514 // map scontigs to actual sequence positions on selection
\r
515 for (vc = 0; vc < scontigs.length; vc += 2)
\r
517 scontigs[vc] = selection.findPosition(scontigs[vc]); // not from 1!
\r
518 scontigs[vc + 1] = selection
\r
519 .findPosition(scontigs[vc + 1]); // exclusive
\r
520 if (scontigs[vc + 1] == selection.getEnd())
\r
523 // trim trailing empty intervals.
\r
524 if ((vc + 2) < scontigs.length)
\r
526 int t[] = new int[vc + 2];
\r
527 System.arraycopy(scontigs, 0, t, 0, vc + 2);
\r
531 * delete intervals in scontigs which are not translated.
\r
532 * 1. map skip into sequence position intervals
\r
533 * 2. truncate existing ranges and add new ranges to exclude untranslated regions.
\r
536 Vector narange = new Vector();
\r
537 for (vc=0; vc<scontigs.length; vc++)
\r
539 narange.addElement(new int[] {scontigs[vc]});
\r
543 while (sint<skip.size())
\r
545 skipint = (int[]) skip.elementAt(sint);
\r
547 iv = (int[]) narange.elementAt(vc);
\r
548 if (iv[0]>=skipint[0] && iv[0]<=skipint[1])
\r
550 if (iv[0]==skipint[0])
\r
552 // delete beginning of range
\r
554 // truncate range and create new one if necessary
\r
555 iv = (int[]) narange.elementAt(vc+1);
\r
556 if (iv[0]<=skipint[1])
\r
559 iv[0] = skipint[1];
\r
565 if (iv[0]<skipint[0])
\r
567 iv = (int[]) narange.elementAt(vc+1);
\r
572 MapList map = new MapList(scontigs, new int[]
\r
573 { 1, resSize }, 3, 1);
\r
575 // update newseq as if it was generated as mapping from product
\r
577 if (product != null)
\r
579 newseq.setName(product.getSource() + "|"
\r
580 + product.getAccessionId());
\r
581 if (product.getMap() != null)
\r
583 //Mapping mp = product.getMap();
\r
584 //newseq.setStart(mp.getPosition(scontigs[0]));
\r
586 // .getPosition(scontigs[scontigs.length - 1]));
\r
589 transferCodedFeatures(selection, newseq, map, null, null);
\r
590 SequenceI rseq = newseq.deriveSequence(); // construct a dataset
\r
591 // sequence for our new
\r
592 // peptide, regardless.
\r
593 // store a mapping (this actually stores a mapping between the dataset
\r
594 // sequences for the two sequences
\r
595 codons.addMap(selection, rseq, map);
\r
599 // register the mapping somehow
\r
605 * Given a peptide newly translated from a dna sequence, copy over and set any
\r
606 * features on the peptide from the DNA. If featureTypes is null, all features
\r
607 * on the dna sequence are searched (rather than just the displayed ones), and
\r
608 * similarly for featureGroups.
\r
613 * @param featureTypes
\r
614 * hash who's keys are the displayed feature type strings
\r
615 * @param featureGroups
\r
616 * hash where keys are feature groups and values are Boolean objects
\r
617 * indicating if they are displayed.
\r
619 private static void transferCodedFeatures(SequenceI dna, SequenceI pep,
\r
620 MapList map, Hashtable featureTypes, Hashtable featureGroups)
\r
622 SequenceFeature[] sf = dna.getDatasetSequence().getSequenceFeatures();
\r
624 jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
\r
625 .selectRefs(dna.getDBRef(),
\r
626 jalview.datamodel.DBRefSource.DNACODINGDBS);
\r
627 if (dnarefs != null)
\r
629 // intersect with pep
\r
630 for (int d = 0; d < dnarefs.length; d++)
\r
632 Mapping mp = dnarefs[d].getMap();
\r
640 for (int f = 0; f < sf.length; f++)
\r
642 fgstate = (featureGroups == null) ? null : ((Boolean) featureGroups
\r
643 .get(sf[f].featureGroup));
\r
644 if ((featureTypes == null || featureTypes.containsKey(sf[f]
\r
646 && (fgstate == null || fgstate.booleanValue()))
\r
648 if (FeatureProperties.isCodingFeature(null, sf[f].getType()))
\r
650 // if (map.intersectsFrom(sf[f].begin, sf[f].end))
\r