Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ClustalxColourScheme | 35 | 195 | 30 | ||
ClustalxColourScheme.ClustalColour | 45 | 1 | 1 | ||
ClustalxColourScheme.ConsensusColour | 60 | 2 | 1 |
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.schemes; | |
22 | ||
23 | import java.awt.Color; | |
24 | import java.util.HashMap; | |
25 | import java.util.List; | |
26 | import java.util.Map; | |
27 | ||
28 | import jalview.api.AlignViewportI; | |
29 | import jalview.datamodel.AnnotatedCollectionI; | |
30 | import jalview.datamodel.SequenceCollectionI; | |
31 | import jalview.datamodel.SequenceI; | |
32 | import jalview.util.ColorUtils; | |
33 | import jalview.util.Comparison; | |
34 | ||
35 | public class ClustalxColourScheme extends ResidueColourScheme | |
36 | { | |
37 | private static final int EIGHTY_FIVE = 85; | |
38 | ||
39 | private static final int FIFTY = 50; | |
40 | ||
41 | private static final int EIGHTY = 80; | |
42 | ||
43 | private static final int SIXTY = 60; | |
44 | ||
45 | enum ClustalColour | |
46 | { | |
47 | RED(0.9f, 0.2f, 0.1f), BLUE(0.5f, 0.7f, 0.9f), GREEN(0.1f, 0.8f, 0.1f), | |
48 | ORANGE(0.9f, 0.6f, 0.3f), CYAN(0.1f, 0.7f, 0.7f), | |
49 | PINK(0.9f, 0.5f, 0.5f), MAGENTA(0.8f, 0.3f, 0.8f), | |
50 | YELLOW(0.8f, 0.8f, 0.0f); | |
51 | ||
52 | final Color colour; | |
53 | ||
54 | 8 | ClustalColour(float r, float g, float b) |
55 | { | |
56 | 8 | colour = new Color(r, g, b); |
57 | } | |
58 | } | |
59 | ||
60 | private class ConsensusColour | |
61 | { | |
62 | Consensus[] cons; | |
63 | ||
64 | Color c; | |
65 | ||
66 | 187 | public ConsensusColour(ClustalColour col, Consensus[] conses) |
67 | { | |
68 | 187 | this.cons = conses; |
69 | 187 | this.c = col.colour; |
70 | } | |
71 | } | |
72 | ||
73 | private int[][] cons2; | |
74 | ||
75 | private ConsensusColour[] colours; | |
76 | ||
77 | private ConsensusColour[] residueColour; | |
78 | ||
79 | private int size; | |
80 | ||
81 | private Consensus[] conses = new Consensus[32]; | |
82 | ||
83 | private boolean includeGaps = true; | |
84 | ||
85 | /** | |
86 | * Default constructor (required for Class.newInstance()) | |
87 | */ | |
88 | 51 | public ClustalxColourScheme() |
89 | { | |
90 | ||
91 | } | |
92 | ||
93 | 13 | public ClustalxColourScheme(AnnotatedCollectionI alignment, |
94 | Map<SequenceI, SequenceCollectionI> hiddenReps) | |
95 | { | |
96 | 13 | alignmentChanged(alignment, hiddenReps); |
97 | } | |
98 | ||
99 | 17 | @Override |
100 | public synchronized void alignmentChanged(AnnotatedCollectionI alignment, | |
101 | Map<SequenceI, SequenceCollectionI> hiddenReps) | |
102 | { | |
103 | 17 | int maxWidth = alignment.getWidth(); |
104 | 17 | List<SequenceI> seqs = alignment.getSequences(hiddenReps); |
105 | 17 | cons2 = new int[maxWidth][24]; |
106 | 17 | includeGaps = isIncludeGaps(); // does nothing - TODO replace with call to |
107 | // get the current setting of the | |
108 | // includeGaps param. | |
109 | 17 | int res = 0; |
110 | ||
111 | 17 | for (SequenceI sq : seqs) |
112 | { | |
113 | 90 | int end_j = sq.getLength() - 1; |
114 | 90 | int length = sq.getLength(); |
115 | ||
116 | 10905 | for (int i = 0; i <= end_j; i++) |
117 | { | |
118 | 10815 | if (length - 1 < i) |
119 | { | |
120 | 0 | res = 23; |
121 | } | |
122 | else | |
123 | { | |
124 | 10815 | res = ResidueProperties.aaIndex[sq.getCharAt(i)]; |
125 | } | |
126 | 10815 | cons2[i][res]++; |
127 | } | |
128 | } | |
129 | ||
130 | 17 | this.size = seqs.size(); |
131 | 17 | makeColours(); |
132 | } | |
133 | ||
134 | 17 | void makeColours() |
135 | { | |
136 | 17 | conses[0] = new Consensus("WLVIMAFCYHP", SIXTY); |
137 | 17 | conses[1] = new Consensus("WLVIMAFCYHP", EIGHTY); |
138 | 17 | conses[2] = new Consensus("ED", FIFTY); |
139 | 17 | conses[3] = new Consensus("KR", SIXTY); |
140 | 17 | conses[4] = new Consensus("G", FIFTY); |
141 | 17 | conses[5] = new Consensus("N", FIFTY); |
142 | 17 | conses[6] = new Consensus("QE", FIFTY); |
143 | 17 | conses[7] = new Consensus("P", FIFTY); |
144 | 17 | conses[8] = new Consensus("TS", FIFTY); |
145 | ||
146 | 17 | conses[26] = new Consensus("A", EIGHTY_FIVE); |
147 | 17 | conses[27] = new Consensus("C", EIGHTY_FIVE); |
148 | 17 | conses[10] = new Consensus("E", EIGHTY_FIVE); |
149 | 17 | conses[11] = new Consensus("F", EIGHTY_FIVE); |
150 | 17 | conses[12] = new Consensus("G", EIGHTY_FIVE); |
151 | 17 | conses[13] = new Consensus("H", EIGHTY_FIVE); |
152 | 17 | conses[14] = new Consensus("I", EIGHTY_FIVE); |
153 | 17 | conses[15] = new Consensus("L", EIGHTY_FIVE); |
154 | 17 | conses[16] = new Consensus("M", EIGHTY_FIVE); |
155 | 17 | conses[17] = new Consensus("N", EIGHTY_FIVE); |
156 | 17 | conses[18] = new Consensus("P", EIGHTY_FIVE); |
157 | 17 | conses[19] = new Consensus("Q", EIGHTY_FIVE); |
158 | 17 | conses[20] = new Consensus("R", EIGHTY_FIVE); |
159 | 17 | conses[21] = new Consensus("S", EIGHTY_FIVE); |
160 | 17 | conses[22] = new Consensus("T", EIGHTY_FIVE); |
161 | 17 | conses[23] = new Consensus("V", EIGHTY_FIVE); |
162 | 17 | conses[24] = new Consensus("W", EIGHTY_FIVE); |
163 | 17 | conses[25] = new Consensus("Y", EIGHTY_FIVE); |
164 | 17 | conses[28] = new Consensus("K", EIGHTY_FIVE); |
165 | 17 | conses[29] = new Consensus("D", EIGHTY_FIVE); |
166 | ||
167 | 17 | conses[30] = new Consensus("G", 0); |
168 | 17 | conses[31] = new Consensus("P", 0); |
169 | ||
170 | // We now construct the colours | |
171 | 17 | colours = new ConsensusColour[11]; |
172 | ||
173 | 17 | Consensus[] tmp8 = new Consensus[1]; |
174 | 17 | tmp8[0] = conses[30]; // G |
175 | 17 | colours[7] = new ConsensusColour(ClustalColour.ORANGE, tmp8); |
176 | ||
177 | 17 | Consensus[] tmp9 = new Consensus[1]; |
178 | 17 | tmp9[0] = conses[31]; // P |
179 | 17 | colours[8] = new ConsensusColour(ClustalColour.YELLOW, tmp9); |
180 | ||
181 | 17 | Consensus[] tmp10 = new Consensus[1]; |
182 | 17 | tmp10[0] = conses[27]; // C |
183 | 17 | colours[9] = new ConsensusColour(ClustalColour.PINK, tmp8); |
184 | ||
185 | 17 | Consensus[] tmp1 = new Consensus[14]; |
186 | 17 | tmp1[0] = conses[0]; // % |
187 | 17 | tmp1[1] = conses[1]; // # |
188 | 17 | tmp1[2] = conses[26]; // A |
189 | 17 | tmp1[3] = conses[27]; // C |
190 | 17 | tmp1[4] = conses[11]; // F |
191 | 17 | tmp1[5] = conses[13]; // H |
192 | 17 | tmp1[6] = conses[14]; // I |
193 | 17 | tmp1[7] = conses[15]; // L |
194 | 17 | tmp1[8] = conses[16]; // M |
195 | 17 | tmp1[9] = conses[23]; // V |
196 | 17 | tmp1[10] = conses[24]; // W |
197 | 17 | tmp1[11] = conses[25]; // Y |
198 | 17 | tmp1[12] = conses[18]; // P |
199 | 17 | tmp1[13] = conses[19]; // p |
200 | 17 | colours[0] = new ConsensusColour(ClustalColour.BLUE, tmp1); |
201 | ||
202 | 17 | colours[10] = new ConsensusColour(ClustalColour.CYAN, tmp1); |
203 | ||
204 | 17 | Consensus[] tmp2 = new Consensus[5]; |
205 | 17 | tmp2[0] = conses[8]; // t |
206 | 17 | tmp2[1] = conses[21]; // S |
207 | 17 | tmp2[2] = conses[22]; // T |
208 | 17 | tmp2[3] = conses[0]; // % |
209 | 17 | tmp2[4] = conses[1]; // # |
210 | 17 | colours[1] = new ConsensusColour(ClustalColour.GREEN, tmp2); |
211 | ||
212 | 17 | Consensus[] tmp3 = new Consensus[3]; |
213 | ||
214 | 17 | tmp3[0] = conses[17]; // N |
215 | 17 | tmp3[1] = conses[29]; // D |
216 | 17 | tmp3[2] = conses[5]; // n |
217 | 17 | colours[2] = new ConsensusColour(ClustalColour.GREEN, tmp3); |
218 | ||
219 | 17 | Consensus[] tmp4 = new Consensus[6]; |
220 | 17 | tmp4[0] = conses[6]; // q = QE |
221 | 17 | tmp4[1] = conses[19]; // Q |
222 | 17 | tmp4[2] = conses[22]; // E |
223 | 17 | tmp4[3] = conses[3]; // + |
224 | 17 | tmp4[4] = conses[28]; // K |
225 | 17 | tmp4[5] = conses[20]; // R |
226 | 17 | colours[3] = new ConsensusColour(ClustalColour.GREEN, tmp4); |
227 | ||
228 | 17 | Consensus[] tmp5 = new Consensus[4]; |
229 | 17 | tmp5[0] = conses[3]; // + |
230 | 17 | tmp5[1] = conses[28]; // K |
231 | 17 | tmp5[2] = conses[20]; // R |
232 | 17 | tmp5[3] = conses[19]; // Q |
233 | 17 | colours[4] = new ConsensusColour(ClustalColour.RED, tmp5); |
234 | ||
235 | 17 | Consensus[] tmp6 = new Consensus[6]; |
236 | 17 | tmp6[0] = conses[3]; // - |
237 | 17 | tmp6[1] = conses[29]; // D |
238 | 17 | tmp6[2] = conses[10]; // E |
239 | 17 | tmp6[3] = conses[6]; // QE |
240 | 17 | tmp6[4] = conses[19]; // Q |
241 | 17 | tmp6[5] = conses[2]; // DE |
242 | 17 | colours[5] = new ConsensusColour(ClustalColour.MAGENTA, tmp6); |
243 | ||
244 | 17 | Consensus[] tmp7 = new Consensus[5]; |
245 | 17 | tmp7[0] = conses[3]; // - |
246 | 17 | tmp7[1] = conses[29]; // D |
247 | 17 | tmp7[2] = conses[10]; // E |
248 | 17 | tmp7[3] = conses[17]; // N |
249 | 17 | tmp7[4] = conses[2]; // DE |
250 | 17 | colours[6] = new ConsensusColour(ClustalColour.MAGENTA, tmp7); |
251 | ||
252 | // Now attach the ConsensusColours to the residue letters | |
253 | 17 | residueColour = new ConsensusColour[20]; |
254 | 17 | residueColour[0] = colours[0]; // A |
255 | 17 | residueColour[1] = colours[4]; // R |
256 | 17 | residueColour[2] = colours[2]; // N |
257 | 17 | residueColour[3] = colours[6]; // D |
258 | 17 | residueColour[4] = colours[0]; // C |
259 | 17 | residueColour[5] = colours[3]; // Q |
260 | 17 | residueColour[6] = colours[5]; // E |
261 | 17 | residueColour[7] = colours[7]; // G |
262 | 17 | residueColour[8] = colours[10]; // H |
263 | 17 | residueColour[9] = colours[0]; // I |
264 | 17 | residueColour[10] = colours[0]; // L |
265 | 17 | residueColour[11] = colours[4]; // K |
266 | 17 | residueColour[12] = colours[0]; // M |
267 | 17 | residueColour[13] = colours[0]; // F |
268 | 17 | residueColour[14] = colours[8]; // P |
269 | 17 | residueColour[15] = colours[1]; // S |
270 | 17 | residueColour[16] = colours[1]; // T |
271 | 17 | residueColour[17] = colours[0]; // W |
272 | 17 | residueColour[18] = colours[10]; // Y |
273 | 17 | residueColour[19] = colours[0]; // V |
274 | } | |
275 | ||
276 | 0 | @Override |
277 | public Color findColour(char c) | |
278 | { | |
279 | 0 | return Color.pink; |
280 | } | |
281 | ||
282 | 19 | @Override |
283 | protected synchronized Color findColour(char c, int j, SequenceI seq) | |
284 | { | |
285 | // TODO why the test for includeGaps here? | |
286 | 19 | if (cons2.length <= j || Comparison.isGap(c) |
287 | /*|| (includeGaps && threshold != 0 && !aboveThreshold(c, j))*/) | |
288 | { | |
289 | 0 | return Color.white; |
290 | } | |
291 | ||
292 | 19 | int i = ResidueProperties.aaIndex[c]; |
293 | ||
294 | 19 | Color colour = Color.white; |
295 | ||
296 | 19 | if (i > 19) |
297 | { | |
298 | 0 | return colour; |
299 | } | |
300 | ||
301 | 170 | for (int k = 0; k < residueColour[i].cons.length; k++) |
302 | { | |
303 | 151 | if (residueColour[i].cons[k].isConserved(cons2, j, size, includeGaps)) |
304 | { | |
305 | 22 | colour = residueColour[i].c; |
306 | } | |
307 | } | |
308 | ||
309 | 19 | if (i == 4) |
310 | { | |
311 | /* | |
312 | * override to colour C pink if >85% conserved | |
313 | */ | |
314 | 3 | if (conses[27].isConserved(cons2, j, size, includeGaps)) |
315 | { | |
316 | 1 | colour = ClustalColour.PINK.colour; |
317 | } | |
318 | } | |
319 | ||
320 | 19 | return colour; |
321 | } | |
322 | ||
323 | /** | |
324 | * @return the includeGaps | |
325 | */ | |
326 | 17 | protected boolean isIncludeGaps() |
327 | { | |
328 | 17 | return includeGaps; |
329 | } | |
330 | ||
331 | /** | |
332 | * @param includeGaps | |
333 | * the includeGaps to set | |
334 | */ | |
335 | 2 | protected void setIncludeGaps(boolean includeGaps) |
336 | { | |
337 | 2 | this.includeGaps = includeGaps; |
338 | } | |
339 | ||
340 | 7 | @Override |
341 | public ColourSchemeI getInstance(AlignViewportI view, | |
342 | AnnotatedCollectionI sg) | |
343 | { | |
344 | 7 | ClustalxColourScheme css = new ClustalxColourScheme(sg, |
345 | 7 | view == null ? null : view.getHiddenRepSequences()); |
346 | 7 | css.includeGaps = includeGaps; |
347 | 7 | return css; |
348 | } | |
349 | ||
350 | 844 | @Override |
351 | public boolean isPeptideSpecific() | |
352 | { | |
353 | 844 | return true; |
354 | } | |
355 | ||
356 | 566 | @Override |
357 | public String getSchemeName() | |
358 | { | |
359 | 566 | return JalviewColourScheme.Clustal.toString(); |
360 | } | |
361 | ||
362 | 47 | @Override |
363 | public boolean isSimple() | |
364 | { | |
365 | 47 | return false; |
366 | } | |
367 | ||
368 | 0 | public String toRuleRep() |
369 | { | |
370 | 0 | makeColours(); |
371 | 0 | HashMap<String, String> cols = new HashMap(); |
372 | 0 | for (String res : ResidueProperties.aa) |
373 | { | |
374 | 0 | StringBuilder sb = new StringBuilder(); |
375 | ||
376 | 0 | int rnum = ResidueProperties.aaIndex[res.charAt(0)]; |
377 | 0 | if (rnum < 0 || rnum >= residueColour.length) |
378 | { | |
379 | 0 | continue; |
380 | } | |
381 | ||
382 | 0 | ConsensusColour cc = residueColour[rnum]; |
383 | 0 | if (cc == null) |
384 | { | |
385 | 0 | continue; |
386 | } | |
387 | // sb.append("Residue "+res+" ("+rnum+")"); | |
388 | // sb.append("\t"); | |
389 | 0 | sb.append(cc.c.toString()); |
390 | 0 | double f = 0; |
391 | 0 | sb.append("\t"); |
392 | 0 | for (Consensus cons : cc.cons) |
393 | { | |
394 | 0 | if (cons.threshold == 0 || f != cons.threshold) |
395 | { | |
396 | 0 | if (f != 0) |
397 | { | |
398 | ||
399 | 0 | sb.append("}, {"); |
400 | } | |
401 | else | |
402 | { | |
403 | 0 | sb.append("{"); |
404 | } | |
405 | 0 | sb.append(cons.threshold); |
406 | 0 | sb.append(","); |
407 | 0 | f = cons.threshold; |
408 | } | |
409 | else | |
410 | { | |
411 | 0 | sb.append(","); |
412 | } | |
413 | 0 | sb.append(cons.maskstr); |
414 | } | |
415 | 0 | sb.append("}"); |
416 | 0 | String clxrep = sb.toString(); |
417 | 0 | String xres = cols.get(clxrep); |
418 | 0 | if (xres == null) |
419 | { | |
420 | 0 | xres = ""; |
421 | } | |
422 | 0 | xres += res; |
423 | 0 | cols.put(clxrep, xres); |
424 | } | |
425 | 0 | StringBuilder sb = new StringBuilder(); |
426 | 0 | for (String clxrep : cols.keySet()) |
427 | { | |
428 | 0 | sb.append(cols.get(clxrep)); |
429 | 0 | sb.append("\t"); |
430 | 0 | sb.append(clxrep); |
431 | 0 | sb.append("\n"); |
432 | ||
433 | } | |
434 | 0 | return sb.toString(); |
435 | } | |
436 | } |