Merge branch 'develop' into features/JAL-2094_colourInterface
[jalview.git] / examples / groovy / featureCounter.groovy
1 import jalview.workers.FeatureCounterI;
2 import jalview.workers.AlignmentAnnotationFactory;
3
4 /*
5  * Example script that registers two alignment annotation calculators
6  * - one that counts residues in a column with Pfam annotation
7  * - one that counts only charged residues with Pfam annotation
8  *
9  * To try:
10  * 1. load uniref50.fa from the examples folder
11  * 2. load features onto it from from examples/exampleFeatures.txt
12  * 3. Open this script in the Groovy console.
13  * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
14  
15  * To explore further, try changing this script to count other kinds of occurrences of 
16  * residue and sequence features at columns in an alignment.
17  */
18
19 /*
20  * A closure that returns true for any Charged residue
21  */
22 def isCharged = { residue ->
23     switch(residue) {
24         case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
25             return true
26     }
27     false
28
29
30 /*
31  * A closure that returns 1 if sequence features include type 'Pfam', else 0
32  * Argument should be a list of SequenceFeature 
33  */
34 def hasPfam = { features -> 
35     for (sf in features)
36     {
37         /*
38          * Here we inspect the type of the sequence feature.
39          * You can also test sf.description, sf.score, sf.featureGroup,
40          * sf.strand, sf.phase, sf.begin, sf.end
41          * or sf.getValue(attributeName) for GFF 'column 9' properties
42          */
43         if ("Pfam".equals(sf.type))
44         {
45             return true
46         }
47     }
48     false
49 }
50
51 /*
52  * Closure that computes an annotation based on 
53  * presence of particular residues and features
54  * Parameters are
55  * - the name (label) for the alignment annotation
56  * - the description (tooltip) for the annotation
57  * - a closure (groovy function) that tests whether to include a residue
58  * - a closure that tests whether to increment count based on sequence features  
59  */
60 def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
61     [
62      getName: { name }, 
63      getDescription: { desc },
64      getMinColour: { [0, 255, 255] }, // cyan
65      getMaxColour: { [0, 0, 255] }, // blue
66      count: 
67          { res, feats -> 
68             def c = 0
69             if (acceptResidue.call(res))
70             {
71                 if (acceptFeatures.call(feats))
72                 {
73                     c++
74                 }
75             }
76             c
77          }
78      ] as FeatureCounterI
79 }
80
81 /*
82  * Define an annotation row that counts any residue with Pfam domain annotation
83  */
84 def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
85
86 /*
87  * Define an annotation row that counts charged residues with Pfam domain annotation
88  */
89 def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
90
91 /*
92  * Register the annotations
93  */
94 AlignmentAnnotationFactory.newCalculator(pfamAnnotation) 
95 AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)