Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package mc_view

File PDBChain.java

 

Coverage histogram

../img/srcFileCovDistChart8.png
19% of files have more coverage

Code metrics

104
215
15
1
689
485
87
0.4
14.33
15
5.8

Classes

Class Line # Actions
PDBChain 40 215 87 87
0.7395209774%
 

Contributing tests

This file is covered by 31 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package mc_view;
22   
23    import jalview.analysis.AlignSeq;
24    import jalview.datamodel.AlignmentAnnotation;
25    import jalview.datamodel.Annotation;
26    import jalview.datamodel.Mapping;
27    import jalview.datamodel.Sequence;
28    import jalview.datamodel.SequenceFeature;
29    import jalview.datamodel.SequenceI;
30    import jalview.schemes.ColourSchemeI;
31    import jalview.schemes.ResidueProperties;
32    import jalview.structure.StructureImportSettings;
33    import jalview.structure.StructureMapping;
34    import jalview.util.Comparison;
35   
36    import java.awt.Color;
37    import java.util.List;
38    import java.util.Vector;
39   
 
40    public class PDBChain
41    {
42    public static final String RESNUM_FEATURE = "RESNUM";
43   
44    private static final String IEASTATUS = "IEA:jalview";
45   
46    public String id;
47   
48    public Vector<Bond> bonds = new Vector<>();
49   
50    public Vector<Atom> atoms = new Vector<>();
51   
52    public Vector<Residue> residues = new Vector<>();
53   
54    public int offset;
55   
56    /**
57    * sequence is the sequence extracted by the chain parsing code
58    */
59    public SequenceI sequence;
60   
61    /**
62    * shadow is the sequence created by any other parsing processes (e.g. Jmol,
63    * RNAview)
64    */
65    public SequenceI shadow = null;
66   
67    public boolean isNa = false;
68   
69    public boolean isVisible = true;
70   
71    public int pdbstart = 0;
72   
73    public int pdbend = 0;
74   
75    public int seqstart = 0;
76   
77    public int seqend = 0;
78   
79    public String pdbid = "";
80   
 
81  169 toggle public PDBChain(String thePdbid, String theId)
82    {
83  169 this.pdbid = thePdbid == null ? thePdbid : thePdbid.toLowerCase();
84  169 this.id = theId;
85    }
86   
87    /**
88    * character used to write newlines
89    */
90    protected String newline = System.getProperty("line.separator");
91   
92    public Mapping shadowMap;
93   
 
94  1 toggle public void setNewlineString(String nl)
95    {
96  1 newline = nl;
97    }
98   
 
99  2 toggle public String getNewlineString()
100    {
101  2 return newline;
102    }
103   
 
104  1 toggle public String print()
105    {
106  1 StringBuilder tmp = new StringBuilder(256);
107   
108  1 for (Bond b : bonds)
109    {
110  3 tmp.append(b.at1.resName).append(" ").append(b.at1.resNumber)
111    .append(" ").append(offset).append(newline);
112    }
113   
114  1 return tmp.toString();
115    }
116   
117    /**
118    * Annotate the residues with their corresponding positions in s1 using the
119    * alignment in as NOTE: This clears all atom.alignmentMapping values on the
120    * structure.
121    *
122    * @param as
123    * @param s1
124    */
 
125  146 toggle public void makeExactMapping(AlignSeq as, SequenceI s1)
126    {
127  146 int pdbpos = as.getSeq2Start() - 2;
128  146 int alignpos = s1.getStart() + as.getSeq1Start() - 3;
129    // first clear out any old alignmentMapping values:
130  146 for (Atom atom : atoms)
131    {
132  13565 atom.alignmentMapping = -1;
133    }
134    // and now trace the alignment onto the atom set.
135  13708 for (int i = 0; i < as.astr1.length(); i++)
136    {
137  13562 if (as.astr1.charAt(i) != '-')
138    {
139  13562 alignpos++;
140    }
141   
142  13562 if (as.astr2.charAt(i) != '-')
143    {
144  13562 pdbpos++;
145    }
146   
147  13562 boolean sameResidue = Comparison.isSameResidue(as.astr1.charAt(i),
148    as.astr2.charAt(i), false);
149  13562 if (sameResidue)
150    {
151  13501 if (pdbpos >= residues.size())
152    {
153  0 continue;
154    }
155  13501 Residue res = residues.elementAt(pdbpos);
156  13501 for (Atom atom : res.atoms)
157    {
158  13504 atom.alignmentMapping = alignpos;
159    }
160    }
161    }
162    }
163   
164    /**
165    * Annotate the residues with their corresponding positions in s1 using the
166    * alignment in as NOTE: This clears all atom.alignmentMapping values on the
167    * structure.
168    *
169    * @param as
170    * @param s1
171    */
 
172  0 toggle public void makeExactMapping(StructureMapping mapping, SequenceI s1)
173    {
174    // first clear out any old alignmentMapping values:
175  0 for (Atom atom : atoms)
176    {
177  0 atom.alignmentMapping = -1;
178    }
179  0 SequenceI ds = s1;
180  0 while (ds.getDatasetSequence() != null)
181    {
182  0 ds = ds.getDatasetSequence();
183    }
184  0 int pdboffset = 0;
185  0 for (Residue res : residues)
186    {
187    // res.number isn't set correctly for discontinuous/mismapped residues
188  0 int seqpos = mapping.getSeqPos(res.atoms.get(0).resNumber);
189  0 char strchar = sequence.getCharAt(pdboffset++);
190  0 if (seqpos == StructureMapping.UNASSIGNED_VALUE)
191    {
192  0 continue;
193    }
194  0 char seqchar = ds.getCharAt(seqpos - ds.getStart());
195   
196  0 boolean sameResidue = Comparison.isSameResidue(
197    seqchar, strchar, false);
198  0 if (sameResidue)
199    {
200  0 for (Atom atom : res.atoms)
201    {
202  0 atom.alignmentMapping = seqpos - 1;
203    }
204    }
205    }
206    }
207   
208    /**
209    * Copies over the RESNUM seqfeatures from the internal chain sequence to the
210    * mapped sequence
211    *
212    * @param seq
213    * @param status
214    * The Status of the transferred annotation
215    */
 
216  151 toggle public void transferRESNUMFeatures(SequenceI seq,
217    String status)
218    {
219  151 SequenceI sq = seq;
220  300 while (sq != null && sq.getDatasetSequence() != null)
221    {
222  149 sq = sq.getDatasetSequence();
223  149 if (sq == sequence)
224    {
225  0 return;
226    }
227    }
228   
229    /*
230    * Remove any existing features for this chain if they exist ?
231    * SequenceFeature[] seqsfeatures=seq.getSequenceFeatures(); int
232    * totfeat=seqsfeatures.length; // Remove any features for this exact chain
233    * ? for (int i=0; i<seqsfeatures.length; i++) { }
234    */
235  151 if (status == null)
236    {
237  145 status = PDBChain.IEASTATUS;
238    }
239   
240  151 List<SequenceFeature> features = sequence.getSequenceFeatures();
241  151 for (SequenceFeature feature : features)
242    {
243  13589 if (feature.getFeatureGroup() != null
244    && feature.getFeatureGroup().equals(pdbid))
245    {
246  13589 int newBegin = 1 + residues.elementAt(feature.getBegin() - offset).atoms
247    .elementAt(0).alignmentMapping;
248  13589 int newEnd = 1 + residues.elementAt(feature.getEnd() - offset).atoms
249    .elementAt(0).alignmentMapping;
250  13589 SequenceFeature tx = new SequenceFeature(feature, newBegin, newEnd,
251    feature.getFeatureGroup(), feature.getScore());
252  13589 tx.setStatus(status
253  13589 + ((tx.getStatus() == null || tx.getStatus().length() == 0)
254    ? ""
255    : ":" + tx.getStatus()));
256  13589 if (tx.begin != 0 && tx.end != 0)
257    {
258  13528 sq.addSequenceFeature(tx);
259    }
260    }
261    }
262    }
263   
264    /**
265    * Traverses the list of residues and constructs bonds where CA-to-CA atoms or
266    * P-to-P atoms are found. Also sets the 'isNa' flag if more than 99% of
267    * residues contain a P not a CA.
268    */
 
269  159 toggle public void makeCaBondList()
270    {
271  159 boolean na = false;
272  159 int numNa = 0;
273  22367 for (int i = 0; i < (residues.size() - 1); i++)
274    {
275  22208 Residue tmpres = residues.elementAt(i);
276  22208 Residue tmpres2 = residues.elementAt(i + 1);
277  22208 Atom at1 = tmpres.findAtom("CA");
278  22208 Atom at2 = tmpres2.findAtom("CA");
279  22208 na = false;
280  22208 if ((at1 == null) && (at2 == null))
281    {
282  2 na = true;
283  2 at1 = tmpres.findAtom("P");
284  2 at2 = tmpres2.findAtom("P");
285    }
286  22208 if ((at1 != null) && (at2 != null))
287    {
288  22208 if (at1.chain.equals(at2.chain))
289    {
290  22208 if (na)
291    {
292  2 numNa++;
293    }
294  22208 makeBond(at1, at2);
295    }
296    }
297    else
298    {
299  0 System.out.println("not found " + i);
300    }
301    }
302   
303    /*
304    * If > 99% 'P', flag as nucleotide; note the count doesn't include the last
305    * residue
306    */
307  159 if (residues.size() > 1 && (numNa / (residues.size() - 1) > 0.99))
308    {
309  1 isNa = true;
310    }
311    }
312   
313    /**
314    * Construct a bond from atom1 to atom2 and add it to the list of bonds for
315    * this chain
316    *
317    * @param at1
318    * @param at2
319    */
 
320  22218 toggle public void makeBond(Atom at1, Atom at2)
321    {
322  22218 bonds.addElement(new Bond(at1, at2));
323    }
324   
325    /**
326    * Traverses the list of atoms and
327    * <ul>
328    * <li>constructs a list of Residues, each containing all the atoms that share
329    * the same residue number</li>
330    * <li>adds a RESNUM sequence feature for each position</li>
331    * <li>creates the sequence string</li>
332    * <li>determines if nucleotide</li>
333    * <li>saves the residue number of the first atom as 'offset'</li>
334    * <li>adds temp factor annotation if the flag is set to do so</li>
335    * </ul>
336    *
337    * @param visibleChainAnnotation
338    */
 
339  162 toggle public void makeResidueList(boolean visibleChainAnnotation)
340    {
341  162 int count = 0;
342  162 Object symbol;
343  162 boolean deoxyn = false;
344  162 boolean nucleotide = false;
345  162 StringBuilder seq = new StringBuilder(256);
346  162 Vector<SequenceFeature> resFeatures = new Vector<>();
347  162 Vector<Annotation> resAnnotation = new Vector<>();
348  162 int iSize = atoms.size() - 1;
349  162 int resNumber = -1;
350  162 char insCode = ' ';
351   
352  22538 for (int i = 0; i <= iSize; i++)
353    {
354  22376 Atom tmp = atoms.elementAt(i);
355  22376 resNumber = tmp.resNumber;
356  22376 insCode = tmp.insCode;
357   
358  22376 int res = resNumber;
359  22376 char ins = insCode;
360   
361  22376 if (i == 0)
362    {
363  162 offset = resNumber;
364    }
365   
366  22376 Vector<Atom> resAtoms = new Vector<>();
367    // Add atoms to a vector while the residue number
368    // remains the same as the first atom's resNumber (res)
369  44773 while ((resNumber == res) && (ins == insCode) && (i < atoms.size()))
370    {
371  22397 resAtoms.add(atoms.elementAt(i));
372  22397 i++;
373   
374  22397 if (i < atoms.size())
375    {
376  22235 resNumber = atoms.elementAt(i).resNumber;
377  22235 insCode = atoms.elementAt(i).insCode;
378    }
379    else
380    {
381  162 resNumber++;
382    }
383    }
384   
385    // We need this to keep in step with the outer for i = loop
386  22376 i--;
387   
388    // Add inserted residues as features to the base residue
389  22376 Atom currAtom = resAtoms.get(0);
390  22376 if (currAtom.insCode != ' ' && !residues.isEmpty()
391    && residues.lastElement().atoms
392    .get(0).resNumber == currAtom.resNumber)
393    {
394  0 String desc = currAtom.resName + ":" + currAtom.resNumIns + " "
395    + pdbid + id;
396  0 SequenceFeature sf = new SequenceFeature("INSERTION", desc, offset
397    + count - 1, offset + count - 1, "PDB_INS");
398  0 resFeatures.addElement(sf);
399  0 residues.lastElement().atoms.addAll(resAtoms);
400    }
401    else
402    {
403    // Make a new Residue object with the new atoms vector
404  22376 residues.addElement(new Residue(resAtoms, resNumber - 1, count));
405   
406  22376 Residue tmpres = residues.lastElement();
407  22376 Atom tmpat = tmpres.atoms.get(0);
408    // Make A new SequenceFeature for the current residue numbering
409  22376 String desc = tmpat.resName
410    + ":" + tmpat.resNumIns + " " + pdbid + id;
411  22376 SequenceFeature sf = new SequenceFeature(RESNUM_FEATURE, desc,
412    offset + count, offset + count, pdbid);
413  22376 resFeatures.addElement(sf);
414  22376 resAnnotation.addElement(new Annotation(tmpat.tfactor));
415    // Keep totting up the sequence
416   
417  ? if ((symbol = ResidueProperties.getAA3Hash()
418    .get(tmpat.resName)) == null)
419    {
420  5 String nucname = tmpat.resName.trim();
421    // use the aaIndex rather than call 'toLower' - which would take a bit
422    // more time.
423  5 deoxyn = nucname.length() == 2
424    && ResidueProperties.aaIndex[nucname
425    .charAt(0)] == ResidueProperties.aaIndex['D'];
426  5 if (tmpat.name.equalsIgnoreCase("CA")
427    || ResidueProperties.nucleotideIndex[nucname
428  3 .charAt((deoxyn ? 1 : 0))] == -1)
429    {
430  2 char r = ResidueProperties.getSingleCharacterCode(
431    ResidueProperties.getCanonicalAminoAcid(tmpat.resName));
432  2 seq.append(r == '0' ? 'X' : r);
433    // System.err.println("PDBReader:Null aa3Hash for " +
434    // tmpat.resName);
435    }
436    else
437    {
438    // nucleotide flag
439  3 nucleotide = true;
440  3 seq.append(nucname.charAt((deoxyn ? 1 : 0)));
441    }
442    }
443    else
444    {
445  22371 if (nucleotide)
446    {
447  0 System.err.println(
448    "Warning: mixed nucleotide and amino acid chain.. its gonna do bad things to you!");
449    }
450  22371 seq.append(ResidueProperties.aa[((Integer) symbol).intValue()]);
451    }
452  22376 count++;
453    }
454    }
455   
456  162 if (id.length() < 1)
457    {
458  0 id = " ";
459    }
460  162 isNa = nucleotide;
461  162 sequence = new Sequence(id, seq.toString(), offset, resNumber - 1); // Note:
462    // resNumber-offset
463    // ~=
464    // seq.size()
465    // Add normalised feature scores to RESNUM indicating start/end of sequence
466    // sf.setScore(offset+count);
467   
468    // System.out.println("PDB Sequence is :\nSequence = " + seq);
469    // System.out.println("No of residues = " + residues.size());
470   
471  162 if (StructureImportSettings.isShowSeqFeatures())
472    {
473  154 iSize = resFeatures.size();
474  20958 for (int i = 0; i < iSize; i++)
475    {
476  20804 sequence.addSequenceFeature(resFeatures.elementAt(i));
477  20804 resFeatures.setElementAt(null, i);
478    }
479    }
480  162 if (visibleChainAnnotation)
481    {
482  118 Annotation[] annots = new Annotation[resAnnotation.size()];
483  118 float max = 0f;
484  118 float min = 0f;
485  118 iSize = annots.length;
486  17997 for (int i = 0; i < iSize; i++)
487    {
488  17879 annots[i] = resAnnotation.elementAt(i);
489  17879 max = Math.max(max, annots[i].value);
490  17879 min = Math.min(min, annots[i].value);
491  17879 resAnnotation.setElementAt(null, i);
492    }
493   
494  118 AlignmentAnnotation tfactorann = new AlignmentAnnotation(
495    "Temperature Factor", "Temperature Factor for " + pdbid + id,
496    annots, min, max, AlignmentAnnotation.LINE_GRAPH);
497  118 tfactorann.setSequenceRef(sequence);
498  118 sequence.addAlignmentAnnotation(tfactorann);
499    }
500    }
501   
502    /**
503    * Colour start/end of bonds by charge
504    * <ul>
505    * <li>ASP and GLU red</li>
506    * <li>LYS and ARG blue</li>
507    * <li>CYS yellow</li>
508    * <li>others light gray</li>
509    * </ul>
510    */
 
511  1 toggle public void setChargeColours()
512    {
513  1 for (Bond b : bonds)
514    {
515  3 if (b.at1 != null && b.at2 != null)
516    {
517  3 b.startCol = getChargeColour(b.at1.resName);
518  3 b.endCol = getChargeColour(b.at2.resName);
519    }
520    else
521    {
522  0 b.startCol = Color.gray;
523  0 b.endCol = Color.gray;
524    }
525    }
526    }
527   
 
528  13 toggle public static Color getChargeColour(String resName)
529    {
530  13 Color result = Color.lightGray;
531  13 if ("ASP".equals(resName) || "GLU".equals(resName))
532    {
533  3 result = Color.red;
534    }
535  10 else if ("LYS".equals(resName) || "ARG".equals(resName))
536    {
537  4 result = Color.blue;
538    }
539  6 else if ("CYS".equals(resName))
540    {
541  3 result = Color.yellow;
542    }
543  13 return result;
544    }
545   
546    /**
547    * Sets the start/end colours of bonds to those of the start/end atoms
548    * according to the specified colour scheme. Note: currently only works for
549    * peptide residues.
550    *
551    * @param cs
552    */
 
553  1 toggle public void setChainColours(ColourSchemeI cs)
554    {
555  1 int index;
556  1 for (Bond b : bonds)
557    {
558  3 try
559    {
560  3 index = ResidueProperties.aa3Hash.get(b.at1.resName).intValue();
561  3 b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0), 0,
562    null, null, 0f);
563   
564  3 index = ResidueProperties.aa3Hash.get(b.at2.resName).intValue();
565  2 b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0), 0,
566    null, null, 0f);
567   
568    } catch (Exception e)
569    {
570  1 b.startCol = Color.gray;
571  1 b.endCol = Color.gray;
572    }
573    }
574    }
575   
 
