import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
import jalview.datamodel.Mapping;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
findXrefSourcesForSequence(seq, dna, sources);
}
}
+ sources.remove(DBRefSource.EMBL); // hack to prevent EMBL xrefs resulting in
+ // redundant datasets
+ if (dna)
+ {
+ sources.remove(DBRefSource.ENSEMBL); // hack to prevent Ensembl and
+ // EnsemblGenomes xref option shown
+ // from cdna panel
+ sources.remove(DBRefSource.ENSEMBLGENOMES);
+ }
+ // redundant datasets
return sources;
}
*/
for (SequenceI rs : foundSeqs)
{
- DBRefEntry[] xrs = DBRefUtils
- .selectDbRefs(!fromDna, rs.getDBRefs());
+ DBRefEntry[] xrs = DBRefUtils.selectDbRefs(!fromDna,
+ rs.getDBRefs());
addXrefsToSources(xrs, sources);
}
}
rseqs = new ArrayList<SequenceI>();
AlignedCodonFrame cf = new AlignedCodonFrame();
- matcher = new SequenceIdMatcher(
- dataset.getSequences());
+ matcher = new SequenceIdMatcher(dataset.getSequences());
for (SequenceI seq : fromSeqs)
{
dss = dss.getDatasetSequence();
}
boolean found = false;
- DBRefEntry[] xrfs = DBRefUtils
- .selectDbRefs(!fromDna, dss.getDBRefs());
+ DBRefEntry[] xrfs = DBRefUtils.selectDbRefs(!fromDna,
+ dss.getDBRefs());
// ENST & ENSP comes in to both Protein and nucleotide, so we need to
// filter them
// out later.
if (matchInDataset != null && xref.getMap().getTo() != null
&& matchInDataset != xref.getMap().getTo())
{
- System.err
- .println("Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
- + "Found:"
- + matchInDataset
- + "\nExpected:"
- + xref.getMap().getTo()
- + "\nFor xref:"
+ System.err.println(
+ "Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
+ + "Found:" + matchInDataset + "\nExpected:"
+ + xref.getMap().getTo() + "\nFor xref:"
+ xref);
}
/*matcher.findIdMatch(mappedTo);*/
}
else
{
- cf.addMap(matchInDataset, dss, xref.getMap().getMap()
- .getInverse(), xref.getMap().getMappedFromId());
+ cf.addMap(matchInDataset, dss,
+ xref.getMap().getMap().getInverse(),
+ xref.getMap().getMappedFromId());
}
}
if (fromDna)
{
// map is from dna seq to a protein product
- cf.addMap(dss, rsq, xref.getMap().getMap(), xref.getMap()
- .getMappedFromId());
+ cf.addMap(dss, rsq, xref.getMap().getMap(),
+ xref.getMap().getMappedFromId());
}
else
{
if (!found)
{
- SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|"
- + xref.getAccessionId());
+ SequenceI matchedSeq = matcher.findIdMatch(
+ xref.getSource() + "|" + xref.getAccessionId());
// if there was a match, check it's at least the right type of
// molecule!
if (matchedSeq != null && matchedSeq.isProtein() == fromDna)
{
ASequenceFetcher sftch = SequenceFetcherFactory.getSequenceFetcher();
SequenceI[] retrieved = null;
- SequenceI dss = seq.getDatasetSequence() == null ? seq : seq
- .getDatasetSequence();
+ SequenceI dss = seq.getDatasetSequence() == null ? seq
+ : seq.getDatasetSequence();
// first filter in case we are retrieving crossrefs that have already been
// retrieved. this happens for cases where a database record doesn't yield
// protein products for CDS
+ removeAlreadyRetrievedSeqs(sourceRefs, fromDna);
+ if (sourceRefs.size() == 0)
+ {
+ // no more work to do! We already had all requested sequence records in
+ // the dataset.
+ return;
+ }
+ try
+ {
+ retrieved = sftch.getSequences(sourceRefs, !fromDna);
+ } catch (Exception e)
+ {
+ System.err.println(
+ "Problem whilst retrieving cross references for Sequence : "
+ + seq.getName());
+ e.printStackTrace();
+ }
+
+ if (retrieved != null)
+ {
+ boolean addedXref = false;
+ List<SequenceI> newDsSeqs = new ArrayList<SequenceI>(),
+ doNotAdd = new ArrayList<SequenceI>();
+
+ for (SequenceI retrievedSequence : retrieved)
+ {
+ // dataset gets contaminated ccwith non-ds sequences. why ??!
+ // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
+ SequenceI retrievedDss = retrievedSequence
+ .getDatasetSequence() == null ? retrievedSequence
+ : retrievedSequence.getDatasetSequence();
+ addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+ retrievedDss);
+ }
+ if (!addedXref)
+ {
+ // try again, after looking for matching IDs
+ // shouldn't need to do this unless the dbref mechanism has broken.
+ updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+ for (SequenceI retrievedSequence : retrieved)
+ {
+ // dataset gets contaminated ccwith non-ds sequences. why ??!
+ // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
+ SequenceI retrievedDss = retrievedSequence
+ .getDatasetSequence() == null ? retrievedSequence
+ : retrievedSequence.getDatasetSequence();
+ addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+ retrievedDss);
+ }
+ }
+ for (SequenceI newToSeq : newDsSeqs)
+ {
+ if (!doNotAdd.contains(newToSeq)
+ && dataset.findIndex(newToSeq) == -1)
+ {
+ dataset.addSequence(newToSeq);
+ matcher.add(newToSeq);
+ }
+ }
+ }
+ }
+
+ /**
+ * Search dataset for sequences with a primary reference contained in
+ * sourceRefs.
+ *
+ * @param sourceRefs
+ * - list of references to filter.
+ * @param fromDna
+ * - type of sequence to search for matching primary reference.
+ */
+ private void removeAlreadyRetrievedSeqs(List<DBRefEntry> sourceRefs,
+ boolean fromDna)
+ {
DBRefEntry[] dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
for (SequenceI sq : dataset.getSequences())
{
}
if (dupeFound)
{
+ // rebuild the search array from the filtered sourceRefs list
dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
}
}
- if (sourceRefs.size() == 0)
- {
- // no more work to do! We already had all requested sequence records in
- // the dataset.
- return;
- }
- try
- {
- retrieved = sftch.getSequences(sourceRefs, !fromDna);
- } catch (Exception e)
- {
- System.err
- .println("Problem whilst retrieving cross references for Sequence : "
- + seq.getName());
- e.printStackTrace();
- }
+ }
- if (retrieved != null)
+ /**
+ * process sequence retrieved via a dbref on source sequence to resolve and
+ * transfer data
+ *
+ * @param cf
+ * @param sourceSequence
+ * @param retrievedSequence
+ * @return true if retrieveSequence was imported
+ */
+ private boolean importCrossRefSeq(AlignedCodonFrame cf,
+ List<SequenceI> newDsSeqs, List<SequenceI> doNotAdd,
+ SequenceI sourceSequence, SequenceI retrievedSequence)
+ {
+ /**
+ * set when retrievedSequence has been verified as a crossreference for
+ * sourceSequence
+ */
+ boolean imported = false;
+ DBRefEntry[] dbr = retrievedSequence.getDBRefs();
+ if (dbr != null)
{
- updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
- for (SequenceI retrievedSequence : retrieved)
+ for (DBRefEntry dbref : dbr)
{
- // dataset gets contaminated ccwith non-ds sequences. why ??!
- // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
- SequenceI retrievedDss = retrievedSequence.getDatasetSequence() == null ? retrievedSequence
- : retrievedSequence.getDatasetSequence();
- DBRefEntry[] dbr = retrievedSequence.getDBRefs();
- if (dbr != null)
+ SequenceI matched = findInDataset(dbref);
+ if (matched == sourceSequence)
{
- for (DBRefEntry dbref : dbr)
+ // verified retrieved and source sequence cross-reference each other
+ imported = true;
+ }
+ // find any entry where we should put in the sequence being
+ // cross-referenced into the map
+ Mapping map = dbref.getMap();
+ if (map != null)
+ {
+ if (map.getTo() != null && map.getMap() != null)
{
- // find any entry where we should put in the sequence being
- // cross-referenced into the map
- Mapping map = dbref.getMap();
- if (map != null)
+ if (map.getTo() == sourceSequence)
+ {
+ // already called to import once, and most likely this sequence
+ // already imported !
+ continue;
+ }
+ if (matched == null)
+ {
+ /*
+ * sequence is new to dataset, so save a reference so it can be added.
+ */
+ newDsSeqs.add(map.getTo());
+ continue;
+ }
+
+ /*
+ * there was a matching sequence in dataset, so now, check to see if we can update the map.getTo() sequence to the existing one.
+ */
+
+ try
{
- if (map.getTo() != null && map.getMap() != null)
+ // compare ms with dss and replace with dss in mapping
+ // if map is congruent
+ SequenceI ms = map.getTo();
+ // TODO findInDataset requires exact sequence match but
+ // 'congruent' test is only for the mapped part
+ // maybe not a problem in practice since only ENA provide a
+ // mapping and it is to the full protein translation of CDS
+ // matcher.findIdMatch(map.getTo());
+ // TODO addendum: if matched is shorter than getTo, this will fail
+ // - when it should really succeed.
+ int sf = map.getMap().getToLowest();
+ int st = map.getMap().getToHighest();
+ SequenceI mappedrg = ms.getSubSequence(sf, st);
+ if (mappedrg.getLength() > 0 && ms.getSequenceAsString()
+ .equals(matched.getSequenceAsString()))
{
- // TODO findInDataset requires exact sequence match but
- // 'congruent' test is only for the mapped part
- // maybe not a problem in practice since only ENA provide a
- // mapping and it is to the full protein translation of CDS
- SequenceI matched = findInDataset(dbref);
- // matcher.findIdMatch(map.getTo());
- if (matched != null)
+ /*
+ * sequences were a match,
+ */
+ String msg = "Mapping updated from " + ms.getName()
+ + " to retrieved crossreference "
+ + matched.getName();
+ System.out.println(msg);
+
+ DBRefEntry[] toRefs = map.getTo().getDBRefs();
+ if (toRefs != null)
{
/*
- * already got an xref to this sequence; update this
- * map to point to the same sequence, and add
- * any new dbrefs to it
+ * transfer database refs
*/
- DBRefEntry[] toRefs = map.getTo().getDBRefs();
- if (toRefs != null)
+ for (DBRefEntry ref : toRefs)
{
- for (DBRefEntry ref : toRefs)
+ if (dbref.getSrcAccString()
+ .equals(ref.getSrcAccString()))
{
- matched.addDBRef(ref); // add or update mapping
+ continue; // avoid overwriting the ref on source sequence
}
+ matched.addDBRef(ref); // add or update mapping
}
- map.setTo(matched);
}
- else
- {
- if (dataset.findIndex(map.getTo()) == -1)
- {
- dataset.addSequence(map.getTo());
- matcher.add(map.getTo());
- }
- }
- try
- {
- // compare ms with dss and replace with dss in mapping
- // if map is congruent
- SequenceI ms = map.getTo();
- int sf = map.getMap().getToLowest();
- int st = map.getMap().getToHighest();
- SequenceI mappedrg = ms.getSubSequence(sf, st);
- // SequenceI loc = dss.getSubSequence(sf, st);
- if (mappedrg.getLength() > 0
- && ms.getSequenceAsString().equals(
- dss.getSequenceAsString()))
- // && mappedrg.getSequenceAsString().equals(
- // loc.getSequenceAsString()))
- {
- String msg = "Mapping updated from " + ms.getName()
- + " to retrieved crossreference "
- + dss.getName();
- System.out.println(msg);
- map.setTo(dss);
+ doNotAdd.add(map.getTo());
+ map.setTo(matched);
- /*
- * give the reverse reference the inverse mapping
- * (if it doesn't have one already)
- */
- setReverseMapping(dss, dbref, cf);
+ /*
+ * give the reverse reference the inverse mapping
+ * (if it doesn't have one already)
+ */
+ setReverseMapping(matched, dbref, cf);
- /*
- * copy sequence features as well, avoiding
- * duplication (e.g. same variation from two
- * transcripts)
- */
- SequenceFeature[] sfs = ms.getSequenceFeatures();
- if (sfs != null)
+ /*
+ * copy sequence features as well, avoiding
+ * duplication (e.g. same variation from two
+ * transcripts)
+ */
+ List<SequenceFeature> sfs = ms.getFeatures()
+ .getAllFeatures();
+ for (SequenceFeature feat : sfs)
+ {
+ /*
+ * make a flyweight feature object which ignores Parent
+ * attribute in equality test; this avoids creating many
+ * otherwise duplicate exon features on genomic sequence
+ */
+ SequenceFeature newFeature = new SequenceFeature(feat)
+ {
+ @Override
+ public boolean equals(Object o)
{
- for (SequenceFeature feat : sfs)
- {
- /*
- * make a flyweight feature object which ignores Parent
- * attribute in equality test; this avoids creating many
- * otherwise duplicate exon features on genomic sequence
- */
- SequenceFeature newFeature = new SequenceFeature(
- feat)
- {
- @Override
- public boolean equals(Object o)
- {
- return super.equals(o, true);
- }
- };
- dss.addSequenceFeature(newFeature);
- }
+ return super.equals(o, true);
}
- }
- cf.addMap(retrievedDss, map.getTo(), map.getMap());
- } catch (Exception e)
- {
- System.err
- .println("Exception when consolidating Mapped sequence set...");
- e.printStackTrace(System.err);
+ };
+ matched.addSequenceFeature(newFeature);
}
}
+ cf.addMap(retrievedSequence, map.getTo(), map.getMap());
+ } catch (Exception e)
+ {
+ System.err.println(
+ "Exception when consolidating Mapped sequence set...");
+ e.printStackTrace(System.err);
}
}
}
- retrievedSequence.updatePDBIds();
- rseqs.add(retrievedDss);
- if (dataset.findIndex(retrievedDss) == -1)
- {
- dataset.addSequence(retrievedDss);
- matcher.add(retrievedDss);
- }
}
}
+ if (imported)
+ {
+ retrievedSequence.updatePDBIds();
+ rseqs.add(retrievedSequence);
+ if (dataset.findIndex(retrievedSequence) == -1)
+ {
+ dataset.addSequence(retrievedSequence);
+ matcher.add(retrievedSequence);
+ }
+ }
+ return imported;
}
+
/**
* Sets the inverse sequence mapping in the corresponding dbref of the mapped
* to sequence (if any). This is used after fetching a cross-referenced
}
/**
- * Returns the first identical sequence in the dataset if any, else null
+ * Returns null or the first sequence in the dataset which is identical to
+ * xref.mapTo, and has a) a primary dbref matching xref, or if none found, the
+ * first one with an ID source|xrefacc
*
* @param xref
+ * with map and mapped-to sequence
* @return
*/
SequenceI findInDataset(DBRefEntry xref)
SequenceI mapsTo = xref.getMap().getTo();
String name = xref.getAccessionId();
String name2 = xref.getSource() + "|" + name;
- SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo : mapsTo
- .getDatasetSequence();
+ SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo
+ : mapsTo.getDatasetSequence();
// first check ds if ds is directly referenced
if (dataset.findIndex(dss) > -1)
{
return dss;
}
- ;
+ DBRefEntry template = new DBRefEntry(xref.getSource(), null,
+ xref.getAccessionId());
+ /**
+ * remember the first ID match - in case we don't find a match to template
+ */
+ SequenceI firstIdMatch = null;
for (SequenceI seq : dataset.getSequences())
{
+ // first check primary refs.
+ List<DBRefEntry> match = DBRefUtils.searchRefs(
+ seq.getPrimaryDBRefs().toArray(new DBRefEntry[0]), template);
+ if (match != null && match.size() == 1 && sameSequence(seq, dss))
+ {
+ return seq;
+ }
/*
* clumsy alternative to using SequenceIdMatcher which currently
* returns sequences with a dbref to the matched accession id
* which we don't want
*/
- if (name.equals(seq.getName()) || seq.getName().startsWith(name2))
+ if (firstIdMatch == null && (name.equals(seq.getName())
+ || seq.getName().startsWith(name2)))
{
if (sameSequence(seq, dss))
{
- return seq;
+ firstIdMatch = seq;
}
}
}
- return null;
+ return firstIdMatch;
}
/**
{
return false;
}
- char[] c1 = seq1.getSequence();
- char[] c2 = seq2.getSequence();
- if (c1.length != c2.length)
+
+ if (seq1.getLength() != seq2.getLength())
{
return false;
}
- for (int i = 0; i < c1.length; i++)
+ int length = seq1.getLength();
+ for (int i = 0; i < length; i++)
{
- int diff = c1[i] - c2[i];
+ int diff = seq1.getCharAt(i) - seq2.getCharAt(i);
/*
* same char or differ in case only ('a'-'A' == 32)
*/
* @return true if matches were found.
*/
private boolean searchDatasetXrefs(boolean fromDna, SequenceI sequenceI,
- DBRefEntry[] lrfs, List<SequenceI> foundSeqs, AlignedCodonFrame cf)
+ DBRefEntry[] lrfs, List<SequenceI> foundSeqs,
+ AlignedCodonFrame cf)
{
boolean found = false;
if (lrfs == null)
// add in wildcards
xref.setVersion(null);
xref.setMap(null);
- found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf, false);
+ found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf,
+ false);
}
return found;
}
{
if (nxt.getDatasetSequence() != null)
{
- System.err
- .println("Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
- + nxt.getDisplayId(true)
- + " has ds reference "
+ System.err.println(
+ "Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
+ + nxt.getDisplayId(true) + " has ds reference "
+ nxt.getDatasetSequence().getDisplayId(true)
+ ")");
}