diff --git a/.gitignore b/.gitignore index 03a8d6d509..5a200e58dd 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ src/htsjdk.iml #japi-compliance-checker /compat_reports/ +/bin/ diff --git a/src/main/java/htsjdk/samtools/util/FileExtensions.java b/src/main/java/htsjdk/samtools/util/FileExtensions.java index 63e2cf4de6..91f0419b5c 100755 --- a/src/main/java/htsjdk/samtools/util/FileExtensions.java +++ b/src/main/java/htsjdk/samtools/util/FileExtensions.java @@ -81,4 +81,5 @@ public final class FileExtensions { public static final Set BLOCK_COMPRESSED = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(".gz", ".gzip", ".bgz", ".bgzf"))); public static final Set GFF3 = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(".gff3", ".gff", ".gff3.gz", ".gff.gz"))); + public static final Set GTF = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(".gtf", ".gtf.gz"))); } diff --git a/src/main/java/htsjdk/tribble/gff/AbstractGxxCodec.java b/src/main/java/htsjdk/tribble/gff/AbstractGxxCodec.java new file mode 100644 index 0000000000..0e65316ed3 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/AbstractGxxCodec.java @@ -0,0 +1,241 @@ +package htsjdk.tribble.gff; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.function.Predicate; + +import htsjdk.samtools.util.LocationAware; +import htsjdk.tribble.AbstractFeatureCodec; +import htsjdk.tribble.Feature; +import htsjdk.tribble.FeatureCodecHeader; +import htsjdk.tribble.TribbleException; +import htsjdk.tribble.annotation.Strand; +import htsjdk.tribble.index.tabix.TabixFormat; +import htsjdk.tribble.readers.AsciiLineReader; +import htsjdk.tribble.readers.AsciiLineReaderIterator; +import htsjdk.tribble.readers.LineIterator; +import htsjdk.tribble.readers.LineIteratorImpl; +import htsjdk.tribble.readers.SynchronousLineReader; +import htsjdk.tribble.util.ParsingUtils; + +/** + * Abstract Base Codec for parsing Gff3 files or GTF codec + */ +public abstract class AbstractGxxCodec extends AbstractFeatureCodec { + + protected static final int NUM_FIELDS = 9; + + protected static final int CHROMOSOME_NAME_INDEX = 0; + protected static final int ANNOTATION_SOURCE_INDEX = 1; + protected static final int FEATURE_TYPE_INDEX = 2; + protected static final int START_LOCATION_INDEX = 3; + protected static final int END_LOCATION_INDEX = 4; + protected static final int SCORE_INDEX = 5; + protected static final int GENOMIC_STRAND_INDEX = 6; + protected static final int GENOMIC_PHASE_INDEX = 7; + protected static final int EXTRA_FIELDS_INDEX = 8; + + + protected final Queue activeFeatures = new ArrayDeque<>(); + protected final Queue featuresToFlush = new ArrayDeque<>(); + protected final Map commentsWithLineNumbers = new LinkedHashMap<>(); + + + protected DecodeDepth decodeDepth; + + protected int currentLine = 0; + + /** filter to removing keys from the EXTRA_FIELDS column */ + protected final Predicate filterOutAttribute; + + + + /** + * @param decodeDepth a value from DecodeDepth + * @param filterOutAttribute filter to remove keys from the EXTRA_FIELDS column + */ + protected AbstractGxxCodec(final DecodeDepth decodeDepth, + final Predicate filterOutAttribute) { + super(Gff3Feature.class); + this.decodeDepth = decodeDepth; + this.filterOutAttribute = filterOutAttribute; + } + + + public enum DecodeDepth { + DEEP, SHALLOW + } + + @Override + public final Gff3Feature decode(final LineIterator lineIterator) throws IOException { + return decode(lineIterator, decodeDepth); + } + + protected abstract Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth depth) + throws IOException; + + + + /** + * Parse attributes field for gff3 feature + * + * @param attributesString attributes field string from line in gff3 file + * @return map of keys to values for attributes of this feature + * @throws UnsupportedEncodingException + */ + protected abstract Map> parseAttributesColumn( + final String attributesString) throws UnsupportedEncodingException; + + + protected final Gff3BaseData parseLine(final String line, final int currentLine, + final Predicate filterOutAttribute) { + final List splitLine = + ParsingUtils.split(line, AbstractGxxConstants.FIELD_DELIMITER); + + if (splitLine.size() != NUM_FIELDS) { + throw new TribbleException( + "Found an invalid number of columns in the given Gff3/GTF file at line + " + + currentLine + " - Given: " + splitLine.size() + " Expected: " + + NUM_FIELDS + " : " + line); + } + + try { + final String contig = URLDecoder.decode(splitLine.get(CHROMOSOME_NAME_INDEX), "UTF-8"); + final String source = + URLDecoder.decode(splitLine.get(ANNOTATION_SOURCE_INDEX), "UTF-8"); + final String type = URLDecoder.decode(splitLine.get(FEATURE_TYPE_INDEX), "UTF-8"); + final int start = Integer.parseInt(splitLine.get(START_LOCATION_INDEX)); + final int end = Integer.parseInt(splitLine.get(END_LOCATION_INDEX)); + final double score = + splitLine.get(SCORE_INDEX).equals(AbstractGxxConstants.UNDEFINED_FIELD_VALUE) + ? -1 + : Double.parseDouble(splitLine.get(SCORE_INDEX)); + final int phase = splitLine.get(GENOMIC_PHASE_INDEX) + .equals(AbstractGxxConstants.UNDEFINED_FIELD_VALUE) ? -1 + : Integer.parseInt(splitLine.get(GENOMIC_PHASE_INDEX)); + final Strand strand = Strand.decode(splitLine.get(GENOMIC_STRAND_INDEX)); + final Map> attributes = + parseAttributesColumn(splitLine.get(EXTRA_FIELDS_INDEX)); + /* remove attibutes matching 'filterOutAttribute' */ + attributes.keySet().removeIf(filterOutAttribute); + return new Gff3BaseData(contig, source, type, start, end, score, strand, phase, + attributes); + } catch (final NumberFormatException ex) { + throw new TribbleException("Cannot read integer value for start/end position from line " + + currentLine + ". Line is: " + line, ex); + } catch (final IOException ex) { + throw new TribbleException( + "Cannot decode feature info from line " + currentLine + ". Line is: " + line, + ex); + } + } + + /** + * Gets map from line number to comment found on that line. The text of the comment EXCLUDES the + * leading # which indicates a comment line. + * + * @return Map from line number to comment found on line + */ + public final Map getCommentsWithLineNumbers() { + return Collections.unmodifiableMap(new LinkedHashMap<>(commentsWithLineNumbers)); + } + + /** + * Gets list of comments parsed by the codec. Excludes leading # which indicates a comment line. + * + * @return + */ + public final List getCommentTexts() { + return Collections.unmodifiableList(new ArrayList<>(commentsWithLineNumbers.values())); + } + + @Override + public final Feature decodeLoc(LineIterator lineIterator) throws IOException { + return decode(lineIterator, DecodeDepth.SHALLOW); + } + + @Override + public abstract boolean canDecode(final String inputFilePath); + + protected boolean canDecodeFirstLine(final String line) { + // make sure line conforms to gtf spec + final List fields = ParsingUtils.split(line, AbstractGxxConstants.FIELD_DELIMITER); + + if (fields.size() != NUM_FIELDS) + return false;; + + // check that start and end fields are integers + try { + /* final int start = */ Integer.parseInt(fields.get(3)); + /* final int end = */ Integer.parseInt(fields.get(4)); + } catch (NumberFormatException | NullPointerException nfe) { + return false; + } + + // check for strand + final String strand = fields.get(GENOMIC_STRAND_INDEX); + return strand.equals(Strand.POSITIVE.toString()) + || strand.equals(Strand.NEGATIVE.toString()) + || strand.equals(Strand.NONE.toString()) || strand.equals("?"); + } + + static String extractSingleAttribute(final List values) { + if (values == null || values.isEmpty()) { + return null; + } + + if (values.size() != 1) { + throw new TribbleException("Attribute has multiple values when only one expected"); + } + return values.get(0); + } + + @Override + public final FeatureCodecHeader readHeader(LineIterator lineIterator) { + + List header = new ArrayList<>(); + while (lineIterator.hasNext()) { + String line = lineIterator.peek(); + if (line.startsWith(Gff3Constants.COMMENT_START)) { + header.add(line); + lineIterator.next(); + } else { + break; + } + } + + return new FeatureCodecHeader(header, FeatureCodecHeader.NO_HEADER_END); + } + + @Override + public final LineIterator makeSourceFromStream(final InputStream bufferedInputStream) { + return new LineIteratorImpl(new SynchronousLineReader(bufferedInputStream)); + } + + @Override + public final LocationAware makeIndexableSourceFromStream( + final InputStream bufferedInputStream) { + return new AsciiLineReaderIterator(AsciiLineReader.from(bufferedInputStream)); + } + + @Override + public abstract boolean isDone(final LineIterator lineIterator); + + @Override + public abstract void close(final LineIterator lineIterator); + + @Override + public final TabixFormat getTabixFormat() { + return TabixFormat.GFF; + } + +} diff --git a/src/main/java/htsjdk/tribble/gff/AbstractGxxConstants.java b/src/main/java/htsjdk/tribble/gff/AbstractGxxConstants.java new file mode 100644 index 0000000000..c4938e05e9 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/AbstractGxxConstants.java @@ -0,0 +1,13 @@ +package htsjdk.tribble.gff; + +/** + * Common constants shared by GtfCodec and Gff3Codec + */ +public class AbstractGxxConstants { + public static final char ATTRIBUTE_DELIMITER = ';'; + public static final char FIELD_DELIMITER = '\t'; + public static final String COMMENT_START = "#"; + public static final String DIRECTIVE_START = "##"; + public static final String UNDEFINED_FIELD_VALUE = "."; + public final static char END_OF_LINE_CHARACTER = '\n'; +} \ No newline at end of file diff --git a/src/main/java/htsjdk/tribble/gff/AbstractGxxWriter.java b/src/main/java/htsjdk/tribble/gff/AbstractGxxWriter.java new file mode 100644 index 0000000000..7e565de783 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/AbstractGxxWriter.java @@ -0,0 +1,155 @@ +package htsjdk.tribble.gff; + +import htsjdk.samtools.util.BlockCompressedOutputStream; +import htsjdk.samtools.util.FileExtensions; +import htsjdk.samtools.util.IOUtil; +import htsjdk.tribble.TribbleException; + +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + + +/** + * A class to write out gff3/gtf files. Features are added using {@link #addFeature(Gff3Feature)}, + * directives using {@link #addDirective(Gff3Codec.Gff3Directive)}, and comments using + * {@link #addComment(String)}. Note that the version 3 directive is automatically added at + * creation, so should not be added separately. + */ +public abstract class AbstractGxxWriter implements Closeable { + + protected final OutputStream out; + + protected AbstractGxxWriter(final Path path, final Set fileExtensions) + throws IOException { + if (fileExtensions.stream().noneMatch(e -> path.toString().endsWith(e))) { + throw new TribbleException( + "File " + path + " does not have extension consistent with gff3/gtf"); + } + + final OutputStream outputStream = + IOUtil.hasGzipFileExtension(path) ? new BlockCompressedOutputStream(path.toFile()) + : Files.newOutputStream(path); + out = new BufferedOutputStream(outputStream); + } + + protected AbstractGxxWriter(final OutputStream stream) { + out = stream; + } + + protected final void writeWithNewLine(final String txt) throws IOException { + out.write(txt.getBytes()); + out.write(AbstractGxxConstants.END_OF_LINE_CHARACTER); + } + + protected final void tryToWrite(final String string) { + try { + out.write(string.getBytes()); + } catch (final IOException ex) { + throw new TribbleException("Error writing out string " + string, ex); + } + } + + protected final void writeFirstEightFields(final Gff3Feature feature) throws IOException { + writeJoinedByDelimiter(AbstractGxxConstants.FIELD_DELIMITER, this::tryToWrite, + Arrays.asList(escapeString(feature.getContig()), escapeString(feature.getSource()), + escapeString(feature.getType()), Integer.toString(feature.getStart()), + Integer.toString(feature.getEnd()), + feature.getScore() < 0 ? AbstractGxxConstants.UNDEFINED_FIELD_VALUE + : Double.toString(feature.getScore()), + feature.getStrand().toString(), + feature.getPhase() < 0 ? AbstractGxxConstants.UNDEFINED_FIELD_VALUE + : Integer.toString(feature.getPhase()))); + } + + protected abstract void writeAttributes(final Map> attributes) + throws IOException; + + protected final void writeJoinedByDelimiter(final char delimiter, + final Consumer consumer, final Collection fields) throws IOException { + boolean isNotFirstField = false; + for (final T field : fields) { + if (isNotFirstField) { + out.write(delimiter); + } else { + isNotFirstField = true; + } + + consumer.accept(field); + } + } + + /*** + * add a feature + * + * @param feature the feature to be added + * @throws IOException + */ + public void addFeature(final Gff3Feature feature) throws IOException { + writeFirstEightFields(feature); + out.write(AbstractGxxConstants.FIELD_DELIMITER); + writeAttributes(feature.getAttributes()); + out.write(AbstractGxxConstants.END_OF_LINE_CHARACTER); + } + + /*** + * escape a String. Default behavior is to call {@link #encodeString(String)} + * + * @param s the string to be escaped + * @return the escaped string + */ + protected String escapeString(final String s) { + return encodeString(s); + } + + static String encodeString(final String s) { + try { + // URLEncoder.encode is hardcoded to change all spaces to +, but we want spaces left + // unchanged so have to do this + // + is escaped to %2B, so no loss of information + return URLEncoder.encode(s, "UTF-8").replace("+", " "); + } catch (final UnsupportedEncodingException ex) { + throw new TribbleException("Encoding failure", ex); + } + } + + /** + * Add comment line + * + * @param comment the comment line (not including leading #) + * @throws IOException + */ + public final void addComment(final String comment) throws IOException { + out.write(AbstractGxxConstants.COMMENT_START.getBytes()); + writeWithNewLine(comment); + } + + @Override + public final void close() throws IOException { + out.close(); + } + + /** opens a writer as a Gff3Writer or as a GtfWriter using the path suffix */ + public static AbstractGxxWriter openWithFileExtension(final Path path) throws IOException { + if (FileExtensions.GFF3.stream().anyMatch(e -> path.toString().endsWith(e))) { + return new Gff3Writer(path); + } else if (FileExtensions.GTF.stream().anyMatch(e -> path.toString().endsWith(e))) { + return new GtfWriter(path); + } else { + throw new IllegalArgumentException( + path.toString() + " doesn't have a gtf or a gff3 suffix"); + } + } + +} diff --git a/src/main/java/htsjdk/tribble/gff/Gff3BaseData.java b/src/main/java/htsjdk/tribble/gff/Gff3BaseData.java index 8d35978860..ffe02d1594 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3BaseData.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3BaseData.java @@ -26,8 +26,8 @@ public class Gff3BaseData implements Locatable { private final int hashCode; public Gff3BaseData(final String contig, final String source, final String type, - final int start, final int end, final Double score, final Strand strand, final int phase, - final Map> attributes) { + final int start, final int end, final Double score, final Strand strand, + final int phase, final Map> attributes) { this.contig = contig; this.source = source; this.type = type; @@ -38,16 +38,20 @@ public Gff3BaseData(final String contig, final String source, final String type, this.strand = strand; this.attributes = copyAttributesSafely(attributes); this.id = Gff3Codec.extractSingleAttribute(attributes.get(Gff3Constants.ID_ATTRIBUTE_KEY)); - this.name = Gff3Codec.extractSingleAttribute(attributes.get(Gff3Constants.NAME_ATTRIBUTE_KEY)); - this.aliases = attributes.getOrDefault(Gff3Constants.ALIAS_ATTRIBUTE_KEY, Collections.emptyList()); + this.name = + Gff3Codec.extractSingleAttribute(attributes.get(Gff3Constants.NAME_ATTRIBUTE_KEY)); + this.aliases = + attributes.getOrDefault(Gff3Constants.ALIAS_ATTRIBUTE_KEY, Collections.emptyList()); this.hashCode = computeHashCode(); } - private static Map> copyAttributesSafely(final Map> attributes) { + private static Map> copyAttributesSafely( + final Map> attributes) { final Map> modifiableDeepMap = new LinkedHashMap<>(); for (final Map.Entry> entry : attributes.entrySet()) { - final List unmodifiableDeepList = Collections.unmodifiableList(new ArrayList<>(entry.getValue())); + final List unmodifiableDeepList = + Collections.unmodifiableList(new ArrayList<>(entry.getValue())); modifiableDeepMap.put(entry.getKey(), unmodifiableDeepList); } @@ -59,20 +63,19 @@ public boolean equals(Object other) { if (other == this) { return true; } - if(!other.getClass().equals(Gff3BaseData.class)) { + if (!other.getClass().equals(Gff3BaseData.class)) { return false; } final Gff3BaseData otherBaseData = (Gff3BaseData) other; - boolean ret = otherBaseData.getContig().equals(getContig()) && - otherBaseData.getSource().equals(getSource()) && - otherBaseData.getType().equals(getType()) && - otherBaseData.getStart() == getStart() && - otherBaseData.getEnd() == getEnd() && - ((Double)otherBaseData.getScore()).equals(score) && - otherBaseData.getPhase() == getPhase() && - otherBaseData.getStrand().equals(getStrand()) && - otherBaseData.getAttributes().equals(getAttributes()); + boolean ret = otherBaseData.getContig().equals(getContig()) + && otherBaseData.getSource().equals(getSource()) + && otherBaseData.getType().equals(getType()) + && otherBaseData.getStart() == getStart() && otherBaseData.getEnd() == getEnd() + && ((Double) otherBaseData.getScore()).equals(score) + && otherBaseData.getPhase() == getPhase() + && otherBaseData.getStrand().equals(getStrand()) + && otherBaseData.getAttributes().equals(getAttributes()); if (getId() == null) { ret = ret && otherBaseData.getId() == null; } else { @@ -82,7 +85,8 @@ public boolean equals(Object other) { if (getName() == null) { ret = ret && otherBaseData.getName() == null; } else { - ret = ret && otherBaseData.getName() != null && otherBaseData.getName().equals(getName()); + ret = ret && otherBaseData.getName() != null + && otherBaseData.getName().equals(getName()); } ret = ret && otherBaseData.getAliases().equals(getAliases()); @@ -157,8 +161,9 @@ public Map> getAttributes() { return attributes; } - /** - * get the values as List for the key, or an empty list if this key is not present + /** + * get the values as List for the key, or an empty list if this key is not + * present * * @param key key whose presence in this map is to be tested * @return the values as List, or an empty list if this key is not present @@ -176,26 +181,33 @@ public List getAttribute(final String key) { public boolean hasAttribute(final String key) { return attributes.containsKey(key); } - + /** - * Most attributes in a GFF file are present just one time in a line, e.g. : gene_biotype, gene_name, etc ... - * This function returns an Optional.empty if the key is not present, - * an Optional.of(value) if there is only one value associated to the key, - * or it throws an IllegalArgumentException if there is more than one value. + * Most attributes in a GFF file are present just one time in a line, e.g. : + * gene_biotype, gene_name, etc ... This function returns an + * Optional.empty if the key is not present, an Optional.of(value) if + * there is only one value associated to the key, or it throws an + * IllegalArgumentException if there is more than one value. * * @param key key whose presence in the attributes is to be tested - * @return Optional<String> if this map contains zero or one attribute for the specified key + * @return Optional<String> if this map contains zero or one attribute for the + * specified key * @throws IllegalArgumentException if there is more than one value */ public Optional getUniqueAttribute(final String key) { final List atts = getAttribute(key); - switch(atts.size()) { - case 0 : return Optional.empty(); - case 1 : return Optional.of(atts.get(0)); - default : throw new IllegalArgumentException("getUniqueAttribute cannot be called with key="+key+" because it contains more than one value " + String.join(", ", atts)); + switch (atts.size()) { + case 0: + return Optional.empty(); + case 1: + return Optional.of(atts.get(0)); + default: + throw new IllegalArgumentException("getUniqueAttribute cannot be called with key=" + + key + " because it contains more than one value " + + String.join(", ", atts)); } } - + public String getId() { return id; } @@ -207,4 +219,11 @@ public String getName() { public List getAliases() { return aliases; } + + @Override + public String toString() { + return "Gff3BaseData [contig=" + contig + ", source=" + source + ", type=" + type + + ", start=" + start + ", end=" + end + ", score=" + score + ", strand=" + strand + + ", phase=" + phase + ", attributes=" + attributes + "]"; + } } diff --git a/src/main/java/htsjdk/tribble/gff/Gff3Codec.java b/src/main/java/htsjdk/tribble/gff/Gff3Codec.java index 6bf5be284c..5a211bcf81 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3Codec.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3Codec.java @@ -1,80 +1,63 @@ package htsjdk.tribble.gff; -import htsjdk.samtools.util.CloserUtil; -import htsjdk.samtools.util.FileExtensions; -import htsjdk.samtools.util.IOUtil; -import htsjdk.samtools.util.LocationAware; - -import htsjdk.samtools.util.Log; -import htsjdk.tribble.AbstractFeatureCodec; -import htsjdk.tribble.Feature; -import htsjdk.tribble.FeatureCodecHeader; -import htsjdk.tribble.TribbleException; -import htsjdk.tribble.annotation.Strand; -import htsjdk.tribble.index.tabix.TabixFormat; -import htsjdk.tribble.readers.*; -import htsjdk.tribble.util.ParsingUtils; - - - -import java.io.*; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import htsjdk.samtools.util.CloserUtil; +import htsjdk.samtools.util.FileExtensions; +import htsjdk.samtools.util.IOUtil; +import htsjdk.samtools.util.Log; +import htsjdk.tribble.TribbleException; +import htsjdk.tribble.readers.LineIterator; +import htsjdk.tribble.util.ParsingUtils; + /** - * Codec for parsing Gff3 files, as defined in https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md - * Note that while spec states that all feature types must be defined in sequence ontology, this implementation makes no check on feature types, and allows any string as feature type + * Codec for parsing Gff3 files, as defined in + * https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md + * Note that while spec states that all feature types must be defined in sequence ontology, this + * implementation makes no check on feature types, and allows any string as feature type * - * Each feature line in the Gff3 file will be emitted as a separate feature. Features linked together through the "Parent" attribute will be linked through {@link Gff3Feature#getParents()}, {@link Gff3Feature#getChildren()}, - * {@link Gff3Feature#getAncestors()}, {@link Gff3Feature#getDescendents()}, amd {@link Gff3Feature#flatten()}. This linking is not guaranteed to be comprehensive when the file is read for only features overlapping a particular - * region, using a tribble index. In this case, a particular feature will only be linked to the subgroup of features it is linked to in the input file which overlap the given region. + * Each feature line in the Gff3 file will be emitted as a separate feature. Features linked + * together through the "Parent" attribute will be linked through {@link Gff3Feature#getParents()}, + * {@link Gff3Feature#getChildren()}, {@link Gff3Feature#getAncestors()}, + * {@link Gff3Feature#getDescendents()}, amd {@link Gff3Feature#flatten()}. This linking is not + * guaranteed to be comprehensive when the file is read for only features overlapping a particular + * region, using a tribble index. In this case, a particular feature will only be linked to the + * subgroup of features it is linked to in the input file which overlap the given region. */ -public class Gff3Codec extends AbstractFeatureCodec { - - - - private static final int NUM_FIELDS = 9; - - private static final int CHROMOSOME_NAME_INDEX = 0; - private static final int ANNOTATION_SOURCE_INDEX = 1; - private static final int FEATURE_TYPE_INDEX = 2; - private static final int START_LOCATION_INDEX = 3; - private static final int END_LOCATION_INDEX = 4; - private static final int SCORE_INDEX = 5; - private static final int GENOMIC_STRAND_INDEX = 6; - private static final int GENOMIC_PHASE_INDEX = 7; - private static final int EXTRA_FIELDS_INDEX = 8; - +public class Gff3Codec extends AbstractGxxCodec { private static final String IS_CIRCULAR_ATTRIBUTE_KEY = "Is_circular"; private static final String ARTEMIS_FASTA_MARKER = ">"; - private final Queue activeFeatures = new ArrayDeque<>(); - private final Queue featuresToFlush = new ArrayDeque<>(); private final Map> activeFeaturesWithIDs = new HashMap<>(); private final Map> activeParentIDs = new HashMap<>(); - private final Map sequenceRegionMap = new LinkedHashMap<>(); - private final Map commentsWithLineNumbers = new LinkedHashMap<>(); private final static Log logger = Log.getInstance(Gff3Codec.class); private boolean reachedFasta = false; - private DecodeDepth decodeDepth; - - private int currentLine = 0; - - /** filter to removing keys from the EXTRA_FIELDS column */ - private final Predicate filterOutAttribute; - public Gff3Codec() { this(DecodeDepth.DEEP); } @@ -85,39 +68,32 @@ public Gff3Codec(final DecodeDepth decodeDepth) { /** * @param decodeDepth a value from DecodeDepth - * @param filterOutAttribute filter to remove keys from the EXTRA_FIELDS column + * @param filterOutAttribute filter to remove keys from the EXTRA_FIELDS column */ public Gff3Codec(final DecodeDepth decodeDepth, final Predicate filterOutAttribute) { - super(Gff3Feature.class); - this.decodeDepth = decodeDepth; - this.filterOutAttribute = filterOutAttribute; + super(decodeDepth, filterOutAttribute); /* check required keys are always kept */ - for (final String key : new String[] {Gff3Constants.PARENT_ATTRIBUTE_KEY, Gff3Constants.ID_ATTRIBUTE_KEY, Gff3Constants.NAME_ATTRIBUTE_KEY}) { + for (final String key : new String[] {Gff3Constants.PARENT_ATTRIBUTE_KEY, + Gff3Constants.ID_ATTRIBUTE_KEY, Gff3Constants.NAME_ATTRIBUTE_KEY}) { if (filterOutAttribute.test(key)) { throw new IllegalArgumentException("Predicate should always accept " + key); - } + } } } - public enum DecodeDepth { - DEEP , - SHALLOW - } - @Override - public Gff3Feature decode(final LineIterator lineIterator) throws IOException { - return decode(lineIterator, decodeDepth); - } - - private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth depth) throws IOException { + protected Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth depth) + throws IOException { currentLine++; /* - Basic strategy: Load features into deque, create maps from a features ID to it, and from a features parents' IDs to it. For each feature, link to parents using these maps. - When reaching flush directive, fasta, or end of file, prepare to flush features by moving all active features to deque of features to flush, and clearing - list of active features and both maps. Always poll featuresToFlush to return any completed top level features. + * Basic strategy: Load features into deque, create maps from a features ID to it, and from + * a features parents' IDs to it. For each feature, link to parents using these maps. When + * reaching flush directive, fasta, or end of file, prepare to flush features by moving all + * active features to deque of features to flush, and clearing list of active features and + * both maps. Always poll featuresToFlush to return any completed top level features. */ if (!lineIterator.hasNext()) { - //no more lines, flush whatever is active + // no more lines, flush whatever is active prepareToFlushFeatures(); return featuresToFlush.poll(); } @@ -125,19 +101,21 @@ private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth de final String line = lineIterator.next(); if (reachedFasta) { - //previously reached fasta, flush whatever is active + // previously reached fasta, flush whatever is active prepareToFlushFeatures(); return featuresToFlush.poll(); } if (line.startsWith(ARTEMIS_FASTA_MARKER)) { - //backwards compatability with Artemis is built into gff3 spec + // backwards compatability with Artemis is built into gff3 spec processDirective(Gff3Directive.FASTA_DIRECTIVE, null); return featuresToFlush.poll(); } - if (line.startsWith(Gff3Constants.COMMENT_START) && !line.startsWith(Gff3Constants.DIRECTIVE_START)) { - commentsWithLineNumbers.put(currentLine, line.substring(Gff3Constants.COMMENT_START.length())); + if (line.startsWith(Gff3Constants.COMMENT_START) + && !line.startsWith(Gff3Constants.DIRECTIVE_START)) { + commentsWithLineNumbers.put(currentLine, + line.substring(Gff3Constants.COMMENT_START.length())); return featuresToFlush.poll(); } @@ -147,12 +125,13 @@ private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth de } - - final Gff3FeatureImpl thisFeature = new Gff3FeatureImpl(parseLine(line, currentLine, this.filterOutAttribute)); + final Gff3FeatureImpl thisFeature = + new Gff3FeatureImpl(parseLine(line, currentLine, super.filterOutAttribute)); activeFeatures.add(thisFeature); if (depth == DecodeDepth.DEEP) { - //link to parents/children/co-features - final List parentIDs = thisFeature.getAttribute(Gff3Constants.PARENT_ATTRIBUTE_KEY); + // link to parents/children/co-features + final List parentIDs = + thisFeature.getAttribute(Gff3Constants.PARENT_ATTRIBUTE_KEY); final String id = thisFeature.getID(); for (final String parentID : parentIDs) { @@ -166,7 +145,8 @@ private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth de if (activeParentIDs.containsKey(parentID)) { activeParentIDs.get(parentID).add(thisFeature); } else { - activeParentIDs.put(parentID, new HashSet<>(Collections.singleton(thisFeature))); + activeParentIDs.put(parentID, + new HashSet<>(Collections.singleton(thisFeature))); } } @@ -177,7 +157,8 @@ private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth de } activeFeaturesWithIDs.get(id).add(thisFeature); } else { - activeFeaturesWithIDs.put(id, new HashSet<>(Collections.singleton(thisFeature))); + activeFeaturesWithIDs.put(id, + new HashSet<>(Collections.singleton(thisFeature))); } } @@ -190,179 +171,124 @@ private Gff3Feature decode(final LineIterator lineIterator, final DecodeDepth de validateFeature(thisFeature); if (depth == DecodeDepth.SHALLOW) { - //flush all features immediatly + // flush all features immediatly prepareToFlushFeatures(); } return featuresToFlush.poll(); } + @Override + protected Map> parseAttributesColumn(String attributesString) + throws UnsupportedEncodingException { + return parseAttributes(attributesString); + } /** * Parse attributes field for gff3 feature + * * @param attributesString attributes field string from line in gff3 file * @return map of keys to values for attributes of this feature * @throws UnsupportedEncodingException */ - static private Map> parseAttributes(final String attributesString) throws UnsupportedEncodingException { + static private Map> parseAttributes(final String attributesString) + throws UnsupportedEncodingException { if (attributesString.equals(Gff3Constants.UNDEFINED_FIELD_VALUE)) { return Collections.emptyMap(); } final Map> attributes = new LinkedHashMap<>(); - final List splitLine = ParsingUtils.split(attributesString,Gff3Constants.ATTRIBUTE_DELIMITER); - for(String attribute : splitLine) { - final List key_value = ParsingUtils.split(attribute,Gff3Constants.KEY_VALUE_SEPARATOR); + final List splitLine = + ParsingUtils.split(attributesString, Gff3Constants.ATTRIBUTE_DELIMITER); + for (String attribute : splitLine) { + final List key_value = + ParsingUtils.split(attribute, Gff3Constants.KEY_VALUE_SEPARATOR); if (key_value.size() != 2) { throw new TribbleException("Attribute string " + attributesString + " is invalid"); } - attributes.put(URLDecoder.decode(key_value.get(0).trim(), "UTF-8"), decodeAttributeValue(key_value.get(1).trim())); + attributes.put(URLDecoder.decode(key_value.get(0).trim(), "UTF-8"), + decodeAttributeValue(key_value.get(1).trim())); } return attributes; } - private static Gff3BaseData parseLine(final String line, final int currentLine, final Predicate filterOutAttribute) { - final List splitLine = ParsingUtils.split(line, Gff3Constants.FIELD_DELIMITER); - - if (splitLine.size() != NUM_FIELDS) { - throw new TribbleException("Found an invalid number of columns in the given Gff3 file at line + " + currentLine + " - Given: " + splitLine.size() + " Expected: " + NUM_FIELDS + " : " + line); - } - - try { - final String contig = URLDecoder.decode(splitLine.get(CHROMOSOME_NAME_INDEX), "UTF-8"); - final String source = URLDecoder.decode(splitLine.get(ANNOTATION_SOURCE_INDEX), "UTF-8"); - final String type = URLDecoder.decode(splitLine.get(FEATURE_TYPE_INDEX), "UTF-8"); - final int start = Integer.parseInt(splitLine.get(START_LOCATION_INDEX)); - final int end = Integer.parseInt(splitLine.get(END_LOCATION_INDEX)); - final double score = splitLine.get(SCORE_INDEX).equals(Gff3Constants.UNDEFINED_FIELD_VALUE) ? -1 : Double.parseDouble(splitLine.get(SCORE_INDEX)); - final int phase = splitLine.get(GENOMIC_PHASE_INDEX).equals(Gff3Constants.UNDEFINED_FIELD_VALUE) ? -1 : Integer.parseInt(splitLine.get(GENOMIC_PHASE_INDEX)); - final Strand strand = Strand.decode(splitLine.get(GENOMIC_STRAND_INDEX)); - final Map> attributes = parseAttributes(splitLine.get(EXTRA_FIELDS_INDEX)); - /* remove attibutes matching 'filterOutAttribute' */ - attributes.keySet().removeIf(filterOutAttribute); - return new Gff3BaseData(contig, source, type, start, end, score, strand, phase, attributes); - } catch (final NumberFormatException ex ) { - throw new TribbleException("Cannot read integer value for start/end position from line " + currentLine + ". Line is: " + line, ex); - } catch (final IOException ex) { - throw new TribbleException("Cannot decode feature info from line " + currentLine + ". Line is: " + line, ex); - } - } - /** * Get list of sequence regions parsed by the codec. + * * @return list of sequence regions */ public List getSequenceRegions() { return Collections.unmodifiableList(new ArrayList<>(sequenceRegionMap.values())); } - /** - * Gets map from line number to comment found on that line. The text of the comment EXCLUDES the leading # which indicates a comment line. - * @return Map from line number to comment found on line - */ - public Map getCommentsWithLineNumbers() { - return Collections.unmodifiableMap(new LinkedHashMap<>(commentsWithLineNumbers)); - } - - /** - * Gets list of comments parsed by the codec. Excludes leading # which indicates a comment line. - * @return - */ - public List getCommentTexts() { - return Collections.unmodifiableList(new ArrayList<>(commentsWithLineNumbers.values())); - } /** - * If sequence region of feature's contig has been specified with sequence region directive, validates that - * feature's coordinates are within the specified sequence region. TribbleException is thrown if invalid. + * If sequence region of feature's contig has been specified with sequence region directive, + * validates that feature's coordinates are within the specified sequence region. + * TribbleException is thrown if invalid. + * * @param feature */ private void validateFeature(final Gff3Feature feature) { if (sequenceRegionMap.containsKey(feature.getContig())) { final SequenceRegion region = sequenceRegionMap.get(feature.getContig()); if (feature.getStart() == region.getStart() && feature.getEnd() == region.getEnd()) { - //landmark feature - final boolean isCircular = Boolean.parseBoolean(extractSingleAttribute(feature.getAttribute(IS_CIRCULAR_ATTRIBUTE_KEY))); + // landmark feature + final boolean isCircular = Boolean.parseBoolean( + extractSingleAttribute(feature.getAttribute(IS_CIRCULAR_ATTRIBUTE_KEY))); region.setCircular(isCircular); } - if (region.isCircular()? !region.overlaps(feature) : !region.contains(feature)) { - throw new TribbleException("feature at " + feature.getContig() + ":" + feature.getStart() + "-" + feature.getEnd() + - " not contained in specified sequence region (" + region.getContig() + ":" + region.getStart() + "-" + region.getEnd()); + if (region.isCircular() ? !region.overlaps(feature) : !region.contains(feature)) { + throw new TribbleException("feature at " + feature.getContig() + ":" + + feature.getStart() + "-" + feature.getEnd() + + " not contained in specified sequence region (" + region.getContig() + ":" + + region.getStart() + "-" + region.getEnd()); } } } - @Override - public Feature decodeLoc(LineIterator lineIterator) throws IOException { - return decode(lineIterator, DecodeDepth.SHALLOW); - } @Override public boolean canDecode(final String inputFilePath) { - boolean canDecode; try { // Simple file and name checks to start with: Path p = IOUtil.getPath(inputFilePath); - canDecode = FileExtensions.GFF3.stream().anyMatch(fe -> p.toString().endsWith(fe)); - - if (canDecode) { + if (!FileExtensions.GFF3.stream().anyMatch(fe -> p.toString().endsWith(fe))) { + return false; + } - // Crack open the file and look at the top of it: - final InputStream inputStream = IOUtil.hasGzipFileExtension(p)? new GZIPInputStream(Files.newInputStream(p)) : Files.newInputStream(p); + // Crack open the file and look at the top of it: + final InputStream inputStream = + IOUtil.hasGzipFileExtension(p) ? new GZIPInputStream(Files.newInputStream(p)) + : Files.newInputStream(p); - try ( BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)) ) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { - String line = br.readLine(); + String line = br.readLine(); - // First line must be GFF version directive - if (Gff3Directive.toDirective(line) != Gff3Directive.VERSION3_DIRECTIVE) { + // First line must be GFF version directive + if (Gff3Directive.toDirective(line) != Gff3Directive.VERSION3_DIRECTIVE) { + return false; + } + while (line.startsWith(Gff3Constants.COMMENT_START)) { + line = br.readLine(); + if (line == null) { return false; } - while (line.startsWith(Gff3Constants.COMMENT_START)) { - line = br.readLine(); - if ( line == null ) { - return false; - } - } - - // make sure line conforms to gtf spec - final List fields = ParsingUtils.split(line, Gff3Constants.FIELD_DELIMITER); - - canDecode &= fields.size() == NUM_FIELDS; - - if (canDecode) { - // check that start and end fields are integers - try { - final int start = Integer.parseInt(fields.get(3)); - final int end = Integer.parseInt(fields.get(4)); - } catch (NumberFormatException | NullPointerException nfe) { - return false; - } - - // check for strand - - final String strand = fields.get(GENOMIC_STRAND_INDEX); - canDecode &= strand.equals(Strand.POSITIVE.toString()) || - strand.equals(Strand.NEGATIVE.toString()) || - strand.equals(Strand.NONE.toString()) || - strand.equals("?"); - } } + return canDecodeFirstLine(line); } - } - catch (FileNotFoundException ex) { + } catch (final FileNotFoundException ex) { logger.error(inputFilePath + " not found."); return false; - } - catch (final IOException ex) { + } catch (final IOException ex) { return false; } - - return canDecode; } static List decodeAttributeValue(final String attributeValue) { - //split on VALUE_DELIMITER, then decode - final List splitValues = ParsingUtils.split(attributeValue, Gff3Constants.VALUE_DELIMITER); + // split on VALUE_DELIMITER, then decode + final List splitValues = + ParsingUtils.split(attributeValue, Gff3Constants.VALUE_DELIMITER); final List decodedValues = new ArrayList<>(); for (final String encodedValue : splitValues) { @@ -387,25 +313,10 @@ static String extractSingleAttribute(final List values) { return values.get(0); } - @Override - public FeatureCodecHeader readHeader(LineIterator lineIterator) { - - List header = new ArrayList<>(); - while(lineIterator.hasNext()) { - String line = lineIterator.peek(); - if (line.startsWith(Gff3Constants.COMMENT_START)) { - header.add(line); - lineIterator.next(); - } else { - break; - } - } - - return new FeatureCodecHeader(header, FeatureCodecHeader.NO_HEADER_END); - } /** * Parse a directive line from a gff3 file + * * @param directiveLine * @throws IOException */ @@ -421,6 +332,7 @@ private void parseDirective(final String directiveLine) throws IOException { /** * Process a gff3 directive + * * @param directive the gff3 directive, indicated by a specific directive line * @param decodedResult the decoding of the directive line by the given directive */ @@ -432,7 +344,8 @@ private void processDirective(final Gff3Directive directive, final Object decode case SEQUENCE_REGION_DIRECTIVE: final SequenceRegion newRegion = (SequenceRegion) decodedResult; if (sequenceRegionMap.containsKey(newRegion.getContig())) { - throw new TribbleException("directive for sequence-region " + newRegion.getContig() + " included more than once."); + throw new TribbleException("directive for sequence-region " + + newRegion.getContig() + " included more than once."); } sequenceRegionMap.put(newRegion.getContig(), newRegion); break; @@ -446,13 +359,14 @@ private void processDirective(final Gff3Directive directive, final Object decode break; default: - throw new IllegalArgumentException( "Directive " + directive + " has been added to Gff3Directive, but is not being handled by Gff3Codec::processDirective. This is a BUG."); + throw new IllegalArgumentException("Directive " + directive + + " has been added to Gff3Directive, but is not being handled by Gff3Codec::processDirective. This is a BUG."); } } /** - * move active top level features to featuresToFlush. clear active features. + * move active top level features to featuresToFlush. clear active features. */ private void prepareToFlushFeatures() { featuresToFlush.addAll(activeFeatures); @@ -461,15 +375,6 @@ private void prepareToFlushFeatures() { activeParentIDs.clear(); } - @Override - public LineIterator makeSourceFromStream(final InputStream bufferedInputStream) { - return new LineIteratorImpl(new SynchronousLineReader(bufferedInputStream)); - } - - @Override - public LocationAware makeIndexableSourceFromStream(final InputStream bufferedInputStream) { - return new AsciiLineReaderIterator(AsciiLineReader.from(bufferedInputStream)); - } @Override public boolean isDone(final LineIterator lineIterator) { @@ -478,7 +383,7 @@ public boolean isDone(final LineIterator lineIterator) { @Override public void close(final LineIterator lineIterator) { - //cleanup resources + // cleanup resources featuresToFlush.clear(); activeFeaturesWithIDs.clear(); activeFeatures.clear(); @@ -486,19 +391,15 @@ public void close(final LineIterator lineIterator) { CloserUtil.close(lineIterator); } - @Override - public TabixFormat getTabixFormat() { - return TabixFormat.GFF; - } - /** - * Enum for parsing directive lines. If information in directive line needs to be parsed beyond specifying directive type, decode method should be overriden + * Enum for parsing directive lines. If information in directive line needs to be parsed beyond + * specifying directive type, decode method should be overriden */ public enum Gff3Directive { VERSION3_DIRECTIVE("##gff-version\\s+3(?:\\.\\d*)*$") { @Override - protected Object decode(final String line) throws IOException { + protected Object decode(final String line) throws IOException { final String[] splitLine = line.split("\\s+"); return splitLine[1]; } @@ -509,12 +410,14 @@ String encode(final Object object) { throw new TribbleException("Cannot encode null in VERSION3_DIRECTIVE"); } if (!(object instanceof String)) { - throw new TribbleException("Cannot encode object of type " + object.getClass() + " in VERSION3_DIRECTIVE"); + throw new TribbleException("Cannot encode object of type " + object.getClass() + + " in VERSION3_DIRECTIVE"); } - final String versionLine = "##gff-version " + (String)object; + final String versionLine = "##gff-version " + (String) object; if (!regexPattern.matcher(versionLine).matches()) { - throw new TribbleException("Version " + (String)object + " is not a valid version"); + throw new TribbleException( + "Version " + (String) object + " is not a valid version"); } return versionLine; @@ -525,6 +428,7 @@ String encode(final Object object) { final private int CONTIG_INDEX = 1; final private int START_INDEX = 2; final private int END_INDEX = 3; + @Override protected Object decode(final String line) throws IOException { final String[] splitLine = line.split("\\s+"); @@ -540,11 +444,13 @@ String encode(final Object object) { throw new TribbleException("Cannot encode null in SEQUENCE_REGION_DIRECTIVE"); } if (!(object instanceof SequenceRegion)) { - throw new TribbleException("Cannot encode object of type " + object.getClass() + " in SEQUENCE_REGION_DIRECTIVE"); + throw new TribbleException("Cannot encode object of type " + object.getClass() + + " in SEQUENCE_REGION_DIRECTIVE"); } final SequenceRegion sequenceRegion = (SequenceRegion) object; - return "##sequence-region " + Gff3Writer.encodeString(sequenceRegion.getContig()) + " " + sequenceRegion.getStart() + " " + sequenceRegion.getEnd(); + return "##sequence-region " + Gff3Writer.encodeString(sequenceRegion.getContig()) + + " " + sequenceRegion.getStart() + " " + sequenceRegion.getEnd(); } }, @@ -570,7 +476,7 @@ String encode(final Object object) { public static Gff3Directive toDirective(final String line) { for (final Gff3Directive directive : Gff3Directive.values()) { - if(directive.regexPattern.matcher(line).matches()) { + if (directive.regexPattern.matcher(line).matches()) { return directive; } } @@ -583,5 +489,4 @@ protected Object decode(final String line) throws IOException { abstract String encode(final Object object); } - } diff --git a/src/main/java/htsjdk/tribble/gff/Gff3Constants.java b/src/main/java/htsjdk/tribble/gff/Gff3Constants.java index fa49b78be8..a55eb7046e 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3Constants.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3Constants.java @@ -1,16 +1,10 @@ package htsjdk.tribble.gff; -public class Gff3Constants { - public static final char FIELD_DELIMITER = '\t'; - public static final char ATTRIBUTE_DELIMITER = ';'; - public static final char KEY_VALUE_SEPARATOR = '='; - public static final char VALUE_DELIMITER = ','; - public static final String COMMENT_START = "#"; - public static final String DIRECTIVE_START = "##"; - public static final String UNDEFINED_FIELD_VALUE = "."; - public static final String PARENT_ATTRIBUTE_KEY = "Parent"; - public final static char END_OF_LINE_CHARACTER = '\n'; - public static final String ID_ATTRIBUTE_KEY = "ID"; - public static final String NAME_ATTRIBUTE_KEY = "Name"; - public static final String ALIAS_ATTRIBUTE_KEY = "Alias"; +public class Gff3Constants extends AbstractGxxConstants { + public static final char KEY_VALUE_SEPARATOR = '='; + public static final char VALUE_DELIMITER = ','; + public static final String PARENT_ATTRIBUTE_KEY = "Parent"; + public static final String ID_ATTRIBUTE_KEY = "ID"; + public static final String NAME_ATTRIBUTE_KEY = "Name"; + public static final String ALIAS_ATTRIBUTE_KEY = "Alias"; } diff --git a/src/main/java/htsjdk/tribble/gff/Gff3Feature.java b/src/main/java/htsjdk/tribble/gff/Gff3Feature.java index 37a879a5b9..3850a49f69 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3Feature.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3Feature.java @@ -9,13 +9,18 @@ import java.util.Set; /** - * Gff3 format spec is defined at https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md - * Discontinuous features which are split between multiple lines in the gff files are implemented as separate features linked as "co-features" + * Gff3 format spec is defined at + * https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md + * Discontinuous features which are split between multiple lines in the gff files are implemented as + * separate features linked as "co-features". + * + * This interface is also used for GTF */ public interface Gff3Feature extends Feature { /** - * Get the set of top level features from which this feature is descended. - * Top level features are features with no linked parents + * Get the set of top level features from which this feature is descended. Top level features + * are features with no linked parents + * * @return set of top level feature from which this feature is descended */ Set getTopLevelFeatures(); @@ -40,14 +45,16 @@ default int getPhase() { return getBaseData().getPhase(); } - default String getType() {return getBaseData().getType();} + default String getType() { + return getBaseData().getType(); + } @Override default String getContig() { return getBaseData().getContig(); } - @Override + @Override default int getStart() { return getBaseData().getStart(); } @@ -56,7 +63,7 @@ default int getStart() { default List getAttribute(final String key) { return getBaseData().getAttribute(key); } - + /** * Returns true if this record contains an attribute for the specified key. * @@ -68,70 +75,93 @@ default boolean hasAttribute(final String key) { } /** - * Most attributes in a GFF file are present just one time in a line, e.g. : gene_biotype, gene_name, etc ... - * This function returns an Optional.empty if the key is not present, - * an Optional.of(value) if there is only one value associated to the key, - * or it throws an IllegalArgumentException if there is more than one value. + * Most attributes in a GFF file are present just one time in a line, e.g. : + * gene_biotype, gene_name, etc ... This function returns an + * Optional.empty if the key is not present, an Optional.of(value) if + * there is only one value associated to the key, or it throws an + * IllegalArgumentException if there is more than one value. * * @param key key whose presence in the attributes is to be tested - * @return Optional<String> if this map contains zero or one attribute for the specified key + * @return Optional<String> if this map contains zero or one attribute for the + * specified key * @throws IllegalArgumentException if there is more than one value. */ default Optional getUniqueAttribute(final String key) { - return getBaseData().getUniqueAttribute(key); + return getBaseData().getUniqueAttribute(key); } - - default Map> getAttributes() { return getBaseData().getAttributes();} - default String getID() { return getBaseData().getId();} + default Map> getAttributes() { + return getBaseData().getAttributes(); + } - default String getName() { return getBaseData().getName();} + default String getID() { + return getBaseData().getId(); + } - default List getAliases() { return getBaseData().getAliases();} + default String getName() { + return getBaseData().getName(); + } - default double getScore() { return getBaseData().getScore();} + default List getAliases() { + return getBaseData().getAliases(); + } + + default double getScore() { + return getBaseData().getScore(); + } /** * Get BaseData object which contains all the basic information of the feature + * * @return */ Gff3BaseData getBaseData(); /** * Gets set of parent features + * * @return set of parent features */ Set getParents(); /** * Gets set of features for which this feature is a parent + * * @return set of child features */ Set getChildren(); /** - * Get set of all features this feature descends from, through chains of Parent attributes. If Derives_From exists for this feature, - * then only features along the inheritance path specified by the Derives_From attribute should be included as ancestors of this feature + * Get set of all features this feature descends from, through chains of Parent attributes. If + * Derives_From exists for this feature, then only features along the inheritance path specified + * by the Derives_From attribute should be included as ancestors of this feature + * * @return set of ancestor features */ Set getAncestors(); /** - * Get set of all features descended from this features, through chains of Parent attributes. If Derives_From attribute exists for a feature, - * it should only be included as a descendent of this feature if the inheritance path specified by its Derives_From attribute includes this feature + * Get set of all features descended from this features, through chains of Parent attributes. If + * Derives_From attribute exists for a feature, it should only be included as a descendent of + * this feature if the inheritance path specified by its Derives_From attribute includes this + * feature + * * @return set of descendents */ Set getDescendents(); /** - * Get set of co-features. Co-features correspond to the other lines in the gff file that together make up a single discontinuous feature + * Get set of co-features. Co-features correspond to the other lines in the gff file that + * together make up a single discontinuous feature + * * @return set of co-features */ Set getCoFeatures(); /*** - * Flatten this feature and all descendents into a set of features. The Derives_From attribute is respected if it exists - * for this feature + * Flatten this feature and all descendents into a set of features. The Derives_From attribute + * is respected if it exists for this feature + * * @return set of this feature and all descendents */ Set flatten(); diff --git a/src/main/java/htsjdk/tribble/gff/Gff3FeatureImpl.java b/src/main/java/htsjdk/tribble/gff/Gff3FeatureImpl.java index 9ac33360fa..fe54521bc1 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3FeatureImpl.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3FeatureImpl.java @@ -8,8 +8,10 @@ import java.util.stream.Collectors; /** - * Gff3 format spec is defined at https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md - * Discontinuous features which are split between multiple lines in the gff files are implemented as separate features linked as "co-features" + * Gff3 format spec is defined at + * https://github.com/The-Sequence-Ontology/Specifications/blob/31f62ad469b31769b43af42e0903448db1826925/gff3.md + * Discontinuous features which are split between multiple lines in the gff files are implemented as + * separate features linked as "co-features" */ public class Gff3FeatureImpl implements Gff3Feature { private final static String DERIVES_FROM_ATTRIBUTE_KEY = "Derives_from"; @@ -24,15 +26,16 @@ public class Gff3FeatureImpl implements Gff3Feature { private final LinkedHashSet coFeatures = new LinkedHashSet<>(); /** - * top level features are features with no parents. Each feature maintains a list - * of its top level features, from which it and all related features descend. + * top level features are features with no parents. Each feature maintains a list of its top + * level features, from which it and all related features descend. */ private final Set topLevelFeatures = new HashSet<>(); public Gff3FeatureImpl(final String contig, final String source, final String type, - final int start, final int end, final Double score, final Strand strand, final int phase, - final Map> attributes) { - baseData = new Gff3BaseData(contig, source, type, start, end, score, strand, phase, attributes); + final int start, final int end, final Double score, final Strand strand, + final int phase, final Map> attributes) { + baseData = new Gff3BaseData(contig, source, type, start, end, score, strand, phase, + attributes); } @@ -42,6 +45,7 @@ public Gff3FeatureImpl(final Gff3BaseData baseData) { /** * Get the set of top level features from which this feature is descended + * * @return set of top level feature from which this feature is descended */ @Override @@ -59,17 +63,23 @@ public boolean isTopLevelFeature() { /** * Gets set of parent features + * * @return set of parent features */ @Override - public Set getParents() {return parents;} + public Set getParents() { + return parents; + } /** * Gets set of features for which this feature is a parent + * * @return set of child features */ @Override - public Set getChildren() {return children;} + public Set getChildren() { + return children; + } @Override public Gff3BaseData getBaseData() { @@ -77,14 +87,20 @@ public Gff3BaseData getBaseData() { } /** - * Get set of all features this feature descends from, through chains of Parent attributes. Derives_From can be used to specify a particular inheritance path for this feature when multiple paths are available + * Get set of all features this feature descends from, through chains of Parent attributes. + * Derives_From can be used to specify a particular inheritance path for this feature when + * multiple paths are available + * * @return set of ancestor features */ @Override public Set getAncestors() { final List ancestors = new ArrayList<>(parents); for (final Gff3FeatureImpl parent : parents) { - ancestors.addAll(getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).isEmpty()? parent.getAncestors() : parent.getAncestors(new HashSet<>(baseData.getAttributes().get(DERIVES_FROM_ATTRIBUTE_KEY)))); + ancestors.addAll( + getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).isEmpty() ? parent.getAncestors() + : parent.getAncestors(new HashSet<>( + baseData.getAttributes().get(DERIVES_FROM_ATTRIBUTE_KEY)))); } return new LinkedHashSet<>(ancestors); } @@ -92,7 +108,8 @@ public Set getAncestors() { private Set getAncestors(final Collection derivingFrom) { final List ancestors = new ArrayList<>(); for (final Gff3FeatureImpl parent : parents) { - if (derivingFrom.contains(parent.getID()) || parent.getAncestors().stream().anyMatch(f -> derivingFrom.contains(f.getID()))) { + if (derivingFrom.contains(parent.getID()) || parent.getAncestors().stream() + .anyMatch(f -> derivingFrom.contains(f.getID()))) { ancestors.add(parent); ancestors.addAll(parent.getAncestors()); } @@ -101,7 +118,10 @@ private Set getAncestors(final Collection derivingFrom) } /** - * Get set of all features descended from this features, through chains of Parent attributes. Derives_From can be used to specify a particular inheritance path for this feature when multiple paths are available + * Get set of all features descended from this features, through chains of Parent attributes. + * Derives_From can be used to specify a particular inheritance path for this feature when + * multiple paths are available + * * @return set of descendents */ @Override @@ -109,20 +129,22 @@ public Set getDescendents() { final List descendants = new ArrayList<>(children); final Set idsInLineage = new HashSet<>(Collections.singleton(baseData.getId())); idsInLineage.addAll(children.stream().map(Gff3Feature::getID).collect(Collectors.toSet())); - for(final Gff3FeatureImpl child : children) { + for (final Gff3FeatureImpl child : children) { descendants.addAll(child.getDescendents(idsInLineage)); } return new LinkedHashSet<>(descendants); } private Set getDescendents(final Set idsInLineage) { - final List childrenToAdd = children.stream().filter(c -> c.getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).isEmpty() || - !Collections.disjoint(idsInLineage, c.getAttribute(DERIVES_FROM_ATTRIBUTE_KEY))). - collect(Collectors.toList()); + final List childrenToAdd = children.stream() + .filter(c -> c.getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).isEmpty() || !Collections + .disjoint(idsInLineage, c.getAttribute(DERIVES_FROM_ATTRIBUTE_KEY))) + .collect(Collectors.toList()); final List descendants = new ArrayList<>(childrenToAdd); final Set updatedIdsInLineage = new HashSet<>(idsInLineage); - updatedIdsInLineage.addAll(childrenToAdd.stream().map(Gff3Feature::getID).collect(Collectors.toSet())); + updatedIdsInLineage + .addAll(childrenToAdd.stream().map(Gff3Feature::getID).collect(Collectors.toSet())); for (final Gff3FeatureImpl child : childrenToAdd) { descendants.addAll(child.getDescendents(updatedIdsInLineage)); } @@ -130,26 +152,40 @@ private Set getDescendents(final Set idsInLineage) { } /** - * Get set of co-features. Co-features correspond to the other lines in the gff file that together make up a single discontinuous feature + * Get set of co-features. Co-features correspond to the other lines in the gff file that + * together make up a single discontinuous feature + * * @return set of co-features */ @Override - public Set getCoFeatures() {return coFeatures;} + public Set getCoFeatures() { + return coFeatures; + } @Override - public boolean hasParents() {return !parents.isEmpty();} + public boolean hasParents() { + return !parents.isEmpty(); + } @Override - public boolean hasChildren() {return !children.isEmpty();} + public boolean hasChildren() { + return !children.isEmpty(); + } @Override - public boolean hasCoFeatures() {return !coFeatures.isEmpty();} + public boolean hasCoFeatures() { + return !coFeatures.isEmpty(); + } public void addParent(final Gff3FeatureImpl parent) { - final Set topLevelFeaturesToAdd = new HashSet<>(parent.getTopLevelFeatures()); + final Set topLevelFeaturesToAdd = + new HashSet<>(parent.getTopLevelFeatures()); if (!getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).isEmpty()) { - topLevelFeaturesToAdd.removeIf(f -> !getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).contains(f.getID()) && f.getDescendents().stream().noneMatch(f2 -> f2.getID()!= null && getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).contains(f2.getID()))); + topLevelFeaturesToAdd.removeIf(f -> !getAttribute(DERIVES_FROM_ATTRIBUTE_KEY) + .contains(f.getID()) + && f.getDescendents().stream().noneMatch(f2 -> f2.getID() != null + && getAttribute(DERIVES_FROM_ATTRIBUTE_KEY).contains(f2.getID()))); } parents.add(parent); parent.addChild(this); @@ -164,7 +200,7 @@ private void addChild(final Gff3FeatureImpl child) { private void addTopLevelFeatures(final Collection topLevelFeaturesToAdd) { topLevelFeatures.addAll(topLevelFeaturesToAdd); - //pass topLevelFeature change through to children + // pass topLevelFeature change through to children for (final Gff3FeatureImpl child : children) { child.addTopLevelFeatures(topLevelFeaturesToAdd); child.removeTopLevelFeature(this); @@ -180,15 +216,18 @@ private void removeTopLevelFeature(final Gff3FeatureImpl topLevelFeatureToRemove } /** - * Add a feature as a coFeature of this feature. When this method is called, the input coFeature will also be - * added as a coFeature of all the other coFeatures of this object, and this feature and all coFeatures will be - * added as coFeatures of the input coFeature. All coFeatures must have equal IDs and parents. + * Add a feature as a coFeature of this feature. When this method is called, the input coFeature + * will also be added as a coFeature of all the other coFeatures of this object, and this + * feature and all coFeatures will be added as coFeatures of the input coFeature. All coFeatures + * must have equal IDs and parents. + * * @param coFeature feature to add as this features coFeature */ public void addCoFeature(final Gff3FeatureImpl coFeature) { if (!parents.equals(coFeature.getParents())) { - throw new TribbleException("Co-features " + baseData.getId() + " do not have same parents"); + throw new TribbleException( + "Co-features " + baseData.getId() + " do not have same parents"); } for (final Gff3FeatureImpl feature : coFeatures) { feature.addCoFeatureShallow(coFeature); @@ -201,7 +240,8 @@ public void addCoFeature(final Gff3FeatureImpl coFeature) { private void addCoFeatureShallow(final Gff3FeatureImpl coFeature) { coFeatures.add(coFeature); if (!coFeature.getID().equals(baseData.getId())) { - throw new TribbleException("Attempting to add co-feature with id " + coFeature.getID() + " to feature with id " + baseData.getId()); + throw new TribbleException("Attempting to add co-feature with id " + coFeature.getID() + + " to feature with id " + baseData.getId()); } } @@ -213,38 +253,41 @@ public boolean equals(Object other) { if (!(other instanceof Gff3Feature)) { return false; } - /* to test for equality, the doubly linked list representation used to represent feature relationships is replaced with a graph representation. - equality for between two features is tested by testing equality between their base data fields, and equality between the graphs they are part of. + /* + * to test for equality, the doubly linked list representation used to represent feature + * relationships is replaced with a graph representation. equality for between two features + * is tested by testing equality between their base data fields, and equality between the + * graphs they are part of. */ - return baseData.equals(((Gff3Feature) other).getBaseData()) && - new Gff3Graph(this).equals(new Gff3Graph((Gff3Feature) other)); + return baseData.equals(((Gff3Feature) other).getBaseData()) + && new Gff3Graph(this).equals(new Gff3Graph((Gff3Feature) other)); } @Override public int hashCode() { - //hash only based on baseData, to keep immutable. + // hash only based on baseData, to keep immutable. return baseData.hashCode(); } - - /*** * flatten this feature and all descendents into a set of features + * * @return set of this feature and all descendents */ @Override public Set flatten() { - final LinkedHashSet features = new LinkedHashSet<>(Collections.singleton(this)); + final LinkedHashSet features = + new LinkedHashSet<>(Collections.singleton(this)); features.addAll(this.getDescendents()); return features; } /** - * Class for graph representation of relationships between features. - * Used for testing equality between features + * Class for graph representation of relationships between features. Used for testing equality + * between features */ private static class Gff3Graph { final private Set nodes = new HashSet<>(); @@ -253,7 +296,8 @@ private static class Gff3Graph { final private Set> coFeatureSets = new HashSet<>(); Gff3Graph(final Gff3Feature feature) { - feature.getTopLevelFeatures().stream().flatMap(f -> f.flatten().stream()).forEach(this::addFeature); + feature.getTopLevelFeatures().stream().flatMap(f -> f.flatten().stream()) + .forEach(this::addFeature); } private void addFeature(final Gff3Feature feature) { @@ -268,20 +312,21 @@ private void addNode(final Gff3Feature feature) { } private void addParentEdges(final Gff3Feature feature) { - for(final Gff3Feature parent : feature.getParents()) { + for (final Gff3Feature parent : feature.getParents()) { parentEdges.add(new Tuple<>(feature.getBaseData(), parent.getBaseData())); } } private void addChildEdges(final Gff3Feature feature) { - for(final Gff3Feature child : feature.getChildren()) { + for (final Gff3Feature child : feature.getChildren()) { childEdges.add(new Tuple<>(feature.getBaseData(), child.getBaseData())); } } private void addCoFeatureSet(final Gff3Feature feature) { if (feature.hasCoFeatures()) { - final Set coFeaturesBaseData = feature.getCoFeatures().stream().map(Gff3Feature::getBaseData).collect(Collectors.toSet()); + final Set coFeaturesBaseData = feature.getCoFeatures().stream() + .map(Gff3Feature::getBaseData).collect(Collectors.toSet()); coFeaturesBaseData.add(feature.getBaseData()); coFeatureSets.add(coFeaturesBaseData); } @@ -296,10 +341,10 @@ public boolean equals(Object other) { return false; } - return nodes.equals(((Gff3Graph) other).nodes) && - parentEdges.equals(((Gff3Graph) other).parentEdges) && - childEdges.equals(((Gff3Graph) other).childEdges) && - coFeatureSets.equals(((Gff3Graph) other).coFeatureSets); + return nodes.equals(((Gff3Graph) other).nodes) + && parentEdges.equals(((Gff3Graph) other).parentEdges) + && childEdges.equals(((Gff3Graph) other).childEdges) + && coFeatureSets.equals(((Gff3Graph) other).coFeatureSets); } @Override @@ -313,4 +358,10 @@ public int hashCode() { } } -} \ No newline at end of file + @Override + public String toString() { + return "Gff3FeatureImpl [baseData=" + baseData + " , parents:" + this.parents.size() + + " , children:" + this.children.size() + "]"; + } + +} diff --git a/src/main/java/htsjdk/tribble/gff/Gff3Writer.java b/src/main/java/htsjdk/tribble/gff/Gff3Writer.java index 0cee78ce73..4ce7581982 100644 --- a/src/main/java/htsjdk/tribble/gff/Gff3Writer.java +++ b/src/main/java/htsjdk/tribble/gff/Gff3Writer.java @@ -1,47 +1,32 @@ package htsjdk.tribble.gff; -import htsjdk.samtools.util.BlockCompressedOutputStream; -import htsjdk.samtools.util.FileExtensions; -import htsjdk.samtools.util.IOUtil; -import htsjdk.tribble.TribbleException; - -import java.io.BufferedOutputStream; -import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.function.Consumer; + +import htsjdk.samtools.util.FileExtensions; +import htsjdk.tribble.TribbleException; /** - * A class to write out gff3 files. Features are added using {@link #addFeature(Gff3Feature)}, directives using {@link #addDirective(Gff3Codec.Gff3Directive)}, - * and comments using {@link #addComment(String)}. Note that the version 3 directive is automatically added at creation, so should not be added separately. + * A class to write out gff3 files. Features are added using {@link #addFeature(Gff3Feature)}, + * directives using {@link #addDirective(Gff3Codec.Gff3Directive)}, and comments using + * {@link #addComment(String)}. Note that the version 3 directive is automatically added at + * creation, so should not be added separately. */ -public class Gff3Writer implements Closeable { +public class Gff3Writer extends AbstractGxxWriter { - private final OutputStream out; private final static String version = "3.1.25"; public Gff3Writer(final Path path) throws IOException { - if (FileExtensions.GFF3.stream().noneMatch(e -> path.toString().endsWith(e))) { - throw new TribbleException("File " + path + " does not have extension consistent with gff3"); - } - - final OutputStream outputStream = IOUtil.hasGzipFileExtension(path)? new BlockCompressedOutputStream(path.toFile()) : Files.newOutputStream(path); - out = new BufferedOutputStream(outputStream); - //start with version directive + super(path, FileExtensions.GFF3); initialize(); } public Gff3Writer(final OutputStream stream) { - out = stream; + super(stream); initialize(); } @@ -53,133 +38,55 @@ private void initialize() { } } - private void writeWithNewLine(final String txt) throws IOException { - out.write(txt.getBytes()); - out.write(Gff3Constants.END_OF_LINE_CHARACTER); - } - - private void tryToWrite(final String string) { - try { - out.write(string.getBytes()); - } catch (final IOException ex) { - throw new TribbleException("Error writing out string " + string, ex); - } - } - - private void writeFirstEightFields(final Gff3Feature feature) throws IOException { - writeJoinedByDelimiter(Gff3Constants.FIELD_DELIMITER, this::tryToWrite, Arrays.asList( - escapeString(feature.getContig()), - escapeString(feature.getSource()), - escapeString(feature.getType()), - Integer.toString(feature.getStart()), - Integer.toString(feature.getEnd()), - feature.getScore() < 0 ? Gff3Constants.UNDEFINED_FIELD_VALUE : Double.toString(feature.getScore()), - feature.getStrand().toString(), - feature.getPhase() < 0 ? Gff3Constants.UNDEFINED_FIELD_VALUE : Integer.toString(feature.getPhase()) - ) - ); - } - void writeAttributes(final Map> attributes) throws IOException { + @Override + protected void writeAttributes(final Map> attributes) throws IOException { if (attributes.isEmpty()) { out.write(Gff3Constants.UNDEFINED_FIELD_VALUE.getBytes()); } - writeJoinedByDelimiter(Gff3Constants.ATTRIBUTE_DELIMITER, e -> writeKeyValuePair(e.getKey(), e.getValue()), attributes.entrySet()); + writeJoinedByDelimiter(Gff3Constants.ATTRIBUTE_DELIMITER, + e -> writeKeyValuePair(e.getKey(), e.getValue()), attributes.entrySet()); } void writeKeyValuePair(final String key, final List values) { try { tryToWrite(key); out.write(Gff3Constants.KEY_VALUE_SEPARATOR); - writeJoinedByDelimiter(Gff3Constants.VALUE_DELIMITER, v -> tryToWrite(escapeString(v)), values); + writeJoinedByDelimiter(Gff3Constants.VALUE_DELIMITER, v -> tryToWrite(escapeString(v)), + values); } catch (final IOException ex) { throw new TribbleException("error writing out key value pair " + key + " " + values); } } - private void writeJoinedByDelimiter(final char delimiter, final Consumer consumer, final Collection fields) throws IOException { - boolean isNotFirstField = false; - for (final T field : fields) { - if (isNotFirstField) { - out.write(delimiter); - } else { - isNotFirstField = true; - } - - consumer.accept(field); - } - } - - /*** - * add a feature - * @param feature the feature to be added - * @throws IOException - */ - public void addFeature(final Gff3Feature feature) throws IOException { - writeFirstEightFields(feature); - out.write(Gff3Constants.FIELD_DELIMITER); - writeAttributes(feature.getAttributes()); - out.write(Gff3Constants.END_OF_LINE_CHARACTER); - } - - /*** - * escape a String. - * Default behavior is to call {@link #encodeString(String)} - * @param s the string to be escaped - * @return the escaped string - */ - protected String escapeString(final String s) { - return encodeString(s); - } - - static String encodeString(final String s) { - try { - //URLEncoder.encode is hardcoded to change all spaces to +, but we want spaces left unchanged so have to do this - //+ is escaped to %2B, so no loss of information - return URLEncoder.encode(s, "UTF-8").replace("+", " "); - } catch (final UnsupportedEncodingException ex) { - throw new TribbleException("Encoding failure", ex); - } - } - /** * Add a directive with an object + * * @param directive the directive to be added * @param object the object to be encoded with the directive * @throws IOException */ - public void addDirective(final Gff3Codec.Gff3Directive directive, final Object object) throws IOException { + public void addDirective(final Gff3Codec.Gff3Directive directive, final Object object) + throws IOException { if (directive == Gff3Codec.Gff3Directive.VERSION3_DIRECTIVE) { - throw new TribbleException("VERSION3_DIRECTIVE is automatically added and should not be added manually."); + throw new TribbleException( + "VERSION3_DIRECTIVE is automatically added and should not be added manually."); } writeWithNewLine(directive.encode(object)); } /** * Add a directive + * * @param directive the directive to be added * @throws IOException */ public void addDirective(final Gff3Codec.Gff3Directive directive) throws IOException { if (directive == Gff3Codec.Gff3Directive.VERSION3_DIRECTIVE) { - throw new TribbleException("VERSION3_DIRECTIVE is automatically added and should not be added manually."); + throw new TribbleException( + "VERSION3_DIRECTIVE is automatically added and should not be added manually."); } addDirective(directive, null); } - - /** - * Add comment line - * @param comment the comment line (not including leading #) - * @throws IOException - */ - public void addComment(final String comment) throws IOException { - out.write(Gff3Constants.COMMENT_START.getBytes()); - writeWithNewLine(comment); - } - - @Override - public void close() throws IOException { - out.close(); - } -} \ No newline at end of file +} diff --git a/src/main/java/htsjdk/tribble/gff/GtfCodec.java b/src/main/java/htsjdk/tribble/gff/GtfCodec.java new file mode 100644 index 0000000000..5b3fc1d100 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/GtfCodec.java @@ -0,0 +1,397 @@ +package htsjdk.tribble.gff; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.zip.GZIPInputStream; + +import htsjdk.samtools.util.CloserUtil; +import htsjdk.samtools.util.FileExtensions; +import htsjdk.samtools.util.IOUtil; +import htsjdk.samtools.util.Log; +import htsjdk.tribble.TribbleException; +import htsjdk.tribble.readers.LineIterator; + +/** + * Codec for parsing GTF files + * @author Pierre Lindenbaum + * + * This codec reads GTF file. + * In `DecodeDepth.DEEP` mode, the features with type="gene" have children with type="transcript|mrna" and `gene_id` linked to the gene. + * Other features having an attribute `transcript_id` linked to their transcript. + */ + +public class GtfCodec extends AbstractGxxCodec { + + private final static Log logger = Log.getInstance(GtfCodec.class); + private final Map id2gene = new HashMap<>(); + private final Map id2transcripts = new HashMap<>(); + private final Map> id2TranscriptComponents = new HashMap<>(); + + public GtfCodec() { + this(DecodeDepth.DEEP); + } + + public GtfCodec(final DecodeDepth decodeDepth) { + this(decodeDepth, KEY -> false); + } + + /** + * @param decodeDepth a value from DecodeDepth + * @param filterOutAttribute filter to remove keys from the EXTRA_FIELDS column + */ + public GtfCodec(final DecodeDepth decodeDepth, final Predicate filterOutAttribute) { + super(decodeDepth, filterOutAttribute); + /* check required keys are always kept */ + for (final String key : new String[] {GtfConstants.GENE_ID, GtfConstants.TRANSCRIPT_ID}) { + if (filterOutAttribute.test(key)) { + throw new IllegalArgumentException("Predicate should always accept " + key); + } + } + } + + /** test if a feature is a gene */ + private boolean isGene(final Gff3Feature feature) { + return feature.getType().equals("gene"); + } + + /** test if a feature is a transcript */ + private boolean isTranscript(final Gff3Feature feature) { + return feature.getType().equals("transcript") || feature.getType().equalsIgnoreCase("mrna"); + } + + @Override + protected Gff3Feature decode(final LineIterator lineIterator, DecodeDepth depth) throws IOException { + currentLine++; + /* + * Basic strategy: Load features into deque, create maps for gene and transcript. + * For each feature, link to parents using these maps. When + * reaching flush directive, or end of file, prepare to flush features by moving all + * active features to deque of features to flush, and clearing list of active features and + * both maps. Always poll featuresToFlush to return any completed top level features. + */ + if (!lineIterator.hasNext()) { + // no more lines, flush whatever is active + prepareToFlushFeatures(); + return featuresToFlush.poll(); + } + + final String line = lineIterator.next(); + + if (line.startsWith(GtfConstants.COMMENT_START)) { + commentsWithLineNumbers.put(currentLine, + line.substring(GtfConstants.COMMENT_START.length())); + return featuresToFlush.poll(); + } + + final Gff3FeatureImpl thisFeature = + new Gff3FeatureImpl(parseLine(line, currentLine, super.filterOutAttribute)); + super.activeFeatures.add(thisFeature); + + switch (depth) { + case SHALLOW: + // flush all features immediatly + prepareToFlushFeatures(); + break; + case DEEP: + if (isGene(thisFeature)) { + final String gene_id = thisFeature.getUniqueAttribute(GtfConstants.GENE_ID) + .orElseThrow(() -> new TribbleException( + "attribute " + GtfConstants.GENE_ID + " missing in " + line)); + if (id2gene.containsKey(gene_id)) { + throw new TribbleException("duplicate gene " + gene_id + " in " + line); + } + id2gene.put(gene_id, thisFeature); + } else if (isTranscript(thisFeature)) { + final String transcript_id = + thisFeature.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID) + .orElseThrow(() -> new TribbleException("attribute " + + GtfConstants.TRANSCRIPT_ID + " missing in " + line)); + if (id2transcripts.containsKey(transcript_id)) { + throw new TribbleException( + "duplicate transcript " + transcript_id + " in " + line); + } + id2transcripts.put(transcript_id, thisFeature); + } else if (thisFeature.hasAttribute(GtfConstants.TRANSCRIPT_ID)) { + final String transcript_id = + thisFeature.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID) + .orElseThrow(() -> new TribbleException("attribute " + + GtfConstants.TRANSCRIPT_ID + " missing in " + line)); + List components = + this.id2TranscriptComponents.get(transcript_id); + if (components == null) { + components = new ArrayList<>(); + this.id2TranscriptComponents.put(transcript_id, components); + } + components.add(thisFeature); + } + break; + default: throw new IllegalStateException(depth.name()); + } + + return featuresToFlush.poll(); + } + + @Override + protected Map> parseAttributesColumn(final String attributesString) + throws UnsupportedEncodingException { + return parseAttributes(attributesString); + } + + /** parse attributes for GTF */ + static Map> parseAttributes(final String attributesString) + throws UnsupportedEncodingException { + if (attributesString.trim().equals(GtfConstants.UNDEFINED_FIELD_VALUE)) { + return Collections.emptyMap(); + } + final Map> attributes = new LinkedHashMap<>(); + + final int len = attributesString.length(); + int i = 0; + for (;;) { + // skip whitespaces + while (i < len && Character.isWhitespace(attributesString.charAt(i))) { + i++; + } + + // end of string + if (i >= len) { + break; + } + + final StringBuilder keyBuilder = new StringBuilder(); + + // consumme key + while (i < len && !Character.isWhitespace(attributesString.charAt(i))) { + char c = attributesString.charAt(i); + if (c == Gff3Constants.KEY_VALUE_SEPARATOR) { + throw new TribbleException( + "unexpected gff3 separator " + Gff3Constants.KEY_VALUE_SEPARATOR + + " in gtf line " + attributesString); + } + keyBuilder.append(c); + i++; + } + // skip whitespaces + while (i < len && Character.isWhitespace(attributesString.charAt(i))) { + i++; + } + + final String key = URLDecoder.decode(keyBuilder.toString().trim(), "UTF-8"); + + /* read VALUE */ + final StringBuilder valueBuilder = new StringBuilder(); + + // no value + if (i >= len) { + logger.warn("no value for '" + key + "' in " + attributesString); + } else { + // first char of value + char c = attributesString.charAt(i); + + if (c == AbstractGxxConstants.ATTRIBUTE_DELIMITER) { // no value + logger.warn("no value for '" + key + "' in " + attributesString); + } else if (c == Gff3Constants.KEY_VALUE_SEPARATOR) { + throw new TribbleException( + "unexpected gff3 separator '" + Gff3Constants.KEY_VALUE_SEPARATOR + + "' in gtf line " + attributesString); + } + // quoted string + else if (c == '\"' || c == '\'') { + final char quote_symbol = c; + i++; + for (;;) { + if (i >= len) + throw new TribbleException( + "unclosed quoted string in " + attributesString); + c = attributesString.charAt(i); + if (c == '\\') { + if (i + 1 >= len) + throw new TribbleException( + "unclosed escape symbol in " + attributesString); + ++i; + c = attributesString.charAt(i); + switch (c) { + case '"': + valueBuilder.append("\""); + break; + case '\'': + valueBuilder.append("\'"); + break; + case 't': + valueBuilder.append("\t"); + break; + case 'n': + valueBuilder.append("\n"); + break; + default: + logger.warn("unparsed escape symbol in " + attributesString); + break; + } + i++; + } else if (c == quote_symbol) { + i++; + break; + } else { + valueBuilder.append(c); + i++; + } + } // end of for + } else /* not a quoted string, for example, a number */ + { + while (i < len) { + c = attributesString.charAt(i); + if (c == Gff3Constants.KEY_VALUE_SEPARATOR) { + throw new TribbleException("unexpected gff3 separator '" + + Gff3Constants.KEY_VALUE_SEPARATOR + "' in gtf line " + + attributesString); + } + if (Character.isWhitespace(c) + || c == AbstractGxxConstants.ATTRIBUTE_DELIMITER) { + break; + } + valueBuilder.append(c); + i++; + } + } + } // end of else 'value' + + List values = attributes.get(key); + if (values == null) { + values = new ArrayList<>(); + attributes.put(key, values); + } + values.add(URLDecoder.decode(valueBuilder.toString(), "UTF-8")); + + // skip whitespaces + while (i < len && Character.isWhitespace(attributesString.charAt(i))) { + i++; + } + if (i >= len) { + break; + } + if (attributesString.charAt(i) != AbstractGxxConstants.ATTRIBUTE_DELIMITER) { + throw new TribbleException("expected a '" + AbstractGxxConstants.ATTRIBUTE_DELIMITER + + "' in gtf line before : \"" + attributesString.substring(i) + "\". " + + attributes); + } + i++; + } + return attributes; + } + + @Override + public boolean canDecode(final String inputFilePath) { + try { + // Simple file and name checks to start with: + Path p = IOUtil.getPath(inputFilePath); + if (!FileExtensions.GTF.stream().anyMatch(fe -> p.toString().endsWith(fe))) { + return false; + } + + // Crack open the file and look at the top of it: + final InputStream inputStream = + IOUtil.hasGzipFileExtension(p) ? new GZIPInputStream(Files.newInputStream(p)) + : Files.newInputStream(p); + + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + for (;;) { + line = br.readLine(); + if (line == null) { + return false; + } + if (line.startsWith(GtfConstants.COMMENT_START)) { + continue; + } + return canDecodeFirstLine(line); + } + + } + + } catch (final FileNotFoundException ex) { + logger.error(inputFilePath + " not found."); + return false; + } catch (final IOException ex) { + return false; + } + + } + + + /** + * move active top level features to featuresToFlush. clear active features. + */ + private void prepareToFlushFeatures() { + + this.id2transcripts.values().stream().forEach(FEAT -> { + final String gene_id = FEAT.getUniqueAttribute(GtfConstants.GENE_ID) + .orElseThrow(() -> new TribbleException( + "attribute " + GtfConstants.GENE_ID + " missing in " + FEAT)); + if (!id2gene.containsKey(gene_id)) { + throw new TribbleException("undefined gene " + gene_id + " in " + FEAT); + } + final Gff3FeatureImpl geneFeat = id2gene.get(gene_id); + FEAT.addParent(geneFeat); + }); + + this.id2TranscriptComponents.values().stream().flatMap(L -> L.stream()).forEach(FEAT -> { + final String transcript_id = FEAT.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID) + .orElseThrow(() -> new TribbleException( + "attribute " + GtfConstants.TRANSCRIPT_ID + " missing in " + FEAT)); + if (!id2transcripts.containsKey(transcript_id)) { + throw new TribbleException( + "undefined transcript " + transcript_id + " in " + FEAT); + } + final Gff3FeatureImpl transcriptFeat = id2transcripts.get(transcript_id); + + /* check they share the same gene_id */ + if(transcriptFeat.hasAttribute(GtfConstants.GENE_ID) && FEAT.hasAttribute(GtfConstants.GENE_ID) && + !transcriptFeat.getUniqueAttribute(GtfConstants.GENE_ID).get().equals(FEAT.getUniqueAttribute(GtfConstants.GENE_ID).get()) ) { + throw new TribbleException( + "same transcript_id bit no the same gene_id" + transcriptFeat + " and " + FEAT); + } + + FEAT.addParent(transcriptFeat); + }); + + + featuresToFlush.addAll(activeFeatures); + id2transcripts.clear(); + id2gene.clear(); + id2TranscriptComponents.clear(); + super.activeFeatures.clear(); + } + + + + @Override + public boolean isDone(LineIterator lineIterator) { + return !lineIterator.hasNext() && id2gene.isEmpty() && id2transcripts.isEmpty() + && id2TranscriptComponents.isEmpty() && featuresToFlush.isEmpty() + && super.activeFeatures.isEmpty(); + } + + @Override + public void close(LineIterator source) { + id2gene.clear(); + id2transcripts.clear(); + id2TranscriptComponents.clear(); + featuresToFlush.clear(); + activeFeatures.clear(); + CloserUtil.close(source); + } +} diff --git a/src/main/java/htsjdk/tribble/gff/GtfConstants.java b/src/main/java/htsjdk/tribble/gff/GtfConstants.java new file mode 100644 index 0000000000..b0ade09e23 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/GtfConstants.java @@ -0,0 +1,11 @@ +package htsjdk.tribble.gff; +/** + * Constants for the GTF format + * @author Pierre Lindenbaum + * + */ +public class GtfConstants extends AbstractGxxConstants { + public static final char VALUE_DELIMITER = ' '; + public static final String GENE_ID = "gene_id"; + public static final String TRANSCRIPT_ID = "transcript_id"; +} diff --git a/src/main/java/htsjdk/tribble/gff/GtfWriter.java b/src/main/java/htsjdk/tribble/gff/GtfWriter.java new file mode 100644 index 0000000000..31a0899ca9 --- /dev/null +++ b/src/main/java/htsjdk/tribble/gff/GtfWriter.java @@ -0,0 +1,47 @@ +package htsjdk.tribble.gff; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import htsjdk.samtools.util.FileExtensions; + + +/** + * A class to write out gtf files. and comments using {@link #addComment(String)}. + * @author Pierre Lindenbaum + */ +public class GtfWriter extends AbstractGxxWriter { + + public GtfWriter(final Path path) throws IOException { + super(path, FileExtensions.GTF); + } + + public GtfWriter(final OutputStream stream) { + super(stream); + } + + + + @Override + protected void writeAttributes(final Map> attributes) throws IOException { + if (attributes.isEmpty()) { + out.write(GtfConstants.UNDEFINED_FIELD_VALUE.getBytes()); + } + boolean first = true; + for (final String key : attributes.keySet()) { + for (String value : attributes.get(key)) { + if (!first) + out.write(GtfConstants.ATTRIBUTE_DELIMITER); + out.write(escapeString(key).getBytes()); + out.write(GtfConstants.VALUE_DELIMITER); + out.write('\"'); + out.write(escapeString(value).getBytes()); + out.write('\"'); + first = false; + } + } + } +} diff --git a/src/test/java/htsjdk/tribble/gff/Gff3CodecTest.java b/src/test/java/htsjdk/tribble/gff/Gff3CodecTest.java index 38b9fb5d9c..9345f03947 100644 --- a/src/test/java/htsjdk/tribble/gff/Gff3CodecTest.java +++ b/src/test/java/htsjdk/tribble/gff/Gff3CodecTest.java @@ -543,4 +543,4 @@ public void extractSingleAttributeTest(final List attributes, final Stri Assert.assertEquals(singleAttribute, expectedSingleAttribute); } } -} \ No newline at end of file +} diff --git a/src/test/java/htsjdk/tribble/gff/Gff3WriterTest.java b/src/test/java/htsjdk/tribble/gff/Gff3WriterTest.java index 62178a0bb6..ec5598fa40 100644 --- a/src/test/java/htsjdk/tribble/gff/Gff3WriterTest.java +++ b/src/test/java/htsjdk/tribble/gff/Gff3WriterTest.java @@ -90,7 +90,18 @@ public void testRoundTrip(final Path path) { } private void writeToFile(final Path path, final List comments, final Set regions, final Set features) { - try (final Gff3Writer writer = new Gff3Writer(path)) { + int n=0; + System.err.println("## N="+features.size()); + try(Gff3Writer w=new Gff3Writer(System.err)) { + for (final Gff3Feature feature : features) { + w.addFeature(feature); + System.err.println("## N="+(++n)+"/"+features.size()+" "+feature.getChildren().size()); + } + } catch(Throwable err){} + + try (final AbstractGxxWriter w = AbstractGxxWriter.openWithFileExtension(path)) { + Assert.assertTrue(w instanceof Gff3Writer); + final Gff3Writer writer = Gff3Writer.class.cast(w); for (final String comment : comments) { writer.addComment(comment); } @@ -202,4 +213,4 @@ private static boolean isGZipped(final File f) { } return magic == GZIPInputStream.GZIP_MAGIC; } -} \ No newline at end of file +} diff --git a/src/test/java/htsjdk/tribble/gff/GtfCodecTest.java b/src/test/java/htsjdk/tribble/gff/GtfCodecTest.java new file mode 100644 index 0000000000..7ff91f6f53 --- /dev/null +++ b/src/test/java/htsjdk/tribble/gff/GtfCodecTest.java @@ -0,0 +1,197 @@ +package htsjdk.tribble.gff; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import htsjdk.HtsjdkTest; +import htsjdk.samtools.util.CloseableIterator; +import htsjdk.tribble.AbstractFeatureReader; +import htsjdk.tribble.TestUtils; +import htsjdk.tribble.annotation.Strand; +import htsjdk.tribble.readers.LineIterator; + + +public class GtfCodecTest extends HtsjdkTest { + + final static String DATA_DIR = TestUtils.DATA_DIR + "/gff/"; + private final Path gencode47_gzipped = Paths.get(DATA_DIR + "gencode.v47.annotation.gtf.gz"); + private final Path gencode47_PCSK9 = Paths.get(DATA_DIR + "gencode.v47.PCSK9.gtf"); + + @DataProvider(name = "basicDecodeDataProvider") + Object[][] basicDecodeDataProvider() { + return new Object[][] {{gencode47_gzipped, 842}, {gencode47_PCSK9, 248}}; + } + + private void basicDecodeTest(final Path inputGtf, GtfCodec.DecodeDepth decodeDepth, + final int expectedCount) throws IOException { + final GtfCodec codec = new GtfCodec(decodeDepth); + Assert.assertTrue(codec.canDecode(inputGtf.toAbsolutePath().toString())); + + try (final AbstractFeatureReader reader = AbstractFeatureReader + .getFeatureReader(inputGtf.toAbsolutePath().toString(), null, codec, false)) { + int countTotalFeatures = 0; + for (final Gff3Feature feature : reader.iterator()) { + countTotalFeatures++; + } + Assert.assertEquals(countTotalFeatures, expectedCount); + } + } + + + + @Test(dataProvider = "basicDecodeDataProvider") + public void basicDecodeDeepTest(final Path inputGtf, final int expectedCount) + throws IOException { + basicDecodeTest(inputGtf, GtfCodec.DecodeDepth.DEEP, expectedCount); + } + + @Test(dataProvider = "basicDecodeDataProvider") + public void basicDecodeShallowTest(final Path inputGtf, final int expectedCount) + throws IOException { + basicDecodeTest(inputGtf, GtfCodec.DecodeDepth.SHALLOW, expectedCount); + } + + @Test(dataProvider = "basicDecodeDataProvider") + public void codecFilterOutFieldsTest(final Path inputGtf, int expectedTotalFeatures) + throws IOException { + final Set skip_attributes = new HashSet<>(Arrays.asList("tag", "havana_gene")); + final GtfCodec codec = + new GtfCodec(GtfCodec.DecodeDepth.SHALLOW, S -> skip_attributes.contains(S)); + Assert.assertTrue(codec.canDecode(inputGtf.toAbsolutePath().toString())); + AbstractFeatureReader reader = AbstractFeatureReader + .getFeatureReader(inputGtf.toAbsolutePath().toString(), null, codec, false); + int countTotalFeatures = 0; + for (final Gff3Feature feature : reader.iterator()) { + for (final String key : skip_attributes) { + Assert.assertTrue(feature.getAttribute(key).isEmpty()); + Assert.assertFalse(feature.hasAttribute(key)); + Assert.assertFalse(feature.getUniqueAttribute(key).isPresent()); + } + countTotalFeatures++; + } + Assert.assertEquals(countTotalFeatures, expectedTotalFeatures); + } + + @Test + public void FeatureContentTest() throws IOException { + final GtfCodec codec = new GtfCodec(GtfCodec.DecodeDepth.SHALLOW); + try (final AbstractFeatureReader reader = + AbstractFeatureReader.getFeatureReader(gencode47_PCSK9.toAbsolutePath().toString(), + null, codec, false)) { + try (CloseableIterator iter = reader.iterator()) { + Assert.assertTrue(iter.hasNext()); + Gff3Feature feature = iter.next(); + Assert.assertNotNull(feature); + Assert.assertEquals(feature.getContig(), "chr1"); + Assert.assertEquals(feature.getSource(), "HAVANA"); + Assert.assertEquals(feature.getType(), "UTR"); + Assert.assertEquals(feature.getStart(), 55039445); + Assert.assertEquals(feature.getEnd(), 55039837); + Assert.assertEquals(feature.getScore(), -1); + Assert.assertEquals(feature.getStrand(), Strand.POSITIVE); + Assert.assertEquals(feature.getPhase(), -1); + Assert.assertEquals(feature.getUniqueAttribute(GtfConstants.GENE_ID).get(), + "ENSG00000169174.13"); + Assert.assertEquals(feature.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID).get(), + "ENST00000713785.1"); + Assert.assertEquals(feature.getUniqueAttribute("gene_type").get(), + "protein_coding"); + Assert.assertEquals(feature.getUniqueAttribute("gene_name").get(), "PCSK9"); + Assert.assertEquals(feature.getUniqueAttribute("transcript_type").get(), + "nonsense_mediated_decay"); + Assert.assertEquals(feature.getUniqueAttribute("transcript_name").get(), + "PCSK9-208"); + Assert.assertEquals(feature.getUniqueAttribute("exon_number").get(), "1"); + Assert.assertEquals(feature.getUniqueAttribute("exon_id").get(), + "ENSE00004011055.2"); + Assert.assertEquals(feature.getUniqueAttribute("level").get(), "2"); + Assert.assertEquals(feature.getUniqueAttribute("protein_id").get(), + "ENSP00000519087.1"); + Assert.assertEquals(feature.getUniqueAttribute("hgnc_id").get(), "HGNC:20001"); + Assert.assertEquals(feature.getUniqueAttribute("havana_gene").get(), + "OTTHUMG00000008136.2"); + Assert.assertFalse(feature.getUniqueAttribute("zz").isPresent()); + Assert.assertTrue(iter.hasNext()); + } + } + } + + @Test(dataProvider = "basicDecodeDataProvider") + private void deepTreeTest(final Path path, int expectNumber) throws IOException { + final GtfCodec codec = new GtfCodec(GtfCodec.DecodeDepth.DEEP); + try (final AbstractFeatureReader reader = AbstractFeatureReader + .getFeatureReader(path.toAbsolutePath().toString(), null, codec, false)) { + try (CloseableIterator iter = reader.iterator()) { + Assert.assertTrue(iter.hasNext()); + while (iter.hasNext()) { + Gff3Feature f1 = iter.next(); + if (!f1.getType().equals("gene")) + continue; + Assert.assertEquals(f1.getType(), "gene"); + Assert.assertTrue(f1.hasAttribute(GtfConstants.GENE_ID)); + Assert.assertTrue(f1.hasAttribute("gene_name")); + Assert.assertTrue(f1.hasChildren()); + for (Gff3Feature f2 : f1.getChildren()) { + Assert.assertEquals(f2.getType(), "transcript"); + Assert.assertTrue(f2.hasAttribute(GtfConstants.GENE_ID)); + Assert.assertTrue(f2.hasAttribute(GtfConstants.TRANSCRIPT_ID)); + + Assert.assertTrue(f2.hasAttribute("gene_name")); + Assert.assertEquals(f1.getUniqueAttribute("gene_name").get(), + f2.getUniqueAttribute("gene_name").get()); + Assert.assertEquals(f1.getUniqueAttribute(GtfConstants.GENE_ID).get(), + f2.getUniqueAttribute(GtfConstants.GENE_ID).get()); + Assert.assertTrue(f2.hasChildren()); + + for (Gff3Feature f3 : f2.getChildren()) { + Assert.assertNotEquals(f3.getType(), "gene"); + Assert.assertNotEquals(f3.getType(), "transcript"); + Assert.assertTrue(f3.hasAttribute(GtfConstants.GENE_ID)); + Assert.assertTrue(f3.hasAttribute(GtfConstants.TRANSCRIPT_ID)); + Assert.assertEquals(f2.getUniqueAttribute(GtfConstants.GENE_ID).get(), + f3.getUniqueAttribute(GtfConstants.GENE_ID).get()); + Assert.assertEquals( + f2.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID).get(), + f3.getUniqueAttribute(GtfConstants.TRANSCRIPT_ID).get()); + Assert.assertFalse(f3.hasChildren()); + } + } + + } + } + } + } + + @Test + public void decodeFeaturesTest() throws IOException { + String s = GtfConstants.UNDEFINED_FIELD_VALUE; + Map> h = GtfCodec.parseAttributes(s); + Assert.assertTrue(h.isEmpty()); + + h = GtfCodec.parseAttributes("key1 \"ABCD\"; key2 12345 ; key3 'hello'"); + for (String k : h.keySet()) { + Assert.assertEquals(h.get(k).size(), 1); + } + Assert.assertEquals(h.get("key1").get(0), "ABCD"); + Assert.assertEquals(h.get("key2").get(0), "12345"); + Assert.assertEquals(h.get("key3").get(0), "hello"); + + h = GtfCodec.parseAttributes("key1 \"A\"; key1 B ; key1 C"); + Assert.assertEquals(h.size(), 1); + Assert.assertEquals(h.get("key1").size(), 3); + Assert.assertEquals(h.get("key1"), Arrays.asList("A", "B", "C")); + + h = GtfCodec.parseAttributes("key1 \"A\\tB\""); + Assert.assertEquals(h.get("key1").get(0), "A\tB"); + } +} diff --git a/src/test/java/htsjdk/tribble/gff/GtfWriterTest.java b/src/test/java/htsjdk/tribble/gff/GtfWriterTest.java new file mode 100644 index 0000000000..2884fafa9c --- /dev/null +++ b/src/test/java/htsjdk/tribble/gff/GtfWriterTest.java @@ -0,0 +1,137 @@ +package htsjdk.tribble.gff; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.zip.GZIPInputStream; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import htsjdk.HtsjdkTest; +import htsjdk.samtools.util.IOUtil; +import htsjdk.tribble.AbstractFeatureReader; +import htsjdk.tribble.TestUtils; +import htsjdk.tribble.TribbleException; +import htsjdk.tribble.readers.LineIterator; + +public class GtfWriterTest extends HtsjdkTest { + private final static String DATA_DIR = TestUtils.DATA_DIR + "/gff/"; + private final Path gencode47_gzipped = Paths.get(DATA_DIR + "gencode.v47.annotation.gtf.gz"); + private final Path gencode47_PCSK9 = Paths.get(DATA_DIR + "gencode.v47.PCSK9.gtf"); + private final static Path[] tmpDir = new Path[] {IOUtil.getDefaultTmpDirPath()}; + + @DataProvider(name = "roundTripDataProvider") + public Object[][] roundTripDataProvider() { + return new Object[][] {{gencode47_gzipped}, {gencode47_PCSK9}}; + } + + @Test(dataProvider = "roundTripDataProvider") + public void testRoundTrip(final Path path) { + + final List comments1 = new ArrayList<>(); + final LinkedHashSet features1 = readFromFile(path, comments1); + + // write out to temp files (one gzipped, on not) + try { + int n; + final Path tempFile = IOUtil.newTempPath("gtfWriter",".gtf", tmpDir); + final Path tempFileGzip = IOUtil.newTempPath("gtfWriter",".gtf.gz", tmpDir); + + n = writeToFile(tempFile, comments1, features1); + Assert.assertEquals(n, features1.size()); + n = writeToFile(tempFileGzip, comments1, features1); + Assert.assertEquals(n, features1.size()); + + // read temp files back in + + Assert.assertTrue(isGZipped(tempFileGzip.toFile())); + final List comments2 = new ArrayList<>(); + final LinkedHashSet features2 = readFromFile(tempFile, comments2); + Assert.assertEquals(features1.size(), features2.size()); + + + final List comments3 = new ArrayList<>(); + final LinkedHashSet features3 = readFromFile(path, comments3); + Assert.assertEquals(features1.size(), features3.size()); + + Assert.assertEquals(features1, features2); + Assert.assertEquals(features1, features3); + + Assert.assertEquals(comments1, comments2); + Assert.assertEquals(comments1, comments3); + } catch (final IOException ex) { + throw new TribbleException("Error creating temp files", ex); + } + } + + private int writeToFile(final Path path, final List comments, + final Set features) { + int n = 0; + try (final AbstractGxxWriter writer = AbstractGxxWriter.openWithFileExtension(path)) { + Assert.assertTrue(writer instanceof GtfWriter); + for (final String comment : comments) { + writer.addComment(comment); + } + + for (final Gff3Feature feature : features) { + writer.addFeature(feature); + n++; + } + return n; + } catch (final IOException ex) { + throw new TribbleException("Error writing to file " + path, ex); + } + } + + private LinkedHashSet readFromFile(final Path path, List commentsStore) { + final GtfCodec codec = new GtfCodec(); + final LinkedHashSet features = new LinkedHashSet<>(); + try (final AbstractFeatureReader reader = AbstractFeatureReader + .getFeatureReader(path.toAbsolutePath().toString(), null, codec, false)) { + for (final Gff3Feature feature : reader.iterator()) { + features.add(feature); + } + + commentsStore.addAll(codec.getCommentTexts()); + } catch (final IOException ex) { + throw new TribbleException("Error reading gtf file " + path); + } + System.err.println("###ICIB " + features.size()); + return features; + } + + @DataProvider(name = "encodeStringDataProvider") + public Object[][] encodeStringDataProvider() { + return new Object[][] {{"%", "%25"}, {";", "%3B"}, {"=", "%3D"}, {"&", "%26"}, {",", "%2C"}, + {" ", " "}, {"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ", + "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM "} // these should + // remain unchanged + }; + } + + @Test(dataProvider = "encodeStringDataProvider") + public void testEncodeString(final String decoded, final String expectedEncoded) { + final String encoded = GtfWriter.encodeString(decoded); + Assert.assertEquals(encoded, expectedEncoded); + } + + private static boolean isGZipped(final File f) { + int magic = 0; + try { + RandomAccessFile raf = new RandomAccessFile(f, "r"); + magic = raf.read() & 0xff | ((raf.read() << 8) & 0xff00); + raf.close(); + } catch (Throwable e) { + e.printStackTrace(System.err); + } + return magic == GZIPInputStream.GZIP_MAGIC; + } +} diff --git a/src/test/resources/htsjdk/tribble/gff/gencode.v47.PCSK9.gtf b/src/test/resources/htsjdk/tribble/gff/gencode.v47.PCSK9.gtf new file mode 100644 index 0000000000..7c75532e86 --- /dev/null +++ b/src/test/resources/htsjdk/tribble/gff/gencode.v47.PCSK9.gtf @@ -0,0 +1,248 @@ +chr1 HAVANA UTR 55039445 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 1; exon_id "ENSE00004011055.2"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55039445 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 1; exon_id "ENSE00004011055.2"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA gene 55039445 55064852 . + . gene_id "ENSG00000169174.13"; gene_type "protein_coding"; gene_name "PCSK9"; level 2; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA transcript 55039445 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55039447 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 1; exon_id "ENSE00003897031.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55039447 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 1; exon_id "ENSE00003897031.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA transcript 55039447 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55039456 55039480 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 1; exon_id "ENSE00001884398.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55039456 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 1; exon_id "ENSE00001884398.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA transcript 55039456 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55039462 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 1; exon_id "ENSE00004013014.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55039462 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 1; exon_id "ENSE00004013014.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA transcript 55039462 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA UTR 55039468 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 1; exon_id "ENSE00004021263.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55039468 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 1; exon_id "ENSE00004021263.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA transcript 55039468 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55039481 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 1; exon_id "ENSE00001884398.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA start_codon 55039481 55039483 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 1; exon_id "ENSE00001884398.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55039548 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 1; exon_id "ENSE00004021261.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55039548 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 1; exon_id "ENSE00004021261.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA transcript 55039548 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA UTR 55039550 55039837 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 1; exon_id "ENSE00004021267.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55039550 55040044 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 1; exon_id "ENSE00004021267.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA transcript 55039550 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 1; exon_id "ENSE00004021261.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 1; exon_id "ENSE00003897031.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 1; exon_id "ENSE00004013014.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 1; exon_id "ENSE00004011055.2"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 1; exon_id "ENSE00004021263.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55039838 55040044 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 1; exon_id "ENSE00004021267.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 1; exon_id "ENSE00004021261.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 1; exon_id "ENSE00003897031.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 1; exon_id "ENSE00004013014.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 1; exon_id "ENSE00004011055.2"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 1; exon_id "ENSE00004021263.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA start_codon 55039838 55039840 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 1; exon_id "ENSE00004021267.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55040295 55040403 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 1; exon_id "ENSE00003897575.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55040295 55040403 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 1; exon_id "ENSE00003897575.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA transcript 55040295 55064797 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55041967 55042089 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 2; exon_id "ENSE00004021272.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55041967 55042089 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 2; exon_id "ENSE00004021272.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 3; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55043843 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55043843 55044010 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 2; exon_id "ENSE00003896896.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 2; exon_id "ENSE00003896896.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 3; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55043843 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 2; exon_id "ENSE00001279167.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55043966 55044034 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673662.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding_CDS_not_defined"; transcript_name "PCSK9-203"; exon_number 1; exon_id "ENSE00003897988.1"; level 2; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530153.1"; +chr1 HAVANA transcript 55043966 55047332 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673662.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding_CDS_not_defined"; transcript_name "PCSK9-203"; level 2; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530153.1"; +chr1 HAVANA CDS 55044011 55044034 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 2; exon_id "ENSE00003896896.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA start_codon 55044011 55044013 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 2; exon_id "ENSE00003896896.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 4; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55046523 55046646 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673662.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding_CDS_not_defined"; transcript_name "PCSK9-203"; exon_number 2; exon_id "ENSE00003896521.1"; level 2; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530153.1"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 4; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55046523 55046646 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 3; exon_id "ENSE00001279161.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55046923 55047332 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673662.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding_CDS_not_defined"; transcript_name "PCSK9-203"; exon_number 3; exon_id "ENSE00003896780.1"; level 2; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530153.1"; +chr1 HAVANA exon 55050934 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 1; exon_id "ENSE00001850558.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA transcript 55050934 55064850 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA CDS 55051343 55051431 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 4; exon_id "ENSE00003897734.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55051343 55051453 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 4; exon_id "ENSE00003897734.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55051432 55051453 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 4; exon_id "ENSE00003897734.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA stop_codon 55051432 55051434 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 4; exon_id "ENSE00003897734.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA CDS 55052278 55052307 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 2; exon_id "ENSE00003646938.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 5; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052278 55052411 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 5; exon_id "ENSE00003897397.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 5; exon_id "ENSE00003897397.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 2; exon_id "ENSE00003646938.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 5; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052278 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 4; exon_id "ENSE00004021268.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55052308 55052411 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 2; exon_id "ENSE00003646938.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA stop_codon 55052308 55052310 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 2; exon_id "ENSE00003646938.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 6; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55052650 55052791 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 6; exon_id "ENSE00003683038.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 3; exon_id "ENSE00003683038.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 2; exon_id "ENSE00003683038.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 6; exon_id "ENSE00003683038.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 3; exon_id "ENSE00003683038.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 6; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55052650 55052791 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 5; exon_id "ENSE00004021270.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 7; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55055993 55056189 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 7; exon_id "ENSE00003626397.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 4; exon_id "ENSE00003626397.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 3; exon_id "ENSE00003626397.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 7; exon_id "ENSE00003626397.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 4; exon_id "ENSE00003626397.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 7; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55055993 55056189 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 6; exon_id "ENSE00004021269.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55056537 55056641 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 7; exon_id "ENSE00004021271.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55056537 55056805 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 7; exon_id "ENSE00004021271.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55056642 55056805 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 7; exon_id "ENSE00004021271.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA stop_codon 55056642 55056644 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 7; exon_id "ENSE00004021271.2"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55057331 55057514 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55057331 55057514 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55057331 55057514 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55057331 55057514 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55057331 55057514 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 8; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 8; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 5; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 8; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 8; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 7; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 5; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 8; exon_id "ENSE00004021262.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55057331 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 8; exon_id "ENSE00001156685.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55057428 55057514 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 4; exon_id "ENSE00001907083.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA CDS 55058036 55058209 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55058036 55058209 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55058036 55058209 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55058036 55058209 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55058036 55058209 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 9; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 9; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 6; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 9; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 5; exon_id "ENSE00003509095.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 9; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 8; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 6; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 9; exon_id "ENSE00004021266.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058036 55058209 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 9; exon_id "ENSE00003509095.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55058499 55058647 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55058499 55058647 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55058499 55058647 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55058499 55058647 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55058499 55058647 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 10; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 10; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 7; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 10; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 6; exon_id "ENSE00003602007.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 10; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 9; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 7; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 10; exon_id "ENSE00004021274.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55058499 55058647 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 10; exon_id "ENSE00003602007.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55059486 55059663 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55059486 55059663 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55059486 55059663 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55059486 55059663 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55059486 55059663 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 11; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 11; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 8; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 11; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 11; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 10; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 8; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 11; exon_id "ENSE00004021273.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55059486 55059663 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 11; exon_id "ENSE00003683046.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55061265 55061350 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 11; exon_id "ENSE00003897219.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55061265 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 11; exon_id "ENSE00003897219.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA UTR 55061351 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 11; exon_id "ENSE00003897219.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA stop_codon 55061351 55061353 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 11; exon_id "ENSE00003897219.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA CDS 55061375 55061556 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55061375 55061556 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55061375 55061556 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55061375 55061556 . + 2 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 12; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 12; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 9; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 12; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 7; exon_id "ENSE00003645672.1"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 12; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 11; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 9; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 12; exon_id "ENSE00004021265.2"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55061375 55061556 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 12; exon_id "ENSE00003645672.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55063369 55063581 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA CDS 55063369 55063581 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 12; exon_id "ENSE00003897035.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA CDS 55063369 55063581 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA CDS 55063369 55063581 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 13; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 13; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA UTR 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 12; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA UTR 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 10; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 13; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55063369 55064797 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 12; exon_id "ENSE00003897035.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA exon 55063369 55064850 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000490692.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "retained_intron"; transcript_name "PCSK9-202"; exon_number 8; exon_id "ENSE00001427326.3"; level 2; transcript_support_level "2"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022279.1"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673726.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-204"; exon_number 13; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000501004.1"; hgnc_id "HGNC:20001"; tag "inferred_exon_combination"; tag "RNA_Seq_supported_only"; tag "upstream_ATG"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530151.1"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673913.2"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-206"; exon_number 12; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000501161.2"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530154.1"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713785.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-208"; exon_number 10; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000519087.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 13; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA exon 55063369 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713787.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "nonsense_mediated_decay"; transcript_name "PCSK9-210"; exon_number 13; exon_id "ENSE00001922690.1"; level 2; protein_id "ENSP00000519089.1"; hgnc_id "HGNC:20001"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55063582 55064797 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 12; exon_id "ENSE00003897035.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA UTR 55063582 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA UTR 55063582 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA UTR 55063582 55064852 . + . gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 13; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA stop_codon 55063582 55063584 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000302118.5"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-201"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000303208.5"; transcript_support_level "1"; hgnc_id "HGNC:20001"; tag "basic"; tag "Ensembl_canonical"; tag "GENCODE_Primary"; tag "MANE_Select"; tag "appris_principal_2"; tag "CCDS"; ccdsid "CCDS603.1"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000022280.2"; +chr1 HAVANA stop_codon 55063582 55063584 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000673903.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-205"; exon_number 12; exon_id "ENSE00003897035.1"; level 2; protein_id "ENSP00000501257.1"; hgnc_id "HGNC:20001"; tag "RNA_Seq_supported_only"; tag "basic"; havana_gene "OTTHUMG00000008136.2"; havana_transcript "OTTHUMT00000530152.1"; +chr1 HAVANA stop_codon 55063582 55063584 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000710286.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-207"; exon_number 12; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000518176.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; +chr1 HAVANA stop_codon 55063582 55063584 . + 0 gene_id "ENSG00000169174.13"; transcript_id "ENST00000713786.1"; gene_type "protein_coding"; gene_name "PCSK9"; transcript_type "protein_coding"; transcript_name "PCSK9-209"; exon_number 13; exon_id "ENSE00004021264.1"; level 2; protein_id "ENSP00000519088.1"; hgnc_id "HGNC:20001"; tag "basic"; tag "appris_alternative_2"; havana_gene "OTTHUMG00000008136.2"; diff --git a/src/test/resources/htsjdk/tribble/gff/gencode.v47.annotation.gtf.gz b/src/test/resources/htsjdk/tribble/gff/gencode.v47.annotation.gtf.gz new file mode 100644 index 0000000000..3a0f7aba7f Binary files /dev/null and b/src/test/resources/htsjdk/tribble/gff/gencode.v47.annotation.gtf.gz differ