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;
}
rseqs = new ArrayList<SequenceI>();
AlignedCodonFrame cf = new AlignedCodonFrame();
- matcher = new SequenceIdMatcher(
- dataset.getSequences());
+ matcher = new SequenceIdMatcher(dataset.getSequences());
for (SequenceI seq : fromSeqs)
{
if (retrieved != null)
{
- updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+ 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();
- importCrossRefSeq(cf, dss, retrievedDss);
- rseqs.add(retrievedDss);
- if (dataset.findIndex(retrievedDss) == -1)
+ 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(retrievedDss);
- matcher.add(retrievedDss);
+ dataset.addSequence(newToSeq);
+ matcher.add(newToSeq);
}
}
}
}
if (dupeFound)
{
+ // rebuild the search array from the filtered sourceRefs list
dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
}
}
* @param cf
* @param sourceSequence
* @param retrievedSequence
+ * @return true if retrieveSequence was imported
*/
- private void importCrossRefSeq(AlignedCodonFrame cf,
+ 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)
{
for (DBRefEntry dbref : dbr)
{
+ SequenceI matched = findInDataset(dbref);
+ if (matched == sourceSequence)
+ {
+ // 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.getTo() != null && map.getMap() != null)
{
- // 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)
+ if (map.getTo() == sourceSequence)
{
- /*
- * already got an xref to this sequence; update this
- * map to point to the same sequence, and add
- * any new dbrefs to it
- */
- DBRefEntry[] toRefs = map.getTo().getDBRefs();
- if (toRefs != null)
- {
- for (DBRefEntry ref : toRefs)
- {
- matched.addDBRef(ref); // add or update mapping
- }
- }
- map.setTo(matched);
+ // already called to import once, and most likely this sequence
+ // already imported !
+ continue;
}
- else
+ if (matched == null)
{
- if (dataset.findIndex(map.getTo()) == -1)
- {
- dataset.addSequence(map.getTo());
- matcher.add(map.getTo());
- }
+ /*
+ * 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
{
// 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(
- sourceSequence.getSequenceAsString()))
+ matched.getSequenceAsString()))
{
+ /*
+ * sequences were a match,
+ */
String msg = "Mapping updated from " + ms.getName()
+ " to retrieved crossreference "
- + sourceSequence.getName();
+ + matched.getName();
System.out.println(msg);
- map.setTo(sourceSequence);
+
+ DBRefEntry[] toRefs = map.getTo().getDBRefs();
+ if (toRefs != null)
+ {
+ /*
+ * transfer database refs
+ */
+ for (DBRefEntry ref : toRefs)
+ {
+ if (dbref.getSrcAccString().equals(
+ ref.getSrcAccString()))
+ {
+ continue; // avoid overwriting the ref on source sequence
+ }
+ matched.addDBRef(ref); // add or update mapping
+ }
+ }
+ doNotAdd.add(map.getTo());
+ map.setTo(matched);
/*
* give the reverse reference the inverse mapping
* (if it doesn't have one already)
*/
- setReverseMapping(sourceSequence, dbref, cf);
+ setReverseMapping(matched, dbref, cf);
/*
* copy sequence features as well, avoiding
* attribute in equality test; this avoids creating many
* otherwise duplicate exon features on genomic sequence
*/
- SequenceFeature newFeature = new SequenceFeature(
- feat)
+ SequenceFeature newFeature = new SequenceFeature(feat)
{
@Override
public boolean equals(Object o)
return super.equals(o, true);
}
};
- sourceSequence.addSequenceFeature(newFeature);
+ matched.addSequenceFeature(newFeature);
}
}
+
}
cf.addMap(retrievedSequence, map.getTo(), map.getMap());
} catch (Exception e)
}
}
}
- retrievedSequence.updatePDBIds();
+ 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)
{
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;
}
/**
MapList mapping = null;
SequenceI dsmapFrom = mapFrom.getDatasetSequence() == null ? mapFrom
: mapFrom.getDatasetSequence();
- SequenceI dsmapTo = mapTo.getDatasetSequence() == null ? mapTo
- : mapTo.getDatasetSequence();
+ SequenceI dsmapTo = mapTo.getDatasetSequence() == null ? mapTo : mapTo
+ .getDatasetSequence();
/*
* look for a reverse mapping, if found make its inverse.
* Note - we do this on dataset sequences only.