1 /* 2 * Jalview - A Sequence Alignment Editor and Viewer (2.11.1.4) 3 * Copyright (C) 2021 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.io; 22 23 import jalview.analysis.Conservation; 24 import jalview.api.AlignViewportI; 25 import jalview.datamodel.AlignmentAnnotation; 26 import jalview.datamodel.AlignmentI; 27 import jalview.datamodel.Annotation; 28 import jalview.datamodel.ColumnSelection; 29 import jalview.datamodel.GraphLine; 30 import jalview.datamodel.HiddenColumns; 31 import jalview.datamodel.HiddenSequences; 32 import jalview.datamodel.SequenceGroup; 33 import jalview.datamodel.SequenceI; 34 import jalview.schemes.ColourSchemeI; 35 import jalview.schemes.ColourSchemeProperty; 36 import jalview.util.ColorUtils; 37 38 import java.awt.Color; 39 import java.io.BufferedReader; 40 import java.io.FileReader; 41 import java.io.InputStreamReader; 42 import java.io.StringReader; 43 import java.net.URL; 44 import java.util.ArrayList; 45 import java.util.BitSet; 46 import java.util.Enumeration; 47 import java.util.Hashtable; 48 import java.util.List; 49 import java.util.Map; 50 import java.util.StringTokenizer; 51 import java.util.Vector; 52 53 public class AnnotationFile 54 { AnnotationFile()55 public AnnotationFile() 56 { 57 init(); 58 } 59 60 /** 61 * character used to write newlines 62 */ 63 protected String newline = System.getProperty("line.separator"); 64 65 /** 66 * set new line string and reset the output buffer 67 * 68 * @param nl 69 */ setNewlineString(String nl)70 public void setNewlineString(String nl) 71 { 72 newline = nl; 73 init(); 74 } 75 getNewlineString()76 public String getNewlineString() 77 { 78 return newline; 79 } 80 81 StringBuffer text; 82 init()83 private void init() 84 { 85 text = new StringBuffer("JALVIEW_ANNOTATION" + newline + "# Created: " 86 + new java.util.Date() + newline + newline); 87 refSeq = null; 88 refSeqId = null; 89 } 90 91 /** 92 * convenience method for pre-2.9 annotation files which have no view, hidden 93 * columns or hidden row keywords. 94 * 95 * @param annotations 96 * @param list 97 * @param properties 98 * @return annotation file as a string. 99 */ printAnnotations(AlignmentAnnotation[] annotations, List<SequenceGroup> list, Hashtable properties)100 public String printAnnotations(AlignmentAnnotation[] annotations, 101 List<SequenceGroup> list, Hashtable properties) 102 { 103 return printAnnotations(annotations, list, properties, null, null, 104 null); 105 106 } 107 108 /** 109 * hold all the information about a particular view definition read from or 110 * written out in an annotations file. 111 */ 112 public class ViewDef 113 { 114 // TODO this class is not used - remove? 115 public final String viewname; 116 117 public final HiddenSequences hidseqs; 118 119 public final HiddenColumns hiddencols; 120 121 public final Hashtable hiddenRepSeqs; 122 ViewDef(String vname, HiddenSequences hseqs, HiddenColumns hcols, Hashtable hRepSeqs)123 public ViewDef(String vname, HiddenSequences hseqs, HiddenColumns hcols, 124 Hashtable hRepSeqs) 125 { 126 this.viewname = vname; 127 this.hidseqs = hseqs; 128 this.hiddencols = hcols; 129 this.hiddenRepSeqs = hRepSeqs; 130 } 131 } 132 133 /** 134 * Prepare an annotation file given a set of annotations, groups, alignment 135 * properties and views. 136 * 137 * @param annotations 138 * @param list 139 * @param properties 140 * @param views 141 * @return annotation file 142 */ printAnnotations(AlignmentAnnotation[] annotations, List<SequenceGroup> list, Hashtable properties, HiddenColumns cs, AlignmentI al, ViewDef view)143 public String printAnnotations(AlignmentAnnotation[] annotations, 144 List<SequenceGroup> list, Hashtable properties, HiddenColumns cs, 145 AlignmentI al, ViewDef view) 146 { 147 if (view != null) 148 { 149 if (view.viewname != null) 150 { 151 text.append("VIEW_DEF\t" + view.viewname + "\n"); 152 } 153 if (list == null) 154 { 155 // list = view.visibleGroups; 156 } 157 if (cs == null) 158 { 159 cs = view.hiddencols; 160 } 161 if (al == null) 162 { 163 // add hidden rep sequences. 164 } 165 } 166 // first target - store and restore all settings for a view. 167 if (al != null && al.hasSeqrep()) 168 { 169 text.append("VIEW_SETREF\t" + al.getSeqrep().getName() + "\n"); 170 } 171 if (cs != null && cs.hasHiddenColumns()) 172 { 173 text.append("VIEW_HIDECOLS\t"); 174 175 String regions = cs.regionsToString(",", "-"); 176 text.append(regions); 177 text.append("\n"); 178 } 179 // TODO: allow efficient recovery of annotation data shown in several 180 // different views 181 if (annotations != null) 182 { 183 boolean oneColour = true; 184 AlignmentAnnotation row; 185 String comma; 186 SequenceI refSeq = null; 187 SequenceGroup refGroup = null; 188 189 StringBuffer colours = new StringBuffer(); 190 StringBuffer graphLine = new StringBuffer(); 191 StringBuffer rowprops = new StringBuffer(); 192 Hashtable<Integer, String> graphGroup = new Hashtable<>(); 193 Hashtable<Integer, Object[]> graphGroup_refs = new Hashtable<>(); 194 BitSet graphGroupSeen = new BitSet(); 195 196 java.awt.Color color; 197 198 for (int i = 0; i < annotations.length; i++) 199 { 200 row = annotations[i]; 201 202 if (!row.visible && !row.hasScore() && !(row.graphGroup > -1 203 && graphGroupSeen.get(row.graphGroup))) 204 { 205 continue; 206 } 207 208 color = null; 209 oneColour = true; 210 211 // mark any sequence references for the row 212 writeSequence_Ref(refSeq, row.sequenceRef); 213 refSeq = row.sequenceRef; 214 // mark any group references for the row 215 writeGroup_Ref(refGroup, row.groupRef); 216 refGroup = row.groupRef; 217 218 boolean hasGlyphs = row.hasIcons, hasLabels = row.hasText, 219 hasValues = row.hasScore, hasText = false; 220 // lookahead to check what the annotation row object actually contains. 221 for (int j = 0; row.annotations != null 222 && j < row.annotations.length 223 && (!hasGlyphs || !hasLabels || !hasValues); j++) 224 { 225 if (row.annotations[j] != null) 226 { 227 hasLabels |= (row.annotations[j].displayCharacter != null 228 && row.annotations[j].displayCharacter.length() > 0 229 && !row.annotations[j].displayCharacter.equals(" ")); 230 hasGlyphs |= (row.annotations[j].secondaryStructure != 0 231 && row.annotations[j].secondaryStructure != ' '); 232 hasValues |= (!Float.isNaN(row.annotations[j].value)); // NaNs can't 233 // be 234 // rendered.. 235 hasText |= (row.annotations[j].description != null 236 && row.annotations[j].description.length() > 0); 237 } 238 } 239 240 if (row.graph == AlignmentAnnotation.NO_GRAPH) 241 { 242 text.append("NO_GRAPH\t"); 243 hasValues = false; // only secondary structure 244 // hasLabels = false; // and annotation description string. 245 } 246 else 247 { 248 if (row.graph == AlignmentAnnotation.BAR_GRAPH) 249 { 250 text.append("BAR_GRAPH\t"); 251 hasGlyphs = false; // no secondary structure 252 253 } 254 else if (row.graph == AlignmentAnnotation.LINE_GRAPH) 255 { 256 hasGlyphs = false; // no secondary structure 257 text.append("LINE_GRAPH\t"); 258 } 259 260 if (row.getThreshold() != null) 261 { 262 graphLine.append("GRAPHLINE\t"); 263 graphLine.append(row.label); 264 graphLine.append("\t"); 265 graphLine.append(row.getThreshold().value); 266 graphLine.append("\t"); 267 graphLine.append(row.getThreshold().label); 268 graphLine.append("\t"); 269 graphLine.append(jalview.util.Format 270 .getHexString(row.getThreshold().colour)); 271 graphLine.append(newline); 272 } 273 274 if (row.graphGroup > -1) 275 { 276 graphGroupSeen.set(row.graphGroup); 277 Integer key = Integer.valueOf(row.graphGroup); 278 if (graphGroup.containsKey(key)) 279 { 280 graphGroup.put(key, graphGroup.get(key) + "\t" + row.label); 281 282 } 283 else 284 { 285 graphGroup_refs.put(key, new Object[] { refSeq, refGroup }); 286 graphGroup.put(key, row.label); 287 } 288 } 289 } 290 291 text.append(row.label + "\t"); 292 if (row.description != null) 293 { 294 text.append(row.description + "\t"); 295 } 296 for (int j = 0; row.annotations != null 297 && j < row.annotations.length; j++) 298 { 299 if (refSeq != null 300 && jalview.util.Comparison.isGap(refSeq.getCharAt(j))) 301 { 302 continue; 303 } 304 305 if (row.annotations[j] != null) 306 { 307 comma = ""; 308 if (hasGlyphs) // could be also hasGlyphs || ... 309 { 310 311 text.append(comma); 312 if (row.annotations[j].secondaryStructure != ' ') 313 { 314 // only write out the field if its not whitespace. 315 text.append(row.annotations[j].secondaryStructure); 316 } 317 comma = ","; 318 } 319 if (hasValues) 320 { 321 if (!Float.isNaN(row.annotations[j].value)) 322 { 323 text.append(comma + row.annotations[j].value); 324 } 325 else 326 { 327 // System.err.println("Skipping NaN - not valid value."); 328 text.append(comma + 0f);// row.annotations[j].value); 329 } 330 comma = ","; 331 } 332 if (hasLabels) 333 { 334 // TODO: labels are emitted after values for bar graphs. 335 if // empty labels are allowed, so 336 (row.annotations[j].displayCharacter != null 337 && row.annotations[j].displayCharacter.length() > 0 338 && !row.annotations[j].displayCharacter.equals(" ")) 339 { 340 text.append(comma + row.annotations[j].displayCharacter); 341 comma = ","; 342 } 343 } 344 if (hasText) 345 { 346 if (row.annotations[j].description != null 347 && row.annotations[j].description.length() > 0 348 && !row.annotations[j].description 349 .equals(row.annotations[j].displayCharacter)) 350 { 351 text.append(comma + row.annotations[j].description); 352 comma = ","; 353 } 354 } 355 if (color != null && !color.equals(row.annotations[j].colour)) 356 { 357 oneColour = false; 358 } 359 360 color = row.annotations[j].colour; 361 362 if (row.annotations[j].colour != null 363 && row.annotations[j].colour != java.awt.Color.black) 364 { 365 text.append(comma + "[" + jalview.util.Format 366 .getHexString(row.annotations[j].colour) + "]"); 367 comma = ","; 368 } 369 } 370 text.append("|"); 371 } 372 373 if (row.hasScore()) 374 { 375 text.append("\t" + row.score); 376 } 377 378 text.append(newline); 379 380 if (color != null && color != java.awt.Color.black && oneColour) 381 { 382 colours.append("COLOUR\t"); 383 colours.append(row.label); 384 colours.append("\t"); 385 colours.append(jalview.util.Format.getHexString(color)); 386 colours.append(newline); 387 } 388 if (row.scaleColLabel || row.showAllColLabels 389 || row.centreColLabels) 390 { 391 rowprops.append("ROWPROPERTIES\t"); 392 rowprops.append(row.label); 393 rowprops.append("\tscaletofit="); 394 rowprops.append(row.scaleColLabel); 395 rowprops.append("\tshowalllabs="); 396 rowprops.append(row.showAllColLabels); 397 rowprops.append("\tcentrelabs="); 398 rowprops.append(row.centreColLabels); 399 rowprops.append(newline); 400 } 401 if (graphLine.length() > 0) 402 { 403 text.append(graphLine.toString()); 404 graphLine.setLength(0); 405 } 406 } 407 408 text.append(newline); 409 410 text.append(colours.toString()); 411 if (graphGroup.size() > 0) 412 { 413 SequenceI oldRefSeq = refSeq; 414 SequenceGroup oldRefGroup = refGroup; 415 for (Map.Entry<Integer, String> combine_statement : graphGroup 416 .entrySet()) 417 { 418 Object[] seqRefAndGroup = graphGroup_refs 419 .get(combine_statement.getKey()); 420 421 writeSequence_Ref(refSeq, (SequenceI) seqRefAndGroup[0]); 422 refSeq = (SequenceI) seqRefAndGroup[0]; 423 424 writeGroup_Ref(refGroup, (SequenceGroup) seqRefAndGroup[1]); 425 refGroup = (SequenceGroup) seqRefAndGroup[1]; 426 text.append("COMBINE\t"); 427 text.append(combine_statement.getValue()); 428 text.append(newline); 429 } 430 writeSequence_Ref(refSeq, oldRefSeq); 431 refSeq = oldRefSeq; 432 433 writeGroup_Ref(refGroup, oldRefGroup); 434 refGroup = oldRefGroup; 435 } 436 text.append(rowprops.toString()); 437 } 438 439 if (list != null) 440 { 441 printGroups(list); 442 } 443 444 if (properties != null) 445 { 446 text.append(newline); 447 text.append(newline); 448 text.append("ALIGNMENT"); 449 Enumeration en = properties.keys(); 450 while (en.hasMoreElements()) 451 { 452 String key = en.nextElement().toString(); 453 text.append("\t"); 454 text.append(key); 455 text.append("="); 456 text.append(properties.get(key)); 457 } 458 // TODO: output alignment visualization settings here if required 459 // iterate through one or more views, defining, marking columns and rows 460 // as visible/hidden, and emmitting view properties. 461 // View specific annotation is 462 } 463 464 return text.toString(); 465 } 466 writeGroup_Ref(SequenceGroup refGroup, SequenceGroup next_refGroup)467 private Object writeGroup_Ref(SequenceGroup refGroup, 468 SequenceGroup next_refGroup) 469 { 470 if (next_refGroup == null) 471 { 472 473 if (refGroup != null) 474 { 475 text.append(newline); 476 text.append("GROUP_REF\t"); 477 text.append("ALIGNMENT"); 478 text.append(newline); 479 } 480 return true; 481 } 482 else 483 { 484 if (refGroup == null || refGroup != next_refGroup) 485 { 486 text.append(newline); 487 text.append("GROUP_REF\t"); 488 text.append(next_refGroup.getName()); 489 text.append(newline); 490 return true; 491 } 492 } 493 return false; 494 } 495 writeSequence_Ref(SequenceI refSeq, SequenceI next_refSeq)496 private boolean writeSequence_Ref(SequenceI refSeq, SequenceI next_refSeq) 497 { 498 499 if (next_refSeq == null) 500 { 501 if (refSeq != null) 502 { 503 text.append(newline); 504 text.append("SEQUENCE_REF\t"); 505 text.append("ALIGNMENT"); 506 text.append(newline); 507 return true; 508 } 509 } 510 else 511 { 512 if (refSeq == null || refSeq != next_refSeq) 513 { 514 text.append(newline); 515 text.append("SEQUENCE_REF\t"); 516 text.append(next_refSeq.getName()); 517 text.append(newline); 518 return true; 519 } 520 } 521 return false; 522 } 523 printGroups(List<SequenceGroup> list)524 protected void printGroups(List<SequenceGroup> list) 525 { 526 SequenceI seqrep = null; 527 for (SequenceGroup sg : list) 528 { 529 if (!sg.hasSeqrep()) 530 { 531 text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t" 532 + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1) 533 + "\t" + "-1\t"); 534 seqrep = null; 535 } 536 else 537 { 538 seqrep = sg.getSeqrep(); 539 text.append("SEQUENCE_REF\t"); 540 text.append(seqrep.getName()); 541 text.append(newline); 542 text.append("SEQUENCE_GROUP\t"); 543 text.append(sg.getName()); 544 text.append("\t"); 545 text.append((seqrep.findPosition(sg.getStartRes()))); 546 text.append("\t"); 547 text.append((seqrep.findPosition(sg.getEndRes()))); 548 text.append("\t"); 549 text.append("-1\t"); 550 } 551 for (int s = 0; s < sg.getSize(); s++) 552 { 553 text.append(sg.getSequenceAt(s).getName()); 554 text.append("\t"); 555 } 556 text.append(newline); 557 text.append("PROPERTIES\t"); 558 text.append(sg.getName()); 559 text.append("\t"); 560 561 if (sg.getDescription() != null) 562 { 563 text.append("description="); 564 text.append(sg.getDescription()); 565 text.append("\t"); 566 } 567 if (sg.cs != null) 568 { 569 text.append("colour="); 570 text.append(ColourSchemeProperty 571 .getColourName(sg.cs.getColourScheme())); 572 text.append("\t"); 573 if (sg.cs.getThreshold() != 0) 574 { 575 text.append("pidThreshold="); 576 text.append(sg.cs.getThreshold()); 577 } 578 if (sg.cs.conservationApplied()) 579 { 580 text.append("consThreshold="); 581 text.append(sg.cs.getConservationInc()); 582 text.append("\t"); 583 } 584 } 585 text.append("outlineColour="); 586 text.append(jalview.util.Format.getHexString(sg.getOutlineColour())); 587 text.append("\t"); 588 589 text.append("displayBoxes="); 590 text.append(sg.getDisplayBoxes()); 591 text.append("\t"); 592 text.append("displayText="); 593 text.append(sg.getDisplayText()); 594 text.append("\t"); 595 text.append("colourText="); 596 text.append(sg.getColourText()); 597 text.append("\t"); 598 text.append("showUnconserved="); 599 text.append(sg.getShowNonconserved()); 600 text.append("\t"); 601 if (sg.textColour != java.awt.Color.black) 602 { 603 text.append("textCol1="); 604 text.append(jalview.util.Format.getHexString(sg.textColour)); 605 text.append("\t"); 606 } 607 if (sg.textColour2 != java.awt.Color.white) 608 { 609 text.append("textCol2="); 610 text.append(jalview.util.Format.getHexString(sg.textColour2)); 611 text.append("\t"); 612 } 613 if (sg.thresholdTextColour != 0) 614 { 615 text.append("textColThreshold="); 616 text.append(sg.thresholdTextColour); 617 text.append("\t"); 618 } 619 if (sg.idColour != null) 620 { 621 text.append("idColour="); 622 text.append(jalview.util.Format.getHexString(sg.idColour)); 623 text.append("\t"); 624 } 625 if (sg.isHidereps()) 626 { 627 text.append("hide=true\t"); 628 } 629 if (sg.isHideCols()) 630 { 631 text.append("hidecols=true\t"); 632 } 633 if (seqrep != null) 634 { 635 // terminate the last line and clear the sequence ref for the group 636 text.append(newline); 637 text.append("SEQUENCE_REF"); 638 } 639 text.append(newline); 640 text.append(newline); 641 642 } 643 } 644 645 SequenceI refSeq = null; 646 647 String refSeqId = null; 648 annotateAlignmentView(AlignViewportI viewport, String file, DataSourceType protocol)649 public boolean annotateAlignmentView(AlignViewportI viewport, String file, 650 DataSourceType protocol) 651 { 652 ColumnSelection colSel = viewport.getColumnSelection(); 653 HiddenColumns hidden = viewport.getAlignment().getHiddenColumns(); 654 if (colSel == null) 655 { 656 colSel = new ColumnSelection(); 657 } 658 if (hidden == null) 659 { 660 hidden = new HiddenColumns(); 661 } 662 boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden, file, 663 protocol); 664 if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns())) 665 { 666 viewport.setColumnSelection(colSel); 667 viewport.getAlignment().setHiddenColumns(hidden); 668 } 669 670 return rslt; 671 } 672 readAnnotationFile(AlignmentI al, String file, DataSourceType sourceType)673 public boolean readAnnotationFile(AlignmentI al, String file, 674 DataSourceType sourceType) 675 { 676 return readAnnotationFile(al, null, file, sourceType); 677 } 678 readAnnotationFile(AlignmentI al, HiddenColumns hidden, String file, DataSourceType sourceType)679 public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden, 680 String file, DataSourceType sourceType) 681 { 682 BufferedReader in = null; 683 try 684 { 685 if (sourceType == DataSourceType.FILE) 686 { 687 in = new BufferedReader(new FileReader(file)); 688 } 689 else if (sourceType == DataSourceType.URL) 690 { 691 URL url = new URL(file); 692 in = new BufferedReader(new InputStreamReader(url.openStream())); 693 } 694 else if (sourceType == DataSourceType.PASTE) 695 { 696 in = new BufferedReader(new StringReader(file)); 697 } 698 else if (sourceType == DataSourceType.CLASSLOADER) 699 { 700 java.io.InputStream is = getClass().getResourceAsStream("/" + file); 701 if (is != null) 702 { 703 in = new BufferedReader(new java.io.InputStreamReader(is)); 704 } 705 } 706 if (in != null) 707 { 708 return parseAnnotationFrom(al, hidden, in); 709 } 710 711 } catch (Exception ex) 712 { 713 ex.printStackTrace(); 714 System.out.println("Problem reading annotation file: " + ex); 715 if (nlinesread > 0) 716 { 717 System.out.println("Last read line " + nlinesread + ": '" + lastread 718 + "' (first 80 chars) ..."); 719 } 720 return false; 721 } 722 return false; 723 } 724 725 long nlinesread = 0; 726 727 String lastread = ""; 728 729 private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE"; 730 parseAnnotationFrom(AlignmentI al, HiddenColumns hidden, BufferedReader in)731 public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden, 732 BufferedReader in) throws Exception 733 { 734 nlinesread = 0; 735 ArrayList<Object[]> combineAnnotation_calls = new ArrayList<>(); 736 ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<>(); 737 boolean modified = false; 738 String groupRef = null; 739 Hashtable groupRefRows = new Hashtable(); 740 741 Hashtable autoAnnots = new Hashtable(); 742 { 743 String line, label, description, token; 744 int graphStyle, index; 745 int refSeqIndex = 1; 746 int existingAnnotations = 0; 747 // when true - will add new rows regardless of whether they are duplicate 748 // auto-annotation like consensus or conservation graphs 749 boolean overrideAutoAnnot = false; 750 if (al.getAlignmentAnnotation() != null) 751 { 752 existingAnnotations = al.getAlignmentAnnotation().length; 753 if (existingAnnotations > 0) 754 { 755 AlignmentAnnotation[] aa = al.getAlignmentAnnotation(); 756 for (int aai = 0; aai < aa.length; aai++) 757 { 758 if (aa[aai].autoCalculated) 759 { 760 // make a note of the name and description 761 autoAnnots.put( 762 autoAnnotsKey(aa[aai], aa[aai].sequenceRef, 763 (aa[aai].groupRef == null ? null 764 : aa[aai].groupRef.getName())), 765 Integer.valueOf(1)); 766 } 767 } 768 } 769 } 770 771 int alWidth = al.getWidth(); 772 773 StringTokenizer st; 774 Annotation[] annotations; 775 AlignmentAnnotation annotation = null; 776 777 // First confirm this is an Annotation file 778 boolean jvAnnotationFile = false; 779 while ((line = in.readLine()) != null) 780 { 781 nlinesread++; 782 lastread = new String(line); 783 if (line.indexOf("#") == 0) 784 { 785 continue; 786 } 787 788 if (line.indexOf("JALVIEW_ANNOTATION") > -1) 789 { 790 jvAnnotationFile = true; 791 break; 792 } 793 } 794 795 if (!jvAnnotationFile) 796 { 797 in.close(); 798 return false; 799 } 800 801 while ((line = in.readLine()) != null) 802 { 803 nlinesread++; 804 lastread = new String(line); 805 if (line.indexOf("#") == 0 806 || line.indexOf("JALVIEW_ANNOTATION") > -1 807 || line.length() == 0) 808 { 809 continue; 810 } 811 812 st = new StringTokenizer(line, "\t"); 813 token = st.nextToken(); 814 if (token.equalsIgnoreCase("COLOUR")) 815 { 816 // TODO: use graduated colour def'n here too 817 colourAnnotations(al, st.nextToken(), st.nextToken()); 818 modified = true; 819 continue; 820 } 821 822 else if (token.equalsIgnoreCase(COMBINE)) 823 { 824 // keep a record of current state and resolve groupRef at end 825 combineAnnotation_calls 826 .add(new Object[] 827 { st, refSeq, groupRef }); 828 modified = true; 829 continue; 830 } 831 else if (token.equalsIgnoreCase("ROWPROPERTIES")) 832 { 833 addRowProperties(al, st); 834 modified = true; 835 continue; 836 } 837 else if (token.equalsIgnoreCase(GRAPHLINE)) 838 { 839 // resolve at end 840 deferredAnnotation_calls 841 .add(new Object[] 842 { GRAPHLINE, st, refSeq, groupRef }); 843 modified = true; 844 continue; 845 } 846 847 else if (token.equalsIgnoreCase("SEQUENCE_REF")) 848 { 849 if (st.hasMoreTokens()) 850 { 851 refSeq = al.findName(refSeqId = st.nextToken()); 852 if (refSeq == null) 853 { 854 refSeqId = null; 855 } 856 try 857 { 858 refSeqIndex = Integer.parseInt(st.nextToken()); 859 if (refSeqIndex < 1) 860 { 861 refSeqIndex = 1; 862 System.out.println( 863 "WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile"); 864 } 865 } catch (Exception ex) 866 { 867 refSeqIndex = 1; 868 } 869 } 870 else 871 { 872 refSeq = null; 873 refSeqId = null; 874 } 875 continue; 876 } 877 else if (token.equalsIgnoreCase("GROUP_REF")) 878 { 879 // Group references could be forward or backwards, so they are 880 // resolved after the whole file is read in 881 groupRef = null; 882 if (st.hasMoreTokens()) 883 { 884 groupRef = st.nextToken(); 885 if (groupRef.length() < 1) 886 { 887 groupRef = null; // empty string 888 } 889 else 890 { 891 if (groupRefRows.get(groupRef) == null) 892 { 893 groupRefRows.put(groupRef, new Vector()); 894 } 895 } 896 } 897 continue; 898 } 899 else if (token.equalsIgnoreCase("SEQUENCE_GROUP")) 900 { 901 addGroup(al, st); 902 modified = true; 903 continue; 904 } 905 906 else if (token.equalsIgnoreCase("PROPERTIES")) 907 { 908 addProperties(al, st); 909 modified = true; 910 continue; 911 } 912 913 else if (token.equalsIgnoreCase("BELOW_ALIGNMENT")) 914 { 915 setBelowAlignment(al, st); 916 modified = true; 917 continue; 918 } 919 else if (token.equalsIgnoreCase("ALIGNMENT")) 920 { 921 addAlignmentDetails(al, st); 922 modified = true; 923 continue; 924 } 925 // else if (token.equalsIgnoreCase("VIEW_DEF")) 926 // { 927 // addOrSetView(al,st); 928 // modified = true; 929 // continue; 930 // } 931 else if (token.equalsIgnoreCase("VIEW_SETREF")) 932 { 933 if (refSeq != null) 934 { 935 al.setSeqrep(refSeq); 936 } 937 modified = true; 938 continue; 939 } 940 else if (token.equalsIgnoreCase("VIEW_HIDECOLS")) 941 { 942 if (st.hasMoreTokens()) 943 { 944 if (hidden == null) 945 { 946 hidden = new HiddenColumns(); 947 } 948 parseHideCols(hidden, st.nextToken()); 949 } 950 modified = true; 951 continue; 952 } 953 else if (token.equalsIgnoreCase("HIDE_INSERTIONS")) 954 { 955 SequenceI sr = refSeq == null ? al.getSeqrep() : refSeq; 956 if (sr == null) 957 { 958 sr = al.getSequenceAt(0); 959 } 960 if (sr != null) 961 { 962 if (hidden == null) 963 { 964 System.err.println( 965 "Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: " 966 + line); 967 } 968 else 969 { 970 // consider deferring this till after the file has been parsed ? 971 hidden.hideList(sr.getInsertions()); 972 } 973 } 974 modified = true; 975 continue; 976 } 977 978 // Parse out the annotation row 979 graphStyle = AlignmentAnnotation.getGraphValueFromString(token); 980 label = st.nextToken(); 981 982 index = 0; 983 annotations = new Annotation[alWidth]; 984 description = null; 985 float score = Float.NaN; 986 987 if (st.hasMoreTokens()) 988 { 989 line = st.nextToken(); 990 991 if (line.indexOf("|") == -1) 992 { 993 description = line; 994 if (st.hasMoreTokens()) 995 { 996 line = st.nextToken(); 997 } 998 } 999 1000 if (st.hasMoreTokens()) 1001 { 1002 // This must be the score 1003 score = Float.valueOf(st.nextToken()).floatValue(); 1004 } 1005 1006 st = new StringTokenizer(line, "|", true); 1007 1008 boolean emptyColumn = true; 1009 boolean onlyOneElement = (st.countTokens() == 1); 1010 1011 while (st.hasMoreElements() && index < alWidth) 1012 { 1013 token = st.nextToken().trim(); 1014 1015 if (onlyOneElement) 1016 { 1017 try 1018 { 1019 score = Float.valueOf(token).floatValue(); 1020 break; 1021 } catch (NumberFormatException ex) 1022 { 1023 } 1024 } 1025 1026 if (token.equals("|")) 1027 { 1028 if (emptyColumn) 1029 { 1030 index++; 1031 } 1032 1033 emptyColumn = true; 1034 } 1035 else 1036 { 1037 annotations[index++] = parseAnnotation(token, graphStyle); 1038 emptyColumn = false; 1039 } 1040 } 1041 1042 } 1043 1044 annotation = new AlignmentAnnotation(label, description, 1045 (index == 0) ? null : annotations, 0, 0, graphStyle); 1046 1047 annotation.score = score; 1048 if (!overrideAutoAnnot && autoAnnots 1049 .containsKey(autoAnnotsKey(annotation, refSeq, groupRef))) 1050 { 1051 // skip - we've already got an automatic annotation of this type. 1052 continue; 1053 } 1054 // otherwise add it! 1055 if (refSeq != null) 1056 { 1057 1058 annotation.belowAlignment = false; 1059 // make a copy of refSeq so we can find other matches in the alignment 1060 SequenceI referedSeq = refSeq; 1061 do 1062 { 1063 // copy before we do any mapping business. 1064 // TODO: verify that undo/redo with 1:many sequence associated 1065 // annotations can be undone correctly 1066 AlignmentAnnotation ann = new AlignmentAnnotation(annotation); 1067 annotation.createSequenceMapping(referedSeq, refSeqIndex, 1068 false); 1069 annotation.adjustForAlignment(); 1070 referedSeq.addAlignmentAnnotation(annotation); 1071 al.addAnnotation(annotation); 1072 al.setAnnotationIndex(annotation, 1073 al.getAlignmentAnnotation().length - existingAnnotations 1074 - 1); 1075 if (groupRef != null) 1076 { 1077 ((Vector) groupRefRows.get(groupRef)).addElement(annotation); 1078 } 1079 // and recover our virgin copy to use again if necessary. 1080 annotation = ann; 1081 1082 } while (refSeqId != null && (referedSeq = al.findName(referedSeq, 1083 refSeqId, true)) != null); 1084 } 1085 else 1086 { 1087 al.addAnnotation(annotation); 1088 al.setAnnotationIndex(annotation, 1089 al.getAlignmentAnnotation().length - existingAnnotations 1090 - 1); 1091 if (groupRef != null) 1092 { 1093 ((Vector) groupRefRows.get(groupRef)).addElement(annotation); 1094 } 1095 } 1096 // and set modification flag 1097 modified = true; 1098 } 1099 // Resolve the groupRefs 1100 Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<>(); 1101 Enumeration en = groupRefRows.keys(); 1102 1103 while (en.hasMoreElements()) 1104 { 1105 groupRef = (String) en.nextElement(); 1106 boolean matched = false; 1107 // Resolve group: TODO: add a getGroupByName method to alignments 1108 for (SequenceGroup theGroup : al.getGroups()) 1109 { 1110 if (theGroup.getName().equals(groupRef)) 1111 { 1112 if (matched) 1113 { 1114 // TODO: specify and implement duplication of alignment annotation 1115 // for multiple group references. 1116 System.err.println( 1117 "Ignoring 1:many group reference mappings for group name '" 1118 + groupRef + "'"); 1119 } 1120 else 1121 { 1122 matched = true; 1123 Vector rowset = (Vector) groupRefRows.get(groupRef); 1124 groupRefLookup.put(groupRef, theGroup); 1125 if (rowset != null && rowset.size() > 0) 1126 { 1127 AlignmentAnnotation alan = null; 1128 for (int elm = 0, elmSize = rowset 1129 .size(); elm < elmSize; elm++) 1130 { 1131 alan = (AlignmentAnnotation) rowset.elementAt(elm); 1132 alan.groupRef = theGroup; 1133 } 1134 } 1135 } 1136 } 1137 } 1138 ((Vector) groupRefRows.get(groupRef)).removeAllElements(); 1139 } 1140 // process any deferred attribute settings for each context 1141 for (Object[] _deferred_args : deferredAnnotation_calls) 1142 { 1143 if (_deferred_args[0] == GRAPHLINE) 1144 { 1145 addLine(al, (StringTokenizer) _deferred_args[1], // st 1146 (SequenceI) _deferred_args[2], // refSeq 1147 (_deferred_args[3] == null) ? null 1148 : groupRefLookup.get(_deferred_args[3]) // the 1149 // reference 1150 // group, or 1151 // null 1152 ); 1153 } 1154 } 1155 1156 // finally, combine all the annotation rows within each context. 1157 /** 1158 * number of combine statements in this annotation file. Used to create 1159 * new groups for combined annotation graphs without disturbing existing 1160 * ones 1161 */ 1162 int combinecount = 0; 1163 for (Object[] _combine_args : combineAnnotation_calls) 1164 { 1165 combineAnnotations(al, ++combinecount, 1166 (StringTokenizer) _combine_args[0], // st 1167 (SequenceI) _combine_args[1], // refSeq 1168 (_combine_args[2] == null) ? null 1169 : groupRefLookup.get(_combine_args[2]) // the reference 1170 // group, 1171 // or null 1172 ); 1173 } 1174 } 1175 return modified; 1176 } 1177 parseHideCols(HiddenColumns hidden, String nextToken)1178 private void parseHideCols(HiddenColumns hidden, String nextToken) 1179 { 1180 StringTokenizer inval = new StringTokenizer(nextToken, ","); 1181 while (inval.hasMoreTokens()) 1182 { 1183 String range = inval.nextToken().trim(); 1184 int from, to = range.indexOf("-"); 1185 if (to == -1) 1186 { 1187 from = to = Integer.parseInt(range); 1188 if (from >= 0) 1189 { 1190 hidden.hideColumns(from, to); 1191 } 1192 } 1193 else 1194 { 1195 from = Integer.parseInt(range.substring(0, to)); 1196 if (to < range.length() - 1) 1197 { 1198 to = Integer.parseInt(range.substring(to + 1)); 1199 } 1200 else 1201 { 1202 to = from; 1203 } 1204 if (from > 0 && to >= from) 1205 { 1206 hidden.hideColumns(from, to); 1207 } 1208 } 1209 } 1210 } 1211 autoAnnotsKey(AlignmentAnnotation annotation, SequenceI refSeq, String groupRef)1212 private Object autoAnnotsKey(AlignmentAnnotation annotation, 1213 SequenceI refSeq, String groupRef) 1214 { 1215 return annotation.graph + "\t" + annotation.label + "\t" 1216 + annotation.description + "\t" 1217 + (refSeq != null ? refSeq.getDisplayId(true) : ""); 1218 } 1219 parseAnnotation(String string, int graphStyle)1220 Annotation parseAnnotation(String string, int graphStyle) 1221 { 1222 // don't do the glyph test if we don't want secondary structure 1223 boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH); 1224 String desc = null, displayChar = null; 1225 char ss = ' '; // secondaryStructure 1226 float value = 0; 1227 boolean parsedValue = false, dcset = false; 1228 1229 // find colour here 1230 Color colour = null; 1231 int i = string.indexOf("["); 1232 int j = string.indexOf("]"); 1233 if (i > -1 && j > -1) 1234 { 1235 colour = ColorUtils.parseColourString(string.substring(i + 1, j)); 1236 if (i > 0 && string.charAt(i - 1) == ',') 1237 { 1238 // clip the preceding comma as well 1239 i--; 1240 } 1241 string = string.substring(0, i) + string.substring(j + 1); 1242 } 1243 1244 StringTokenizer st = new StringTokenizer(string, ",", true); 1245 String token; 1246 boolean seenContent = false; 1247 int pass = 0; 1248 while (st.hasMoreTokens()) 1249 { 1250 pass++; 1251 token = st.nextToken().trim(); 1252 if (token.equals(",")) 1253 { 1254 if (!seenContent && parsedValue && !dcset) 1255 { 1256 // allow the value below the bar/line to be empty 1257 dcset = true; 1258 displayChar = " "; 1259 } 1260 seenContent = false; 1261 continue; 1262 } 1263 else 1264 { 1265 seenContent = true; 1266 } 1267 1268 if (!parsedValue) 1269 { 1270 try 1271 { 1272 displayChar = token; 1273 // foo 1274 value = Float.valueOf(token).floatValue(); 1275 parsedValue = true; 1276 continue; 1277 } catch (NumberFormatException ex) 1278 { 1279 } 1280 } 1281 else 1282 { 1283 if (token.length() == 1) 1284 { 1285 displayChar = token; 1286 } 1287 } 1288 if (hasSymbols && (token.length() == 1 1289 && "()<>[]{}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" 1290 .contains(token))) 1291 { 1292 // Either this character represents a helix or sheet 1293 // or an integer which can be displayed 1294 ss = token.charAt(0); 1295 if (displayChar.equals(token.substring(0, 1))) 1296 { 1297 displayChar = ""; 1298 } 1299 } 1300 else if (desc == null || (parsedValue && pass > 2)) 1301 { 1302 desc = token; 1303 } 1304 1305 } 1306 // if (!dcset && string.charAt(string.length() - 1) == ',') 1307 // { 1308 // displayChar = " "; // empty display char symbol. 1309 // } 1310 if (displayChar != null && desc != null && desc.length() == 1) 1311 { 1312 if (displayChar.length() > 1) 1313 { 1314 // switch desc and displayChar - legacy support 1315 String tmp = displayChar; 1316 displayChar = desc; 1317 desc = tmp; 1318 } 1319 else 1320 { 1321 if (displayChar.equals(desc)) 1322 { 1323 // duplicate label - hangover from the 'robust parser' above 1324 desc = null; 1325 } 1326 } 1327 } 1328 Annotation anot = new Annotation(displayChar, desc, ss, value); 1329 1330 anot.colour = colour; 1331 1332 return anot; 1333 } 1334 colourAnnotations(AlignmentI al, String label, String colour)1335 void colourAnnotations(AlignmentI al, String label, String colour) 1336 { 1337 Color awtColour = ColorUtils.parseColourString(colour); 1338 Annotation[] annotations; 1339 for (int i = 0; i < al.getAlignmentAnnotation().length; i++) 1340 { 1341 if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label)) 1342 { 1343 annotations = al.getAlignmentAnnotation()[i].annotations; 1344 for (int j = 0; j < annotations.length; j++) 1345 { 1346 if (annotations[j] != null) 1347 { 1348 annotations[j].colour = awtColour; 1349 } 1350 } 1351 } 1352 } 1353 } 1354 combineAnnotations(AlignmentI al, int combineCount, StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef)1355 void combineAnnotations(AlignmentI al, int combineCount, 1356 StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef) 1357 { 1358 String group = st.nextToken(); 1359 // First make sure we are not overwriting the graphIndex 1360 int graphGroup = 0; 1361 if (al.getAlignmentAnnotation() != null) 1362 { 1363 for (int i = 0; i < al.getAlignmentAnnotation().length; i++) 1364 { 1365 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; 1366 1367 if (aa.graphGroup > graphGroup) 1368 { 1369 // try to number graphGroups in order of occurence. 1370 graphGroup = aa.graphGroup + 1; 1371 } 1372 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef 1373 && aa.label.equalsIgnoreCase(group)) 1374 { 1375 if (aa.graphGroup > -1) 1376 { 1377 graphGroup = aa.graphGroup; 1378 } 1379 else 1380 { 1381 if (graphGroup <= combineCount) 1382 { 1383 graphGroup = combineCount + 1; 1384 } 1385 aa.graphGroup = graphGroup; 1386 } 1387 break; 1388 } 1389 } 1390 1391 // Now update groups 1392 while (st.hasMoreTokens()) 1393 { 1394 group = st.nextToken(); 1395 for (int i = 0; i < al.getAlignmentAnnotation().length; i++) 1396 { 1397 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; 1398 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef 1399 && aa.label.equalsIgnoreCase(group)) 1400 { 1401 aa.graphGroup = graphGroup; 1402 break; 1403 } 1404 } 1405 } 1406 } 1407 else 1408 { 1409 System.err.println( 1410 "Couldn't combine annotations. None are added to alignment yet!"); 1411 } 1412 } 1413 addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef)1414 void addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef, 1415 SequenceGroup groupRef) 1416 { 1417 String group = st.nextToken(); 1418 AlignmentAnnotation[] alannot = al.getAlignmentAnnotation(); 1419 String nextToken = st.nextToken(); 1420 float value = 0f; 1421 try 1422 { 1423 value = Float.valueOf(nextToken); 1424 } catch (NumberFormatException e) 1425 { 1426 System.err.println("line " + nlinesread + ": Threshold '" + nextToken 1427 + "' invalid, setting to zero"); 1428 } 1429 String label = st.hasMoreTokens() ? st.nextToken() : null; 1430 Color colour = null; 1431 if (st.hasMoreTokens()) 1432 { 1433 colour = ColorUtils.parseColourString(st.nextToken()); 1434 } 1435 if (alannot != null) 1436 { 1437 for (int i = 0; i < alannot.length; i++) 1438 { 1439 if (alannot[i].label.equalsIgnoreCase(group) 1440 && (seqRef == null || alannot[i].sequenceRef == seqRef) 1441 && (groupRef == null || alannot[i].groupRef == groupRef)) 1442 { 1443 alannot[i].setThreshold(new GraphLine(value, label, colour)); 1444 } 1445 } 1446 } 1447 } 1448 addGroup(AlignmentI al, StringTokenizer st)1449 void addGroup(AlignmentI al, StringTokenizer st) 1450 { 1451 SequenceGroup sg = new SequenceGroup(); 1452 sg.setName(st.nextToken()); 1453 String rng = ""; 1454 try 1455 { 1456 rng = st.nextToken(); 1457 if (rng.length() > 0 && !rng.startsWith("*")) 1458 { 1459 sg.setStartRes(Integer.parseInt(rng) - 1); 1460 } 1461 else 1462 { 1463 sg.setStartRes(0); 1464 } 1465 rng = st.nextToken(); 1466 if (rng.length() > 0 && !rng.startsWith("*")) 1467 { 1468 sg.setEndRes(Integer.parseInt(rng) - 1); 1469 } 1470 else 1471 { 1472 sg.setEndRes(al.getWidth() - 1); 1473 } 1474 } catch (Exception e) 1475 { 1476 System.err.println( 1477 "Couldn't parse Group Start or End Field as '*' or a valid column or sequence index: '" 1478 + rng + "' - assuming alignment width for group."); 1479 // assume group is full width 1480 sg.setStartRes(0); 1481 sg.setEndRes(al.getWidth() - 1); 1482 } 1483 1484 String index = st.nextToken(); 1485 if (index.equals("-1")) 1486 { 1487 while (st.hasMoreElements()) 1488 { 1489 sg.addSequence(al.findName(st.nextToken()), false); 1490 } 1491 } 1492 else 1493 { 1494 StringTokenizer st2 = new StringTokenizer(index, ","); 1495 1496 while (st2.hasMoreTokens()) 1497 { 1498 String tmp = st2.nextToken(); 1499 if (tmp.equals("*")) 1500 { 1501 for (int i = 0; i < al.getHeight(); i++) 1502 { 1503 sg.addSequence(al.getSequenceAt(i), false); 1504 } 1505 } 1506 else if (tmp.indexOf("-") >= 0) 1507 { 1508 StringTokenizer st3 = new StringTokenizer(tmp, "-"); 1509 1510 int start = (Integer.parseInt(st3.nextToken())); 1511 int end = (Integer.parseInt(st3.nextToken())); 1512 1513 if (end > start) 1514 { 1515 for (int i = start; i <= end; i++) 1516 { 1517 sg.addSequence(al.getSequenceAt(i - 1), false); 1518 } 1519 } 1520 } 1521 else 1522 { 1523 sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1), 1524 false); 1525 } 1526 } 1527 } 1528 1529 if (refSeq != null) 1530 { 1531 sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1); 1532 sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1); 1533 sg.setSeqrep(refSeq); 1534 } 1535 1536 if (sg.getSize() > 0) 1537 { 1538 al.addGroup(sg); 1539 } 1540 } 1541 addRowProperties(AlignmentI al, StringTokenizer st)1542 void addRowProperties(AlignmentI al, StringTokenizer st) 1543 { 1544 String label = st.nextToken(), keyValue, key, value; 1545 boolean scaletofit = false, centerlab = false, showalllabs = false; 1546 while (st.hasMoreTokens()) 1547 { 1548 keyValue = st.nextToken(); 1549 key = keyValue.substring(0, keyValue.indexOf("=")); 1550 value = keyValue.substring(keyValue.indexOf("=") + 1); 1551 if (key.equalsIgnoreCase("scaletofit")) 1552 { 1553 scaletofit = Boolean.valueOf(value).booleanValue(); 1554 } 1555 if (key.equalsIgnoreCase("showalllabs")) 1556 { 1557 showalllabs = Boolean.valueOf(value).booleanValue(); 1558 } 1559 if (key.equalsIgnoreCase("centrelabs")) 1560 { 1561 centerlab = Boolean.valueOf(value).booleanValue(); 1562 } 1563 AlignmentAnnotation[] alr = al.getAlignmentAnnotation(); 1564 if (alr != null) 1565 { 1566 for (int i = 0; i < alr.length; i++) 1567 { 1568 if (alr[i].label.equalsIgnoreCase(label)) 1569 { 1570 alr[i].centreColLabels = centerlab; 1571 alr[i].scaleColLabel = scaletofit; 1572 alr[i].showAllColLabels = showalllabs; 1573 } 1574 } 1575 } 1576 } 1577 } 1578 addProperties(AlignmentI al, StringTokenizer st)1579 void addProperties(AlignmentI al, StringTokenizer st) 1580 { 1581 1582 // So far we have only added groups to the annotationHash, 1583 // the idea is in the future properties can be added to 1584 // alignments, other annotations etc 1585 if (al.getGroups() == null) 1586 { 1587 return; 1588 } 1589 1590 String name = st.nextToken(); 1591 SequenceGroup sg = null; 1592 for (SequenceGroup _sg : al.getGroups()) 1593 { 1594 if ((sg = _sg).getName().equals(name)) 1595 { 1596 break; 1597 } 1598 else 1599 { 1600 sg = null; 1601 } 1602 } 1603 1604 if (sg != null) 1605 { 1606 String keyValue, key, value; 1607 ColourSchemeI def = sg.getColourScheme(); 1608 while (st.hasMoreTokens()) 1609 { 1610 keyValue = st.nextToken(); 1611 key = keyValue.substring(0, keyValue.indexOf("=")); 1612 value = keyValue.substring(keyValue.indexOf("=") + 1); 1613 1614 if (key.equalsIgnoreCase("description")) 1615 { 1616 sg.setDescription(value); 1617 } 1618 else if (key.equalsIgnoreCase("colour")) 1619 { 1620 // TODO need to notify colourscheme of view reference once it is 1621 // available 1622 sg.cs.setColourScheme( 1623 ColourSchemeProperty.getColourScheme(null, al, value)); 1624 } 1625 else if (key.equalsIgnoreCase("pidThreshold")) 1626 { 1627 sg.cs.setThreshold(Integer.parseInt(value), true); 1628 1629 } 1630 else if (key.equalsIgnoreCase("consThreshold")) 1631 { 1632 sg.cs.setConservationInc(Integer.parseInt(value)); 1633 Conservation c = new Conservation("Group", sg.getSequences(null), 1634 sg.getStartRes(), sg.getEndRes() + 1); 1635 1636 c.calculate(); 1637 c.verdict(false, 25); // TODO: refer to conservation percent threshold 1638 1639 sg.cs.setConservation(c); 1640 1641 } 1642 else if (key.equalsIgnoreCase("outlineColour")) 1643 { 1644 sg.setOutlineColour(ColorUtils.parseColourString(value)); 1645 } 1646 else if (key.equalsIgnoreCase("displayBoxes")) 1647 { 1648 sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue()); 1649 } 1650 else if (key.equalsIgnoreCase("showUnconserved")) 1651 { 1652 sg.setShowNonconserved(Boolean.valueOf(value).booleanValue()); 1653 } 1654 else if (key.equalsIgnoreCase("displayText")) 1655 { 1656 sg.setDisplayText(Boolean.valueOf(value).booleanValue()); 1657 } 1658 else if (key.equalsIgnoreCase("colourText")) 1659 { 1660 sg.setColourText(Boolean.valueOf(value).booleanValue()); 1661 } 1662 else if (key.equalsIgnoreCase("textCol1")) 1663 { 1664 sg.textColour = ColorUtils.parseColourString(value); 1665 } 1666 else if (key.equalsIgnoreCase("textCol2")) 1667 { 1668 sg.textColour2 = ColorUtils.parseColourString(value); 1669 } 1670 else if (key.equalsIgnoreCase("textColThreshold")) 1671 { 1672 sg.thresholdTextColour = Integer.parseInt(value); 1673 } 1674 else if (key.equalsIgnoreCase("idColour")) 1675 { 1676 Color idColour = ColorUtils.parseColourString(value); 1677 sg.setIdColour(idColour == null ? Color.black : idColour); 1678 } 1679 else if (key.equalsIgnoreCase("hide")) 1680 { 1681 // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847 1682 sg.setHidereps(true); 1683 } 1684 else if (key.equalsIgnoreCase("hidecols")) 1685 { 1686 // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847 1687 sg.setHideCols(true); 1688 } 1689 sg.recalcConservation(); 1690 } 1691 if (sg.getColourScheme() == null) 1692 { 1693 sg.setColourScheme(def); 1694 } 1695 } 1696 } 1697 setBelowAlignment(AlignmentI al, StringTokenizer st)1698 void setBelowAlignment(AlignmentI al, StringTokenizer st) 1699 { 1700 String token; 1701 AlignmentAnnotation aa, ala[] = al.getAlignmentAnnotation(); 1702 if (ala == null) 1703 { 1704 System.err.print( 1705 "Warning - no annotation to set below for sequence associated annotation:"); 1706 } 1707 while (st.hasMoreTokens()) 1708 { 1709 token = st.nextToken(); 1710 if (ala == null) 1711 { 1712 System.err.print(" " + token); 1713 } 1714 else 1715 { 1716 for (int i = 0; i < al.getAlignmentAnnotation().length; i++) 1717 { 1718 aa = al.getAlignmentAnnotation()[i]; 1719 if (aa.sequenceRef == refSeq && aa.label.equals(token)) 1720 { 1721 aa.belowAlignment = true; 1722 } 1723 } 1724 } 1725 } 1726 if (ala == null) 1727 { 1728 System.err.print("\n"); 1729 } 1730 } 1731 addAlignmentDetails(AlignmentI al, StringTokenizer st)1732 void addAlignmentDetails(AlignmentI al, StringTokenizer st) 1733 { 1734 String keyValue, key, value; 1735 while (st.hasMoreTokens()) 1736 { 1737 keyValue = st.nextToken(); 1738 key = keyValue.substring(0, keyValue.indexOf("=")); 1739 value = keyValue.substring(keyValue.indexOf("=") + 1); 1740 al.setProperty(key, value); 1741 } 1742 } 1743 1744 /** 1745 * Write annotations as a CSV file of the form 'label, value, value, ...' for 1746 * each row. 1747 * 1748 * @param annotations 1749 * @return CSV file as a string. 1750 */ printCSVAnnotations(AlignmentAnnotation[] annotations)1751 public String printCSVAnnotations(AlignmentAnnotation[] annotations) 1752 { 1753 if (annotations == null) 1754 { 1755 return ""; 1756 } 1757 StringBuffer sp = new StringBuffer(); 1758 for (int i = 0; i < annotations.length; i++) 1759 { 1760 String atos = annotations[i].toString(); 1761 int p = 0; 1762 do 1763 { 1764 int cp = atos.indexOf("\n", p); 1765 sp.append(annotations[i].label); 1766 sp.append(","); 1767 if (cp > p) 1768 { 1769 sp.append(atos.substring(p, cp + 1)); 1770 } 1771 else 1772 { 1773 sp.append(atos.substring(p)); 1774 sp.append(newline); 1775 } 1776 p = cp + 1; 1777 } while (p > 0); 1778 } 1779 return sp.toString(); 1780 } 1781 printAnnotationsForView(AlignViewportI viewport)1782 public String printAnnotationsForView(AlignViewportI viewport) 1783 { 1784 return printAnnotations( 1785 viewport.isShowAnnotation() 1786 ? viewport.getAlignment().getAlignmentAnnotation() 1787 : null, 1788 viewport.getAlignment().getGroups(), 1789 viewport.getAlignment().getProperties(), 1790 viewport.getAlignment().getHiddenColumns(), 1791 viewport.getAlignment(), null); 1792 } 1793 printAnnotationsForAlignment(AlignmentI al)1794 public String printAnnotationsForAlignment(AlignmentI al) 1795 { 1796 return printAnnotations(al.getAlignmentAnnotation(), al.getGroups(), 1797 al.getProperties(), null, al, null); 1798 } 1799 } 1800