Merge branch 'releases/Release_2_11_3_Branch'
[jalview.git] / src / jalview / datamodel / GroupSet.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.datamodel;
22
23 import java.awt.Color;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.BitSet;
27 import java.util.HashMap;
28 import java.util.List;
29
30 import jalview.analysis.AverageDistanceEngine;
31 import jalview.bin.Console;
32
33 public class GroupSet implements GroupSetI
34 {
35   List<BitSet> groups = Arrays.asList();
36
37   public GroupSet(GroupSet grps)
38   {
39     abs = grps.abs;
40     colorMap = new HashMap<BitSet, Color>(grps.colorMap);
41     groups = new ArrayList<BitSet>(grps.groups);
42     newick = grps.newick;
43     thresh = grps.thresh;
44     treeType = grps.treeType;
45   }
46
47   public GroupSet()
48   {
49     // TODO Auto-generated constructor stub
50   }
51
52   public GroupSet(boolean abs2, float thresh2, List<BitSet> groups2,
53           String treeType2, String newick2)
54   {
55     abs = abs2;
56     thresh = thresh2;
57     groups = groups2;
58     treeType = treeType2;
59     newick = newick2;
60   }
61
62   @Override
63   public boolean hasGroups()
64   {
65     return groups != null;
66   }
67
68   String newick = null;
69
70   @Override
71   public String getNewick()
72   {
73     return newick;
74   }
75
76   @Override
77   public boolean hasTree()
78   {
79     return newick != null && newick.length() > 0;
80   }
81
82   boolean abs = false;
83
84   double thresh = 0;
85
86   String treeType = null;
87
88   @Override
89   public void updateGroups(List<BitSet> colGroups)
90   {
91     if (colGroups != null)
92     {
93       groups = colGroups;
94     }
95   }
96
97   @Override
98   public BitSet getGroupsFor(int column)
99   {
100     if (groups != null)
101     {
102       for (BitSet gp : groups)
103       {
104         if (gp.get(column))
105         {
106           return gp;
107         }
108       }
109     }
110     // return singleton set;
111     BitSet bs = new BitSet();
112     bs.set(column);
113     return bs;
114   }
115
116   HashMap<BitSet, Color> colorMap = new HashMap<>();
117
118   @Override
119   public Color getColourForGroup(BitSet bs)
120   {
121     if (bs == null)
122     {
123       return Color.white;
124     }
125     Color groupCol = colorMap.get(bs);
126     if (groupCol == null)
127     {
128       return Color.white;
129     }
130     return groupCol;
131   }
132
133   @Override
134   public void setColorForGroup(BitSet bs, Color color)
135   {
136     colorMap.put(bs, color);
137   }
138
139   @Override
140   public void restoreGroups(List<BitSet> newgroups, String treeMethod,
141           String tree, double thresh2)
142   {
143     treeType = treeMethod;
144     groups = newgroups;
145     thresh = thresh2;
146     newick = tree;
147
148   }
149
150   @Override
151   public boolean hasCutHeight()
152   {
153     return groups != null && thresh != 0;
154   }
155
156   @Override
157   public double getCutHeight()
158   {
159     return thresh;
160   }
161
162   @Override
163   public String getTreeMethod()
164   {
165     return treeType;
166   }
167
168   public static GroupSet makeGroups(ContactMatrixI matrix, boolean autoCut)
169   {
170     return makeGroups(matrix, autoCut, 0, autoCut);
171   }
172
173   public static GroupSet makeGroups(ContactMatrixI matrix, boolean auto,
174           float thresh, boolean abs)
175   {
176     AverageDistanceEngine clusterer = new AverageDistanceEngine(null, null,
177             matrix, true);
178     double height = clusterer.findHeight(clusterer.getTopNode());
179     Console.debug("Column tree height: " + height);
180     String newick = new jalview.io.NewickFile(clusterer.getTopNode(), false,
181             true).print();
182     String treeType = "UPGMA";
183     Console.trace("Newick string\n" + newick);
184
185     List<BinaryNode> nodegroups;
186     float cut = -1f;
187     if (auto)
188     {
189       double rootw = 0;
190       int p = 2;
191       BinaryNode bn = clusterer.getTopNode();
192       while (p-- > 0 & bn.left() != null)
193       {
194         if (bn.left() != null)
195         {
196           bn = bn.left();
197         }
198         if (bn.left() != null)
199         {
200           rootw = bn.height;
201         }
202       }
203       thresh = Math.max((float) (rootw / height) - 0.01f, 0);
204       cut = thresh;
205       nodegroups = clusterer.groupNodes(thresh);
206     }
207     else
208     {
209       if (abs ? (height > thresh) : (0 < thresh && thresh < 1))
210       {
211         cut = abs ? thresh : (float) (thresh * height);
212         Console.debug("Threshold " + cut + " for height=" + height);
213         nodegroups = clusterer.groupNodes(cut);
214       }
215       else
216       {
217         nodegroups = new ArrayList<BinaryNode>();
218         nodegroups.add(clusterer.getTopNode());
219       }
220     }
221
222     List<BitSet> groups = new ArrayList<>();
223     for (BinaryNode root : nodegroups)
224     {
225       BitSet gpset = new BitSet();
226       for (BinaryNode leaf : clusterer.findLeaves(root))
227       {
228         gpset.set((Integer) leaf.element());
229       }
230       groups.add(gpset);
231     }
232     GroupSet grps = new GroupSet(abs, (cut == -1f) ? thresh : cut, groups,
233             treeType, newick);
234     return grps;
235   }
236
237   @Override
238   public List<BitSet> getGroups()
239   {
240     return groups;
241   }
242 }