Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
SequenceGroup | 48 | 425 | 214 |
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.beans.PropertyChangeListener; | |
25 | import java.beans.PropertyChangeSupport; | |
26 | import java.util.ArrayList; | |
27 | import java.util.Arrays; | |
28 | import java.util.Collection; | |
29 | import java.util.Collections; | |
30 | import java.util.HashMap; | |
31 | import java.util.List; | |
32 | import java.util.Map; | |
33 | ||
34 | import jalview.analysis.AAFrequency; | |
35 | import jalview.analysis.AlignmentUtils; | |
36 | import jalview.analysis.Conservation; | |
37 | import jalview.renderer.ResidueShader; | |
38 | import jalview.renderer.ResidueShaderI; | |
39 | import jalview.schemes.ColourSchemeI; | |
40 | import jalview.util.Constants; | |
41 | ||
42 | /** | |
43 | * Collects a set contiguous ranges on a set of sequences | |
44 | * | |
45 | * @author $author$ | |
46 | * @version $Revision$ | |
47 | */ | |
48 | public class SequenceGroup implements AnnotatedCollectionI | |
49 | { | |
50 | // TODO ideally this event notification functionality should be separated into | |
51 | // a | |
52 | // subclass of ViewportProperties similarly to ViewportRanges. Done here as | |
53 | // quick fix for JAL-2665 | |
54 | public static final String SEQ_GROUP_CHANGED = "Sequence group changed"; | |
55 | ||
56 | protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( | |
57 | this); | |
58 | ||
59 | 0 | public void addPropertyChangeListener(PropertyChangeListener listener) |
60 | { | |
61 | 0 | changeSupport.addPropertyChangeListener(listener); |
62 | } | |
63 | ||
64 | 0 | public void removePropertyChangeListener(PropertyChangeListener listener) |
65 | { | |
66 | 0 | changeSupport.removePropertyChangeListener(listener); |
67 | } | |
68 | // end of event notification functionality initialisation | |
69 | ||
70 | String groupName; | |
71 | ||
72 | String description; | |
73 | ||
74 | Conservation conserve; | |
75 | ||
76 | boolean displayBoxes = true; | |
77 | ||
78 | boolean displayText = true; | |
79 | ||
80 | boolean colourText = false; | |
81 | ||
82 | /** | |
83 | * True if the group is defined as a group on the alignment, false if it is | |
84 | * just a selection. | |
85 | */ | |
86 | boolean isDefined = false; | |
87 | ||
88 | /** | |
89 | * after Olivier's non-conserved only character display | |
90 | */ | |
91 | boolean showNonconserved = false; | |
92 | ||
93 | /** | |
94 | * group members | |
95 | */ | |
96 | private List<SequenceI> sequences; | |
97 | ||
98 | /** | |
99 | * representative sequence for this group (if any) | |
100 | */ | |
101 | private SequenceI seqrep = null; | |
102 | ||
103 | int width = -1; | |
104 | ||
105 | /** | |
106 | * Colourscheme applied to group if any | |
107 | */ | |
108 | public ResidueShaderI cs; | |
109 | ||
110 | /** | |
111 | * start column (base 0) | |
112 | */ | |
113 | private int startRes = 0; | |
114 | ||
115 | /** | |
116 | * end column (base 0) | |
117 | */ | |
118 | private int endRes = 0; | |
119 | ||
120 | public Color outlineColour = Color.black; | |
121 | ||
122 | public Color idColour = null; | |
123 | ||
124 | public int thresholdTextColour = 0; | |
125 | ||
126 | public Color textColour = Color.black; | |
127 | ||
128 | public Color textColour2 = Color.white; | |
129 | ||
130 | /** | |
131 | * consensus calculation property | |
132 | */ | |
133 | private boolean ignoreGapsInConsensus = true; | |
134 | ||
135 | /** | |
136 | * consensus calculation property | |
137 | */ | |
138 | private boolean showSequenceLogo = false; | |
139 | ||
140 | /** | |
141 | * flag indicating if logo should be rendered normalised | |
142 | */ | |
143 | private boolean normaliseSequenceLogo; | |
144 | ||
145 | /* | |
146 | * visibility of rows or represented rows covered by group | |
147 | */ | |
148 | private boolean hidereps = false; | |
149 | ||
150 | /* | |
151 | * visibility of columns intersecting this group | |
152 | */ | |
153 | private boolean hidecols = false; | |
154 | ||
155 | AlignmentAnnotation consensus = null; | |
156 | ||
157 | List<AlignmentAnnotation> ssConsensus = null; | |
158 | ||
159 | List<String> secondaryStructureSources = null; | |
160 | ||
161 | AlignmentAnnotation conservation = null; | |
162 | ||
163 | private boolean showConsensusHistogram; | |
164 | ||
165 | private AnnotatedCollectionI context; | |
166 | ||
167 | public Map<String, ProfilesI> hSSConsensusProfileMap; | |
168 | ||
169 | List<AlignmentAnnotation> annotationsFromTree; | |
170 | ||
171 | /** | |
172 | * Creates a new SequenceGroup object. | |
173 | */ | |
174 | 971 | public SequenceGroup() |
175 | { | |
176 | 971 | groupName = "JGroup:" + this.hashCode(); |
177 | 971 | cs = new ResidueShader(); |
178 | 971 | sequences = new ArrayList<>(); |
179 | 971 | annotationsFromTree = new ArrayList<>(); |
180 | } | |
181 | ||
182 | /** | |
183 | * Creates a new SequenceGroup object. | |
184 | * | |
185 | * @param sequences | |
186 | * @param groupName | |
187 | * @param scheme | |
188 | * @param displayBoxes | |
189 | * @param displayText | |
190 | * @param colourText | |
191 | * @param start | |
192 | * first column of group | |
193 | * @param end | |
194 | * last column of group | |
195 | */ | |
196 | 79 | public SequenceGroup(List<SequenceI> sequences, String groupName, |
197 | ColourSchemeI scheme, boolean displayBoxes, boolean displayText, | |
198 | boolean colourText, int start, int end) | |
199 | { | |
200 | 79 | this(); |
201 | 79 | this.sequences = sequences; |
202 | 79 | this.groupName = groupName; |
203 | 79 | this.displayBoxes = displayBoxes; |
204 | 79 | this.displayText = displayText; |
205 | 79 | this.colourText = colourText; |
206 | 79 | this.cs = new ResidueShader(scheme); |
207 | 79 | startRes = start; |
208 | 79 | endRes = end; |
209 | 79 | recalcConservation(); |
210 | } | |
211 | ||
212 | /** | |
213 | * copy constructor | |
214 | * | |
215 | * @param seqsel | |
216 | */ | |
217 | 107 | public SequenceGroup(SequenceGroup seqsel) |
218 | { | |
219 | 107 | this(); |
220 | 107 | if (seqsel != null) |
221 | { | |
222 | 99 | sequences = new ArrayList<>(); |
223 | 99 | sequences.addAll(seqsel.sequences); |
224 | 99 | if (seqsel.groupName != null) |
225 | { | |
226 | 99 | groupName = new String(seqsel.groupName); |
227 | } | |
228 | 99 | displayBoxes = seqsel.displayBoxes; |
229 | 99 | displayText = seqsel.displayText; |
230 | 99 | colourText = seqsel.colourText; |
231 | ||
232 | 99 | startRes = seqsel.startRes; |
233 | 99 | endRes = seqsel.endRes; |
234 | 99 | cs = new ResidueShader((ResidueShader) seqsel.cs); |
235 | 99 | if (seqsel.description != null) |
236 | { | |
237 | 1 | description = new String(seqsel.description); |
238 | } | |
239 | 99 | hidecols = seqsel.hidecols; |
240 | 99 | hidereps = seqsel.hidereps; |
241 | 99 | showNonconserved = seqsel.showNonconserved; |
242 | 99 | showSequenceLogo = seqsel.showSequenceLogo; |
243 | 99 | normaliseSequenceLogo = seqsel.normaliseSequenceLogo; |
244 | 99 | showConsensusHistogram = seqsel.showConsensusHistogram; |
245 | 99 | idColour = seqsel.idColour; |
246 | 99 | outlineColour = seqsel.outlineColour; |
247 | 99 | seqrep = seqsel.seqrep; |
248 | 99 | textColour = seqsel.textColour; |
249 | 99 | textColour2 = seqsel.textColour2; |
250 | 99 | thresholdTextColour = seqsel.thresholdTextColour; |
251 | 99 | width = seqsel.width; |
252 | 99 | ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus; |
253 | 99 | if (seqsel.conserve != null) |
254 | { | |
255 | 0 | recalcConservation(); // safer than |
256 | // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ?? | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
261 | /** | |
262 | * Constructor that copies the given list of sequences | |
263 | * | |
264 | * @param seqs | |
265 | */ | |
266 | 11 | public SequenceGroup(List<SequenceI> seqs) |
267 | { | |
268 | 11 | this(); |
269 | 11 | this.sequences.addAll(seqs); |
270 | } | |
271 | ||
272 | 40467 | public boolean isShowSequenceLogo() |
273 | { | |
274 | 40467 | return showSequenceLogo; |
275 | } | |
276 | ||
277 | 2 | public SequenceI[] getSelectionAsNewSequences(AlignmentI align) |
278 | { | |
279 | 2 | int iSize = sequences.size(); |
280 | 2 | SequenceI[] seqs = new SequenceI[iSize]; |
281 | 2 | SequenceI[] inorder = getSequencesInOrder(align); |
282 | ||
283 | 18 | for (int i = 0, ipos = 0; i < inorder.length; i++) |
284 | { | |
285 | 16 | SequenceI seq = inorder[i]; |
286 | 16 | SequenceI seqipos = seqs[ipos] = seq.getSubSequence(startRes, |
287 | endRes + 1); | |
288 | 16 | if (seqipos != null) |
289 | { | |
290 | 16 | if (seq.getAnnotation() != null) |
291 | { | |
292 | 1 | AlignmentAnnotation[] alann = align.getAlignmentAnnotation(); |
293 | // Only copy annotation that is either a score or referenced by the | |
294 | // alignment's annotation vector | |
295 | 2 | for (int a = 0; a < seq.getAnnotation().length; a++) |
296 | { | |
297 | 1 | AlignmentAnnotation tocopy = seq.getAnnotation()[a]; |
298 | 1 | if (alann != null) |
299 | { | |
300 | 1 | boolean found = false; |
301 | 1 | for (int pos = 0, np = alann.length; pos < np; pos++) |
302 | { | |
303 | 1 | if (alann[pos] == tocopy) |
304 | { | |
305 | 1 | found = true; |
306 | 1 | break; |
307 | } | |
308 | } | |
309 | 1 | if (!found) |
310 | { | |
311 | 0 | continue; |
312 | } | |
313 | } | |
314 | 1 | AlignmentAnnotation newannot = new AlignmentAnnotation( |
315 | seq.getAnnotation()[a]); | |
316 | 1 | newannot.restrict(startRes, endRes); |
317 | 1 | newannot.setSequenceRef(seqs[ipos]); |
318 | 1 | newannot.adjustForAlignment(); |
319 | 1 | ContactMatrixI cm = seq |
320 | .getContactMatrixFor(seq.getAnnotation()[a]); | |
321 | 1 | if (cm != null) |
322 | { | |
323 | 1 | seqs[ipos].addContactListFor(newannot, cm); |
324 | } | |
325 | 1 | seqipos.addAlignmentAnnotation(newannot); |
326 | } | |
327 | } | |
328 | 16 | ipos++; |
329 | } | |
330 | else | |
331 | { | |
332 | 0 | iSize--; |
333 | } | |
334 | } | |
335 | 2 | if (iSize != inorder.length) |
336 | { | |
337 | 0 | SequenceI[] nseqs = new SequenceI[iSize]; |
338 | 0 | System.arraycopy(seqs, 0, nseqs, 0, iSize); |
339 | 0 | seqs = nseqs; |
340 | } | |
341 | 2 | return seqs; |
342 | ||
343 | } | |
344 | ||
345 | /** | |
346 | * If sequence ends in gaps, the end residue can be correctly calculated here | |
347 | * | |
348 | * @param seq | |
349 | * SequenceI | |
350 | * @return int | |
351 | */ | |
352 | 0 | public int findEndRes(SequenceI seq) |
353 | { | |
354 | 0 | int eres = 0; |
355 | 0 | char ch; |
356 | ||
357 | 0 | for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++) |
358 | { | |
359 | 0 | ch = seq.getCharAt(j); |
360 | 0 | if (!jalview.util.Comparison.isGap((ch))) |
361 | { | |
362 | 0 | eres++; |
363 | } | |
364 | } | |
365 | ||
366 | 0 | if (eres > 0) |
367 | { | |
368 | 0 | eres += seq.getStart() - 1; |
369 | } | |
370 | ||
371 | 0 | return eres; |
372 | } | |
373 | ||
374 | 18788 | @Override |
375 | public List<SequenceI> getSequences() | |
376 | { | |
377 | 18788 | return sequences; |
378 | } | |
379 | ||
380 | 2112 | @Override |
381 | public List<SequenceI> getSequences( | |
382 | Map<SequenceI, SequenceCollectionI> hiddenReps) | |
383 | { | |
384 | 2112 | if (hiddenReps == null) |
385 | { | |
386 | // TODO: need a synchronizedCollection here ? | |
387 | 2112 | return sequences; |
388 | } | |
389 | else | |
390 | { | |
391 | 0 | List<SequenceI> allSequences = new ArrayList<>(); |
392 | 0 | for (SequenceI seq : sequences) |
393 | { | |
394 | 0 | allSequences.add(seq); |
395 | 0 | if (hiddenReps.containsKey(seq)) |
396 | { | |
397 | 0 | SequenceCollectionI hsg = hiddenReps.get(seq); |
398 | 0 | for (SequenceI seq2 : hsg.getSequences()) |
399 | { | |
400 | 0 | if (seq2 != seq && !allSequences.contains(seq2)) |
401 | { | |
402 | 0 | allSequences.add(seq2); |
403 | } | |
404 | } | |
405 | } | |
406 | } | |
407 | ||
408 | 0 | return allSequences; |
409 | } | |
410 | } | |
411 | ||
412 | 5 | public SequenceI[] getSequencesAsArray( |
413 | Map<SequenceI, SequenceCollectionI> map) | |
414 | { | |
415 | 5 | List<SequenceI> tmp = getSequences(map); |
416 | 5 | if (tmp == null) |
417 | { | |
418 | 0 | return null; |
419 | } | |
420 | 5 | return tmp.toArray(new SequenceI[tmp.size()]); |
421 | } | |
422 | ||
423 | 19 | public List<String> getSecondaryStructureSources() |
424 | { | |
425 | 19 | return secondaryStructureSources; |
426 | } | |
427 | ||
428 | 47 | public void setSecondaryStructureSources( |
429 | List<String> secondaryStructureSources) | |
430 | { | |
431 | 47 | this.secondaryStructureSources = secondaryStructureSources; |
432 | } | |
433 | ||
434 | /** | |
435 | * DOCUMENT ME! | |
436 | * | |
437 | * @param col | |
438 | * DOCUMENT ME! | |
439 | * | |
440 | * @return DOCUMENT ME! | |
441 | */ | |
442 | 0 | public boolean adjustForRemoveLeft(int col) |
443 | { | |
444 | // return value is true if the group still exists | |
445 | 0 | if (startRes >= col) |
446 | { | |
447 | 0 | startRes = startRes - col; |
448 | } | |
449 | ||
450 | 0 | if (endRes >= col) |
451 | { | |
452 | 0 | endRes = endRes - col; |
453 | ||
454 | 0 | if (startRes > endRes) |
455 | { | |
456 | 0 | startRes = 0; |
457 | } | |
458 | } | |
459 | else | |
460 | { | |
461 | // must delete this group!! | |
462 | 0 | return false; |
463 | } | |
464 | ||
465 | 0 | return true; |
466 | } | |
467 | ||
468 | /** | |
469 | * DOCUMENT ME! | |
470 | * | |
471 | * @param col | |
472 | * DOCUMENT ME! | |
473 | * | |
474 | * @return DOCUMENT ME! | |
475 | */ | |
476 | 0 | public boolean adjustForRemoveRight(int col) |
477 | { | |
478 | 0 | if (startRes > col) |
479 | { | |
480 | // delete this group | |
481 | 0 | return false; |
482 | } | |
483 | ||
484 | 0 | if (endRes >= col) |
485 | { | |
486 | 0 | endRes = col; |
487 | } | |
488 | ||
489 | 0 | return true; |
490 | } | |
491 | ||
492 | /** | |
493 | * DOCUMENT ME! | |
494 | * | |
495 | * @return DOCUMENT ME! | |
496 | */ | |
497 | 247 | public String getName() |
498 | { | |
499 | 247 | return groupName; |
500 | } | |
501 | ||
502 | 16 | public String getDescription() |
503 | { | |
504 | 16 | return description; |
505 | } | |
506 | ||
507 | /** | |
508 | * DOCUMENT ME! | |
509 | * | |
510 | * @param name | |
511 | * DOCUMENT ME! | |
512 | */ | |
513 | 23 | public void setName(String name) |
514 | { | |
515 | 23 | groupName = name; |
516 | // TODO: URGENT: update dependent objects (annotation row) | |
517 | } | |
518 | ||
519 | 20 | public void setDescription(String desc) |
520 | { | |
521 | 20 | description = desc; |
522 | } | |
523 | ||
524 | /** | |
525 | * DOCUMENT ME! | |
526 | * | |
527 | * @return DOCUMENT ME! | |
528 | */ | |
529 | 0 | public Conservation getConservation() |
530 | { | |
531 | 0 | return conserve; |
532 | } | |
533 | ||
534 | /** | |
535 | * DOCUMENT ME! | |
536 | * | |
537 | * @param c | |
538 | * DOCUMENT ME! | |
539 | */ | |
540 | 0 | public void setConservation(Conservation c) |
541 | { | |
542 | 0 | conserve = c; |
543 | } | |
544 | ||
545 | /** | |
546 | * Add s to this sequence group. If aligment sequence is already contained in | |
547 | * group, it will not be added again, but recalculation may happen if the flag | |
548 | * is set. | |
549 | * | |
550 | * @param s | |
551 | * alignment sequence to be added | |
552 | * @param recalc | |
553 | * true means Group's conservation should be recalculated | |
554 | */ | |
555 | 623 | public void addSequence(SequenceI s, boolean recalc) |
556 | { | |
557 | 623 | synchronized (sequences) |
558 | { | |
559 | 623 | if (s != null && !sequences.contains(s)) |
560 | { | |
561 | 612 | sequences.add(s); |
562 | 612 | changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, |
563 | sequences.size() - 1, sequences.size()); | |
564 | } | |
565 | ||
566 | 623 | if (recalc) |
567 | { | |
568 | 1 | recalcConservation(); |
569 | } | |
570 | } | |
571 | } | |
572 | ||
573 | /** | |
574 | * Max Gaps Threshold (percent) for performing a conservation calculation | |
575 | */ | |
576 | private int consPercGaps = 25; | |
577 | ||
578 | /** | |
579 | * @return Max Gaps Threshold for performing a conservation calculation | |
580 | */ | |
581 | 0 | public int getConsPercGaps() |
582 | { | |
583 | 0 | return consPercGaps; |
584 | } | |
585 | ||
586 | /** | |
587 | * set Max Gaps Threshold (percent) for performing a conservation calculation | |
588 | * | |
589 | * @param consPercGaps | |
590 | */ | |
591 | 0 | public void setConsPercGaps(int consPercGaps) |
592 | { | |
593 | 0 | this.consPercGaps = consPercGaps; |
594 | } | |
595 | ||
596 | /** | |
597 | * calculate residue conservation and colourschemes for group - but only if | |
598 | * necessary. returns true if the calculation resulted in a visible change to | |
599 | * group | |
600 | */ | |
601 | 381 | public boolean recalcConservation() |
602 | { | |
603 | 381 | return recalcConservation(false); |
604 | } | |
605 | ||
606 | /** | |
607 | * calculate residue conservation for group - but only if necessary. returns | |
608 | * true if the calculation resulted in a visible change to group | |
609 | * | |
610 | * @param defer | |
611 | * when set, colourschemes for this group are not refreshed after | |
612 | * recalculation | |
613 | */ | |
614 | 381 | public boolean recalcConservation(boolean defer) |
615 | { | |
616 | 381 | if (cs == null && consensus == null && conservation == null) |
617 | { | |
618 | 0 | return false; |
619 | } | |
620 | // TODO: try harder to detect changes in state in order to minimise | |
621 | // recalculation effort | |
622 | 381 | boolean upd = false; |
623 | 381 | try |
624 | { | |
625 | 381 | ProfilesI cnsns = AAFrequency.calculate(sequences, startRes, |
626 | endRes + 1, showSequenceLogo); | |
627 | 381 | if (consensus != null) |
628 | { | |
629 | 120 | _updateConsensusRow(cnsns, sequences.size()); |
630 | 120 | upd = true; |
631 | } | |
632 | 381 | if (cs != null) |
633 | { | |
634 | 381 | cs.setConsensus(cnsns); |
635 | 381 | upd = true; |
636 | } | |
637 | ||
638 | 381 | hSSConsensusProfileMap = new HashMap<String, ProfilesI>(); |
639 | 381 | List<String> ssSources = new ArrayList<String>(); |
640 | 381 | AnnotatedCollectionI aa = this.getContext(); |
641 | ||
642 | 381 | if (aa != null) |
643 | { | |
644 | 302 | ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation( |
645 | aa.getAlignmentAnnotation()); | |
646 | } | |
647 | 381 | if (ssSources != null) |
648 | { | |
649 | 381 | ssSources.add(Constants.SS_ALL_PROVIDERS); |
650 | ||
651 | 381 | for (String ssSource : ssSources) |
652 | { | |
653 | 381 | ProfilesI hSSConsensus = AAFrequency.calculateSS(sequences, |
654 | startRes, endRes + 1, showSequenceLogo, ssSource); | |
655 | 381 | hSSConsensusProfileMap.put(ssSource, hSSConsensus); |
656 | } | |
657 | } | |
658 | ||
659 | 381 | if (ssConsensus != null) |
660 | { | |
661 | 0 | _updateSSConsensusRow(hSSConsensusProfileMap, sequences.size()); |
662 | 0 | upd = true; |
663 | } | |
664 | ||
665 | 381 | if (cs != null) |
666 | { | |
667 | 381 | cs.setSSConsensusProfileMap(hSSConsensusProfileMap); |
668 | 381 | upd = true; |
669 | } | |
670 | ||
671 | 381 | if ((conservation != null) |
672 | || (cs != null && cs.conservationApplied())) | |
673 | { | |
674 | 3 | Conservation c = new Conservation(groupName, sequences, startRes, |
675 | endRes + 1); | |
676 | 3 | c.calculate(); |
677 | 3 | c.verdict(false, consPercGaps); |
678 | 3 | if (conservation != null) |
679 | { | |
680 | 0 | _updateConservationRow(c); |
681 | } | |
682 | 3 | if (cs != null) |
683 | { | |
684 | 3 | if (cs.conservationApplied()) |
685 | { | |
686 | 3 | cs.setConservation(c); |
687 | } | |
688 | } | |
689 | // eager update - will cause a refresh of overview regardless | |
690 | 3 | upd = true; |
691 | } | |
692 | 381 | if (cs != null && !defer) |
693 | { | |
694 | // TODO: JAL-2034 should cs.alignmentChanged modify return state | |
695 | 381 | cs.alignmentChanged(context != null ? context : this, null); |
696 | 381 | return true; |
697 | } | |
698 | else | |
699 | { | |
700 | 0 | return upd; |
701 | } | |
702 | } catch (java.lang.OutOfMemoryError err) | |
703 | { | |
704 | // TODO: catch OOM | |
705 | 0 | jalview.bin.Console |
706 | .outPrintln("Out of memory loading groups: " + err); | |
707 | } | |
708 | 0 | return upd; |
709 | } | |
710 | ||
711 | 0 | private void _updateConservationRow(Conservation c) |
712 | { | |
713 | 0 | if (conservation == null) |
714 | { | |
715 | 0 | getConservation(); |
716 | } | |
717 | // update Labels | |
718 | 0 | conservation.label = "Conservation for " + getName(); |
719 | 0 | conservation.description = "Conservation for group " + getName() |
720 | + " less than " + consPercGaps + "% gaps"; | |
721 | // preserve width if already set | |
722 | 0 | int aWidth = (conservation.annotations != null) |
723 | 0 | ? (endRes < conservation.annotations.length |
724 | ? conservation.annotations.length | |
725 | : endRes + 1) | |
726 | : endRes + 1; | |
727 | 0 | conservation.annotations = null; |
728 | 0 | conservation.annotations = new Annotation[aWidth]; // should be alignment |
729 | // width | |
730 | 0 | c.completeAnnotations(conservation, null, startRes, endRes + 1); |
731 | } | |
732 | ||
733 | public ProfilesI consensusData = null; | |
734 | ||
735 | 120 | private void _updateConsensusRow(ProfilesI cnsns, long nseq) |
736 | { | |
737 | 120 | if (consensus == null) |
738 | { | |
739 | 0 | getConsensus(); |
740 | } | |
741 | 120 | consensus.label = "Consensus for " + getName(); |
742 | 120 | consensus.description = "Percent Identity"; |
743 | 120 | consensusData = cnsns; |
744 | // preserve width if already set | |
745 | 120 | int aWidth = (consensus.annotations != null) |
746 | 120 | ? (endRes < consensus.annotations.length |
747 | ? consensus.annotations.length | |
748 | : endRes + 1) | |
749 | : endRes + 1; | |
750 | 120 | consensus.annotations = null; |
751 | 120 | consensus.annotations = new Annotation[aWidth]; // should be alignment width |
752 | ||
753 | 120 | AAFrequency.completeConsensus(consensus, cnsns, startRes, endRes + 1, |
754 | ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting | |
755 | // container | |
756 | // for | |
757 | // ignoreGapsInConsensusCalculation); | |
758 | } | |
759 | ||
760 | /** | |
761 | * Updates the secondary structure consensus row based on the provided | |
762 | * profiles map and the number of sequences. | |
763 | * | |
764 | * @param hSSConsensusProfileMap | |
765 | * A map containing secondary structure consensus profiles for each | |
766 | * providers. | |
767 | * @param nseq | |
768 | * The number of sequences. | |
769 | */ | |
770 | 0 | private void _updateSSConsensusRow( |
771 | Map<String, ProfilesI> hSSConsensusProfileMap, long nseq) | |
772 | { | |
773 | // Get a list of secondary structure sources from the profile map keys | |
774 | 0 | List<String> ssSources = new ArrayList<>( |
775 | hSSConsensusProfileMap.keySet()); | |
776 | 0 | secondaryStructureSources = new ArrayList<String>(); |
777 | ||
778 | // Sort the secondary structure sources alphabetically | |
779 | 0 | Collections.sort(ssSources); |
780 | ||
781 | // Initialize ssConsensus if it is null | |
782 | 0 | if (ssConsensus == null) |
783 | { | |
784 | 0 | getSSConsensus(ssSources); |
785 | } | |
786 | ||
787 | // Iterate through each alignment annotation in the ssConsensus list | |
788 | 0 | for (AlignmentAnnotation aa : ssConsensus) |
789 | { | |
790 | 0 | ProfilesI profile = null; |
791 | 0 | String ssSource = null; |
792 | ||
793 | // Find the matching profile for the current annotation based on its | |
794 | // description | |
795 | 0 | for (String source : ssSources) |
796 | { | |
797 | 0 | if (aa.description.startsWith(source)) |
798 | { | |
799 | 0 | profile = hSSConsensusProfileMap.get(source); |
800 | 0 | ssSource = source; |
801 | } | |
802 | } | |
803 | ||
804 | // If no matching profile is found, continue to the next annotation | |
805 | 0 | if (profile == null) |
806 | { | |
807 | 0 | continue; |
808 | } | |
809 | ||
810 | // Update the label and description of the annotation with the | |
811 | // source/provider | |
812 | 0 | aa.label = Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " " |
813 | + ssSource + " " + getName(); | |
814 | 0 | aa.description = ssSource |
815 | + Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " for " | |
816 | + getName(); | |
817 | ||
818 | // Get the width of the annotations array | |
819 | 0 | int aWidth = (aa.annotations != null) |
820 | 0 | ? (endRes < aa.annotations.length ? aa.annotations.length |
821 | : endRes + 1) | |
822 | : endRes + 1; | |
823 | 0 | aa.annotations = new Annotation[aWidth]; |
824 | ||
825 | // Complete the secondary structure consensus | |
826 | 0 | AAFrequency.completeSSConsensus(aa, profile, startRes, endRes + 1, |
827 | ignoreGapsInConsensus, showSequenceLogo, nseq); | |
828 | ||
829 | // Add the provider to the list if the no of sequences | |
830 | // contributed to the secondary structure consensus is | |
831 | // more than 0. | |
832 | 0 | if (aa.getNoOfSequencesIncluded() > 0 |
833 | && !Constants.SS_ALL_PROVIDERS.equals(ssSource)) | |
834 | { | |
835 | // Remove "All" from the hidden types list{ | |
836 | 0 | secondaryStructureSources.add(ssSource); |
837 | } | |
838 | } | |
839 | } | |
840 | ||
841 | /** | |
842 | * @param s | |
843 | * sequence to either add or remove from group | |
844 | * @param recalc | |
845 | * flag passed to delete/addSequence to indicate if group properties | |
846 | * should be recalculated | |
847 | */ | |
848 | 4 | public void addOrRemove(SequenceI s, boolean recalc) |
849 | { | |
850 | 4 | synchronized (sequences) |
851 | { | |
852 | 4 | if (sequences.contains(s)) |
853 | { | |
854 | 1 | deleteSequence(s, recalc); |
855 | } | |
856 | else | |
857 | { | |
858 | 3 | addSequence(s, recalc); |
859 | } | |
860 | } | |
861 | } | |
862 | ||
863 | 0 | public boolean addOrRemoveAnnotation(AlignmentAnnotation alignmentAnnotation) |
864 | { | |
865 | 0 | synchronized (annotationsFromTree) |
866 | { | |
867 | 0 | if (annotationsFromTree.contains(alignmentAnnotation)) |
868 | { | |
869 | 0 | annotationsFromTree.remove(alignmentAnnotation); |
870 | 0 | return false; |
871 | } | |
872 | else | |
873 | { | |
874 | 0 | annotationsFromTree.add(alignmentAnnotation); |
875 | 0 | return true; |
876 | } | |
877 | } | |
878 | } | |
879 | ||
880 | /** | |
881 | * remove | |
882 | * | |
883 | * @param s | |
884 | * to be removed | |
885 | * @param recalc | |
886 | * true means recalculate conservation | |
887 | */ | |
888 | 35 | public void deleteSequence(SequenceI s, boolean recalc) |
889 | { | |
890 | 35 | synchronized (sequences) |
891 | { | |
892 | 35 | sequences.remove(s); |
893 | 35 | changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, |
894 | sequences.size() + 1, sequences.size()); | |
895 | ||
896 | 35 | if (recalc) |
897 | { | |
898 | 0 | recalcConservation(); |
899 | } | |
900 | } | |
901 | } | |
902 | ||
903 | /** | |
904 | * | |
905 | * | |
906 | * @return the first column selected by this group. Runs from 0<=i<N_cols | |
907 | */ | |
908 | 840727 | @Override |
909 | public int getStartRes() | |
910 | { | |
911 | 840823 | return startRes; |
912 | } | |
913 | ||
914 | /** | |
915 | * | |
916 | * @return the groups last selected column. Runs from 0<=i<N_cols | |
917 | */ | |
918 | 749091 | @Override |
919 | public int getEndRes() | |
920 | { | |
921 | 749061 | return endRes; |
922 | } | |
923 | ||
924 | /** | |
925 | * Set the first column selected by this group. Runs from 0<=i<N_cols | |
926 | * | |
927 | * @param newStart | |
928 | */ | |
929 | 91 | public void setStartRes(int newStart) |
930 | { | |
931 | 91 | int before = startRes; |
932 | 91 | startRes = Math.max(0, newStart); // sanity check for negative start column |
933 | // positions | |
934 | 91 | changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes); |
935 | ||
936 | } | |
937 | ||
938 | /** | |
939 | * Set the groups last selected column. Runs from 0<=i<N_cols | |
940 | * | |
941 | * @param i | |
942 | */ | |
943 | 112 | public void setEndRes(int i) |
944 | { | |
945 | 112 | int before = endRes; |
946 | 112 | endRes = i; |
947 | 112 | changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, endRes); |
948 | } | |
949 | ||
950 | /** | |
951 | * @return number of sequences in group | |
952 | */ | |
953 | 466 | public int getSize() |
954 | { | |
955 | 466 | return sequences.size(); |
956 | } | |
957 | ||
958 | /** | |
959 | * @param i | |
960 | * @return the ith sequence | |
961 | */ | |
962 | 58 | public SequenceI getSequenceAt(int i) |
963 | { | |
964 | 58 | return sequences.get(i); |
965 | } | |
966 | ||
967 | /** | |
968 | * @param state | |
969 | * colourText | |
970 | */ | |
971 | 18 | public void setColourText(boolean state) |
972 | { | |
973 | 18 | colourText = state; |
974 | } | |
975 | ||
976 | /** | |
977 | * DOCUMENT ME! | |
978 | * | |
979 | * @return DOCUMENT ME! | |
980 | */ | |
981 | 291090 | public boolean getColourText() |
982 | { | |
983 | 291090 | return colourText; |
984 | } | |
985 | ||
986 | /** | |
987 | * DOCUMENT ME! | |
988 | * | |
989 | * @param state | |
990 | * DOCUMENT ME! | |
991 | */ | |
992 | 14 | public void setDisplayText(boolean state) |
993 | { | |
994 | 14 | displayText = state; |
995 | } | |
996 | ||
997 | /** | |
998 | * DOCUMENT ME! | |
999 | * | |
1000 | * @return DOCUMENT ME! | |
1001 | */ | |
1002 | 291075 | public boolean getDisplayText() |
1003 | { | |
1004 | 291075 | return displayText; |
1005 | } | |
1006 | ||
1007 | /** | |
1008 | * DOCUMENT ME! | |
1009 | * | |
1010 | * @param state | |
1011 | * DOCUMENT ME! | |
1012 | */ | |
1013 | 14 | public void setDisplayBoxes(boolean state) |
1014 | { | |
1015 | 14 | displayBoxes = state; |
1016 | } | |
1017 | ||
1018 | /** | |
1019 | * DOCUMENT ME! | |
1020 | * | |
1021 | * @return DOCUMENT ME! | |
1022 | */ | |
1023 | 291084 | public boolean getDisplayBoxes() |
1024 | { | |
1025 | 291084 | return displayBoxes; |
1026 | } | |
1027 | ||
1028 | /** | |
1029 | * computes the width of current set of sequences and returns it | |
1030 | * | |
1031 | * @return DOCUMENT ME! | |
1032 | */ | |
1033 | 664 | @Override |
1034 | public int getWidth() | |
1035 | { | |
1036 | 664 | synchronized (sequences) |
1037 | { | |
1038 | // MC This needs to get reset when characters are inserted and deleted | |
1039 | 664 | boolean first = true; |
1040 | 664 | for (SequenceI seq : sequences) |
1041 | { | |
1042 | 2204 | if (first || seq.getLength() > width) |
1043 | { | |
1044 | 664 | width = seq.getLength(); |
1045 | 664 | first = false; |
1046 | } | |
1047 | } | |
1048 | 664 | return width; |
1049 | } | |
1050 | } | |
1051 | ||
1052 | /** | |
1053 | * DOCUMENT ME! | |
1054 | * | |
1055 | * @param c | |
1056 | * DOCUMENT ME! | |
1057 | */ | |
1058 | 69 | public void setOutlineColour(Color c) |
1059 | { | |
1060 | 69 | outlineColour = c; |
1061 | } | |
1062 | ||
1063 | /** | |
1064 | * DOCUMENT ME! | |
1065 | * | |
1066 | * @return DOCUMENT ME! | |
1067 | */ | |
1068 | 1617 | public Color getOutlineColour() |
1069 | { | |
1070 | 1617 | return outlineColour; |
1071 | } | |
1072 | ||
1073 | /** | |
1074 | * | |
1075 | * returns the sequences in the group ordered by the ordering given by al. | |
1076 | * this used to return an array with null entries regardless, new behaviour is | |
1077 | * below. TODO: verify that this does not affect use in applet or application | |
1078 | * | |
1079 | * @param al | |
1080 | * Alignment | |
1081 | * @return SequenceI[] intersection of sequences in group with al, ordered by | |
1082 | * al, or null if group does not intersect with al | |
1083 | */ | |
1084 | 121 | public SequenceI[] getSequencesInOrder(AlignmentI al) |
1085 | { | |
1086 | 121 | return getSequencesInOrder(al, true); |
1087 | } | |
1088 | ||
1089 | /** | |
1090 | * return an array representing the intersection of the group with al, | |
1091 | * optionally returning an array the size of al.getHeight() where nulls mark | |
1092 | * the non-intersected sequences | |
1093 | * | |
1094 | * @param al | |
1095 | * @param trim | |
1096 | * @return null or array | |
1097 | */ | |
1098 | 127 | public SequenceI[] getSequencesInOrder(AlignmentI al, boolean trim) |
1099 | { | |
1100 | 127 | synchronized (sequences) |
1101 | { | |
1102 | 127 | int sSize = sequences.size(); |
1103 | 127 | int alHeight = al.getHeight(); |
1104 | ||
1105 | 127 | SequenceI[] seqs = new SequenceI[(trim) ? sSize : alHeight]; |
1106 | ||
1107 | 127 | int index = 0; |
1108 | 975 | for (int i = 0; i < alHeight && index < sSize; i++) |
1109 | { | |
1110 | 848 | if (sequences.contains(al.getSequenceAt(i))) |
1111 | { | |
1112 | 281 | seqs[(trim) ? index : i] = al.getSequenceAt(i); |
1113 | 281 | index++; |
1114 | } | |
1115 | } | |
1116 | 127 | if (index == 0) |
1117 | { | |
1118 | 57 | return null; |
1119 | } | |
1120 | 70 | if (!trim) |
1121 | { | |
1122 | 0 | return seqs; |
1123 | } | |
1124 | 70 | if (index < seqs.length) |
1125 | { | |
1126 | 0 | SequenceI[] dummy = seqs; |
1127 | 0 | seqs = new SequenceI[index]; |
1128 | 0 | while (--index >= 0) |
1129 | { | |
1130 | 0 | seqs[index] = dummy[index]; |
1131 | 0 | dummy[index] = null; |
1132 | } | |
1133 | } | |
1134 | 70 | return seqs; |
1135 | } | |
1136 | } | |
1137 | ||
1138 | /** | |
1139 | * @return the idColour | |
1140 | */ | |
1141 | 18 | public Color getIdColour() |
1142 | { | |
1143 | 18 | return idColour; |
1144 | } | |
1145 | ||
1146 | /** | |
1147 | * @param idColour | |
1148 | * the idColour to set | |
1149 | */ | |
1150 | 7 | public void setIdColour(Color idColour) |
1151 | { | |
1152 | 7 | this.idColour = idColour; |
1153 | } | |
1154 | ||
1155 | /** | |
1156 | * @return the representative sequence for this group | |
1157 | */ | |
1158 | 291049 | @Override |
1159 | public SequenceI getSeqrep() | |
1160 | { | |
1161 | 291049 | return seqrep; |
1162 | } | |
1163 | ||
1164 | /** | |
1165 | * set the representative sequence for this group. Note - this affects the | |
1166 | * interpretation of the Hidereps attribute. | |
1167 | * | |
1168 | * @param seqrep | |
1169 | * the seqrep to set (null means no sequence representative) | |
1170 | */ | |
1171 | 17 | @Override |
1172 | public void setSeqrep(SequenceI seqrep) | |
1173 | { | |
1174 | 17 | this.seqrep = seqrep; |
1175 | } | |
1176 | ||
1177 | /** | |
1178 | * | |
1179 | * @return true if group has a sequence representative | |
1180 | */ | |
1181 | 6 | @Override |
1182 | public boolean hasSeqrep() | |
1183 | { | |
1184 | 6 | return seqrep != null; |
1185 | } | |
1186 | ||
1187 | /** | |
1188 | * set visibility of sequences covered by (if no sequence representative is | |
1189 | * defined) or represented by this group. | |
1190 | * | |
1191 | * @param visibility | |
1192 | */ | |
1193 | 6 | public void setHidereps(boolean visibility) |
1194 | { | |
1195 | 6 | hidereps = visibility; |
1196 | } | |
1197 | ||
1198 | /** | |
1199 | * | |
1200 | * @return true if sequences represented (or covered) by this group should be | |
1201 | * hidden | |
1202 | */ | |
1203 | 8 | public boolean isHidereps() |
1204 | { | |
1205 | 8 | return hidereps; |
1206 | } | |
1207 | ||
1208 | /** | |
1209 | * set intended visibility of columns covered by this group | |
1210 | * | |
1211 | * @param visibility | |
1212 | */ | |
1213 | 1 | public void setHideCols(boolean visibility) |
1214 | { | |
1215 | 1 | hidecols = visibility; |
1216 | } | |
1217 | ||
1218 | /** | |
1219 | * | |
1220 | * @return true if columns covered by group should be hidden | |
1221 | */ | |
1222 | 8 | public boolean isHideCols() |
1223 | { | |
1224 | 8 | return hidecols; |
1225 | } | |
1226 | ||
1227 | /** | |
1228 | * create a new sequence group from the intersection of this group with an | |
1229 | * alignment Hashtable of hidden representatives | |
1230 | * | |
1231 | * @param alignment | |
1232 | * (may not be null) | |
1233 | * @param map | |
1234 | * (may be null) | |
1235 | * @return new group containing sequences common to this group and alignment | |
1236 | */ | |
1237 | 57 | public SequenceGroup intersect(AlignmentI alignment, |
1238 | Map<SequenceI, SequenceCollectionI> map) | |
1239 | { | |
1240 | 57 | SequenceGroup sgroup = new SequenceGroup(this); |
1241 | 57 | SequenceI[] insect = getSequencesInOrder(alignment); |
1242 | 57 | sgroup.sequences = new ArrayList<>(); |
1243 | 57 | for (int s = 0; insect != null && s < insect.length; s++) |
1244 | { | |
1245 | 0 | if (map == null || map.containsKey(insect[s])) |
1246 | { | |
1247 | 0 | sgroup.sequences.add(insect[s]); |
1248 | } | |
1249 | } | |
1250 | 57 | return sgroup; |
1251 | } | |
1252 | ||
1253 | 0 | public List<AlignmentAnnotation> getAnnotationsFromTree() |
1254 | { | |
1255 | 0 | return annotationsFromTree; |
1256 | } | |
1257 | ||
1258 | 0 | public void setAnnotationsFromTree( |
1259 | List<AlignmentAnnotation> annotationsFromTree) | |
1260 | { | |
1261 | 0 | this.annotationsFromTree = annotationsFromTree; |
1262 | } | |
1263 | ||
1264 | /** | |
1265 | * @return the showUnconserved | |
1266 | */ | |
1267 | 285275 | public boolean getShowNonconserved() |
1268 | { | |
1269 | 285275 | return showNonconserved; |
1270 | } | |
1271 | ||
1272 | /** | |
1273 | * @param showNonconserved | |
1274 | * the showUnconserved to set | |
1275 | */ | |
1276 | 74 | public void setShowNonconserved(boolean displayNonconserved) |
1277 | { | |
1278 | 74 | this.showNonconserved = displayNonconserved; |
1279 | } | |
1280 | ||
1281 | /** | |
1282 | * set this alignmentAnnotation object as the one used to render consensus | |
1283 | * annotation | |
1284 | * | |
1285 | * @param aan | |
1286 | */ | |
1287 | 24 | public void setConsensus(AlignmentAnnotation aan) |
1288 | { | |
1289 | 24 | if (consensus == null) |
1290 | { | |
1291 | 24 | consensus = aan; |
1292 | } | |
1293 | } | |
1294 | ||
1295 | 0 | public void setSSConsensusRow(AlignmentAnnotation aan) |
1296 | { | |
1297 | ||
1298 | 0 | if (ssConsensus == null) |
1299 | { | |
1300 | 0 | ssConsensus = new ArrayList<AlignmentAnnotation>(); |
1301 | 0 | ssConsensus.add(aan); |
1302 | } | |
1303 | else | |
1304 | { | |
1305 | 0 | boolean annotExists = ssConsensus.stream() |
1306 | .anyMatch(ssa -> ssa.label.equals(aan.label)); | |
1307 | 0 | if (!annotExists) |
1308 | { | |
1309 | 0 | ssConsensus.add(aan); |
1310 | } | |
1311 | } | |
1312 | } | |
1313 | ||
1314 | /** | |
1315 | * | |
1316 | * @return automatically calculated consensus row note: the row is a stub if a | |
1317 | * consensus calculation has not yet been performed on the group | |
1318 | */ | |
1319 | 658 | public AlignmentAnnotation getConsensus() |
1320 | { | |
1321 | // TODO get or calculate and get consensus annotation row for this group | |
1322 | 658 | int aWidth = this.getWidth(); |
1323 | // pointer | |
1324 | // possibility | |
1325 | // here. | |
1326 | 658 | if (aWidth < 0) |
1327 | { | |
1328 | 0 | return null; |
1329 | } | |
1330 | 658 | if (consensus == null) |
1331 | { | |
1332 | 0 | consensus = new AlignmentAnnotation("", "", new Annotation[1], 0f, |
1333 | 100f, AlignmentAnnotation.BAR_GRAPH); | |
1334 | 0 | consensus.hasText = true; |
1335 | 0 | consensus.autoCalculated = true; |
1336 | 0 | consensus.groupRef = this; |
1337 | 0 | consensus.label = "Consensus for " + getName(); |
1338 | 0 | consensus.description = "Percent Identity"; |
1339 | } | |
1340 | 658 | return consensus; |
1341 | } | |
1342 | ||
1343 | 0 | public List<AlignmentAnnotation> getSSConsensus(List<String> ssSources) |
1344 | { | |
1345 | // TODO get or calculate and get consensus annotation row for this group | |
1346 | 0 | int aWidth = this.getWidth(); |
1347 | // pointer | |
1348 | // possibility | |
1349 | // here. | |
1350 | 0 | if (aWidth < 0) |
1351 | { | |
1352 | 0 | return null; |
1353 | } | |
1354 | 0 | if (ssConsensus == null && ssSources != null) |
1355 | { | |
1356 | 0 | ssConsensus = new ArrayList<AlignmentAnnotation>(); |
1357 | ||
1358 | 0 | for (String ssSource : ssSources) |
1359 | { | |
1360 | 0 | AlignmentAnnotation aa = new AlignmentAnnotation("", "", |
1361 | new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); | |
1362 | // Setting the annotation visibility to true of the provider is "All" | |
1363 | // and false otherwise. | |
1364 | 0 | aa.visible = Constants.SS_ALL_PROVIDERS.equals(ssSource); |
1365 | 0 | aa.hasText = true; |
1366 | 0 | aa.autoCalculated = true; |
1367 | 0 | aa.groupRef = this; |
1368 | ||
1369 | 0 | aa.label = Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " " |
1370 | + ssSource + " " + getName(); | |
1371 | 0 | aa.description = ssSource |
1372 | + Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " for " | |
1373 | + getName(); | |
1374 | 0 | ssConsensus.add(aa); |
1375 | } | |
1376 | ||
1377 | } | |
1378 | 0 | return ssConsensus; |
1379 | } | |
1380 | ||
1381 | /** | |
1382 | * set this alignmentAnnotation object as the one used to render consensus | |
1383 | * annotation | |
1384 | * | |
1385 | * @param aan | |
1386 | */ | |
1387 | 0 | public void setConservationRow(AlignmentAnnotation aan) |
1388 | { | |
1389 | 0 | if (conservation == null) |
1390 | { | |
1391 | 0 | conservation = aan; |
1392 | } | |
1393 | } | |
1394 | ||
1395 | /** | |
1396 | * get the conservation annotation row for this group | |
1397 | * | |
1398 | * @return autoCalculated annotation row | |
1399 | */ | |
1400 | 0 | public AlignmentAnnotation getConservationRow() |
1401 | { | |
1402 | 0 | if (conservation == null) |
1403 | { | |
1404 | 0 | conservation = new AlignmentAnnotation("", "", new Annotation[1], 0f, |
1405 | 11f, AlignmentAnnotation.BAR_GRAPH); | |
1406 | } | |
1407 | ||
1408 | 0 | conservation.hasText = true; |
1409 | 0 | conservation.autoCalculated = true; |
1410 | 0 | conservation.groupRef = this; |
1411 | 0 | conservation.label = "Conservation for " + getName(); |
1412 | 0 | conservation.description = "Conservation for group " + getName() |
1413 | + " less than " + consPercGaps + "% gaps"; | |
1414 | 0 | return conservation; |
1415 | } | |
1416 | ||
1417 | /** | |
1418 | * | |
1419 | * @return true if annotation rows have been instantiated for this group | |
1420 | */ | |
1421 | 0 | public boolean hasAnnotationRows() |
1422 | { | |
1423 | 0 | return consensus != null || conservation != null; |
1424 | } | |
1425 | ||
1426 | 0 | public SequenceI getConsensusSeq() |
1427 | { | |
1428 | 0 | getConsensus(); |
1429 | 0 | StringBuffer seqs = new StringBuffer(); |
1430 | 0 | for (int i = 0; i < consensus.annotations.length; i++) |
1431 | { | |
1432 | 0 | if (consensus.annotations[i] != null) |
1433 | { | |
1434 | 0 | String desc = consensus.annotations[i].description; |
1435 | 0 | if (desc.length() > 1 && desc.charAt(0) == '[') |
1436 | { | |
1437 | 0 | seqs.append(desc.charAt(1)); |
1438 | } | |
1439 | else | |
1440 | { | |
1441 | 0 | seqs.append(consensus.annotations[i].displayCharacter); |
1442 | } | |
1443 | } | |
1444 | } | |
1445 | ||
1446 | 0 | SequenceI sq = new Sequence("Group" + getName() + " Consensus", |
1447 | seqs.toString()); | |
1448 | 0 | sq.setDescription("Percentage Identity Consensus " |
1449 | 0 | + ((ignoreGapsInConsensus) ? " without gaps" : "")); |
1450 | 0 | return sq; |
1451 | } | |
1452 | ||
1453 | 48 | public void setIgnoreGapsConsensus(boolean state) |
1454 | { | |
1455 | 48 | if (this.ignoreGapsInConsensus != state && consensus != null) |
1456 | { | |
1457 | 0 | ignoreGapsInConsensus = state; |
1458 | 0 | recalcConservation(); |
1459 | } | |
1460 | 48 | ignoreGapsInConsensus = state; |
1461 | } | |
1462 | ||
1463 | 39841 | public boolean getIgnoreGapsConsensus() |
1464 | { | |
1465 | 39841 | return ignoreGapsInConsensus; |
1466 | } | |
1467 | ||
1468 | /** | |
1469 | * @param showSequenceLogo | |
1470 | * indicates if a sequence logo is shown for consensus annotation | |
1471 | */ | |
1472 | 57 | public void setshowSequenceLogo(boolean showSequenceLogo) |
1473 | { | |
1474 | // TODO: decouple calculation from settings update | |
1475 | 57 | if (this.showSequenceLogo != showSequenceLogo && consensus != null) |
1476 | { | |
1477 | 0 | this.showSequenceLogo = showSequenceLogo; |
1478 | 0 | recalcConservation(); |
1479 | } | |
1480 | 57 | this.showSequenceLogo = showSequenceLogo; |
1481 | } | |
1482 | ||
1483 | /** | |
1484 | * | |
1485 | * @param showConsHist | |
1486 | * flag indicating if the consensus histogram for this group should | |
1487 | * be rendered | |
1488 | */ | |
1489 | 57 | public void setShowConsensusHistogram(boolean showConsHist) |
1490 | { | |
1491 | ||
1492 | 57 | if (showConsensusHistogram != showConsHist && consensus != null) |
1493 | { | |
1494 | 0 | this.showConsensusHistogram = showConsHist; |
1495 | 0 | recalcConservation(); |
1496 | } | |
1497 | 57 | this.showConsensusHistogram = showConsHist; |
1498 | } | |
1499 | ||
1500 | ||
1501 | /** | |
1502 | * @return the showConsensusHistogram | |
1503 | */ | |
1504 | 651 | public boolean isShowConsensusHistogram() |
1505 | { | |
1506 | 651 | return showConsensusHistogram; |
1507 | } | |
1508 | ||
1509 | /** | |
1510 | * set flag indicating if logo should be normalised when rendered | |
1511 | * | |
1512 | * @param norm | |
1513 | */ | |
1514 | 57 | public void setNormaliseSequenceLogo(boolean norm) |
1515 | { | |
1516 | 57 | normaliseSequenceLogo = norm; |
1517 | } | |
1518 | ||
1519 | 651 | public boolean isNormaliseSequenceLogo() |
1520 | { | |
1521 | 651 | return normaliseSequenceLogo; |
1522 | } | |
1523 | ||
1524 | 0 | @Override |
1525 | /** | |
1526 | * returns a new array with all annotation involving this group | |
1527 | */ | |
1528 | public AlignmentAnnotation[] getAlignmentAnnotation() | |
1529 | { | |
1530 | // TODO add in other methods like 'getAlignmentAnnotation(String label), | |
1531 | // etc' | |
1532 | 0 | ArrayList<AlignmentAnnotation> annot = new ArrayList<>(); |
1533 | 0 | synchronized (sequences) |
1534 | { | |
1535 | 0 | for (SequenceI seq : sequences) |
1536 | { | |
1537 | 0 | AlignmentAnnotation[] aa = seq.getAnnotation(); |
1538 | 0 | if (aa != null) |
1539 | { | |
1540 | 0 | for (AlignmentAnnotation al : aa) |
1541 | { | |
1542 | 0 | if (al.groupRef == this) |
1543 | { | |
1544 | 0 | annot.add(al); |
1545 | } | |
1546 | } | |
1547 | } | |
1548 | } | |
1549 | 0 | if (consensus != null) |
1550 | { | |
1551 | 0 | annot.add(consensus); |
1552 | } | |
1553 | 0 | if (conservation != null) |
1554 | { | |
1555 | 0 | annot.add(conservation); |
1556 | } | |
1557 | } | |
1558 | 0 | return annot.toArray(new AlignmentAnnotation[0]); |
1559 | } | |
1560 | ||
1561 | 0 | @Override |
1562 | public Iterable<AlignmentAnnotation> findAnnotation(String calcId) | |
1563 | { | |
1564 | 0 | return AlignmentAnnotation.findAnnotation( |
1565 | Arrays.asList(getAlignmentAnnotation()), calcId); | |
1566 | } | |
1567 | ||
1568 | 0 | @Override |
1569 | public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq, | |
1570 | String calcId, String label) | |
1571 | { | |
1572 | 0 | return AlignmentAnnotation.findAnnotations( |
1573 | Arrays.asList(getAlignmentAnnotation()), seq, calcId, label); | |
1574 | } | |
1575 | ||
1576 | /** | |
1577 | * Answer true if any annotation matches the calcId passed in (if not null). | |
1578 | * | |
1579 | * @param calcId | |
1580 | * @return | |
1581 | */ | |
1582 | 0 | public boolean hasAnnotation(String calcId) |
1583 | { | |
1584 | 0 | return AlignmentAnnotation |
1585 | .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId); | |
1586 | } | |
1587 | ||
1588 | /** | |
1589 | * Remove all sequences from the group (leaving other properties unchanged). | |
1590 | */ | |
1591 | 15 | public void clear() |
1592 | { | |
1593 | 15 | synchronized (sequences) |
1594 | { | |
1595 | 15 | int before = sequences.size(); |
1596 | 15 | sequences.clear(); |
1597 | 15 | changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, |
1598 | sequences.size()); | |
1599 | } | |
1600 | } | |
1601 | ||
1602 | /** | |
1603 | * Sets the alignment or group context for this group, and whether it is | |
1604 | * defined as a group | |
1605 | * | |
1606 | * @param ctx | |
1607 | * the context for the group | |
1608 | * @param defined | |
1609 | * whether the group is defined on the alignment or is just a | |
1610 | * selection | |
1611 | * @throws IllegalArgumentException | |
1612 | * if setting the context would result in a circular reference chain | |
1613 | */ | |
1614 | 107 | public void setContext(AnnotatedCollectionI ctx, boolean defined) |
1615 | { | |
1616 | 107 | setContext(ctx); |
1617 | 106 | this.isDefined = defined; |
1618 | } | |
1619 | ||
1620 | /** | |
1621 | * Sets the alignment or group context for this group | |
1622 | * | |
1623 | * @param ctx | |
1624 | * the context for the group | |
1625 | * @throws IllegalArgumentException | |
1626 | * if setting the context would result in a circular reference chain | |
1627 | */ | |
1628 | 151 | public void setContext(AnnotatedCollectionI ctx) |
1629 | { | |
1630 | 151 | AnnotatedCollectionI ref = ctx; |
1631 | 397 | while (ref != null) |
1632 | { | |
1633 | 249 | if (ref == this || ref.getContext() == ctx) |
1634 | { | |
1635 | 3 | throw new IllegalArgumentException( |
1636 | "Circular reference in SequenceGroup.context"); | |
1637 | } | |
1638 | 246 | ref = ref.getContext(); |
1639 | } | |
1640 | 148 | this.context = ctx; |
1641 | } | |
1642 | ||
1643 | /* | |
1644 | * (non-Javadoc) | |
1645 | * | |
1646 | * @see jalview.datamodel.AnnotatedCollectionI#getContext() | |
1647 | */ | |
1648 | 517 | @Override |
1649 | public AnnotatedCollectionI getContext() | |
1650 | { | |
1651 | 517 | return context; |
1652 | } | |
1653 | ||
1654 | 9 | public boolean isDefined() |
1655 | { | |
1656 | 9 | return isDefined; |
1657 | } | |
1658 | ||
1659 | 51 | public void setColourScheme(ColourSchemeI scheme) |
1660 | { | |
1661 | 51 | if (cs == null) |
1662 | { | |
1663 | 1 | cs = new ResidueShader(); |
1664 | } | |
1665 | 51 | cs.setColourScheme(scheme); |
1666 | } | |
1667 | ||
1668 | 2 | public void setGroupColourScheme(ResidueShaderI scheme) |
1669 | { | |
1670 | 2 | cs = scheme; |
1671 | } | |
1672 | ||
1673 | 73 | public ColourSchemeI getColourScheme() |
1674 | { | |
1675 | 73 | return cs == null ? null : cs.getColourScheme(); |
1676 | } | |
1677 | ||
1678 | 409043 | public ResidueShaderI getGroupColourScheme() |
1679 | { | |
1680 | 409044 | return cs; |
1681 | } | |
1682 | ||
1683 | 72 | @Override |
1684 | public boolean isNucleotide() | |
1685 | { | |
1686 | 72 | if (context != null) |
1687 | { | |
1688 | 72 | return context.isNucleotide(); |
1689 | } | |
1690 | 0 | return false; |
1691 | } | |
1692 | ||
1693 | /** | |
1694 | * @param seq | |
1695 | * @return true if seq is a member of the group | |
1696 | */ | |
1697 | ||
1698 | 35 | public boolean contains(SequenceI seq1) |
1699 | { | |
1700 | 35 | return sequences.contains(seq1); |
1701 | } | |
1702 | ||
1703 | 0 | public boolean containsAnnotation(AlignmentAnnotation annot) |
1704 | { | |
1705 | 0 | return annotationsFromTree.contains(annot); |
1706 | } | |
1707 | ||
1708 | /** | |
1709 | * @param seq | |
1710 | * @param apos | |
1711 | * @return true if startRes<=apos and endRes>=apos and seq is in the group | |
1712 | */ | |
1713 | 15 | public boolean contains(SequenceI seq, int apos) |
1714 | { | |
1715 | 15 | return (startRes <= apos && endRes >= apos) && sequences.contains(seq); |
1716 | } | |
1717 | ||
1718 | //// | |
1719 | //// Contact Matrix Holder Boilerplate | |
1720 | //// | |
1721 | ContactMapHolder cmholder = new ContactMapHolder(); | |
1722 | ||
1723 | 0 | @Override |
1724 | public Collection<ContactMatrixI> getContactMaps() | |
1725 | { | |
1726 | 0 | return cmholder.getContactMaps(); |
1727 | } | |
1728 | ||
1729 | 0 | @Override |
1730 | public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann) | |
1731 | { | |
1732 | 0 | return cmholder.getContactMatrixFor(ann); |
1733 | } | |
1734 | ||
1735 | 0 | @Override |
1736 | public ContactListI getContactListFor(AlignmentAnnotation _aa, int column) | |
1737 | { | |
1738 | 0 | return cmholder.getContactListFor(_aa, column); |
1739 | } | |
1740 | ||
1741 | 0 | @Override |
1742 | public AlignmentAnnotation addContactList(ContactMatrixI cm) | |
1743 | { | |
1744 | 0 | AlignmentAnnotation aa = cmholder.addContactList(cm); |
1745 | ||
1746 | 0 | Annotation _aa[] = new Annotation[getWidth()]; |
1747 | 0 | Annotation dummy = new Annotation(0.0f); |
1748 | 0 | for (int i = 0; i < _aa.length; _aa[i++] = dummy) |
1749 | { | |
1750 | 0 | ; |
1751 | } | |
1752 | 0 | aa.annotations = _aa; |
1753 | // TODO passing annotations back to context to be added | |
1754 | 0 | return aa; |
1755 | } | |
1756 | ||
1757 | 0 | @Override |
1758 | public void addContactListFor(AlignmentAnnotation annotation, | |
1759 | ContactMatrixI cm) | |
1760 | { | |
1761 | 0 | cmholder.addContactListFor(annotation, cm); |
1762 | } | |
1763 | ||
1764 | } |