check carefully that JAL-2885 (configurable Ensembl/Genomes Endpoints) functionality is still present
*
* @param cdsSeq
* @param contig
+ * @param proteinProduct
* @param mapping
- * @return list of DBRefEntrys added.
+ * @return list of DBRefEntrys added
*/
- public static List<DBRefEntry> propagateDBRefsToCDS(SequenceI cdsSeq,
+ protected static List<DBRefEntry> propagateDBRefsToCDS(SequenceI cdsSeq,
SequenceI contig, SequenceI proteinProduct, Mapping mapping)
{
+
- // gather direct refs from contig congrent with mapping
+ // gather direct refs from contig congruent with mapping
List<DBRefEntry> direct = new ArrayList<>();
HashSet<String> directSources = new HashSet<>();
++
if (contig.getDBRefs() != null)
{
for (DBRefEntry dbr : contig.getDBRefs())
List<SequenceI> proteinSeqs)
{
List<int[]> skip = new ArrayList<>();
- int skipint[] = null;
- ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring
- // intervals
- int vc;
- int[] scontigs = new int[contigs.length];
+ int[] skipint = null;
++
int npos = 0;
- for (vc = 0; vc < contigs.length; vc += 2)
- {
- if (vc == 0)
- {
- vismapping.addShift(npos, contigs[vc]);
- }
- else
- {
- // hidden region
- vismapping.addShift(npos, contigs[vc] - contigs[vc - 1] + 1);
- }
- scontigs[vc] = contigs[vc];
- scontigs[vc + 1] = contigs[vc + 1];
- }
+ int vc = 0;
+
+ int[] scontigs = new int[startcontigs.length];
+ System.arraycopy(startcontigs, 0, scontigs, 0, startcontigs.length);
// allocate a roughly sized buffer for the protein sequence
StringBuilder protein = new StringBuilder(seqstring.length() / 2);
package jalview.datamodel;
import jalview.datamodel.features.SequenceFeaturesI;
+import jalview.util.MapList;
import java.util.BitSet;
+ import java.util.Iterator;
import java.util.List;
import java.util.Vector;
public int replace(char c1, char c2);
/**
+ * Answers the GeneLociI, or null if not known
+ *
+ * @return
+ */
+ GeneLociI getGeneLoci();
+
+ /**
+ * Sets the mapping to gene loci for the sequence
+ *
+ * @param speciesId
+ * @param assemblyId
+ * @param chromosomeId
+ * @param map
+ */
+ void setGeneLoci(String speciesId, String assemblyId,
+ String chromosomeId, MapList map);
++
++
++ /**
+ * Returns the sequence string constructed from the substrings of a sequence
+ * defined by the int[] ranges provided by an iterator. E.g. the iterator
+ * could iterate over all visible regions of the alignment
+ *
+ * @param it
+ * the iterator to use
+ * @return a String corresponding to the sequence
+ */
+ public String getSequenceStringFromIterator(Iterator<int[]> it);
+
+ /**
+ * Locate the first position in this sequence which is not contained in an
+ * iterator region. If no such position exists, return 0
+ *
+ * @param it
+ * iterator over regions
+ * @return first residue not contained in regions
+ */
+ public int firstResidueOutsideIterator(Iterator<int[]> it);
}
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ 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.
- *
- * 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 <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
package jalview.ext.ensembl;
-/**
- * A data class to model the data and rest version of one Ensembl domain,
- * currently for rest.ensembl.org and rest.ensemblgenomes.org
- *
- * @author gmcarstairs
- */
-class EnsemblInfo
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.json.simple.JSONArray;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+public class EnsemblInfo extends EnsemblRestClient
{
- /*
- * The http domain this object is holding data values for
- */
- String domain;
/*
- * The latest version Jalview has tested for, e.g. "4.5"; a minor version change should be
- * ok, a major version change may break stuff
+ * cached results of REST /info/divisions service, currently
+ * <pre>
+ * {
+ * { "ENSEMBLFUNGI", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLBACTERIA", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLPROTISTS", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLMETAZOA", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLPLANTS", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBL", "http://rest.ensembl.org" }
+ * }
+ * </pre>
+ * The values for EnsemblGenomes are retrieved by a REST call, that for
+ * Ensembl is added programmatically for convenience of lookup
*/
- String expectedRestVersion;
+ private static Map<String, String> divisions;
- /*
- * Major / minor / point version e.g. "4.5.1"
- * @see http://rest.ensembl.org/info/rest/?content-type=application/json
- */
- String restVersion;
+ @Override
+ public String getDbName()
+ {
+ return "ENSEMBL";
+ }
- /*
- * data version
- * @see http://rest.ensembl.org/info/data/?content-type=application/json
- */
- String dataVersion;
+ @Override
+ public AlignmentI getSequenceRecords(String queries) throws Exception
+ {
+ return null;
+ }
- /*
- * true when http://rest.ensembl.org/info/ping/?content-type=application/json
- * returns response code 200 and not {"error":"Database is unavailable"}
+ @Override
+ protected URL getUrl(List<String> ids) throws MalformedURLException
+ {
+ return null;
+ }
+
+ @Override
+ protected boolean useGetRequest()
+ {
+ return true;
+ }
+
+ @Override
+ protected String getRequestMimeType(boolean multipleIds)
+ {
+ return "application/json";
+ }
+
+ @Override
+ protected String getResponseMimeType()
+ {
+ return "application/json";
+ }
+
+ /**
+ * Answers the domain (http://rest.ensembl.org or
+ * http://rest.ensemblgenomes.org) for the given division, or null if not
+ * recognised by Ensembl.
+ *
+ * @param division
+ * @return
*/
- boolean restAvailable;
+ public String getDomain(String division)
+ {
+ if (divisions == null)
+ {
+ fetchDivisions();
+ }
+ return divisions.get(division.toUpperCase());
+ }
- /*
- * absolute time when availability was last checked
+ /**
+ * On first request only, populate the lookup map by fetching the list of
+ * divisions known to EnsemblGenomes.
*/
- long lastAvailableCheckTime;
+ void fetchDivisions()
+ {
+ divisions = new HashMap<>();
- /*
- * absolute time when version numbers were last checked
+ /*
+ * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
+ */
- divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ENSEMBL_REST);
++ divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
+
+ BufferedReader br = null;
+ try
+ {
- URL url = getDivisionsUrl(ENSEMBL_GENOMES_REST);
++ URL url = getDivisionsUrl(ensemblGenomesDomain);
+ if (url != null)
+ {
+ br = getHttpResponse(url, null);
+ }
- parseResponse(br, ENSEMBL_GENOMES_REST);
++ parseResponse(br, ensemblGenomesDomain);
+ } catch (IOException e)
+ {
+ // ignore
+ } finally
+ {
+ if (br != null)
+ {
+ try
+ {
+ br.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses the JSON response to /info/divisions, and add each to the lookup map
+ *
+ * @param br
+ * @param domain
*/
- long lastVersionCheckTime;
+ void parseResponse(BufferedReader br, String domain)
+ {
+ JSONParser jp = new JSONParser();
+
+ try
+ {
+ JSONArray parsed = (JSONArray) jp.parse(br);
- // flag set to true if REST major version is not the one expected
- boolean restMajorVersionMismatch;
+ Iterator rvals = parsed.iterator();
+ while (rvals.hasNext())
+ {
+ String division = rvals.next().toString();
+ divisions.put(division.toUpperCase(), domain);
+ }
+ } catch (IOException | ParseException | NumberFormatException e)
+ {
+ // ignore
+ }
+ }
/**
- * Constructor given expected REST version number e.g 4.5 or 3.4.3
+ * Constructs the URL for the EnsemblGenomes /info/divisions REST service
+ * @param domain TODO
*
- * @param restExpected
+ * @return
+ * @throws MalformedURLException
*/
- EnsemblInfo(String theDomain, String restExpected)
+ URL getDivisionsUrl(String domain) throws MalformedURLException
{
- domain = theDomain;
- expectedRestVersion = restExpected;
- lastAvailableCheckTime = -1;
- lastVersionCheckTime = -1;
+ return new URL(domain
+ + "/info/divisions?content-type=application/json");
}
+ /**
+ * Returns the set of 'divisions' recognised by Ensembl or EnsemblGenomes
+ *
+ * @return
+ */
+ public Set<String> getDivisions() {
+ if (divisions == null)
+ {
+ fetchDivisions();
+ }
+
+ return divisions.keySet();
+ }
}
*/
public class EnsemblLookup extends EnsemblRestClient
{
-
+ private static final String SPECIES = "species";
+ private static final String OBJECT_TYPE_TRANSLATION = "Translation";
+ private static final String PARENT = "Parent";
+ private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+ private static final String ID = "id";
+ private static final String OBJECT_TYPE_GENE = "Gene";
+ private static final String OBJECT_TYPE = "object_type";
+
+ /**
+ * keep track of last identifier retrieved to break loops
+ */
+ private String lastId;
/**
* Default constructor (to use rest.ensembl.org)
static
{
+ domainData = new HashMap<>();
- domainData.put(ENSEMBL_REST,
- new EnsemblData(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION));
- domainData.put(ENSEMBL_GENOMES_REST, new EnsemblData(
- ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION));
+ domainData.put(DEFAULT_ENSEMBL_BASEURL,
- new EnsemblInfo(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION));
- domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL,
- new EnsemblInfo(
++ new EnsemblData(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION));
++ domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL, new EnsemblData(
+ DEFAULT_ENSEMBL_GENOMES_BASEURL, LATEST_ENSEMBLGENOMES_REST_VERSION));
}
protected volatile boolean inProgress = false;
*/
public EnsemblRestClient()
{
- this(ENSEMBL_REST);
+ super();
+
+ /*
+ * initialise domain info lazily
+ */
+ if (!domainData.containsKey(ensemblDomain))
+ {
+ domainData.put(ensemblDomain,
- new EnsemblInfo(ensemblDomain, LATEST_ENSEMBL_REST_VERSION));
++ new EnsemblData(ensemblDomain, LATEST_ENSEMBL_REST_VERSION));
+ }
+ if (!domainData.containsKey(ensemblGenomesDomain))
+ {
- domainData.put(ensemblGenomesDomain, new EnsemblInfo(
++ domainData.put(ensemblGenomesDomain, new EnsemblData(
+ ensemblGenomesDomain, LATEST_ENSEMBLGENOMES_REST_VERSION));
+ }
}
/**
List<DnaVariant> codon1Variants = new ArrayList<>();
List<DnaVariant> codon2Variants = new ArrayList<>();
List<DnaVariant> codon3Variants = new ArrayList<>();
++
List<DnaVariant> codonVariants[] = new ArrayList[3];
codonVariants[0] = codon1Variants;
codonVariants[1] = codon2Variants;
import jalview.bin.Jalview;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
++import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
*/
assertFalse(alignFrame.hideFeatureColumns("exon", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy().isEmpty());
++
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
++
assertFalse(alignFrame.hideFeatureColumns("exon", false));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy().isEmpty());
++
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
/*
* hiding a feature in all columns does nothing
*/
assertFalse(alignFrame.hideFeatureColumns("Metal", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- List<int[]> hidden = alignFrame.getViewport().getAlignment()
- .getHiddenColumns().getHiddenColumnsCopy();
- assertTrue(hidden.isEmpty());
++
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
+
+
+ /*
+ * threshold Metal to hide features where score < 5
+ * seq1 feature in columns 1-5 is hidden
+ * seq2 feature in columns 6-10 is shown
+ */
+ FeatureColourI fc = new FeatureColour(Color.red, Color.blue, 0f, 10f);
+ fc.setAboveThreshold(true);
+ fc.setThreshold(5f);
+ alignFrame.getFeatureRenderer().setColour("Metal", fc);
+ assertTrue(alignFrame.hideFeatureColumns("Metal", true));
- hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy();
- assertEquals(hidden.size(), 1);
- assertEquals(hidden.get(0)[0], 5);
- assertEquals(hidden.get(0)[1], 9);
++ HiddenColumns hidden = alignFrame.getViewport().getAlignment().getHiddenColumns();
++ assertEquals(hidden.getNumberOfRegions(), 1);
++ Iterator<int[]> regions = hidden.iterator();
++ int[] next = regions.next();
++ assertEquals(next[0], 5);
++ assertEquals(next[1], 9);
+
/*
* hide a feature present in some columns
* sequence positions [2-4], [7-9] are column positions
* [1-3], [6-8] base zero
*/
+ alignFrame.getViewport().showAllHiddenColumns();
assertTrue(alignFrame.hideFeatureColumns("Turn", true));
- hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy();
- assertEquals(hidden.size(), 2);
- assertEquals(hidden.get(0)[0], 1);
- assertEquals(hidden.get(0)[1], 3);
- assertEquals(hidden.get(1)[0], 6);
- assertEquals(hidden.get(1)[1], 8);
- Iterator<int[]> regions = alignFrame.getViewport().getAlignment()
++ regions = alignFrame.getViewport().getAlignment()
+ .getHiddenColumns().iterator();
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 2);
- int[] next = regions.next();
++ next = regions.next();
+ assertEquals(next[0], 1);
+ assertEquals(next[1], 3);
+ next = regions.next();
+ assertEquals(next[0], 6);
+ assertEquals(next[1], 8);
}
@BeforeClass(alwaysRun = true)
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
+ import jalview.datamodel.ColumnSelection;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
+ import jalview.datamodel.HiddenColumns;
+ import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+ import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.io.FileFormat;
import java.awt.Component;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
+ import java.util.Iterator;
import java.util.List;
import javax.swing.JMenu;
assertFalse(linkMenu.isEnabled());
}
+
+ /**
+ * Test for adding feature links
+ */
+ @Test(groups = { "Functional" })
+ public void testHideInsertions()
+ {
+ // get sequences from the alignment
+ List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+ // add our own seqs to avoid problems with changes to existing sequences
+ // (gap at end of sequences varies depending on how tests are run!)
+ Sequence seqGap1 = new Sequence("GappySeq",
+ "AAAA----AA-AAAAAAA---AAA-----------AAAAAAAAAA--");
+ seqGap1.createDatasetSequence();
+ seqs.add(seqGap1);
+ Sequence seqGap2 = new Sequence("LessGappySeq",
+ "AAAAAA-AAAAA---AAA--AAAAA--AAAAAAA-AAAAAA");
+ seqGap2.createDatasetSequence();
+ seqs.add(seqGap2);
+ Sequence seqGap3 = new Sequence("AnotherGapSeq",
+ "AAAAAA-AAAAAA--AAAAAA-AAAAAAAAAAA---AAAAAAAA");
+ seqGap3.createDatasetSequence();
+ seqs.add(seqGap3);
+ Sequence seqGap4 = new Sequence("NoGaps",
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ seqGap4.createDatasetSequence();
+ seqs.add(seqGap4);
+
+ ColumnSelection sel = new ColumnSelection();
+ parentPanel.av.getAlignment().getHiddenColumns()
+ .revealAllHiddenColumns(sel);
+
+ // get the Popup Menu for 7th sequence - no insertions
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(7), null);
++ testee = new PopupMenu(parentPanel, seqs.get(7), null);
+ testee.hideInsertions_actionPerformed(null);
+
+ HiddenColumns hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ Iterator<int[]> it = hidden.iterator();
+ assertFalse(it.hasNext());
+
+ // get the Popup Menu for GappySeq - this time we have insertions
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(4), null);
++ testee = new PopupMenu(parentPanel, seqs.get(4), null);
+ testee.hideInsertions_actionPerformed(null);
+ hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ it = hidden.iterator();
+
+ assertTrue(it.hasNext());
+ int[] region = it.next();
+ assertEquals(region[0], 4);
+ assertEquals(region[1], 7);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 10);
+ assertEquals(region[1], 10);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 18);
+ assertEquals(region[1], 20);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 24);
+ assertEquals(region[1], 34);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 45);
+ assertEquals(region[1], 46);
+
+ assertFalse(it.hasNext());
+
+ sel = new ColumnSelection();
+ hidden.revealAllHiddenColumns(sel);
+
+ // make a sequence group and hide insertions within the group
+ SequenceGroup sg = new SequenceGroup();
+ sg.setStartRes(8);
+ sg.setEndRes(42);
+ sg.addSequence(seqGap2, false);
+ sg.addSequence(seqGap3, false);
+ parentPanel.av.setSelectionGroup(sg);
+
+ // hide columns outside and within selection
+ // only hidden columns outside the collection will be retained (unless also
+ // gaps in the selection)
+ hidden.hideColumns(1, 10);
+ hidden.hideColumns(31, 40);
+
+ // get the Popup Menu for LessGappySeq in the sequence group
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(5), null);
++ testee = new PopupMenu(parentPanel, seqs.get(5), null);
+ testee.hideInsertions_actionPerformed(null);
+ hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ it = hidden.iterator();
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 1);
+ assertEquals(region[1], 7);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 13);
+ assertEquals(region[1], 14);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 34);
+ assertEquals(region[1], 34);
+ }
+
}