X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FStockholmFile.java;h=5d645cafe30874f85fe0b58a06619da2571c91c8;hb=0ae965fc73680bdc69b06986c060ff17342c4787;hp=f5b517728c85ce77ad785c9030e7b7e475ed2046;hpb=be762d8d9c71a7aa3121e845c45911c7192b7827;p=jalview.git diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java index f5b5177..5d645ca 100644 --- a/src/jalview/io/StockholmFile.java +++ b/src/jalview/io/StockholmFile.java @@ -23,20 +23,6 @@ */ package jalview.io; -import jalview.analysis.Rna; -import jalview.datamodel.AlignmentAnnotation; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.Annotation; -import jalview.datamodel.DBRefEntry; -import jalview.datamodel.Mapping; -import jalview.datamodel.Sequence; -import jalview.datamodel.SequenceFeature; -import jalview.datamodel.SequenceI; -import jalview.schemes.ResidueProperties; -import jalview.util.Comparison; -import jalview.util.Format; -import jalview.util.MessageManager; - import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; @@ -45,6 +31,7 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Vector; @@ -53,8 +40,21 @@ import com.stevesoft.pat.Regex; import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses; import fr.orsay.lri.varna.factories.RNAFactory; import fr.orsay.lri.varna.models.rna.RNA; - -// import org.apache.log4j.*; +import jalview.analysis.Rna; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.DBRefSource; +import jalview.datamodel.Mapping; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; +import jalview.schemes.ResidueProperties; +import jalview.util.Comparison; +import jalview.util.DBRefUtils; +import jalview.util.Format; +import jalview.util.MessageManager; /** * This class is supposed to parse a Stockholm format file into Jalview There @@ -76,13 +76,22 @@ public class StockholmFile extends AlignFile { private static final String ANNOTATION = "annotation"; - private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "("); - - private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")"); + // private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "("); + // + // private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")"); public static final Regex DETECT_BRACKETS = new Regex( "(<|>|\\[|\\]|\\(|\\)|\\{|\\})"); + // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using + // NOT_RNASS first. + public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + // use the following regex to decide an annotations (whole) line is NOT an RNA + // SS (it contains only E,H,e,h and other non-brace/non-alpha chars) + private static final Regex NOT_RNASS = new Regex( + "^[^<>[\\](){}ADFJ-RUVWYZadfj-ruvwyz]*$"); + StringBuffer out; // output buffer AlignmentI al; @@ -197,7 +206,7 @@ public class StockholmFile extends AlignFile String version; // String id; Hashtable seqAnn = new Hashtable(); // Sequence related annotations - LinkedHashMap seqs = new LinkedHashMap(); + LinkedHashMap seqs = new LinkedHashMap<>(); Regex p, r, rend, s, x; // Temporary line for processing RNA annotation // String RNAannot = ""; @@ -231,8 +240,8 @@ public class StockholmFile extends AlignFile Regex openparen = new Regex("(<|\\[)", "("); Regex closeparen = new Regex("(>|\\])", ")"); - // Detect if file is RNA by looking for bracket types - Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))"); + // // Detect if file is RNA by looking for bracket types + // Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))"); rend.optimize(); p.optimize(); @@ -253,7 +262,7 @@ public class StockholmFile extends AlignFile // End of the alignment, pass stuff back this.noSeqs = seqs.size(); - String seqdb, dbsource = null; + String dbsource = null; Regex pf = new Regex("PF[0-9]{5}(.*)"); // Finds AC for Pfam Regex rf = new Regex("RF[0-9]{5}(.*)"); // Finds AC for Rfam if (getAlignmentProperty("AC") != null) @@ -324,17 +333,15 @@ public class StockholmFile extends AlignFile if (accAnnotations != null && accAnnotations.containsKey("AC")) { - if (dbsource != null) + String dbr = (String) accAnnotations.get("AC"); + if (dbr != null) { - String dbr = (String) accAnnotations.get("AC"); - if (dbr != null) - { - // we could get very clever here - but for now - just try to - // guess accession type from source of alignment plus structure - // of accession - guessDatabaseFor(seqO, dbr, dbsource); - - } + // we could get very clever here - but for now - just try to + // guess accession type from type of sequence, source of alignment + // plus + // structure + // of accession + guessDatabaseFor(seqO, dbr, dbsource); } // else - do what ? add the data anyway and prompt the user to // specify what references these are ? @@ -519,6 +526,11 @@ public class StockholmFile extends AlignFile treeName = an.stringMatched(2); treeString = new StringBuffer(); } + // TODO: JAL-3532 - this is where GF comments and database + // references are lost + // suggest overriding this method for Stockholm files to catch and + // properly + // process CC, DR etc into multivalued properties setAlignmentProperty(an.stringMatched(1), an.stringMatched(2)); } } @@ -658,7 +670,7 @@ public class StockholmFile extends AlignFile strucAnn = new Hashtable(); } - Vector newStruc = new Vector(); + Vector newStruc = new Vector<>(); parseAnnotationRow(newStruc, type, ns); for (AlignmentAnnotation alan : newStruc) { @@ -710,7 +722,7 @@ public class StockholmFile extends AlignFile private void guessDatabaseFor(Sequence seqO, String dbr, String dbsource) { DBRefEntry dbrf = null; - List dbrs = new ArrayList(); + List dbrs = new ArrayList<>(); String seqdb = "Unknown", sdbac = "" + dbr; int st = -1, en = -1, p; if ((st = sdbac.indexOf("/")) > -1) @@ -747,6 +759,13 @@ public class StockholmFile extends AlignFile st = -1; } } + if (dbsource == null) + { + // make up an origin based on whether the sequence looks like it is + // nucleotide + // or protein + dbsource = (seqO.isProtein()) ? "PFAM" : "RFAM"; + } if (dbsource.equals("PFAM")) { seqdb = "UNIPROT"; @@ -824,9 +843,14 @@ public class StockholmFile extends AlignFile } boolean ss = false, posterior = false; type = id2type(type); + + boolean isrnass = false; if (type.equalsIgnoreCase("secondary structure")) { ss = true; + isrnass = !NOT_RNASS.search(annots); // sorry about the double negative + // here (it's easier for dealing with + // other non-alpha-non-brace chars) } if (type.equalsIgnoreCase("posterior probability")) { @@ -844,7 +868,7 @@ public class StockholmFile extends AlignFile { // if (" .-_".indexOf(pos) == -1) { - if (DETECT_BRACKETS.search(pos)) + if (isrnass && RNASS_BRACKETS.indexOf(pos) >= 0) { ann.secondaryStructure = Rna.getRNASecStrucState(pos).charAt(0); ann.displayCharacter = "" + pos.charAt(0); @@ -917,6 +941,12 @@ public class StockholmFile extends AlignFile return annot; } + private String dbref_to_ac_record(DBRefEntry ref) + { + return ref.getSource().toString() + " ; " + + ref.getAccessionId().toString(); + } + @Override public String print(SequenceI[] s, boolean jvSuffix) { @@ -928,29 +958,50 @@ public class StockholmFile extends AlignFile int max = 0; int maxid = 0; int in = 0; - Hashtable dataRef = null; - while ((in < s.length) && (s[in] != null)) + int slen = s.length; + SequenceI seq; + Hashtable dataRef = null; + boolean isAA = s[in].isProtein(); + while ((in < slen) && ((seq = s[in]) != null)) { - String tmp = printId(s[in], jvSuffix); - max = Math.max(max, s[in].getLength()); + String tmp = printId(seq, jvSuffix); + max = Math.max(max, seq.getLength()); if (tmp.length() > maxid) { maxid = tmp.length(); } - if (s[in].getDBRefs() != null) + List seqrefs = seq.getDBRefs(); + int ndb; + if (seqrefs != null && (ndb = seqrefs.size()) > 0) { - for (int idb = 0; idb < s[in].getDBRefs().length; idb++) + if (dataRef == null) + { + dataRef = new Hashtable<>(); + } + List primrefs = seq.getPrimaryDBRefs(); + if (primrefs.size() >= 1) { - if (dataRef == null) + dataRef.put(tmp, dbref_to_ac_record(primrefs.get(0))); + } + else + { + for (int idb = 0; idb < seq.getDBRefs().size(); idb++) { - dataRef = new Hashtable(); + DBRefEntry dbref = seq.getDBRefs().get(idb); + dataRef.put(tmp, dbref_to_ac_record(dbref)); + // if we put in a uniprot or EMBL record then we're done: + if (isAA && DBRefSource.UNIPROT + .equals(DBRefUtils.getCanonicalName(dbref.getSource()))) + { + break; + } + if (!isAA && DBRefSource.EMBL + .equals(DBRefUtils.getCanonicalName(dbref.getSource()))) + { + break; + } } - - String datAs1 = s[in].getDBRefs()[idb].getSource().toString() - + " ; " - + s[in].getDBRefs()[idb].getAccessionId().toString(); - dataRef.put(tmp, datAs1); } } in++; @@ -976,14 +1027,15 @@ public class StockholmFile extends AlignFile // output database accessions if (dataRef != null) { - Enumeration en = dataRef.keys(); + Enumeration en = dataRef.keys(); while (en.hasMoreElements()) { Object idd = en.nextElement(); - String type = (String) dataRef.remove(idd); + String type = dataRef.remove(idd); out.append(new Format("%-" + (maxid - 2) + "s") .form("#=GS " + idd.toString() + " ")); - if (type.contains("PFAM") || type.contains("RFAM")) + if (isAA && type.contains("UNIPROT") + || (!isAA && type.contains("EMBL"))) { out.append(" AC " + type.substring(type.indexOf(";") + 1)); @@ -997,13 +1049,13 @@ public class StockholmFile extends AlignFile } // output annotations - while (i < s.length && s[i] != null) + while (i < slen && (seq = s[i]) != null) { - AlignmentAnnotation[] alAnot = s[i].getAnnotation(); + AlignmentAnnotation[] alAnot = seq.getAnnotation(); if (alAnot != null) { Annotation[] ann; - for (int j = 0; j < alAnot.length; j++) + for (int j = 0, nj = alAnot.length; j < nj; j++) { String key = type2id(alAnot[j].label); @@ -1023,37 +1075,38 @@ public class StockholmFile extends AlignFile // out.append("#=GR "); out.append(new Format("%-" + maxid + "s").form( - "#=GR " + printId(s[i], jvSuffix) + " " + key + " ")); + "#=GR " + printId(seq, jvSuffix) + " " + key + " ")); ann = alAnot[j].annotations; - String seq = ""; - for (int k = 0; k < ann.length; k++) + String sseq = ""; + for (int k = 0, nk = ann.length; k < nk; k++) { - seq += outputCharacter(key, k, isrna, ann, s[i]); + sseq += outputCharacter(key, k, isrna, ann, seq); } - out.append(seq); + out.append(sseq); out.append(newline); } } out.append(new Format("%-" + maxid + "s") - .form(printId(s[i], jvSuffix) + " ")); - out.append(s[i].getSequenceAsString()); + .form(printId(seq, jvSuffix) + " ")); + out.append(seq.getSequenceAsString()); out.append(newline); i++; } // alignment annotation AlignmentAnnotation aa; - if (al.getAlignmentAnnotation() != null) + AlignmentAnnotation[] an = al.getAlignmentAnnotation(); + if (an != null) { - for (int ia = 0; ia < al.getAlignmentAnnotation().length; ia++) + for (int ia = 0, na = an.length; ia < na; ia++) { - aa = al.getAlignmentAnnotation()[ia]; + aa = an[ia]; if (aa.autoCalculated || !aa.visible || aa.sequenceRef != null) { continue; } - String seq = ""; + String sseq = ""; String label; String key = ""; if (aa.label.equals("seq")) @@ -1062,7 +1115,7 @@ public class StockholmFile extends AlignFile } else { - key = type2id(aa.label.toLowerCase()); + key = type2id(aa.label.toLowerCase(Locale.ROOT)); if (key == null) { label = aa.label; @@ -1081,11 +1134,11 @@ public class StockholmFile extends AlignFile out.append( new Format("%-" + maxid + "s").form("#=GC " + label + " ")); boolean isrna = aa.isValidStruc(); - for (int j = 0; j < aa.annotations.length; j++) + for (int j = 0, nj = aa.annotations.length; j < nj; j++) { - seq += outputCharacter(key, j, isrna, aa.annotations, null); + sseq += outputCharacter(key, j, isrna, aa.annotations, null); } - out.append(seq); + out.append(sseq); out.append(newline); } } @@ -1114,22 +1167,36 @@ public class StockholmFile extends AlignFile String ch = (annot == null) ? ((sequenceI == null) ? "-" : Character.toString(sequenceI.getCharAt(k))) - : annot.displayCharacter; + : (annot.displayCharacter == null + ? String.valueOf(annot.secondaryStructure) + : annot.displayCharacter); + if (ch == null) + { + ch = " "; + } if (key != null && key.equals("SS")) { + char ssannotchar = ' '; + boolean charset = false; if (annot == null) { // sensible gap character - return ' '; + ssannotchar = ' '; + charset = true; } else { // valid secondary structure AND no alternative label (e.g. ' B') if (annot.secondaryStructure > ' ' && ch.length() < 2) { - return annot.secondaryStructure; + ssannotchar = annot.secondaryStructure; + charset = true; } } + if (charset) + { + return (ssannotchar == ' ' && isrna) ? '.' : ssannotchar; + } } if (ch.length() == 0) @@ -1144,7 +1211,9 @@ public class StockholmFile extends AlignFile { seq = ch.charAt(1); } - return seq; + + return (seq == ' ' && key != null && key.equals("SS") && isrna) ? '.' + : seq; } public String print()