import jalview.analysis.WUSSParseException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
}
/**
+ * Get the RNA Secondary Structure SequenceFeature Array if present
+ */
+ public SequenceFeature[] getRnaSecondaryStructure()
+ {
+ return this._rnasecstr;
+ }
+
+ /**
+ * Check the RNA Secondary Structure is equivalent to one in given
+ * AlignmentAnnotation param
+ */
+ public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that)
+ {
+ return rnaSecondaryStructureEquivalent(that, true);
+ }
+
+ public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that, boolean compareType)
+ {
+ SequenceFeature[] thisSfArray = this.getRnaSecondaryStructure();
+ SequenceFeature[] thatSfArray = that.getRnaSecondaryStructure();
+ if (thisSfArray == null || thatSfArray == null)
+ {
+ return thisSfArray == null && thatSfArray == null;
+ }
+ if (thisSfArray.length != thatSfArray.length)
+ {
+ return false;
+ }
+ Arrays.sort(thisSfArray, new SFSortByEnd()); // probably already sorted
+ // like this
+ Arrays.sort(thatSfArray, new SFSortByEnd()); // probably already sorted
+ // like this
+ for (int i=0; i < thisSfArray.length; i++) {
+ SequenceFeature thisSf = thisSfArray[i];
+ SequenceFeature thatSf = thatSfArray[i];
+ if (compareType) {
+ if (thisSf.getType() == null || thatSf.getType() == null) {
+ if (thisSf.getType() == null && thatSf.getType() == null) {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ if (! thisSf.getType().equals(thatSf.getType())) {
+ return false;
+ }
+ }
+ if (!(thisSf.getBegin() == thatSf.getBegin()
+ && thisSf.getEnd() == thatSf.getEnd()))
+ {
+ return false;
+ }
+ }
+ return true;
+
+ }
+
+ /**
* map of positions in the associated annotation
*/
private Map<Integer, Annotation> sequenceMapping;
char firstChar = 0;
for (int i = 0; i < annotations.length; i++)
{
+ // DEBUG System.out.println(i + ": " + annotations[i]);
if (annotations[i] == null)
{
continue;
if (annotations[i].secondaryStructure == 'H'
|| annotations[i].secondaryStructure == 'E')
{
+ // DEBUG System.out.println( "/H|E/ '" +
+ // annotations[i].secondaryStructure + "'");
hasIcons |= true;
}
else
// Check for RNA secondary structure
{
- // System.out.println(annotations[i].secondaryStructure);
+ // DEBUG System.out.println( "/else/ '" +
+ // annotations[i].secondaryStructure + "'");
// TODO: 2.8.2 should this ss symbol validation check be a function in
// RNA/ResidueProperties ?
if (annotations[i].secondaryStructure == '('
|| annotations[i].secondaryStructure == 'B'
|| annotations[i].secondaryStructure == 'C'
|| annotations[i].secondaryStructure == 'D'
- || annotations[i].secondaryStructure == 'E'
+ // || annotations[i].secondaryStructure == 'E' // ambiguous on
+ // its own -- already checked above
|| annotations[i].secondaryStructure == 'F'
|| annotations[i].secondaryStructure == 'G'
- || annotations[i].secondaryStructure == 'H'
+ // || annotations[i].secondaryStructure == 'H' // ambiguous on
+ // its own -- already checked above
|| annotations[i].secondaryStructure == 'I'
|| annotations[i].secondaryStructure == 'J'
|| annotations[i].secondaryStructure == 'K'
// &&
// annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
firstChar != ' ' && firstChar != '$' && firstChar != 0xCE
- && firstChar != '(' && firstChar != '[' && firstChar != '>'
+ && firstChar != '(' && firstChar != '[' && firstChar != '<'
&& firstChar != '{' && firstChar != 'A' && firstChar != 'B'
&& firstChar != 'C' && firstChar != 'D' && firstChar != 'E'
&& firstChar != 'F' && firstChar != 'G' && firstChar != 'H'
}
return aa;
}
+
}
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(
+ "^[^<>[\\](){}A-DF-Za-df-z]*$");
+
StringBuffer out; // output buffer
AlignmentI al;
String version;
// String id;
Hashtable seqAnn = new Hashtable(); // Sequence related annotations
- LinkedHashMap<String, String> seqs = new LinkedHashMap<String, String>();
+ LinkedHashMap<String, String> seqs = new LinkedHashMap<>();
Regex p, r, rend, s, x;
// Temporary line for processing RNA annotation
// String RNAannot = "";
strucAnn = new Hashtable();
}
- Vector<AlignmentAnnotation> newStruc = new Vector<AlignmentAnnotation>();
+ Vector<AlignmentAnnotation> newStruc = new Vector<>();
parseAnnotationRow(newStruc, type, ns);
for (AlignmentAnnotation alan : newStruc)
{
private void guessDatabaseFor(Sequence seqO, String dbr, String dbsource)
{
DBRefEntry dbrf = null;
- List<DBRefEntry> dbrs = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> dbrs = new ArrayList<>();
String seqdb = "Unknown", sdbac = "" + dbr;
int st = -1, en = -1, p;
if ((st = sdbac.indexOf("/")) > -1)
}
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"))
{
{
// 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);
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)
{
seq = ch.charAt(1);
}
- return seq;
+
+ return (seq == ' ' && key != null && key.equals("SS") && isrna) ? '.'
+ : seq;
}
public String print()
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
}
static String PfamFile = "examples/PF00111_seed.stk",
- RfamFile = "examples/RF00031_folded.stk";
+ RfamFile = "examples/RF00031_folded.stk",
+ RnaSSTestFile = "examples/rna_ss_test.stk";
@Test(groups = { "Functional" })
public void pfamFileIO() throws Exception
// we might want to revise this in future
int aa_new_size = (aa_new == null ? 0 : aa_new.length);
int aa_original_size = (aa_original == null ? 0 : aa_original.length);
- Map<Integer, BitSet> orig_groups = new HashMap<Integer, BitSet>();
- Map<Integer, BitSet> new_groups = new HashMap<Integer, BitSet>();
+ Map<Integer, BitSet> orig_groups = new HashMap<>();
+ Map<Integer, BitSet> new_groups = new HashMap<>();
if (aa_new != null && aa_original != null)
{
{
for (char ch : new char[] { '{', '}', '[', ']', '(', ')', '<', '>' })
{
- Assert.assertTrue(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
- "Didn't recognise " + ch + " as a WUSS bracket");
+ Assert.assertTrue(StockholmFile.RNASS_BRACKETS.indexOf(ch) >= 0,
+ "Didn't recognise '" + ch + "' as a WUSS bracket");
}
- for (char ch : new char[] { '@', '!', 'V', 'Q', '*', ' ', '-', '.' })
+ for (char ch : new char[] { '@', '!', '*', ' ', '-', '.' })
{
- Assert.assertFalse(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
- "Shouldn't recognise " + ch + " as a WUSS bracket");
+ Assert.assertFalse(StockholmFile.RNASS_BRACKETS.indexOf(ch) >= 0,
+ "Shouldn't recognise '" + ch + "' as a WUSS bracket");
}
}
private static void roundTripSSForRNA(String aliFile, String annFile)
testAlignmentEquivalence(al, newAl, true, true, true);
}
+
+ // this is the single sequence alignment and the SS annotations equivalent to
+ // the ones in file RnaSSTestFile
+ String aliFileRnaSS = ">Test.sequence/1-14\n"
+ + "GUACAAAAAAAAAA";
+ String annFileRnaSSAlphaChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|(,(|E,E|H,H|B,B|h,h|e,e|b,b|(,(|E,E|),)|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ String wrongAnnFileRnaSSAlphaChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|(,(|H,H|E,E|B,B|h,h|e,e|b,b|(,(|E,E|),)|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ @Test(groups = { "Functional" })
+ public void stockholmFileRnaSSAlphaChars() throws Exception
+ {
+ AppletFormatAdapter af = new AppletFormatAdapter();
+ AlignmentI al = af.readFile(RnaSSTestFile, DataSourceType.FILE,
+ jalview.io.FileFormat.Stockholm);
+ Iterable<AlignmentAnnotation> aai = al.findAnnotations(null, null,
+ "Secondary Structure");
+ AlignmentAnnotation aa = aai.iterator().next();
+ Assert.assertTrue(aa.isRNA(),
+ "'" + RnaSSTestFile + "' not recognised as RNA SS");
+ Assert.assertTrue(aa.isValidStruc(),
+ "'" + RnaSSTestFile + "' not recognised as valid structure");
+ Annotation[] as = aa.annotations;
+ char[] As = new char[as.length];
+ for (int i = 0; i < as.length; i++)
+ {
+ As[i] = as[i].secondaryStructure;
+ }
+ char[] shouldBe = { '<', '(', 'E', 'H', 'B', 'h', 'e', 'b', '(', 'E',
+ ')', 'e', ')', '>' };
+ Assert.assertTrue(
+ Arrays.equals(As, shouldBe),
+ "Annotation is " + new String(As) + " but should be "
+ + new String(shouldBe));
+
+ // this should result in the same RNA SS Annotations
+ AlignmentI newAl = new AppletFormatAdapter().readFile(
+ aliFileRnaSS,
+ DataSourceType.PASTE, jalview.io.FileFormat.Fasta);
+ AnnotationFile aaf = new AnnotationFile();
+ aaf.readAnnotationFile(newAl, annFileRnaSSAlphaChars,
+ DataSourceType.PASTE);
+
+ Assert.assertTrue(
+ testRnaSSAnnotationsEquivalent(al.getAlignmentAnnotation()[0],
+ newAl.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD be pair-wise equivalent (but apparently aren't): \n"
+ + "RNA SS A 1:" + al.getAlignmentAnnotation()[0] + "\n"
+ + "RNA SS A 2:" + newAl.getAlignmentAnnotation()[0]);
+
+ // this should NOT result in the same RNA SS Annotations
+ newAl = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ aaf = new AnnotationFile();
+ aaf.readAnnotationFile(newAl, wrongAnnFileRnaSSAlphaChars,
+ DataSourceType.PASTE);
+
+ boolean mismatch = testRnaSSAnnotationsEquivalent(al.getAlignmentAnnotation()[0],
+ newAl.getAlignmentAnnotation()[0]);
+ Assert.assertFalse(mismatch,
+ "RNA SS Annotations SHOULD NOT be pair-wise equivalent (but apparently are): \n"
+ + "RNA SS A 1:" + al.getAlignmentAnnotation()[0] + "\n"
+ + "RNA SS A 2:" + newAl.getAlignmentAnnotation()[0]);
+ }
+
+ private static boolean testRnaSSAnnotationsEquivalent(
+ AlignmentAnnotation a1,
+ AlignmentAnnotation a2)
+ {
+ return a1.rnaSecondaryStructureEquivalent(a2);
+ }
+
+ String annFileRnaSSWithSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H| , |B,B|h,h| , |b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ String annFileRnaSSWithoutSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H|.,.|B,B|h,h|.,.|b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+
+ String wrongAnnFileRnaSSWithoutSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H|Z,Z|B,B|h,h|z,z|b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+
+ @Test(groups = { "Functional" })
+ public void stockholmFileRnaSSSpaceChars() throws Exception
+ {
+ AlignmentI alWithSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile afWithSpaces = new AnnotationFile();
+ afWithSpaces.readAnnotationFile(alWithSpaces,
+ annFileRnaSSWithSpaceChars, DataSourceType.PASTE);
+
+ Iterable<AlignmentAnnotation> aaiWithSpaces = alWithSpaces
+ .findAnnotations(null, null, "Secondary Structure");
+ AlignmentAnnotation aaWithSpaces = aaiWithSpaces.iterator().next();
+ Assert.assertTrue(aaWithSpaces.isRNA(),
+ "'" + aaWithSpaces + "' not recognised as RNA SS");
+ Assert.assertTrue(aaWithSpaces.isValidStruc(),
+ "'" + aaWithSpaces + "' not recognised as valid structure");
+ Annotation[] annWithSpaces = aaWithSpaces.annotations;
+ char[] As = new char[annWithSpaces.length];
+ for (int i = 0; i < annWithSpaces.length; i++)
+ {
+ As[i] = annWithSpaces[i].secondaryStructure;
+ }
+ // check all spaces and dots are spaces in the internal representation
+ char[] shouldBe = { '<', ' ', 'H', ' ', 'B', 'h', ' ', 'b', '(', 'E',
+ ' ', 'e', ')', '>' };
+ Assert.assertTrue(Arrays.equals(As, shouldBe), "Annotation is "
+ + new String(As) + " but should be " + new String(shouldBe));
+
+ // this should result in the same RNA SS Annotations
+ AlignmentI alWithoutSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile afWithoutSpaces = new AnnotationFile();
+ afWithoutSpaces.readAnnotationFile(alWithoutSpaces,
+ annFileRnaSSWithoutSpaceChars,
+ DataSourceType.PASTE);
+
+ Assert.assertTrue(
+ testRnaSSAnnotationsEquivalent(
+ alWithSpaces.getAlignmentAnnotation()[0],
+ alWithoutSpaces.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD be pair-wise equivalent (but apparently aren't): \n"
+ + "RNA SS A 1:"
+ + alWithSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure()
+ + "\n" + "RNA SS A 2:"
+ + alWithoutSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure());
+
+ // this should NOT result in the same RNA SS Annotations
+ AlignmentI wrongAlWithoutSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile wrongAfWithoutSpaces = new AnnotationFile();
+ wrongAfWithoutSpaces.readAnnotationFile(wrongAlWithoutSpaces,
+ wrongAnnFileRnaSSWithoutSpaceChars,
+ DataSourceType.PASTE);
+
+ Assert.assertFalse(
+ testRnaSSAnnotationsEquivalent(
+ alWithSpaces.getAlignmentAnnotation()[0],
+ wrongAlWithoutSpaces.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD NOT be pair-wise equivalent (but apparently are): \n"
+ + "RNA SS A 1:"
+ + alWithSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure()
+ + "\n" + "RNA SS A 2:"
+ + wrongAlWithoutSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure());
+
+ // check no spaces in the output
+ // TODO: create a better 'save as <format>' pattern
+ alWithSpaces.getAlignmentAnnotation()[0].visible = true;
+ StockholmFile sf = new StockholmFile(alWithSpaces);
+
+ String stockholmFile = sf.print(alWithSpaces.getSequencesArray(), true);
+ Pattern noSpacesInRnaSSAnnotation = Pattern
+ .compile("\\n#=GC SS_cons\\s+\\S{14}\\n");
+ Matcher m = noSpacesInRnaSSAnnotation.matcher(stockholmFile);
+ boolean matches = m.find();
+ Assert.assertTrue(matches,
+ "StockholmFile output does not contain expected output (may contain spaces):\n"
+ + stockholmFile);
+
+ }
}