X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FAnnotationFile.java;h=8706ad5d3154443552e74ecfb840bfbfef1e0058;hb=8edebdd9789b2d93fb8f9db24b8be2c1e6317690;hp=3d42475fb3dfe765def8761c77bb28eef6777ee0;hpb=db7a726e4cf2c7d5f650085bd07b7f19254688e9;p=jalview.git diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index 3d42475..8706ad5 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -1,29 +1,55 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8) - * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.io; -import java.io.*; -import java.net.*; -import java.util.*; - -import jalview.analysis.*; -import jalview.datamodel.*; -import jalview.schemes.*; +import jalview.analysis.Conservation; +import jalview.api.AlignViewportI; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.GraphLine; +import jalview.datamodel.HiddenSequences; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.schemes.ColourSchemeI; +import jalview.schemes.ColourSchemeProperty; +import jalview.schemes.ResidueProperties; +import jalview.schemes.UserColourScheme; +import jalview.util.Comparison; +import jalview.util.Format; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Vector; public class AnnotationFile { @@ -64,18 +90,18 @@ public class AnnotationFile } /** - * convenience method for pre-2.4 feature files which have no view, hidden - * columns or hidden row keywords. + * convenience method for pre-2.8.3 annotation files which have no view, + * hidden columns or hidden row keywords. * * @param annotations * @param list * @param properties - * @return feature file as a string. + * @return annotation file as a string. */ public String printAnnotations(AlignmentAnnotation[] annotations, List list, Hashtable properties) { - return printAnnotations(annotations, list, properties, null); + return printAnnotations(annotations, list, properties, null, null, null); } @@ -116,10 +142,56 @@ public class AnnotationFile * @return annotation file */ public String printAnnotations(AlignmentAnnotation[] annotations, - List list, Hashtable properties, ViewDef[] views) + List list, Hashtable properties, + ColumnSelection cs, AlignmentI al, ViewDef view) { - // TODO: resolve views issue : annotationFile could contain visible region, - // or full data + hidden region specifications for a view. + if (view != null) + { + if (view.viewname != null) + { + text.append("VIEW_DEF\t" + view.viewname + "\n"); + } + if (list == null) + { + list = view.visibleGroups; + } + if (cs == null) + { + cs = view.hiddencols; + } + if (al == null) + { + // add hidden rep sequences. + } + } + // first target - store and restore all settings for a view. + if (al != null && al.hasSeqrep()) + { + text.append("VIEW_SETREF\t" + al.getSeqrep().getName() + "\n"); + } + if (cs != null && cs.hasHiddenColumns()) + { + text.append("VIEW_HIDECOLS\t"); + List hc = cs.getHiddenColumns(); + boolean comma = false; + for (int[] r : hc) + { + if (!comma) + { + comma = true; + } + else + { + text.append(","); + } + text.append(r[0]); + text.append("-"); + text.append(r[1]); + } + text.append("\n"); + } + // TODO: allow efficient recovery of annotation data shown in several + // different views if (annotations != null) { boolean oneColour = true; @@ -131,7 +203,8 @@ public class AnnotationFile StringBuffer colours = new StringBuffer(); StringBuffer graphLine = new StringBuffer(); StringBuffer rowprops = new StringBuffer(); - Hashtable graphGroup = new Hashtable(); + Hashtable graphGroup = new Hashtable(); + Hashtable graphGroup_refs = new Hashtable(); BitSet graphGroupSeen = new BitSet(); java.awt.Color color; @@ -140,7 +213,10 @@ public class AnnotationFile { row = annotations[i]; - if (!row.visible && !row.hasScore() && !(row.graphGroup>-1 && graphGroupSeen.get(row.graphGroup))) + if (!row.visible + && !row.hasScore() + && !(row.graphGroup > -1 && graphGroupSeen + .get(row.graphGroup))) { continue; } @@ -148,53 +224,12 @@ public class AnnotationFile color = null; oneColour = true; - if (row.sequenceRef == null) - { - if (refSeq != null) - { - text.append(newline); - text.append("SEQUENCE_REF\tALIGNMENT"); - text.append(newline); - } - - refSeq = null; - } - - else - { - if (refSeq == null || refSeq != row.sequenceRef) - { - refSeq = row.sequenceRef; - text.append(newline); - text.append("SEQUENCE_REF\t"); - text.append(refSeq.getName()); - text.append(newline); - } - } + // mark any sequence references for the row + writeSequence_Ref(refSeq, row.sequenceRef); + refSeq = row.sequenceRef; // mark any group references for the row - if (row.groupRef == null) - { - - if (refGroup != null) - { - text.append(newline); - text.append("GROUP_REF\tALIGNMENT"); - text.append(newline); - } - - refGroup = null; - } - else - { - if (refGroup == null || refGroup != row.groupRef) - { - refGroup = row.groupRef; - text.append(newline); - text.append("GROUP_REF\t"); - text.append(refGroup.getName()); - text.append(newline); - } - } + writeGroup_Ref(refGroup, row.groupRef); + refGroup = row.groupRef; boolean hasGlyphs = row.hasIcons, hasLabels = row.hasText, hasValues = row.hasScore, hasText = false; // lookahead to check what the annotation row object actually contains. @@ -245,21 +280,24 @@ public class AnnotationFile graphLine.append("\t"); graphLine.append(row.getThreshold().label); graphLine.append("\t"); - graphLine.append(jalview.util.Format.getHexString(row - .getThreshold().colour)); + graphLine + .append(Format.getHexString(row.getThreshold().colour)); graphLine.append(newline); } if (row.graphGroup > -1) { graphGroupSeen.set(row.graphGroup); - String key = String.valueOf(row.graphGroup); + Integer key = new Integer(row.graphGroup); if (graphGroup.containsKey(key)) { graphGroup.put(key, graphGroup.get(key) + "\t" + row.label); + } else { + graphGroup_refs.put(key, new Object[] + { refSeq, refGroup }); graphGroup.put(key, row.label); } } @@ -274,7 +312,7 @@ public class AnnotationFile && j < row.annotations.length; j++) { if (refSeq != null - && jalview.util.Comparison.isGap(refSeq.getCharAt(j))) + && Comparison.isGap(refSeq.getCharAt(j))) { continue; } @@ -341,7 +379,7 @@ public class AnnotationFile { text.append(comma + "[" - + jalview.util.Format + + Format .getHexString(row.annotations[j].colour) + "]"); comma = ","; @@ -351,7 +389,9 @@ public class AnnotationFile } if (row.hasScore()) + { text.append("\t" + row.score); + } text.append(newline); @@ -360,7 +400,7 @@ public class AnnotationFile colours.append("COLOUR\t"); colours.append(row.label); colours.append("\t"); - colours.append(jalview.util.Format.getHexString(color)); + colours.append(Format.getHexString(color)); colours.append(newline); } if (row.scaleColLabel || row.showAllColLabels @@ -376,21 +416,40 @@ public class AnnotationFile rowprops.append(row.centreColLabels); rowprops.append(newline); } + if (graphLine.length() > 0) + { + text.append(graphLine.toString()); + graphLine.setLength(0); + } } text.append(newline); text.append(colours.toString()); - text.append(graphLine.toString()); if (graphGroup.size() > 0) { - Enumeration en = graphGroup.elements(); - while (en.hasMoreElements()) + SequenceI oldRefSeq = refSeq; + SequenceGroup oldRefGroup = refGroup; + for (Map.Entry combine_statement : graphGroup + .entrySet()) { + Object[] seqRefAndGroup = graphGroup_refs.get(combine_statement + .getKey()); + + writeSequence_Ref(refSeq, (SequenceI) seqRefAndGroup[0]); + refSeq = (SequenceI) seqRefAndGroup[0]; + + writeGroup_Ref(refGroup, (SequenceGroup) seqRefAndGroup[1]); + refGroup = (SequenceGroup) seqRefAndGroup[1]; text.append("COMBINE\t"); - text.append(en.nextElement()); + text.append(combine_statement.getValue()); text.append(newline); } + writeSequence_Ref(refSeq, oldRefSeq); + refSeq = oldRefSeq; + + writeGroup_Ref(refGroup, oldRefGroup); + refGroup = oldRefGroup; } text.append(rowprops.toString()); } @@ -415,12 +474,70 @@ public class AnnotationFile text.append(properties.get(key)); } // TODO: output alignment visualization settings here if required - + // iterate through one or more views, defining, marking columns and rows as visible/hidden, and emmitting view properties. + // View specific annotation is } return text.toString(); } + private Object writeGroup_Ref(SequenceGroup refGroup, + SequenceGroup next_refGroup) + { + if (next_refGroup == null) + { + + if (refGroup != null) + { + text.append(newline); + text.append("GROUP_REF\t"); + text.append("ALIGNMENT"); + text.append(newline); + } + return true; + } + else + { + if (refGroup == null || refGroup != next_refGroup) + { + text.append(newline); + text.append("GROUP_REF\t"); + text.append(next_refGroup.getName()); + text.append(newline); + return true; + } + } + return false; + } + + private boolean writeSequence_Ref(SequenceI refSeq, SequenceI next_refSeq) + { + + if (next_refSeq == null) + { + if (refSeq != null) + { + text.append(newline); + text.append("SEQUENCE_REF\t"); + text.append("ALIGNMENT"); + text.append(newline); + return true; + } + } + else + { + if (refSeq == null || refSeq != next_refSeq) + { + text.append(newline); + text.append("SEQUENCE_REF\t"); + text.append(next_refSeq.getName()); + text.append(newline); + return true; + } + } + return false; + } + public void printGroups(List list) { SequenceI seqrep = null; @@ -482,7 +599,7 @@ public class AnnotationFile } } text.append("outlineColour="); - text.append(jalview.util.Format.getHexString(sg.getOutlineColour())); + text.append(Format.getHexString(sg.getOutlineColour())); text.append("\t"); text.append("displayBoxes="); @@ -500,13 +617,13 @@ public class AnnotationFile if (sg.textColour != java.awt.Color.black) { text.append("textCol1="); - text.append(jalview.util.Format.getHexString(sg.textColour)); + text.append(Format.getHexString(sg.textColour)); text.append("\t"); } if (sg.textColour2 != java.awt.Color.white) { text.append("textCol2="); - text.append(jalview.util.Format.getHexString(sg.textColour2)); + text.append(Format.getHexString(sg.textColour2)); text.append("\t"); } if (sg.thresholdTextColour != 0) @@ -518,7 +635,7 @@ public class AnnotationFile if (sg.idColour != null) { text.append("idColour="); - text.append(jalview.util.Format.getHexString(sg.idColour)); + text.append(Format.getHexString(sg.idColour)); text.append("\t"); } if (sg.isHidereps()) @@ -545,9 +662,33 @@ public class AnnotationFile String refSeqId = null; + public boolean annotateAlignmentView(AlignViewportI viewport, + String file, String protocol) + { + ColumnSelection colSel = viewport.getColumnSelection(); + if (colSel == null) + { + colSel = new ColumnSelection(); + } + boolean rslt = readAnnotationFile(viewport.getAlignment(), colSel, + file, protocol); + if (rslt + && (colSel.hasSelectedColumns() || colSel.hasHiddenColumns())) + { + viewport.setColumnSelection(colSel); + } + + return rslt; + } public boolean readAnnotationFile(AlignmentI al, String file, String protocol) { + return readAnnotationFile(al, null, file, protocol); + } + + public boolean readAnnotationFile(AlignmentI al, ColumnSelection colSel, + String file, String protocol) + { BufferedReader in = null; try { @@ -574,30 +715,36 @@ public class AnnotationFile } if (in != null) { - return parseAnnotationFrom(al, in); + return parseAnnotationFrom(al, colSel, in); } } catch (Exception ex) { ex.printStackTrace(); System.out.println("Problem reading annotation file: " + ex); - if (nlinesread>0) { - System.out.println("Last read line "+nlinesread+": '"+lastread+"' (first 80 chars) ..."); + if (nlinesread > 0) + { + System.out.println("Last read line " + nlinesread + ": '" + + lastread + "' (first 80 chars) ..."); } return false; } return false; } - long nlinesread=0; - String lastread=""; - public boolean parseAnnotationFrom(AlignmentI al, BufferedReader in) + + long nlinesread = 0; + + String lastread = ""; + + private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE"; + + public boolean parseAnnotationFrom(AlignmentI al, ColumnSelection colSel, + BufferedReader in) throws Exception { nlinesread = 0; - /** - * number of combine statements in this annotation file. Used to create new groups for combined annotation graphs without disturbing existing ones - */ - int combinecount = 0; + ArrayList combineAnnotation_calls = new ArrayList(); + ArrayList deferredAnnotation_calls = new ArrayList(); boolean modified = false; String groupRef = null; Hashtable groupRefRows = new Hashtable(); @@ -642,7 +789,8 @@ public class AnnotationFile boolean jvAnnotationFile = false; while ((line = in.readLine()) != null) { - nlinesread++;lastread = new String(line); + nlinesread++; + lastread = new String(line); if (line.indexOf("#") == 0) { continue; @@ -663,7 +811,8 @@ public class AnnotationFile while ((line = in.readLine()) != null) { - nlinesread++;lastread = new String(line); + nlinesread++; + lastread = new String(line); if (line.indexOf("#") == 0 || line.indexOf("JALVIEW_ANNOTATION") > -1 || line.length() == 0) @@ -681,9 +830,11 @@ public class AnnotationFile continue; } - else if (token.equalsIgnoreCase("COMBINE")) + else if (token.equalsIgnoreCase(COMBINE)) { - combineAnnotations(al, combinecount++, st); + // keep a record of current state and resolve groupRef at end + combineAnnotation_calls.add(new Object[] + { st, refSeq, groupRef }); modified = true; continue; } @@ -693,9 +844,11 @@ public class AnnotationFile modified = true; continue; } - else if (token.equalsIgnoreCase("GRAPHLINE")) + else if (token.equalsIgnoreCase(GRAPHLINE)) { - addLine(al, st); + // resolve at end + deferredAnnotation_calls.add(new Object[] + { GRAPHLINE, st, refSeq, groupRef }); modified = true; continue; } @@ -755,6 +908,7 @@ public class AnnotationFile else if (token.equalsIgnoreCase("SEQUENCE_GROUP")) { addGroup(al, st); + modified = true; continue; } @@ -777,6 +931,58 @@ public class AnnotationFile modified = true; continue; } + // else if (token.equalsIgnoreCase("VIEW_DEF")) + // { + // addOrSetView(al,st); + // modified = true; + // continue; + // } + else if (token.equalsIgnoreCase("VIEW_SETREF")) + { + if (refSeq != null) + { + al.setSeqrep(refSeq); + } + modified = true; + continue; + } + else if (token.equalsIgnoreCase("VIEW_HIDECOLS")) + { + if (st.hasMoreTokens()) + { + if (colSel == null) + { + colSel = new ColumnSelection(); + } + parseHideCols(colSel, st.nextToken()); + } + modified = true; + continue; + } + else if (token.equalsIgnoreCase("HIDE_INSERTIONS")) + { + SequenceI sr = refSeq == null ? al.getSeqrep() : refSeq; + if (sr == null) + { + sr = al.getSequenceAt(0); + } + if (sr != null) + { + if (colSel == null) + { + System.err + .println("Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: " + + line); + } + else + { + // consider deferring this till after the file has been parsed ? + colSel.hideInsertionsFor(sr); + } + } + modified = true; + continue; + } // Parse out the annotation row graphStyle = AlignmentAnnotation.getGraphValueFromString(token); @@ -795,7 +1001,9 @@ public class AnnotationFile { description = line; if (st.hasMoreTokens()) + { line = st.nextToken(); + } } if (st.hasMoreTokens()) @@ -898,7 +1106,8 @@ public class AnnotationFile // and set modification flag modified = true; } - // Finally, resolve the groupRefs + // Resolve the groupRefs + Hashtable groupRefLookup = new Hashtable(); Enumeration en = groupRefRows.keys(); while (en.hasMoreElements()) @@ -922,6 +1131,7 @@ public class AnnotationFile { matched = true; Vector rowset = (Vector) groupRefRows.get(groupRef); + groupRefLookup.put(groupRef, theGroup); if (rowset != null && rowset.size() > 0) { AlignmentAnnotation alan = null; @@ -936,10 +1146,77 @@ public class AnnotationFile } ((Vector) groupRefRows.get(groupRef)).removeAllElements(); } + // process any deferred attribute settings for each context + for (Object[] _deferred_args : deferredAnnotation_calls) + { + if (_deferred_args[0] == GRAPHLINE) + { + addLine(al, + (StringTokenizer) _deferred_args[1], // st + (SequenceI) _deferred_args[2], // refSeq + (_deferred_args[3] == null) ? null : groupRefLookup + .get(_deferred_args[3]) // the reference + // group, or null + ); + } + } + + // finally, combine all the annotation rows within each context. + /** + * number of combine statements in this annotation file. Used to create + * new groups for combined annotation graphs without disturbing existing + * ones + */ + int combinecount = 0; + for (Object[] _combine_args : combineAnnotation_calls) + { + combineAnnotations(al, + ++combinecount, + (StringTokenizer) _combine_args[0], // st + (SequenceI) _combine_args[1], // refSeq + (_combine_args[2] == null) ? null : groupRefLookup + .get(_combine_args[2]) // the reference group, + // or null + ); + } } return modified; } + private void parseHideCols(ColumnSelection colSel, String nextToken) + { + StringTokenizer inval = new StringTokenizer(nextToken,","); + while (inval.hasMoreTokens()) + { + String range = inval.nextToken().trim(); + int from, to = range.indexOf("-"); + if (to == -1) + { + from = to = Integer.parseInt(range); + if (from >= 0) + { + colSel.hideColumns(from, to); + } + } + else + { + from = Integer.parseInt(range.substring(0, to)); + if (to < range.length() - 1) + { + to = Integer.parseInt(range.substring(to + 1)); + } + else + { + to = from; + } + if (from > 0 && to >= from) + { + colSel.hideColumns(from, to); + } + } + } + } + private Object autoAnnotsKey(AlignmentAnnotation annotation, SequenceI refSeq, String groupRef) { @@ -1092,30 +1369,35 @@ public class AnnotationFile } } - void combineAnnotations(AlignmentI al, int combineCount, StringTokenizer st) + void combineAnnotations(AlignmentI al, int combineCount, + StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef) { String group = st.nextToken(); // First make sure we are not overwriting the graphIndex - int graphGroup=0; + int graphGroup = 0; if (al.getAlignmentAnnotation() != null) { for (int i = 0; i < al.getAlignmentAnnotation().length; i++) { AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; - if (aa.graphGroup>graphGroup) + + if (aa.graphGroup > graphGroup) { // try to number graphGroups in order of occurence. - graphGroup=aa.graphGroup; + graphGroup = aa.graphGroup + 1; } - if (aa.label.equalsIgnoreCase(group)) + if (aa.sequenceRef == seqRef && aa.groupRef == groupRef + && aa.label.equalsIgnoreCase(group)) { - if (aa.graphGroup>-1) + if (aa.graphGroup > -1) { graphGroup = aa.graphGroup; - } else { - if (graphGroup >= combineCount) + } + else + { + if (graphGroup <= combineCount) { - graphGroup++; + graphGroup = combineCount + 1; } aa.graphGroup = graphGroup; } @@ -1129,9 +1411,11 @@ public class AnnotationFile group = st.nextToken(); for (int i = 0; i < al.getAlignmentAnnotation().length; i++) { - if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group)) + AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; + if (aa.sequenceRef == seqRef && aa.groupRef == groupRef + && aa.label.equalsIgnoreCase(group)) { - al.getAlignmentAnnotation()[i].graphGroup = graphGroup; + aa.graphGroup = graphGroup; break; } } @@ -1144,19 +1428,29 @@ public class AnnotationFile } } - void addLine(AlignmentI al, StringTokenizer st) + void addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef, + SequenceGroup groupRef) { String group = st.nextToken(); AlignmentAnnotation annotation = null, alannot[] = al .getAlignmentAnnotation(); + float value = new Float(st.nextToken()).floatValue(); + String label = st.hasMoreTokens() ? st.nextToken() : null; + java.awt.Color colour = null; + if (st.hasMoreTokens()) + { + UserColourScheme ucs = new UserColourScheme(st.nextToken()); + colour = ucs.findColour('A'); + } if (alannot != null) { for (int i = 0; i < alannot.length; i++) { - if (alannot[i].label.equalsIgnoreCase(group)) + if (alannot[i].label.equalsIgnoreCase(group) + && (seqRef == null || alannot[i].sequenceRef == seqRef) + && (groupRef == null || alannot[i].groupRef == groupRef)) { - annotation = alannot[i]; - break; + alannot[i].setThreshold(new GraphLine(value, label, colour)); } } } @@ -1164,16 +1458,6 @@ public class AnnotationFile { return; } - float value = new Float(st.nextToken()).floatValue(); - String label = st.hasMoreTokens() ? st.nextToken() : null; - java.awt.Color colour = null; - if (st.hasMoreTokens()) - { - UserColourScheme ucs = new UserColourScheme(st.nextToken()); - colour = ucs.findColour('A'); - } - - annotation.setThreshold(new GraphLine(value, label, colour)); } void addGroup(AlignmentI al, StringTokenizer st) @@ -1503,4 +1787,19 @@ public class AnnotationFile } return sp.toString(); } + + public String printAnnotationsForView(AlignViewportI viewport) + { + return printAnnotations(viewport.isShowAnnotation() ? viewport + .getAlignment().getAlignmentAnnotation() : null, viewport + .getAlignment().getGroups(), viewport.getAlignment() + .getProperties(), viewport.getColumnSelection(), + viewport.getAlignment(), null); + } + + public String printAnnotationsForAlignment(AlignmentI al) + { + return printAnnotations(al.getAlignmentAnnotation(), al.getGroups(), + al.getProperties(), null, al, null); + } }