576  1 toggle public void setChainColours(Color col)
577    {
578  1 for (Bond b : bonds)
579    {
580  2 b.startCol = col;
581  2 b.endCol = col;
582    }
583    }
584   
585    /**
586    * copy any sequence annotation onto the sequence mapped using the provided
587    * StructureMapping
588    *
589    * @param mapping
590    * - positional mapping between destination sequence and pdb resnum
591    * @param sqmpping
592    * - mapping between destination sequence and local chain
593    */
 
594  151 toggle public void transferResidueAnnotation(StructureMapping mapping,
595    jalview.datamodel.Mapping sqmpping)
596    {
597  151 SequenceI sq = mapping.getSequence();
598  151 SequenceI dsq = sq;
599  151 if (sqmpping == null)
600    {
601    // SIFTS mappings are recorded in the StructureMapping object...
602   
603  0 sqmpping = mapping.getSeqToPdbMapping();
604    }
605  151 if (sq != null)
606    {
607  300 while (dsq.getDatasetSequence() != null)
608    {
609  149 dsq = dsq.getDatasetSequence();
610    }
611    // any annotation will be transferred onto the dataset sequence
612   
613  151 if (shadow != null && shadow.getAnnotation() != null)
614    {
615   
616  0 for (AlignmentAnnotation ana : shadow.getAnnotation())
617    {
618  0 List<AlignmentAnnotation> transfer = sq
619    .getAlignmentAnnotations(ana.getCalcId(), ana.label);
620  0 if (transfer == null || transfer.size() == 0)
621    {
622  0 ana = new AlignmentAnnotation(ana);
623  0 ana.liftOver(sequence, shadowMap);
624  0 ana.liftOver(dsq, sqmpping);
625  0 dsq.addAlignmentAnnotation(ana);
626    }
627    else
628    {
629  0 continue;
630    }
631    }
632    }
633    else
634    {
635  151 if (sequence != null && sequence.getAnnotation() != null)
636    {
637  127 for (AlignmentAnnotation ana : sequence.getAnnotation())
638    {
639  243 List<AlignmentAnnotation> transfer = dsq
640    .getAlignmentAnnotations(ana.getCalcId(), ana.label);
641  243 if (transfer == null || transfer.size() == 0)
642    {
643  51 ana = new AlignmentAnnotation(ana);
644  51 ana.liftOver(dsq, sqmpping);
645  51 dsq.addAlignmentAnnotation(ana);
646    // mapping.transfer(ana);
647    }
648    else
649    {
650  192 continue;
651    }
652    }
653    }
654    }
655  151 if (false)
656    {
657    // Useful for debugging mappings - adds annotation for mapped position
658  0 float min = -1, max = 0;
659  0 Annotation[] an = new Annotation[sq.getEnd() - sq.getStart() + 1];
660  0 for (int i = sq.getStart(), j = sq
661  0 .getEnd(), k = 0; i <= j; i++, k++)
662    {
663  0 int prn = mapping.getPDBResNum(k + 1);
664   
665  0 an[k] = new Annotation(prn);
666  0 if (min == -1)
667    {
668  0 min = k;
669  0 max = k;
670    }
671    else
672    {
673  0 if (min > k)
674    {
675  0 min = k;
676    }
677  0 else if (max < k)
678    {
679  0 max = k;
680    }
681    }
682    }
683  0 sq.addAlignmentAnnotation(new AlignmentAnnotation("PDB.RESNUM",
684    "PDB Residue Numbering for " + this.pdbid + ":" + this.id,
685    an, min, max, AlignmentAnnotation.LINE_GRAPH));
686    }
687    }
688    }
689    }