Extending Jalview with Groovy - A customisable feature counter

The groovy script below shows how to add a new calculation track to a Jalview alignment window.

As currently written, it will add two tracks to a protein alignment view which count Pfam features in each column, and ones where a charge residue also occur.

To try it for yourself:

  1. Copy and paste it into the groovy script console
  2. Load the example Feredoxin project (the one that opens by default when you first launched Jalview)
  3. Select Calculations→Execute Groovy Script from the alignment window's menu bar to run the script on the current view.
http://www.jalview.org/examples/groovy/featureCounter.groovy - rendered with hilite.me
/*
 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.10)
 * Copyright (C) 2016 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.
 */
 
import jalview.workers.FeatureCounterI;
import jalview.workers.AlignmentAnnotationFactory;

/*
 * Example script that registers two alignment annotation calculators
 * - one that counts residues in a column with Pfam annotation
 * - one that counts only charged residues with Pfam annotation
 *
 * To try:
 * 1. load uniref50.fa from the examples folder
 * 2. load features onto it from from examples/exampleFeatures.txt
 * 3. Open this script in the Groovy console.
 * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
 
 * To explore further, try changing this script to count other kinds of occurrences of 
 * residue and sequence features at columns in an alignment.
 */

/*
 * A closure that returns true for any Charged residue
 */
def isCharged = { residue ->
    switch(residue) {
        case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
            return true
    }
    false
} 

/*
 * A closure that returns 1 if sequence features include type 'Pfam', else 0
 * Argument should be a list of SequenceFeature 
 */
def hasPfam = { features -> 
    for (sf in features)
    {
        /*
         * Here we inspect the type of the sequence feature.
         * You can also test sf.description, sf.score, sf.featureGroup,
         * sf.strand, sf.phase, sf.begin, sf.end
         * or sf.getValue(attributeName) for GFF 'column 9' properties
         */
        if ("Pfam".equals(sf.type))
        {
            return true
        }
    }
    false
}

/*
 * Closure that computes an annotation based on 
 * presence of particular residues and features
 * Parameters are
 * - the name (label) for the alignment annotation
 * - the description (tooltip) for the annotation
 * - a closure (groovy function) that tests whether to include a residue
 * - a closure that tests whether to increment count based on sequence features  
 */
def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
    [
     getName: { name }, 
     getDescription: { desc },
     getMinColour: { [0, 255, 255] }, // cyan
     getMaxColour: { [0, 0, 255] }, // blue
     count: 
         { res, feats -> 
            def c = 0
            if (acceptResidue.call(res))
            {
                if (acceptFeatures.call(feats))
                {
                    c++
                }
            }
            c
         }
     ] as FeatureCounterI
}

/*
 * Define an annotation row that counts any residue with Pfam domain annotation
 */
def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)

/*
 * Define an annotation row that counts charged residues with Pfam domain annotation
 */
def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)

/*
 * Register the annotations
 */
AlignmentAnnotationFactory.newCalculator(pfamAnnotation) 
AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)