X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fext%2Fensembl%2FEnsemblGene.java;h=63a6a6ca7a0589f44034d89dfd5508087128686e;hb=990ed4ffbaa7a95b2ebb6bf6ab0440310f6e83ab;hp=919134ccb3e267b974c6135d7648666409f518eb;hpb=17ff1f476e009b3a3c7e892e416edc2a4af8a2bc;p=jalview.git diff --git a/src/jalview/ext/ensembl/EnsemblGene.java b/src/jalview/ext/ensembl/EnsemblGene.java index 919134c..63a6a6c 100644 --- a/src/jalview/ext/ensembl/EnsemblGene.java +++ b/src/jalview/ext/ensembl/EnsemblGene.java @@ -23,6 +23,8 @@ package jalview.ext.ensembl; import jalview.api.FeatureColourI; import jalview.api.FeatureSettingsModelI; import jalview.datamodel.AlignmentI; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.GeneLociI; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; @@ -32,6 +34,7 @@ import jalview.io.gff.SequenceOntologyI; import jalview.schemes.FeatureColour; import jalview.schemes.FeatureSettingsAdapter; import jalview.util.MapList; +import jalview.util.Platform; import java.awt.Color; import java.io.UnsupportedEncodingException; @@ -49,13 +52,11 @@ import com.stevesoft.pat.Regex; */ public class EnsemblGene extends EnsemblSeqProxy { - private static final String GENE_PREFIX = "gene:"; - /* * accepts anything as we will attempt lookup of gene or * transcript id or gene name */ - private static final Regex ACCESSION_REGEX = new Regex(".*"); + private static Regex ACCESSION_REGEX; private static final EnsemblFeatureType[] FEATURES_TO_FETCH = { EnsemblFeatureType.gene, EnsemblFeatureType.transcript, @@ -138,7 +139,6 @@ public class EnsemblGene extends EnsemblSeqProxy * convert to a non-duplicated list of gene identifiers */ List geneIds = getGeneIds(query); - AlignmentI al = null; for (String geneId : geneIds) { @@ -150,8 +150,12 @@ public class EnsemblGene extends EnsemblSeqProxy { continue; } + if (geneAlignment.getHeight() == 1) { + // ensure id has 'correct' case for the Ensembl identifier + geneId = geneAlignment.getSequenceAt(0).getName(); + findGeneLoci(geneAlignment.getSequenceAt(0), geneId); getTranscripts(geneAlignment, geneId); } if (al == null) @@ -167,6 +171,67 @@ public class EnsemblGene extends EnsemblSeqProxy } /** + * Calls the /lookup/id REST service, parses the response for gene + * coordinates, and if successful, adds these to the sequence. If this fails, + * fall back on trying to parse the sequence description in case it is in + * Ensembl-gene format e.g. chromosome:GRCh38:17:45051610:45109016:1. + * + * @param seq + * @param geneId + */ + void findGeneLoci(SequenceI seq, String geneId) + { + GeneLociI geneLoci = new EnsemblLookup(getDomain()).getGeneLoci(geneId); + if (geneLoci != null) + { + seq.setGeneLoci(geneLoci.getSpeciesId(), geneLoci.getAssemblyId(), + geneLoci.getChromosomeId(), geneLoci.getMap()); + } + else + { + parseChromosomeLocations(seq); + } + } + + /** + * Parses and saves fields of an Ensembl-style description e.g. + * chromosome:GRCh38:17:45051610:45109016:1 + * + * @param seq + */ + boolean parseChromosomeLocations(SequenceI seq) + { + String description = seq.getDescription(); + if (description == null) + { + return false; + } + String[] tokens = description.split(":"); + if (tokens.length == 6 && tokens[0].startsWith(DBRefEntry.CHROMOSOME)) + { + String ref = tokens[1]; + String chrom = tokens[2]; + try + { + int chStart = Integer.parseInt(tokens[3]); + int chEnd = Integer.parseInt(tokens[4]); + boolean forwardStrand = "1".equals(tokens[5]); + String species = ""; // not known here + int[] from = new int[] { seq.getStart(), seq.getEnd() }; + int[] to = new int[] { forwardStrand ? chStart : chEnd, + forwardStrand ? chEnd : chStart }; + MapList map = new MapList(from, to, 1, 1); + seq.setGeneLoci(species, ref, chrom, map); + return true; + } catch (NumberFormatException e) + { + System.err.println("Bad integers in description " + description); + } + } + return false; + } + + /** * Converts a query, which may contain one or more gene, transcript, or * external (to Ensembl) identifiers, into a non-redundant list of gene * identifiers. @@ -299,7 +364,7 @@ public class EnsemblGene extends EnsemblSeqProxy * look for exon features of the transcript, failing that for CDS * (for example ENSG00000124610 has 1 CDS but no exon features) */ - String parentId = "transcript:" + accId; + String parentId = accId; List splices = findFeatures(gene, SequenceOntologyI.EXON, parentId); if (splices.isEmpty()) @@ -330,7 +395,7 @@ public class EnsemblGene extends EnsemblSeqProxy * Ensembl has gene name as transcript Name * EnsemblGenomes doesn't, but has a url-encoded description field */ - String description = (String) transcriptFeature.getValue(NAME); + String description = transcriptFeature.getDescription(); if (description == null) { description = (String) transcriptFeature.getValue(DESCRIPTION); @@ -360,6 +425,8 @@ public class EnsemblGene extends EnsemblSeqProxy cdna.transferFeatures(gene.getFeatures().getPositionalFeatures(), transcript.getDatasetSequence(), mapping, parentId); + mapTranscriptToChromosome(transcript, gene, mapping); + /* * fetch and save cross-references */ @@ -374,6 +441,42 @@ public class EnsemblGene extends EnsemblSeqProxy } /** + * If the gene has a mapping to chromosome coordinates, derive the transcript + * chromosome regions and save on the transcript sequence + * + * @param transcript + * @param gene + * @param mapping + * the mapping from gene to transcript positions + */ + protected void mapTranscriptToChromosome(SequenceI transcript, + SequenceI gene, MapList mapping) + { + GeneLociI loci = gene.getGeneLoci(); + if (loci == null) + { + return; + } + + MapList geneMapping = loci.getMap(); + + List exons = mapping.getFromRanges(); + List transcriptLoci = new ArrayList<>(); + + for (int[] exon : exons) + { + transcriptLoci.add(geneMapping.locateInTo(exon[0], exon[1])); + } + + List transcriptRange = Arrays.asList(new int[] { + transcript.getStart(), transcript.getEnd() }); + MapList mapList = new MapList(transcriptRange, transcriptLoci, 1, 1); + + transcript.setGeneLoci(loci.getSpeciesId(), loci.getAssemblyId(), + loci.getChromosomeId(), mapList); + } + + /** * Returns the 'transcript_id' property of the sequence feature (or null) * * @param feature @@ -381,7 +484,7 @@ public class EnsemblGene extends EnsemblSeqProxy */ protected String getTranscriptId(SequenceFeature feature) { - return (String) feature.getValue("transcript_id"); + return (String) feature.getValue(JSON_ID); } /** @@ -403,7 +506,7 @@ public class EnsemblGene extends EnsemblSeqProxy { List transcriptFeatures = new ArrayList<>(); - String parentIdentifier = GENE_PREFIX + accId; + String parentIdentifier = accId; List sfs = geneSequence.getFeatures() .getFeaturesByOntology(SequenceOntologyI.TRANSCRIPT); @@ -413,7 +516,7 @@ public class EnsemblGene extends EnsemblSeqProxy for (SequenceFeature sf : sfs) { String parent = (String) sf.getValue(PARENT); - if (parentIdentifier.equals(parent)) + if (parentIdentifier.equalsIgnoreCase(parent)) { transcriptFeatures.add(sf); } @@ -434,30 +537,34 @@ public class EnsemblGene extends EnsemblSeqProxy @Override public String getTestQuery() { - return "ENSG00000157764"; // BRAF, 5 transcripts, reverse strand + return Platform.isJS() ? "ENSG00000123569" : "ENSG00000157764"; + // ENSG00000123569 // H2BFWT histone, 2 transcripts, reverse strand + // ENSG00000157764 // BRAF, 5 transcripts, reverse strand // ENSG00000090266 // NDUFB2, 15 transcripts, forward strand // ENSG00000101812 // H2BFM histone, 3 transcripts, forward strand - // ENSG00000123569 // H2BFWT histone, 2 transcripts, reverse strand } /** - * Answers true for a feature of type 'gene' (or a sub-type of gene in the - * Sequence Ontology), whose ID is the accession we are retrieving + * Answers a list of sequence features (if any) whose type is 'gene' (or a + * subtype of gene in the Sequence Ontology), and whose ID is the accession we + * are retrieving */ @Override - protected boolean identifiesSequence(SequenceFeature sf, String accId) + protected List getIdentifyingFeatures(SequenceI seq, + String accId) { - if (SequenceOntologyFactory.getInstance().isA(sf.getType(), - SequenceOntologyI.GENE)) + List result = new ArrayList<>(); + List sfs = seq.getFeatures() + .getFeaturesByOntology(SequenceOntologyI.GENE); + for (SequenceFeature sf : sfs) { - // NB features as gff use 'ID'; rest services return as 'id' - String id = (String) sf.getValue("ID"); - if ((GENE_PREFIX + accId).equals(id)) + String id = (String) sf.getValue(JSON_ID); + if (accId.equalsIgnoreCase(id)) { - return true; + result.add(sf); } } - return false; + return result; } /** @@ -470,7 +577,7 @@ public class EnsemblGene extends EnsemblSeqProxy @Override protected boolean retainFeature(SequenceFeature sf, String accessionId) { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = sf.getType(); if (so.isA(type, SequenceOntologyI.GENE)) { @@ -479,7 +586,7 @@ public class EnsemblGene extends EnsemblSeqProxy if (isTranscript(type)) { String parent = (String) sf.getValue(PARENT); - if (!(GENE_PREFIX + accessionId).equals(parent)) + if (!accessionId.equalsIgnoreCase(parent)) { return false; } @@ -488,17 +595,6 @@ public class EnsemblGene extends EnsemblSeqProxy } /** - * Answers false. This allows an optimisation - a single 'gene' feature is all - * that is needed to identify the positions of the gene on the genomic - * sequence. - */ - @Override - protected boolean isSpliceable() - { - return false; - } - - /** * Override to do nothing as Ensembl doesn't return a protein sequence for a * gene identifier */ @@ -510,6 +606,10 @@ public class EnsemblGene extends EnsemblSeqProxy @Override public Regex getAccessionValidator() { + if (ACCESSION_REGEX == null) + { + ACCESSION_REGEX = Platform.newRegex(".*", null); + } return ACCESSION_REGEX; } @@ -528,7 +628,7 @@ public class EnsemblGene extends EnsemblSeqProxy { return new FeatureSettingsAdapter() { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); @Override public boolean isFeatureDisplayed(String type)