JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / jalview / analysis / ParseProperties.java
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 jalview.analysis;
22
23 //import com.stevesoft.pat.Regex;
24
25 import jalview.datamodel.AlignmentAnnotation;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.jsdev.RegExp;
29 import jalview.jsdev.api.RegExpInterface;
30
31 public class ParseProperties
32 {
33   /**
34    * Methods for parsing free text properties on alignments and sequences. There
35    * are a number of ways we might want to do this: arbitrary regex. and an
36    * associated score name for the number that's extracted. Regex that provides
37    * both score and name.
38    * 
39    * We may also want to : - modify description to remove parsed numbers (this
40    * behaviour is dangerous since exporting the alignment would lose the
41    * original form then) -
42    * 
43    */
44   /**
45    * The alignment being operated on
46    */
47   private AlignmentI al = null;
48
49   /**
50    * initialise a new property parser
51    * 
52    * @param al
53    */
54   public ParseProperties(AlignmentI al)
55   {
56     this.al = al;
57   }
58
59   public int getScoresFromDescription(String ScoreName,
60           String ScoreDescriptions, String regex, boolean repeat)
61   {
62     return getScoresFromDescription(new String[]
63     { ScoreName }, new String[]
64     { ScoreDescriptions }, regex, repeat);
65   }
66
67   public int getScoresFromDescription(String[] ScoreNames,
68           String[] ScoreDescriptions, String regex, boolean repeat)
69   {
70     return getScoresFromDescription(al.getSequencesArray(), ScoreNames,
71             ScoreDescriptions, regex, repeat);
72   }
73
74   /**
75    * Extract scores for sequences by applying regex to description string.
76    * 
77    * @param seqs
78    *          seuqences to extract annotation from.
79    * @param ScoreNames
80    *          labels for each numeric field in regex match
81    * @param ScoreDescriptions
82    *          description for each numeric field in regex match
83    * @param regex
84    *          Regular Expression string for passing to
85    *          <code>new jalview.jsdevt.Regex(regex)</code>
86    * @param repeat
87    *          true means the regex will be applied multiple times along the
88    *          description string of each sequence
89    * @return total number of sequences that matched the regex
90    */
91   public int getScoresFromDescription(SequenceI[] seqs,
92           String[] ScoreNames, String[] ScoreDescriptions, String regex,
93           boolean repeat)
94   {
95     int count = 0;
96     RegExpInterface pattern = RegExp.newRegex(regex);
97     if (pattern.numSubs() > ScoreNames.length)
98     {
99       // Check that we have enough labels and descriptions for any parsed
100       // scores.
101       int onamelen = ScoreNames.length;
102       String[] tnames = new String[pattern.numSubs() + 1];
103       System.arraycopy(ScoreNames, 0, tnames, 0, ScoreNames.length);
104       String base = tnames[ScoreNames.length - 1];
105       ScoreNames = tnames;
106       String descrbase = ScoreDescriptions[onamelen - 1];
107       if (descrbase == null)
108       {
109         descrbase = "Score parsed from (" + regex + ")";
110       }
111       tnames = new String[pattern.numSubs() + 1];
112       System.arraycopy(ScoreDescriptions, 0, tnames, 0,
113               ScoreDescriptions.length);
114       ScoreDescriptions = tnames;
115       for (int i = onamelen; i < ScoreNames.length; i++)
116       {
117         ScoreNames[i] = base + "_" + i;
118         ScoreDescriptions[i] = descrbase + " (column " + i + ")";
119       }
120     }
121     for (int i = 0; i < seqs.length; i++)
122     {
123       String descr = seqs[i].getDescription();
124       if (descr == null)
125       {
126         continue;
127       }
128       int pos = 0;
129       boolean added = false;
130       int reps = 0;
131       while ((repeat || pos == 0) && pattern.searchFrom(descr, pos))
132       {
133         pos = pattern.matchedTo();
134         for (int cols = 0; cols < pattern.numSubs(); cols++)
135         {
136           String sstring = pattern.stringMatchedI(cols + 1);
137           double score = Double.NaN;
138           try
139           {
140             score = new Double(sstring).doubleValue();
141           } catch (Exception e)
142           {
143             // don't try very hard to parse if regex was wrong.
144             continue;
145           }
146           // add score to sequence annotation.
147           AlignmentAnnotation an = new AlignmentAnnotation(ScoreNames[cols]
148                   + ((reps > 0) ? "_" + reps : ""),
149                   ScoreDescriptions[cols], null);
150           an.setScore(score);
151           System.out.println(seqs[i].getName() + " score: '"
152                   + ScoreNames[cols] + "' = " + score); // DEBUG
153           an.setSequenceRef(seqs[i]);
154           seqs[i].addAlignmentAnnotation(an);
155           al.addAnnotation(an);
156           added = true;
157         }
158         reps++; // repeated matches
159       }
160       if (added)
161       {
162         count++;
163       }
164     }
165     return count;
166   }
167 }