JAL-2416 replaced dependency on ResidueProperties with loaded score
[jalview.git] / src / jalview / analysis / scoremodels / FeatureScoreModel.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.scoremodels;
22
23 import jalview.api.analysis.ScoreModelI;
24 import jalview.api.analysis.ViewBasedAnalysisI;
25 import jalview.datamodel.AlignmentView;
26 import jalview.datamodel.SeqCigar;
27 import jalview.datamodel.SequenceFeature;
28 import jalview.util.SetUtils;
29
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 public class FeatureScoreModel implements ScoreModelI, ViewBasedAnalysisI
37 {
38   jalview.api.FeatureRenderer fr;
39
40   @Override
41   public boolean configureFromAlignmentView(
42           jalview.api.AlignmentViewPanel view)
43   {
44     fr = view.cloneFeatureRenderer();
45     return true;
46   }
47
48   /**
49    * Calculates a distance measure [i][j] between each pair of sequences as the
50    * average number of features they have but do not share. That is, find the
51    * features each sequence pair has at each column, ignore feature types they
52    * have in common, and count the rest. The totals are normalised by the number
53    * of columns processed.
54    */
55   @Override
56   public float[][] findDistances(AlignmentView seqData)
57   {
58     List<String> dft = fr.getDisplayedFeatureTypes();
59     SeqCigar[] seqs = seqData.getSequences();
60     int noseqs = seqs.length;
61     int cpwidth = 0;// = seqData.getWidth();
62     float[][] distance = new float[noseqs][noseqs];
63     if (dft.isEmpty())
64     {
65       return distance;
66     }
67
68     // need to get real position for view position
69     int[] viscont = seqData.getVisibleContigs();
70
71     /*
72      * scan each column, compute and add to each distance[i, j]
73      * the number of feature types that seqi and seqj do not share
74      */
75     for (int vc = 0; vc < viscont.length; vc += 2)
76     {
77       for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++)
78       {
79         cpwidth++;
80
81         /*
82          * first pass: record features types in column for each sequence
83          */
84         Map<SeqCigar, Set<String>> sfap = findFeatureTypesAtColumn(
85                 seqs, cpos);
86
87         /*
88          * count feature types on either i'th or j'th sequence but not both
89          * and add this 'distance' measure to the total for [i, j] for j > i
90          */
91         for (int i = 0; i < (noseqs - 1); i++)
92         {
93           for (int j = i + 1; j < noseqs; j++)
94           {
95             int seqDistance = SetUtils.countDisjunction(sfap.get(seqs[i]),
96                     sfap.get(seqs[j]));
97             distance[i][j] += seqDistance;
98           }
99         }
100       }
101     }
102
103     /*
104      * normalise the distance scores (summed over columns) by the
105      * number of visible columns used in the calculation
106      */
107     for (int i = 0; i < noseqs; i++)
108     {
109       for (int j = i + 1; j < noseqs; j++)
110       {
111         distance[i][j] /= cpwidth;
112         distance[j][i] = distance[i][j];
113       }
114     }
115     return distance;
116   }
117
118   /**
119    * Builds and returns a list (one per SeqCigar) of visible feature types at
120    * the given column position
121    * 
122    * @param seqs
123    * @param columnPosition
124    * @return
125    */
126   protected Map<SeqCigar, Set<String>> findFeatureTypesAtColumn(
127           SeqCigar[] seqs, int columnPosition)
128   {
129     Map<SeqCigar, Set<String>> sfap = new HashMap<SeqCigar, Set<String>>();
130     for (SeqCigar seq : seqs)
131     {
132       Set<String> types = new HashSet<String>();
133       int spos = seq.findPosition(columnPosition);
134       if (spos != -1)
135       {
136         List<SequenceFeature> sfs = fr.findFeaturesAtRes(seq.getRefSeq(),
137                 spos);
138         for (SequenceFeature sf : sfs)
139         {
140           types.add(sf.getType());
141         }
142       }
143       sfap.put(seq, types);
144     }
145     return sfap;
146   }
147
148   @Override
149   public String getName()
150   {
151     return "Sequence Feature Similarity";
152   }
153
154   @Override
155   public boolean isDNA()
156   {
157     return true;
158   }
159
160   @Override
161   public boolean isProtein()
162   {
163     return true;
164   }
165
166   @Override
167   public String toString()
168   {
169     return "Score between sequences based on hamming distance between binary vectors marking features displayed at each column";
170   }
171 }