X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FStockholmFile.java;h=1c84f004bb2cb77aca45021d28d271bb3ca59d37;hb=d9f963f9290e699cd00304461ebdc85c5bc4c53a;hp=ff2b4fafb51648c39ac166bd8fc0b393d670306f;hpb=11fa2109fa963fbd910cb127f9161132ec97b9bf;p=jalview.git diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java index ff2b4fa..1c84f00 100644 --- a/src/jalview/io/StockholmFile.java +++ b/src/jalview/io/StockholmFile.java @@ -1,31 +1,54 @@ /* - * 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 2.8.2) + * Copyright (C) 2014 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. */ /* * This extension was written by Benjamin Schuster-Boeckler at sanger.ac.uk */ package jalview.io; -import java.io.*; -import java.util.*; - -import com.stevesoft.pat.*; -import jalview.datamodel.*; +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.util.Format; +import jalview.util.MessageManager; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +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.*; @@ -38,12 +61,18 @@ import jalview.util.Format; * into Jalview's local representation. * * @author bsb at sanger.ac.uk + * @author Natasha Shersnev (Dundee, UK) (Stockholm file writer) + * @author Lauren Lui (UCSC, USA) (RNA secondary structure annotation import as + * stockholm) + * @author Anne Menard (Paris, FR) (VARNA parsing of Stockholm file data) * @version 0.3 + jalview mods * */ public class StockholmFile extends AlignFile { // static Logger logger = Logger.getLogger("jalview.io.StockholmFile"); + protected ArrayList result; + StringBuffer out; // output buffer AlignmentI al; @@ -76,6 +105,71 @@ public class StockholmFile extends AlignFile } /** + * Parse a file in Stockholm format into Jalview's data model using VARNA + * + * @throws IOException + * If there is an error with the input file + */ + public void parse_with_VARNA(java.io.File inFile) throws IOException + { + FileReader fr = null; + fr = new FileReader(inFile); + + BufferedReader r = new BufferedReader(fr); + result = null; + try + { + result = RNAFactory.loadSecStrStockholm(r); + } catch (ExceptionUnmatchedClosingParentheses umcp) + { + errormessage = "Unmatched parentheses in annotation. Aborting (" + + umcp.getMessage() + ")"; + throw new IOException(umcp); + } + // DEBUG System.out.println("this is the secondary scructure:" + // +result.size()); + SequenceI[] seqs = new SequenceI[result.size()]; + String id = null; + for (int i = 0; i < result.size(); i++) + { + // DEBUG System.err.println("Processing i'th sequence in Stockholm file") + RNA current = result.get(i); + + String seq = current.getSeq(); + String rna = current.getStructDBN(true); + // DEBUG System.out.println(seq); + // DEBUG System.err.println(rna); + int begin = 0; + int end = seq.length() - 1; + id = safeName(getDataName()); + seqs[i] = new Sequence(id, seq, begin, end); + String[] annot = new String[rna.length()]; + Annotation[] ann = new Annotation[rna.length()]; + for (int j = 0; j < rna.length(); j++) + { + annot[j] = rna.substring(j, j + 1); + + } + + for (int k = 0; k < rna.length(); k++) + { + ann[k] = new Annotation(annot[k], "", + jalview.schemes.ResidueProperties.getRNASecStrucState( + annot[k]).charAt(0), 0f); + + } + AlignmentAnnotation align = new AlignmentAnnotation("Sec. str.", + current.getID(), ann); + + seqs[i].addAlignmentAnnotation(align); + seqs[i].setRNA(result.get(i)); + this.annotations.addElement(align); + } + this.setSeqs(seqs); + + } + + /** * Parse a file in Stockholm format into Jalview's data model. The file has to * be passed at construction time * @@ -93,22 +187,22 @@ public class StockholmFile extends AlignFile Hashtable seqAnn = new Hashtable(); // Sequence related annotations Hashtable seqs = new Hashtable(); Regex p, r, rend, s, x; - // Temporary line for processing RNA annotation // String RNAannot = ""; // ------------------ Parsing File ---------------------- // First, we have to check that this file has STOCKHOLM format, i.e. the // first line must match + r = new Regex("# STOCKHOLM ([\\d\\.]+)"); if (!r.search(nextLine())) { - throw new IOException( - "This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'"); + throw new IOException(MessageManager.getString("exception.stockholm_invalid_format")); } else { version = r.stringMatched(1); + // logger.debug("Stockholm version: " + version); } @@ -146,7 +240,7 @@ public class StockholmFile extends AlignFile // End of the alignment, pass stuff back this.noSeqs = seqs.size(); - String propety = null; + String seqdb, 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) @@ -154,11 +248,12 @@ public class StockholmFile extends AlignFile String dbType = getAlignmentProperty("AC").toString(); if (pf.search(dbType)) { - propety = "PFAM"; + // PFAM Alignment - so references are typically from Uniprot + dbsource = "PFAM"; } else if (rf.search(dbType)) { - propety = "RFAM"; + dbsource = "RFAM"; } } // logger.debug("Number of sequences: " + this.noSeqs); @@ -203,7 +298,6 @@ public class StockholmFile extends AlignFile String desc = (String) accAnnotations.get("DE"); seqO.setDescription((desc == null) ? "" : desc); } - // Add DB References (if any) if (accAnnotations != null && accAnnotations.containsKey("DR")) { @@ -216,16 +310,22 @@ public class StockholmFile extends AlignFile } } - if (accAnnotations != null && accAnnotations.containsKey("AC") - && propety != null) + if (accAnnotations != null && accAnnotations.containsKey("AC")) { - String dbr = (String) accAnnotations.get("AC"); - if (dbr != null) + if (dbsource != null) { - String src = propety; - String acn = dbr.toString(); - jalview.util.DBRefUtils.parseToDbRef(seqO, src, "0", acn); + 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); + + } } + // else - do what ? add the data anyway and prompt the user to + // specify what references these are ? } Hashtable features = null; @@ -315,7 +415,7 @@ public class StockholmFile extends AlignFile if (!x.search(line)) { // logger.error("Could not parse sequence line: " + line); - throw new IOException("Could not parse sequence line: " + line); + throw new IOException(MessageManager.formatMessage("exception.couldnt_parse_sequence_line", new String[]{line})); } String ns = (String) seqs.get(x.stringMatched(1)); if (ns == null) @@ -427,7 +527,7 @@ public class StockholmFile extends AlignFile } else { - throw new IOException("Error parsing " + line); + throw new IOException(MessageManager.formatMessage("exception.error_parsing_line", new String[]{line})); } } else if (annType.equals("GC")) @@ -523,6 +623,8 @@ public class StockholmFile extends AlignFile } ns += seq; content.put(description, ns); + + // if(type.equals("SS")){ Hashtable strucAnn; if (seqAnn.containsKey(acc)) { @@ -535,9 +637,11 @@ public class StockholmFile extends AlignFile Vector newStruc = new Vector(); parseAnnotationRow(newStruc, type, ns); + strucAnn.put(type, newStruc); seqAnn.put(acc, strucAnn); } + // } else { System.err @@ -548,8 +652,7 @@ public class StockholmFile extends AlignFile } else { - throw new IOException("Unknown annotation detected: " + annType - + " " + annContent); + throw new IOException(MessageManager.formatMessage("exception.unknown_annotation_detected", new String[]{annType,annContent})); } } } @@ -563,6 +666,114 @@ public class StockholmFile extends AlignFile } } + /** + * Demangle an accession string and guess the originating sequence database + * for a given sequence + * + * @param seqO + * sequence to be annotated + * @param dbr + * Accession string for sequence + * @param dbsource + * source database for alignment (PFAM or RFAM) + */ + private void guessDatabaseFor(Sequence seqO, String dbr, String dbsource) + { + DBRefEntry dbrf = null; + List dbrs = new ArrayList(); + String seqdb = "Unknown", sdbac = "" + dbr; + int st = -1, en = -1, p; + if ((st = sdbac.indexOf("/")) > -1) + { + String num, range = sdbac.substring(st + 1); + sdbac = sdbac.substring(0, st); + if ((p = range.indexOf("-")) > -1) + { + p++; + if (p < range.length()) + { + num = range.substring(p).trim(); + try + { + en = Integer.parseInt(num); + } catch (NumberFormatException x) + { + // could warn here that index is invalid + en = -1; + } + } + } + else + { + p = range.length(); + } + num = range.substring(0, p).trim(); + try + { + st = Integer.parseInt(num); + } catch (NumberFormatException x) + { + // could warn here that index is invalid + st = -1; + } + } + if (dbsource.equals("PFAM")) + { + seqdb = "UNIPROT"; + if (sdbac.indexOf(".") > -1) + { + // strip of last subdomain + sdbac = sdbac.substring(0, sdbac.indexOf(".")); + dbrf = jalview.util.DBRefUtils.parseToDbRef(seqO, seqdb, dbsource, + sdbac); + if (dbrf != null) + { + dbrs.add(dbrf); + } + } + dbrf = jalview.util.DBRefUtils.parseToDbRef(seqO, dbsource, dbsource, + dbr); + if (dbr != null) + { + dbrs.add(dbrf); + } + } + else + { + seqdb = "EMBL"; // total guess - could be ENA, or something else these + // days + if (sdbac.indexOf(".") > -1) + { + // strip off last subdomain + sdbac = sdbac.substring(0, sdbac.indexOf(".")); + dbrf = jalview.util.DBRefUtils.parseToDbRef(seqO, seqdb, dbsource, + sdbac); + if (dbrf != null) + { + dbrs.add(dbrf); + } + } + + dbrf = jalview.util.DBRefUtils.parseToDbRef(seqO, dbsource, dbsource, + dbr); + if (dbrf != null) + { + dbrs.add(dbrf); + } + } + if (st != -1 && en != -1) + { + for (DBRefEntry d : dbrs) + { + jalview.util.MapList mp = new jalview.util.MapList(new int[] + { seqO.getStart(), seqO.getEnd() }, new int[] + { st, en }, 1, 1); + jalview.datamodel.Mapping mping = new Mapping(mp); + d.setMap(mping); + } + } + } + protected static AlignmentAnnotation parseAnnotationRow( Vector annotation, String label, String annots) { @@ -630,7 +841,9 @@ public class StockholmFile extends AlignFile { annot = (AlignmentAnnotation) e.nextElement(); if (annot.label.equals(type)) + { break; + } annot = null; } if (annot == null) @@ -675,7 +888,9 @@ public class StockholmFile extends AlignFile for (int idb = 0; idb < s[in].getDBRef().length; idb++) { if (dataRef == null) + { dataRef = new Hashtable(); + } String datAs1 = s[in].getDBRef()[idb].getSource().toString() + " ; " @@ -748,7 +963,9 @@ public class StockholmFile extends AlignFile String key = type2id(feature); if (key == null) + { continue; + } // out.append("#=GR "); out.append(new Format("%-" + maxid + "s").form("#=GR " @@ -809,12 +1026,18 @@ public class StockholmFile extends AlignFile String label; if (aa.label.equals("seq")) + { label = "seq_cons"; + } else + { label = type2id(aa.label.toLowerCase()) + "_cons"; + } if (label == null) + { label = aa.label; + } out.append(new Format("%-" + maxid + "s").form("#=GC " + label + " ")); @@ -826,9 +1049,13 @@ public class StockholmFile extends AlignFile { char ll = aa.annotations[j].secondaryStructure; if (Character.toString(ll).equals(" ")) + { seq += "C"; + } else + { seq += ll; + } } else if (ch.length() == 1) { @@ -909,44 +1136,29 @@ public class StockholmFile extends AlignFile } if (key != null) { - return (String) key; + return key; } System.err.println("Warning : Unknown Stockholm annotation type: " + type); return key; } + /** - * //ssline is complete secondary structure line private AlignmentAnnotation - * addHelices(Vector annotation, String label, String ssline) { - * - * // decide on secondary structure or not. Annotation[] els = new - * Annotation[ssline.length()]; for (int i = 0; i < ssline.length(); i++) { - * String pos = ssline.substring(i, i + 1); Annotation ann; ann = new - * Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not - * - * ann.secondaryStructure = - * jalview.schemes.ResidueProperties.getRNAssState(pos).charAt(0); - * - * ann.displayCharacter = "x" + ann.displayCharacter; - * - * System.out.println(ann.displayCharacter); - * - * els[i] = ann; } AlignmentAnnotation helicesAnnot = null; Enumeration e = - * annotation.elements(); while (e.hasMoreElements()) { helicesAnnot = - * (AlignmentAnnotation) e.nextElement(); if (helicesAnnot.label.equals(type)) - * break; helicesAnnot = null; } if (helicesAnnot == null) { helicesAnnot = - * new AlignmentAnnotation(type, type, els); - * annotation.addElement(helicesAnnot); } else { Annotation[] anns = new - * Annotation[helicesAnnot.annotations.length + els.length]; - * System.arraycopy(helicesAnnot.annotations, 0, anns, 0, - * helicesAnnot.annotations.length); System.arraycopy(els, 0, anns, - * helicesAnnot.annotations.length, els.length); helicesAnnot.annotations = - * anns; } - * - * helicesAnnot.features = Rna.GetBasePairs(ssline); - * Rna.HelixMap(helicesAnnot.features); + * make a friendly ID string. * - * - * return helicesAnnot; } + * @param dataName + * @return truncated dataName to after last '/' */ + private String safeName(String dataName) + { + int b = 0; + while ((b = dataName.indexOf("/")) > -1 && b < dataName.length()) + { + dataName = dataName.substring(b + 1).trim(); + + } + int e = (dataName.length() - dataName.indexOf(".")) + 1; + dataName = dataName.substring(1, e).trim(); + return dataName; + } }