Visualization framework: replace summary_tree with bigwig datatype for all feature track coverage data, yielding better performance and a standardized approach for working with coverage data. Update Trackster to work with bigwig coverage data.

This commit is contained in:
Jeremy Goecks
2013-05-09 11:44:45 -04:00
parent 1c19a78e98
commit 4f3acda1ca
24 changed files with 227 additions and 629 deletions
+9 -15
View File
@@ -9,12 +9,7 @@
<datatype extension="fli" type="galaxy.datatypes.tabular:FeatureLocationIndex" display_in_upload="false"/>
<datatype extension="bam" type="galaxy.datatypes.binary:Bam" mimetype="application/octet-stream" display_in_upload="true">
<converter file="bam_to_bai.xml" target_datatype="bai"/>
<converter file="bam_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<!--
Caution: (a) this converter requires bedtools to be installed and (b) it is very memory intensive and
is not recommended for most laptops/desktops.
<converter file="bam_to_bigwig_converter.xml" target_datatype="bigwig"/>
-->
<converter file="bam_to_bigwig_converter.xml" target_datatype="bigwig"/>
<display file="ucsc/bam.xml" />
<display file="ensembl/ensembl_bam.xml" />
<display file="igv/bam.xml" />
@@ -25,7 +20,7 @@
<converter file="interval_to_coverage.xml" target_datatype="coverage"/>
<converter file="bed_to_bgzip_converter.xml" target_datatype="bgzip"/>
<converter file="bed_to_tabix_converter.xml" target_datatype="tabix" depends_on="bgzip"/>
<converter file="bed_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
<converter file="bed_to_fli_converter.xml" target_datatype="fli"/>
<!-- <display file="ucsc/interval_as_bed.xml" /> -->
<display file="igb/bed.xml" />
@@ -51,7 +46,7 @@
<datatype extension="chrint" type="galaxy.datatypes.interval:ChromatinInteractions" display_in_upload="True">
<converter file="interval_to_bgzip_converter.xml" target_datatype="bgzip"/>
<converter file="interval_to_tabix_converter.xml" target_datatype="tabix" depends_on="bgzip"/>
<converter file="interval_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
</datatype>
<!-- MSI added Datatypes -->
<datatype extension="csv" type="galaxy.datatypes.tabular:Tabular" subclass="True" display_in_upload="true" /> <!-- FIXME: csv is 'tabular'ized data, but not 'tab-delimited'; the class used here is intended for 'tab-delimited' -->
@@ -93,7 +88,7 @@
<datatype extension="gff" type="galaxy.datatypes.interval:Gff" display_in_upload="true">
<converter file="gff_to_bed_converter.xml" target_datatype="bed"/>
<converter file="gff_to_interval_index_converter.xml" target_datatype="interval_index"/>
<converter file="gff_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
<converter file="gff_to_fli_converter.xml" target_datatype="fli"/>
<display file="ensembl/ensembl_gff.xml" inherit="True"/>
<!-- <display file="gbrowse/gbrowse_gff.xml" inherit="True" /> -->
@@ -103,7 +98,7 @@
<datatype extension="gmaj.zip" type="galaxy.datatypes.images:Gmaj" mimetype="application/zip"/>
<datatype extension="gtf" type="galaxy.datatypes.interval:Gtf" display_in_upload="true">
<converter file="gff_to_interval_index_converter.xml" target_datatype="interval_index"/>
<converter file="gff_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
</datatype>
<datatype extension="toolshed.gz" type="galaxy.datatypes.binary:Binary" mimetype="multipart/x-gzip" subclass="True" />
<datatype extension="h5" type="galaxy.datatypes.binary:Binary" mimetype="application/octet-stream" subclass="True" />
@@ -115,7 +110,7 @@
<converter file="interval_to_bed12_converter.xml" target_datatype="bed12"/>
<converter file="interval_to_bgzip_converter.xml" target_datatype="bgzip"/>
<converter file="interval_to_tabix_converter.xml" target_datatype="tabix" depends_on="bgzip"/>
<converter file="interval_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="interval_to_bigwig_converter.xml" target_datatype="bigwig"/>
<!-- <display file="ucsc/interval_as_bed.xml" inherit="True" /> -->
<display file="ensembl/ensembl_interval_as_bed.xml" inherit="True"/>
<display file="gbrowse/gbrowse_interval_as_bed.xml" inherit="True"/>
@@ -156,7 +151,7 @@
<datatype extension="encodepeak" type="galaxy.datatypes.interval:ENCODEPeak" display_in_upload="True">
<converter file="encodepeak_to_tabix_converter.xml" target_datatype="tabix" depends_on="bgzip"/>
<converter file="encodepeak_to_bgzip_converter.xml" target_datatype="bgzip"/>
<converter file="encodepeak_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
</datatype>
<datatype extension="pdf" type="galaxy.datatypes.images:Pdf" mimetype="application/pdf"/>
<datatype extension="pileup" type="galaxy.datatypes.tabular:Pileup" display_in_upload="true">
@@ -172,7 +167,7 @@
<datatype extension="Roadmaps" type="galaxy.datatypes.assembly:Roadmaps" display_in_upload="false"/>
<datatype extension="sam" type="galaxy.datatypes.tabular:Sam" display_in_upload="true">
<converter file="sam_to_bam.xml" target_datatype="bam"/>
<converter file="sam_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="sam_to_bigwig_converter.xml" target_datatype="bigwig"/>
</datatype>
<datatype extension="scf" type="galaxy.datatypes.binary:Scf" mimetype="application/octet-stream" display_in_upload="true"/>
<datatype extension="Sequences" type="galaxy.datatypes.assembly:Sequences" display_in_upload="false"/>
@@ -190,7 +185,7 @@
<converter file="vcf_to_bgzip_converter.xml" target_datatype="bgzip"/>
<converter file="vcf_to_vcf_bgzip_converter.xml" target_datatype="vcf_bgzip"/>
<converter file="vcf_to_tabix_converter.xml" target_datatype="tabix" depends_on="bgzip"/>
<converter file="vcf_to_summary_tree_converter.xml" target_datatype="summary_tree"/>
<converter file="bed_gff_or_vcf_to_bigwig_converter.xml" target_datatype="bigwig"/>
<display file="ucsc/vcf.xml" />
<display file="igv/vcf.xml" />
<display file="rviewer/vcf.xml" inherit="True"/>
@@ -203,7 +198,6 @@
<!-- <display file="gbrowse/gbrowse_wig.xml" /> -->
<display file="igb/wig.xml" />
</datatype>
<datatype extension="summary_tree" type="galaxy.datatypes.binary:Binary" subclass="True" />
<datatype extension="interval_index" type="galaxy.datatypes.binary:Binary" subclass="True" />
<datatype extension="tabix" type="galaxy.datatypes.binary:Binary" subclass="True" />
<datatype extension="bgzip" type="galaxy.datatypes.binary:Binary" subclass="True" />
+1 -1
View File
@@ -103,7 +103,7 @@ class Bam( Binary ):
"""Class describing a BAM binary file"""
file_ext = "bam"
track_type = "ReadTrack"
data_sources = { "data": "bai", "index": [ "bigwig", "summary_tree" ] }
data_sources = { "data": "bai", "index": "bigwig" }
MetadataElement( name="bam_index", desc="BAM Index File", param=metadata.FileParameter, file_ext="bai", readonly=True, no_value=None, visible=False, optional=True )
@@ -1,7 +1,14 @@
<tool id="CONVERTER_bam_to_bigwig_0" name="Convert BAM to BigWig" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command>
bedtools genomecov -bg -split -ibam $input -g $chromInfo | wigToBigWig stdin $chromInfo $output
bedtools genomecov -bg -split -ibam $input -g $chromInfo
## Streaming the bedgraph file to wigToBigWig is fast but very memory intensive; hence, this
## should only be used on systems with large RAM.
## | wigToBigWig stdin $chromInfo $output
## This can be used anywhere.
> temp.bg ; bedGraphToBigWig temp.bg $chromInfo $output
</command>
<inputs>
<param format="bam" name="input" type="data" label="Choose BAM file"/>
@@ -1,14 +0,0 @@
<tool id="CONVERTER_bam_to_summary_tree_0" name="Convert BAM to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">
sam_or_bam_to_summary_tree_converter.py --bam $input1 $input1.metadata.bam_index $output1
</command>
<inputs>
<param format="bam" name="input1" type="data" label="Choose BAM file"/>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -0,0 +1,25 @@
<tool id="CONVERTER_bed_gff_or_vcf_to_bigwig_0" name="Convert BED, GFF, or VCF to BigWig" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command>
## Remove comments and sort by chromosome.
grep -v '^#' $input | sort -k1,1 |
## Generate coverage bedgraph.
bedtools genomecov -bg -split -i stdin -g $chromInfo
## Streaming the bedgraph file to wigToBigWig is fast but very memory intensive; hence, this
## should only be used on systems with large RAM.
## | wigToBigWig stdin $chromInfo $output
## This can be used anywhere.
> temp.bg ; bedGraphToBigWig temp.bg $chromInfo $output
</command>
<inputs>
<param format="bed,gff,vcf" name="input" type="data" label="Choose input file"/>
</inputs>
<outputs>
<data format="bigwig" name="output"/>
</outputs>
<help>
</help>
</tool>
@@ -1,14 +0,0 @@
<tool id="CONVERTER_bed_to_summary_tree_0" name="Convert BED to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">interval_to_summary_tree_converter.py $input1 $output1</command>
<inputs>
<page>
<param format="bed" name="input1" type="data" label="Choose BED file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -1,20 +0,0 @@
<tool id="CONVERTER_encodepeak_to_summary_tree_0" name="Convert ENCODEPeak to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">interval_to_summary_tree_converter.py
-c ${input1.metadata.chromCol}
-s ${input1.metadata.startCol}
-e ${input1.metadata.endCol}
$input1 $output1
</command>
<inputs>
<page>
<param format="ENCODEPeak" name="input1" type="data" label="Choose ENCODEPeak file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -1,14 +0,0 @@
<tool id="CONVERTER_gff_to_summary_tree_0" name="Convert GFF to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">interval_to_summary_tree_converter.py $input1 $output1 --gff</command>
<inputs>
<page>
<param format="gff" name="input1" type="data" label="Choose GFF file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -1,63 +0,0 @@
#!/usr/bin/env python
"""
Convert from interval file to summary tree file. Default input file format is BED (0-based, half-open intervals).
usage: %prog <options> in_file out_file
-c, --chr-col: chromosome column, default=1
-s, --start-col: start column, default=2
-e, --end-col: end column, default=3
-t, --strand-col: strand column, default=6
-G, --gff: input is GFF format, meaning start and end coordinates are 1-based, closed interval
"""
from __future__ import division
import sys, fileinput, optparse
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
from galaxy.visualization.tracks.summary import *
from bx.intervals.io import *
from galaxy.datatypes.util.gff_util import *
def main():
# Read options, args.
parser = optparse.OptionParser()
parser.add_option( '-c', '--chr-col', type='int', dest='chrom_col', default=1 )
parser.add_option( '-s', '--start-col', type='int', dest='start_col', default=2 )
parser.add_option( '-e', '--end-col', type='int', dest='end_col', default=3 )
parser.add_option( '-t', '--strand-col', type='int', dest='strand_col', default=6 )
parser.add_option( '-G', '--gff', dest="gff_format", action="store_true" )
(options, args) = parser.parse_args()
input_fname, output_fname = args
# Convert column indices to 0-based.
options.chrom_col -= 1
options.start_col -= 1
options.end_col -= 1
options.strand_col -= 1
# Do conversion.
if options.gff_format:
reader_wrapper_class = GFFReaderWrapper
chr_col, start_col, end_col, strand_col = ( 0, 3, 4, 6 )
else:
reader_wrapper_class = NiceReaderWrapper
chr_col, start_col, end_col, strand_col = ( options.chrom_col, options.start_col, options.end_col, options.strand_col )
reader_wrapper = reader_wrapper_class( fileinput.FileInput( input_fname ),
chrom_col=chr_col,
start_col=start_col,
end_col=end_col,
strand_col=strand_col,
fix_strand=True )
st = SummaryTree()
for feature in list( reader_wrapper ):
if isinstance( feature, GenomicInterval ):
# Tree expects BED coordinates.
if type( feature ) is GFFFeature:
convert_gff_coords_to_bed( feature )
st.insert_range( feature.chrom, long( feature.start ), long( feature.end ) )
st.write( output_fname )
if __name__ == "__main__":
main()
@@ -1,20 +0,0 @@
<tool id="CONVERTER_interval_to_summary_tree_0" name="Convert Interval to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">interval_to_summary_tree_converter.py
-c ${input1.metadata.chromCol}
-s ${input1.metadata.startCol}
-e ${input1.metadata.endCol}
$input1 $output1
</command>
<inputs>
<page>
<param format="interval" name="input1" type="data" label="Choose Interval file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -1,42 +0,0 @@
#!/usr/bin/env python
from __future__ import division
import sys, os, optparse
sys.stderr = open(os.devnull, 'w') # suppress stderr as cython produces warning on some systems:
# csamtools.so:6: RuntimeWarning: __builtin__.file size changed
from galaxy import eggs
import pkg_resources
if sys.version_info[:2] == (2, 4):
pkg_resources.require( "ctypes" )
pkg_resources.require( "pysam" )
from pysam import csamtools
from galaxy.visualization.tracks.summary import *
def main():
parser = optparse.OptionParser()
parser.add_option( '-S', '--sam', action="store_true", dest="is_sam" )
parser.add_option( '-B', '--bam', action="store_true", dest="is_bam" )
options, args = parser.parse_args()
if options.is_bam:
input_fname = args[0]
index_fname = args[1]
out_fname = args[2]
samfile = csamtools.Samfile( filename=input_fname, mode='rb', index_filename=index_fname )
elif options.is_sam:
input_fname = args[0]
out_fname = args[1]
samfile = csamtools.Samfile( filename=input_fname, mode='r' )
st = SummaryTree()
for read in samfile.fetch():
st.insert_range( samfile.getrname( read.rname ), read.pos, read.pos + read.rlen )
st.write(out_fname)
if __name__ == "__main__":
main()
@@ -1,14 +0,0 @@
<tool id="CONVERTER_sam_to_summary_tree_0" name="Convert SAM to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">sam_or_bam_to_summary_tree_converter.py --sam $input1 $output1</command>
<inputs>
<page>
<param format="sam" name="input1" type="data" label="Choose sam file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
@@ -1,30 +0,0 @@
#!/usr/bin/env python
"""
Convert from VCF file to summary tree file.
usage: %prog in_file out_file
"""
from __future__ import division
import optparse
import galaxy_utils.sequence.vcf
from galaxy.visualization.tracks.summary import SummaryTree
def main():
# Read options, args.
parser = optparse.OptionParser()
(options, args) = parser.parse_args()
in_file, out_file = args
# Do conversion.
st = SummaryTree()
for line in list( galaxy_utils.sequence.vcf.Reader( open( in_file ) ) ):
# VCF format provides a chrom and 1-based position for each variant.
# SummaryTree expects 0-based coordinates.
st.insert_range( line.chrom, long( line.pos-1 ), long( line.pos ) )
st.write(out_file)
if __name__ == "__main__":
main()
@@ -1,14 +0,0 @@
<tool id="CONVERTER_vcf_to_summary_tree_0" name="Convert VCF to Summary Tree" version="1.0.0" hidden="true">
<!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
<command interpreter="python">vcf_to_summary_tree_converter.py $input1 $output1</command>
<inputs>
<page>
<param format="vcf" name="input1" type="data" label="Choose VCF file"/>
</page>
</inputs>
<outputs>
<data format="summary_tree" name="output1"/>
</outputs>
<help>
</help>
</tool>
+5 -5
View File
@@ -47,7 +47,7 @@ class Interval( Tabular ):
file_ext = "interval"
line_class = "region"
track_type = "FeatureTrack"
data_sources = { "data": "tabix", "index": "summary_tree" }
data_sources = { "data": "tabix", "index": "bigwig" }
"""Add metadata elements"""
MetadataElement( name="chromCol", default=1, desc="Chrom column", param=metadata.ColumnParameter )
@@ -354,7 +354,7 @@ class BedGraph( Interval ):
class Bed( Interval ):
"""Tab delimited data in BED format"""
file_ext = "bed"
data_sources = { "data": "tabix", "index": "summary_tree", "feature_search": "fli" }
data_sources = { "data": "tabix", "index": "bigwig", "feature_search": "fli" }
track_type = Interval.track_type
"""Add metadata elements"""
@@ -569,7 +569,7 @@ class Gff( Tabular, _RemoteCallMixin ):
"""Tab delimited data in Gff format"""
file_ext = "gff"
column_names = [ 'Seqname', 'Source', 'Feature', 'Start', 'End', 'Score', 'Strand', 'Frame', 'Group' ]
data_sources = { "data": "interval_index", "index": "summary_tree", "feature_search": "fli" }
data_sources = { "data": "interval_index", "index": "bigwig", "feature_search": "fli" }
track_type = Interval.track_type
"""Add metadata elements"""
@@ -1288,7 +1288,7 @@ class ENCODEPeak( Interval ):
file_ext = "encodepeak"
column_names = [ 'Chrom', 'Start', 'End', 'Name', 'Score', 'Strand', 'SignalValue', 'pValue', 'qValue', 'Peak' ]
data_sources = { "data": "tabix", "index": "summary_tree" }
data_sources = { "data": "tabix", "index": "bigwig" }
"""Add metadata elements"""
MetadataElement( name="chromCol", default=1, desc="Chrom column", param=metadata.ColumnParameter )
@@ -1307,7 +1307,7 @@ class ChromatinInteractions( Interval ):
file_ext = "chrint"
track_type = "DiagonalHeatmapTrack"
data_sources = { "data": "tabix", "index": "summary_tree" }
data_sources = { "data": "tabix", "index": "bigwig" }
column_names = [ 'Chrom1', 'Start1', 'End1', 'Chrom2', 'Start2', 'End2', 'Value' ]
+2 -2
View File
@@ -359,7 +359,7 @@ class Taxonomy( Tabular ):
class Sam( Tabular ):
file_ext = 'sam'
track_type = "ReadTrack"
data_sources = { "data": "bam", "index": "summary_tree" }
data_sources = { "data": "bam", "index": "bigwig" }
def __init__(self, **kwd):
"""Initialize taxonomy datatype"""
@@ -537,7 +537,7 @@ class ElandMulti( Tabular ):
class Vcf( Tabular ):
""" Variant Call Format for describing SNPs and other simple genome variations. """
track_type = "VariantTrack"
data_sources = { "data": "tabix", "index": "summary_tree" }
data_sources = { "data": "tabix", "index": "bigwig" }
file_ext = 'vcf'
column_names = [ 'Chrom', 'Pos', 'ID', 'Ref', 'Alt', 'Qual', 'Filter', 'Info', 'Format', 'data' ]
@@ -14,7 +14,6 @@ from galaxy.util.json import from_json_string
from bx.interval_index_file import Indexes
from bx.bbi.bigwig_file import BigWigFile
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.tracks.summary import summary_tree_from_file
from galaxy.visualization.data_providers.basic import BaseDataProvider
from galaxy.visualization.data_providers.cigar import get_ref_based_read_seq_and_cigar
from galaxy.datatypes.interval import Bed, Gff, Gtf
@@ -800,79 +799,6 @@ class RawVcfDataProvider( VcfDataProvider ):
return line_filter_iter()
class SummaryTreeDataProvider( GenomeDataProvider ):
"""
Summary tree data provider for the Galaxy track browser.
"""
dataset_type = 'summary_tree'
CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance
def valid_chroms( self ):
st = summary_tree_from_file( self.converted_dataset.file_name )
return st.chrom_blocks.keys()
def get_data( self, chrom, start, end, level=None, resolution=None, detail_cutoff=None, draw_cutoff=None, **kwargs ):
"""
Returns summary tree data for a given genomic region.
"""
filename = self.converted_dataset.file_name
st = self.CACHE[filename]
if st is None:
st = summary_tree_from_file( self.converted_dataset.file_name )
self.CACHE[filename] = st
# Look for chrom in tree using both naming conventions.
if chrom not in st.chrom_blocks:
chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
if chrom not in st.chrom_blocks:
return None
# Get or compute level.
if level:
level = int( level )
elif resolution:
resolution = max( 1, ceil( float( resolution ) ) )
level = ceil( log( resolution, st.block_size ) ) - 1
level = int( max( level, 0 ) )
else:
# Either level or resolution is required.
return None
if level <= 1:
return "detail"
# Use level to get results.
stats = st.chrom_stats[ chrom ]
results = st.query( chrom, int(start), int(end), level, detail_cutoff=detail_cutoff, draw_cutoff=draw_cutoff )
if results == "detail" or results == "draw":
return results
else:
return {
'dataset_type': self.dataset_type,
'data': results,
'max': stats[ level ][ "max" ],
'avg': stats[ level ][ "avg" ],
'delta': stats[ level ][ "delta" ],
'level': level
}
def has_data( self, chrom ):
"""
Returns true if dataset has data for this chrom
"""
# Get summary tree.
filename = self.converted_dataset.file_name
st = self.CACHE[filename]
if st is None:
st = summary_tree_from_file( self.converted_dataset.file_name )
self.CACHE[filename] = st
# Check for data.
return st.chrom_blocks.get(chrom, None) or st.chrom_blocks.get(_convert_between_ucsc_and_ensemble_naming(chrom), None)
class BamDataProvider( GenomeDataProvider, FilterableMixin ):
"""
Provides access to intervals from a sorted indexed BAM file. Coordinate
@@ -29,7 +29,6 @@ class DataProviderRegistry( object ):
"interval_index": genome.IntervalIndexDataProvider,
"bai": genome.BamDataProvider,
"bam": genome.SamDataProvider,
"summary_tree": genome.SummaryTreeDataProvider,
"bigwig": genome.BigWigDataProvider,
"bigbed": genome.BigBedDataProvider
}
-117
View File
@@ -1,117 +0,0 @@
'''
This module cannot be moved due to the use of pickling.
'''
import sys, os
import cPickle
# TODO: What are the performance implications of setting min level to 1? Data
# structure size and/or query speed? It would be nice to have level 1 data
# so that client does not have to compute it.
MIN_LEVEL = 2
class SummaryTree:
'''
Summary tree data structure for feature aggregation across large genomic regions.
'''
def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
self.chrom_blocks = {}
self.levels = levels
self.draw_cutoff = draw_cutoff
self.detail_cutoff = detail_cutoff
self.block_size = block_size
self.chrom_stats = {}
def find_block( self, num, level ):
""" Returns block that num is in for level. """
return ( num / self.block_size ** level )
def insert_range( self, chrom, start, end ):
""" Inserts a feature at chrom:start-end into the tree. """
# Get or set up chrom blocks.
if chrom in self.chrom_blocks:
blocks = self.chrom_blocks[ chrom ]
else:
blocks = self.chrom_blocks[ chrom ] = {}
self.chrom_stats[ chrom ] = {}
for level in range( MIN_LEVEL, self.levels + 1 ):
blocks[ level ] = {}
# Insert feature into all matching blocks at all levels.
for level in range( MIN_LEVEL, self.levels + 1 ):
block_level = blocks[ level ]
starting_block = self.find_block( start, level )
ending_block = self.find_block( end, level )
for block in range( starting_block, ending_block + 1 ):
if block in block_level:
block_level[ block ] += 1
else:
block_level[ block ] = 1
def finish( self ):
""" Compute stats for levels. """
for chrom, blocks in self.chrom_blocks.iteritems():
for level in range( self.levels, MIN_LEVEL - 1, -1 ):
# Set level's stats.
max_val = max( blocks[ level ].values() )
self.chrom_stats[ chrom ][ level ] = {}
self.chrom_stats[ chrom ][ level ][ "delta" ] = self.block_size ** level
self.chrom_stats[ chrom ][ level ][ "max" ] = max_val
self.chrom_stats[ chrom ][ level ][ "avg" ] = float( max_val ) / len( blocks[ level ] )
self.chrom_blocks[ chrom ] = dict( [ ( key, value ) for key, value in blocks.iteritems() ] )
def query( self, chrom, start, end, level, draw_cutoff=None, detail_cutoff=None ):
""" Queries tree for data. """
# Set cutoffs to self's attributes if not defined.
if draw_cutoff != 0:
draw_cutoff = self.draw_cutoff
if detail_cutoff != 0:
detail_cutoff = self.detail_cutoff
# Get data.
if chrom in self.chrom_blocks:
stats = self.chrom_stats[ chrom ]
# For backwards compatibility:
if "detail_level" in stats and level <= stats[ "detail_level" ]:
return "detail"
elif "draw_level" in stats and level <= stats[ "draw_level" ]:
return "draw"
# If below draw, detail level, return string to denote this.
max = stats[ level ][ "max" ]
if max < detail_cutoff:
return "detail"
if max < draw_cutoff:
return "draw"
# Return block data.
blocks = self.chrom_blocks[ chrom ]
results = []
multiplier = self.block_size ** level
starting_block = self.find_block( start, level )
ending_block = self.find_block( end, level )
for block in range( starting_block, ending_block + 1 ):
val = 0
if block in blocks[ level ]:
val = blocks[ level ][ block ]
results.append( ( block * multiplier, val ) )
return results
return None
def write( self, filename ):
""" Writes tree to file. """
self.finish()
cPickle.dump( self, open( filename, 'wb' ), 2 )
def summary_tree_from_file( filename ):
st_file = open( filename, "rb" )
st = cPickle.load( st_file )
st_file.close()
return st
+29 -20
View File
@@ -145,32 +145,41 @@ class DatasetsController( BaseAPIController, UsesVisualizationMixin, UsesHistory
extra_info = None
mode = kwargs.get( "mode", "Auto" )
# Handle histogram mode uniquely for now:
data_provider_registry = trans.app.data_provider_registry
# Coverage mode uses index data.
if mode == "Coverage":
# Get summary using minimal cutoffs.
indexer = data_provider_registry.get_data_provider( trans, original_dataset=dataset, source='index' )
summary = indexer.get_data( chrom, low, high, detail_cutoff=0, draw_cutoff=0, **kwargs )
if summary == "detail":
# Use maximum level of detail--2--to get summary data no matter the resolution.
summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ],
level=2, detail_cutoff=0, draw_cutoff=0 )
return summary
return indexer.get_data( chrom, low, high, **kwargs )
if 'index' in data_sources and data_sources['index']['name'] == "summary_tree" and mode == "Auto":
# Only check for summary_tree if it's Auto mode (which is the default)
#
# Have to choose between indexer and data provider
# TODO:
# (1) add logic back in for no_detail
# (2) handle scenario where mode is Squish/Pack but data requested is large, so reduced data needed to be returned.
# If mode is Auto, need to determine what type of data to return.
if mode == "Auto":
# Get stats from indexer.
indexer = data_provider_registry.get_data_provider( trans, original_dataset=dataset, source='index' )
summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ] )
if summary is None:
return { 'dataset_type': indexer.dataset_type, 'data': None }
if summary == "draw":
kwargs["no_detail"] = True # meh
extra_info = "no_detail"
elif summary != "detail":
return summary
stats = indexer.get_data( chrom, low, high, stats=True )
# If stats were requested, return them.
if 'stats' in kwargs:
if stats[ 'data' ][ 'max' ] == 0:
return { 'dataset_type': indexer.dataset_type, 'data': None }
else:
return stats
# Use heuristic based on max depth and region size to determine whether to
# return coverage data. When zoomed out and region is large, max depth
# is determining factor. However, when sufficiently zoomed in and region is
# small, coverage data is no longer provided.
if int( high ) - int( low ) > 50000 and stats[ 'data' ][ 'max' ] > 1000:
return indexer.get_data( chrom, low, high )
#
# Provide individual data points.
#
# Get data provider.
data_provider = data_provider_registry.get_data_provider( trans, original_dataset=dataset, source='data' )
-1
View File
@@ -58,7 +58,6 @@ var ConfigSetting = Backbone.Model.extend({
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
{ key: 'reverse_strand_color', label: 'Antisense strand color', type: 'color', default_value: null },
{ key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
{ key: 'histogram_max', label: 'Histogram maximum', type: 'float', default_value: null, help: 'Clear value to set automatically' },
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true }
]
});
-44
View File
@@ -133,49 +133,6 @@ Painter.prototype.default_prefs = {};
*/
Painter.prototype.draw = function(ctx, width, height, w_scale) {};
/**
* SummaryTreePainter, a histogram showing number of intervals in a region
*/
var SummaryTreePainter = function(data, view_start, view_end, prefs, mode) {
Painter.call(this, data, view_start, view_end, prefs, mode);
};
SummaryTreePainter.prototype.default_prefs = { show_counts: false };
SummaryTreePainter.prototype.draw = function(ctx, width, height, w_scale) {
var view_start = this.view_start,
points = this.data.data,
max = (this.prefs.histogram_max ? this.prefs.histogram_max : this.data.max),
// Set base Y so that max label and data do not overlap. Base Y is where rectangle bases
// start. However, height of each rectangle is relative to required_height; hence, the
// max rectangle is required_height.
base_y = height,
delta_x_px = Math.ceil(this.data.delta * w_scale);
ctx.save();
for (var i = 0, len = points.length; i < len; i++) {
var x = Math.floor( (points[i][0] - view_start) * w_scale );
var y = points[i][1];
if (!y) { continue; }
var y_px = y / max * height;
if (y !== 0 && y_px < 1) { y_px = 1; }
ctx.fillStyle = this.prefs.block_color;
ctx.fillRect( x, base_y - y_px, delta_x_px, y_px );
// Draw number count if it can fit the number with some padding, otherwise things clump up
var text_padding_req_x = 4;
if (this.prefs.show_counts && (ctx.measureText(y).width + text_padding_req_x) < delta_x_px) {
ctx.fillStyle = this.prefs.label_color;
ctx.textAlign = "center";
ctx.fillText(y, x + (delta_x_px/2), 10);
}
}
ctx.restore();
};
var LinePainter = function(data, view_start, view_end, prefs, mode) {
Painter.call( this, data, view_start, view_end, prefs, mode );
var i, len;
@@ -1692,7 +1649,6 @@ extend(VariantPainter.prototype, Painter.prototype, {
return {
Scaler: Scaler,
SummaryTreePainter: SummaryTreePainter,
LinePainter: LinePainter,
LinkedFeaturePainter: LinkedFeaturePainter,
ReadPainter: ReadPainter,
+147 -99
View File
@@ -2076,11 +2076,10 @@ var Tile = function(track, region, resolution, canvas, data) {
*/
Tile.prototype.predisplay_actions = function() {};
var SummaryTreeTile = function(track, region, resolution, canvas, data, max_val) {
var LineTrackTile = function(track, region, resolution, canvas, data) {
Tile.call(this, track, region, resolution, canvas, data);
this.max_val = max_val;
};
extend(SummaryTreeTile.prototype, Tile.prototype);
LineTrackTile.prototype.predisplay_actions = function() {};
var FeatureTrackTile = function(track, region, resolution, canvas, data, w_scale, mode, message, all_slotted, feature_mapper) {
// Attribute init.
@@ -2601,7 +2600,7 @@ extend(Track.prototype, Drawable.prototype, {
track.enabled = false;
track.tile_cache.clear();
track.data_manager.clear();
track.content_div.css("height", "auto");
track.tiles_div.css("height", "auto");
/*
if (!track.content_div.text()) {
track.content_div.text(DATA_LOADING);
@@ -2669,7 +2668,7 @@ extend(Track.prototype, Drawable.prototype, {
track.tiles_div.css( "height", track.visible_height_px + "px" );
track.enabled = true;
// predraw_init may be asynchronous, wait for it and then draw
$.when(track.predraw_init()).done(function() {
$.when.apply($, track.predraw_init()).done(function() {
init_deferred.resolve();
track.container_div.removeClass("nodata error pending");
track.request_draw();
@@ -2688,7 +2687,29 @@ extend(Track.prototype, Drawable.prototype, {
/**
* Additional initialization required before drawing track for the first time.
*/
predraw_init: function() {},
predraw_init: function() {
var track = this;
return $.getJSON( track.dataset.url(),
{ data_type: 'data', stats: true, chrom: track.view.chrom, low: 0,
high: track.view.max_high, hda_ldda: track.dataset.get('hda_ldda') }, function(result) {
track.container_div.addClass( "line-track" );
var data = result.data;
// Tracks may not have stat data either because there is no data or data is not yet ready.
if (data && data.min && data.max) {
// Compute default minimum and maximum values
var min_value = data.min,
max_value = data.max;
// If mean and sd are present, use them to compute a ~95% window
// but only if it would shrink the range on one side
min_value = Math.floor( Math.min( 0, Math.max( min_value, data.mean - 2 * data.sd ) ) );
max_value = Math.ceil( Math.max( 0, Math.min( max_value, data.mean + 2 * data.sd ) ) );
// Update the prefs
track.prefs.min_value = min_value;
track.prefs.max_value = max_value;
}
});
},
/**
* Returns all drawables in this drawable.
@@ -2800,6 +2821,32 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
};
},
/**
* Set track bounds for current chromosome.
*/
set_min_max: function() {
var track = this;
return $.getJSON( track.dataset.url(),
{ data_type: 'data', stats: true, chrom: track.view.chrom, low: 0,
high: track.view.max_high, hda_ldda: track.dataset.get('hda_ldda') },
function(result) {
var data = result.data;
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
// Compute default minimum and maximum values
var min_value = data.min,
max_value = data.max;
// If mean and sd are present, use them to compute a ~95% window
// but only if it would shrink the range on one side
min_value = Math.floor( Math.min( 0, Math.max( min_value, data.mean - 2 * data.sd ) ) );
max_value = Math.ceil( Math.max( 0, Math.min( max_value, data.mean + 2 * data.sd ) ) );
// Update the prefs
track.prefs.min_value = min_value;
track.prefs.max_value = max_value;
}
});
},
/**
* Change track's mode.
*/
@@ -2808,6 +2855,10 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
// TODO: is it necessary to store the mode in two places (.mode and track_config)?
track.mode = new_mode;
track.config.values['mode'] = new_mode;
// FIXME: find a better way to get Auto data w/o clearing cache; using mode in the
// data manager would work if Auto data were checked for compatibility when a specific
// mode is chosen.
if (new_mode === 'Auto') { this.data_manager.clear(); }
track.request_draw(true);
this.action_icons.mode_icon.attr("title", "Set display mode (now: " + track.mode + ")");
return track;
@@ -2954,10 +3005,11 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
/**
* Add a maximum/minimum label to track.
*/
_add_yaxis_label: function(type, val, pref_name, on_change) {
_add_yaxis_label: function(type, on_change) {
var track = this,
css_class = (type === 'max' ? 'top' : 'bottom'),
text = (type === 'max' ? 'max' : 'min'),
pref_name = (type === 'max' ? 'max_value' : 'min_value'),
// Default action for on_change is to redraw track.
on_change = on_change || function() {
track.request_draw(true);
@@ -2966,11 +3018,11 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
if (label.length !== 0) {
// Label already exists, so update value.
label.text(val);
label.text(track.prefs[pref_name]);
}
else {
// Add label.
label = $("<div/>").text(val).make_text_editable({
label = $("<div/>").text(track.prefs[pref_name]).make_text_editable({
num_cols: 12,
on_finish: function(new_val) {
$(".bs-tooltip").remove();
@@ -2989,6 +3041,29 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
* drawn/fetched and shown.
*/
postdraw_actions: function(tiles, width, w_scale, clear_after) {
//
// If some tiles have line track tiles (which denote coverage data), redraw all tiles using coverage data.
//
var non_line_track_tiles = _.filter(tiles, function(tile) {
return !(tile instanceof LineTrackTile);
});
if (tiles.length !== non_line_track_tiles.length) {
// Clear because this is set when drawing.
this.max_height_px = 0;
var track = this;
_.each(non_line_track_tiles, function(tile) {
tile.html_elt.remove();
track.draw_helper(true, tile.region, tile.resolution, track.tiles_div, w_scale, { mode: 'Coverage' });
});
track._add_yaxis_label('max');
}
else {
// Remove Y-axis labels because there are no line track tiles.
this.container_div.find('.yaxislabel').remove();
}
//
// If some tiles have icons, set padding of tiles without icons so features and rows align.
//
@@ -3004,16 +3079,6 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
}
});
}
//
// If using SummaryTree tiles, show max.
//
var track = this,
first_tile = tiles[0];
if (first_tile instanceof SummaryTreeTile) {
var max_val = (this.prefs.histogram_max ? this.prefs.histogram_max : first_tile.max_val);
this._add_yaxis_label('max', max_val, 'histogram_max');
}
},
/**
@@ -3021,12 +3086,13 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
* jQuery.Deferred object that is fulfilled when tile can be drawn again.
*/
draw_helper: function(force, region, resolution, parent_element, w_scale, kwargs) {
var track = this,
key = this._gen_tile_cache_key(w_scale, region),
is_tile = function(o) { return (o && 'track' in o); };
// Init kwargs if necessary to avoid having to check if kwargs defined.
if (!kwargs) { kwargs = {}; }
var track = this,
key = this._gen_tile_cache_key(w_scale, region),
is_tile = function(o) { return (o && 'track' in o); },
mode = kwargs.mode || track.mode;
// Check tile cache, if found show existing tile in correct position
var tile = (force ? undefined : track.tile_cache.get_elt(key));
@@ -3041,7 +3107,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
var can_draw_now = true;
// Get the track data, maybe a deferred
var tile_data = track.data_manager.get_data(region, track.mode, resolution, track.data_url_extra_params);
var tile_data = track.data_manager.get_data(region, mode, resolution, track.data_url_extra_params);
if ( is_deferred( tile_data ) ) {
can_draw_now = false;
}
@@ -3049,7 +3115,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
// Get reference data if needed, maybe a deferred
var seq_data;
if ( view.reference_track ) {
seq_data = view.reference_track.data_manager.get_data(region, track.mode, resolution, view.reference_track.data_url_extra_params);
seq_data = view.reference_track.data_manager.get_data(region, mode, resolution, view.reference_track.data_url_extra_params);
if ( is_deferred( seq_data ) ) {
can_draw_now = false;
}
@@ -3066,7 +3132,6 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
// HACK: this is FeatureTrack-specific.
// If track mode is Auto, determine mode and update.
var mode = track.mode;
if (mode === "Auto" && track.get_mode) {
mode = track.get_mode(tile_data);
track.update_auto_mode(mode);
@@ -3079,7 +3144,6 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
tile_high = region.get('end'),
width = Math.ceil( (tile_high - tile_low) * w_scale ) + track.left_offset,
height = track.get_canvas_height(tile_data, mode, w_scale, width);
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
@@ -3115,12 +3179,14 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
},
/**
* Draw a track tile for summary tree data.
* Draw line (bigwig) data onto tile.
*/
_draw_summary_tree_tile: function(result, ctx, region, resolution, w_scale) {
var painter = new painters.SummaryTreePainter(result, region.get('start'), region.get('end'), this.prefs);
painter.draw(ctx, ctx.canvas.width, ctx.canvas.height, w_scale);
return new SummaryTreeTile(this, region, resolution, ctx.canvas, result.data, result.max);
_draw_line_track_tile: function(result, ctx, mode, resolution, region, w_scale) {
var canvas = ctx.canvas,
painter = new painters.LinePainter(result.data, region.get('start'), region.get('end'), this.prefs, mode);
painter.draw(ctx, canvas.width, canvas.height, w_scale);
return new LineTrackTile(this, region, resolution, canvas, result.data);
},
/**
@@ -3277,10 +3343,17 @@ var LabelTrack = function (view, container) {
};
extend(LabelTrack.prototype, Track.prototype, {
build_header_div: function() {},
init: function() {
// Enable by default because there should always be data when drawing track.
this.enabled = true;
},
/**
* Additional initialization required before drawing track for the first time.
*/
predraw_init: function() {},
_draw: function() {
var view = this.view,
range = view.high - view.low,
@@ -3623,8 +3696,8 @@ extend(CompositeTrack.prototype, TiledTrack.prototype, {
t = function() { track.update_all_min_max(); };
// Add min, max labels.
this._add_yaxis_label('min', this.drawables[0].prefs.min_value, 'min_value', t);
this._add_yaxis_label('max', this.drawables[0].prefs.max_value, 'max_value', t);
this._add_yaxis_label('min', t);
this._add_yaxis_label('max', t);
}
});
@@ -3655,6 +3728,11 @@ extend(ReferenceTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
this.enabled = true;
},
/**
* Additional initialization required before drawing track for the first time.
*/
predraw_init: function() {},
can_draw: Drawable.prototype.can_draw,
/**
@@ -3716,42 +3794,15 @@ var LineTrack = function (view, container, obj_dict) {
saved_values: obj_dict.prefs,
onchange: function() {
track.set_name(track.prefs.name);
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
track.request_redraw(true);
}
});
this.prefs = this.config.values;
this.visible_height_px = this.config.values.height;
this.vertical_range = this.config.values.max_value - this.config.values.min_value;
};
extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
predraw_init: function() {
var track = this;
track.vertical_range = undefined;
return $.getJSON( track.dataset.url(),
{ data_type: 'data', stats: true, chrom: track.view.chrom, low: 0,
high: track.view.max_high, hda_ldda: track.dataset.get('hda_ldda') }, function(result) {
track.container_div.addClass( "line-track" );
var data = result.data;
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
// Compute default minimum and maximum values
var min_value = data.min,
max_value = data.max;
// If mean and sd are present, use them to compute a ~95% window
// but only if it would shrink the range on one side
min_value = Math.floor( Math.min( 0, Math.max( min_value, data.mean - 2 * data.sd ) ) );
max_value = Math.ceil( Math.max( 0, Math.min( max_value, data.mean + 2 * data.sd ) ) );
// Update the prefs
track.prefs.min_value = min_value;
track.prefs.max_value = max_value;
}
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
track.total_frequency = data.total_frequency;
});
},
/**
* Actions to be taken before drawing.
*/
@@ -3759,18 +3810,10 @@ extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
before_draw: function() {},
/**
* Draw LineTrack tile.
* Draw track tile.
*/
draw_tile: function(result, ctx, mode, resolution, region, w_scale) {
// Paint onto canvas.
var
canvas = ctx.canvas,
tile_low = region.get('start'),
tile_high = region.get('end'),
painter = new painters.LinePainter(result.data, tile_low, tile_high, this.prefs, mode);
painter.draw(ctx, canvas.width, canvas.height, w_scale);
return new Tile(this, region, resolution, canvas, result.data);
return this._draw_line_track_tile(result, ctx, mode, resolution, region, w_scale);
},
/**
@@ -3811,14 +3854,12 @@ var DiagonalHeatmapTrack = function (view, container, obj_dict) {
saved_values: obj_dict.prefs,
onchange: function() {
track.set_name(track.prefs.name);
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
this.request_redraw(true);
}
});
this.prefs = this.config.values;
this.visible_height_px = this.config.values.height;
this.vertical_range = this.config.values.max_value - this.config.values.min_value;
};
extend(DiagonalHeatmapTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
/**
@@ -3863,7 +3904,8 @@ var FeatureTrack = function(view, container, obj_dict) {
{ key: 'label_color', label: 'Label color', type: 'color', default_value: 'black' },
{ key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true,
help: 'Show the number of items in each bin when drawing summary histogram' },
{ key: 'histogram_max', label: 'Histogram maximum', type: 'float', default_value: null, help: 'clear value to set automatically' },
{ key: 'min_value', label: 'Histogram minimum', type: 'float', default_value: null, help: 'clear value to set automatically' },
{ key: 'max_value', label: 'Histogram maximum', type: 'float', default_value: null, help: 'clear value to set automatically' },
{ key: 'connector_style', label: 'Connector style', type: 'select', default_value: 'fishbones',
options: [ { label: 'Line with arrows', value: 'fishbone' }, { label: 'Arcs', value: 'arcs' } ] },
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
@@ -3905,12 +3947,14 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
* drawn/fetched and shown.
*/
postdraw_actions: function(tiles, width, w_scale, clear_after) {
TiledTrack.prototype.postdraw_actions.call(this, tiles, clear_after);
TiledTrack.prototype.postdraw_actions.call(this, tiles, width, w_scale, clear_after);
var track = this,
i;
// If mode is Coverage and tiles do not share max, redraw tiles as necessary using new max.
/*
This code isn't used right now because Coverage mode uses predefined max in preferences.
if (track.mode === "Coverage") {
// Get global max.
var global_max = -1;
@@ -3928,7 +3972,8 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
track.draw_helper(true, tile.index, tile.resolution, tile.html_elt.parent(), w_scale, { more_tile_data: { max: global_max } } );
}
}
}
}
*/
//
// Update filter attributes, UI.
@@ -3992,17 +4037,17 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
this.action_icons.show_more_rows_icon.hide();
}
},
update_auto_mode: function( mode ) {
var mode;
if ( this.mode === "Auto" ) {
if ( mode === "no_detail" ) {
mode = "feature spans";
} else if ( mode === "summary_tree" ) {
mode = "coverage histogram";
}
this.action_icons.mode_icon.attr("title", "Set display mode (now: Auto/" + mode + ")");
}
},
/**
* Place features in slots for drawing (i.e. pack features).
* this.slotters[level] is created in this method. this.slotters[level]
@@ -4022,15 +4067,13 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
return slotter.slot_features( features );
},
/**
* Returns appropriate display mode based on data.
*/
get_mode: function(data) {
if (data.dataset_type === "summary_tree") {
mode = "summary_tree";
}
// HACK: use no_detail mode track is in overview to prevent overview from being too large.
else if (data.extra_info === "no_detail" || this.is_overview) {
if (data.extra_info === "no_detail" || this.is_overview) {
mode = "no_detail";
}
else {
@@ -4054,12 +4097,13 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
}
return mode;
},
/**
* Returns canvas height needed to display data; return value is an integer that denotes the
* number of pixels required.
*/
get_canvas_height: function(result, mode, w_scale, canvas_width) {
if (mode === "summary_tree" || mode === "Coverage") {
if (mode === "Coverage" || result.dataset_type === 'bigwig') {
return this.summary_draw_height;
}
else {
@@ -4071,6 +4115,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
return Math.max(MIN_TRACK_HEIGHT, dummy_painter.get_required_height(rows_required, canvas_width) );
}
},
/**
* Draw FeatureTrack tile.
* @param result result from server
@@ -4087,10 +4132,10 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
tile_low = region.get('start'),
tile_high = region.get('end'),
left_offset = this.left_offset;
// Drawing the summary tree.
if (mode === "summary_tree" || mode === "Coverage") {
return this._draw_summary_tree_tile(result, ctx, region, resolution, w_scale);
// If data is line track data, draw line track tile.
if (result.dataset_type === 'bigwig') {
return this._draw_line_track_tile(result, ctx, 'Histogram', resolution, region, w_scale);
}
// Handle row-by-row tracks
@@ -4147,6 +4192,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
return new FeatureTrackTile(track, region, resolution, canvas, result.data, w_scale, mode, result.message, all_slotted, feature_mapper);
},
/**
* Returns true if data is compatible with a given mode.
*/
@@ -4155,24 +4201,25 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
if (mode === "Auto") {
return true;
}
// Histogram mode requires summary_tree data.
// Histogram mode requires bigwig data.
else if (mode === "Coverage") {
return data.dataset_type === "summary_tree";
return data.dataset_type === "bigwig";
}
// All other modes--Dense, Squish, Pack--require data + details.
else if (data.extra_info === "no_detail" || data.dataset_type === "summary_tree") {
else if (data.extra_info === "no_detail") {
return false;
}
else {
return true;
}
},
/**
* Returns true if data can be subsetted.
*/
can_subset: function(data) {
// Do not subset summary tree data, entries with a message, or data with no detail.
if (data.dataset_type === "summary_tree" || data.message || data.extra_info === "no_detail") {
// Do not subset entries with a message or data with no detail.
if (data.dataset_type === 'bigwig' || data.message || data.extra_info === "no_detail") {
return false;
}
@@ -4217,9 +4264,9 @@ extend(VariantTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
* Draw tile.
*/
draw_tile: function(result, ctx, mode, resolution, region, w_scale) {
// Data could be summary tree data or variant data.
if (result.dataset_type === 'summary_tree') {
return this._draw_summary_tree_tile(result, ctx, region, resolution, w_scale);
// Data could be coverage data or variant data.
if (result.dataset_type === 'bigwig') {
return this._draw_line_track_tile(result, ctx, "Histogram", region, resolution, w_scale);
}
else { // result.dataset_type === 'variant'
var view = this.view,
@@ -4235,7 +4282,7 @@ extend(VariantTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
* number of pixels required.
*/
get_canvas_height: function(result, mode, w_scale, canvas_width) {
if (result.dataset_type === 'summary_tree') {
if (result.dataset_type === 'bigwig') {
return this.summary_draw_height;
}
else {
@@ -4264,9 +4311,11 @@ extend(VariantTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
* Additional initialization required before drawing track for the first time.
*/
predraw_init: function() {
var deferreds = [ Track.prototype.predraw_init.call(this) ];
if (!this.dataset.get_metadata('sample_names')) {
return this.dataset.fetch();
deferreds.push(this.dataset.fetch());
}
return deferreds;
},
/**
@@ -4277,7 +4326,7 @@ extend(VariantTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
TiledTrack.prototype.postdraw_actions.call(this, tiles, width, w_scale, clear_after);
// Add summary/sample labels if needed and not already included.
if ( !(tiles[0] instanceof SummaryTreeTile) && this.prefs.show_labels) {
if ( !(tiles[0] instanceof LineTrackTile) && this.prefs.show_labels) {
var font_size;
// Add and/or style labels.
@@ -4343,7 +4392,6 @@ var ReadTrack = function (view, container, obj_dict) {
{ key: 'show_insertions', label: 'Show insertions', type: 'bool', default_value: false },
{ key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
{ key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true },
{ key: 'histogram_max', label: 'Histogram maximum', type: 'float', default_value: null, help: 'Clear value to set automatically' },
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true }
],
saved_values: obj_dict.prefs,
+1 -4
View File
@@ -505,9 +505,6 @@ var GenomeDataManager = Cache.extend({
// FIXME: constant should go somewhere.
extra_params.num_samples = 1000 * detail_multiplier;
}
else if (cur_data.dataset_type === 'summary_tree') {
extra_params.level = Math.min(cur_data.level - 1, 2);
}
return this.load_data(region, mode, resolution, extra_params);
},
@@ -579,7 +576,7 @@ var GenomeDataManager = Cache.extend({
data_point[0] <= subregion.get('end');
});
},
'refseq': function(data, subregion) {
refseq: function(data, subregion) {
var seq_start = subregion.get('start') - entry.region.get('start'),
seq_end = entry.data.length - ( entry.region.get('end') - subregion.get('end') );
return entry.data.slice(seq_start, seq_end);