commit/galaxy-central: jgoecks: 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.
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/51f4926f6dd8/ Changeset: 51f4926f6dd8 User: jgoecks Date: 2013-05-09 17:44:45 Summary: 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. Affected #: 24 files diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 datatypes_conf.xml.sample --- a/datatypes_conf.xml.sample +++ b/datatypes_conf.xml.sample @@ -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" /> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/binary.py --- a/lib/galaxy/datatypes/binary.py +++ b/lib/galaxy/datatypes/binary.py @@ -103,7 +103,7 @@ """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 ) diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml --- a/lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml +++ b/lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml @@ -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"/> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/bed_gff_or_vcf_to_bigwig_converter.xml --- /dev/null +++ b/lib/galaxy/datatypes/converters/bed_gff_or_vcf_to_bigwig_converter.xml @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/encodepeak_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/encodepeak_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/gff_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/gff_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py --- a/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py +++ /dev/null @@ -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() diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py --- a/lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py +++ /dev/null @@ -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() diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/sam_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/sam_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py --- a/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py +++ /dev/null @@ -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() \ No newline at end of file diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.xml +++ /dev/null @@ -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> diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/interval.py --- a/lib/galaxy/datatypes/interval.py +++ b/lib/galaxy/datatypes/interval.py @@ -47,7 +47,7 @@ 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 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 @@ """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 @@ 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 @@ 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' ] diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/datatypes/tabular.py --- a/lib/galaxy/datatypes/tabular.py +++ b/lib/galaxy/datatypes/tabular.py @@ -359,7 +359,7 @@ 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 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' ] diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/visualization/data_providers/genome.py --- a/lib/galaxy/visualization/data_providers/genome.py +++ b/lib/galaxy/visualization/data_providers/genome.py @@ -14,7 +14,6 @@ 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 @@ 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 diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/visualization/data_providers/registry.py --- a/lib/galaxy/visualization/data_providers/registry.py +++ b/lib/galaxy/visualization/data_providers/registry.py @@ -29,7 +29,6 @@ "interval_index": genome.IntervalIndexDataProvider, "bai": genome.BamDataProvider, "bam": genome.SamDataProvider, - "summary_tree": genome.SummaryTreeDataProvider, "bigwig": genome.BigWigDataProvider, "bigbed": genome.BigBedDataProvider } diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/visualization/tracks/summary.py --- a/lib/galaxy/visualization/tracks/summary.py +++ /dev/null @@ -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 - diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 lib/galaxy/webapps/galaxy/api/datasets.py --- a/lib/galaxy/webapps/galaxy/api/datasets.py +++ b/lib/galaxy/webapps/galaxy/api/datasets.py @@ -145,32 +145,41 @@ 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' ) diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 static/scripts/utils/config.js --- a/static/scripts/utils/config.js +++ b/static/scripts/utils/config.js @@ -58,7 +58,6 @@ { 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 } ] }); diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 static/scripts/viz/trackster/painters.js --- a/static/scripts/viz/trackster/painters.js +++ b/static/scripts/viz/trackster/painters.js @@ -133,49 +133,6 @@ */ 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 @@ return { Scaler: Scaler, - SummaryTreePainter: SummaryTreePainter, LinePainter: LinePainter, LinkedFeaturePainter: LinkedFeaturePainter, ReadPainter: ReadPainter, diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 static/scripts/viz/trackster/tracks.js --- a/static/scripts/viz/trackster/tracks.js +++ b/static/scripts/viz/trackster/tracks.js @@ -2076,11 +2076,10 @@ */ 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 @@ 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 @@ 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 @@ /** * 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. @@ -2801,6 +2822,32 @@ }, /** + * 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. */ change_mode: function(new_mode) { @@ -2808,6 +2855,10 @@ // 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 @@ /** * 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 @@ 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(); @@ -2990,6 +3042,29 @@ */ 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. // var icons_present = _.find(tiles, function(tile) { @@ -3004,16 +3079,6 @@ } }); } - - // - // 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 @@ * jQuery.Deferred object that is fulfilled when tile can be drawn again. */ draw_helper: function(force, region, resolution, parent_element, w_scale, kwargs) { + // 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); }; - - // Init kwargs if necessary to avoid having to check if kwargs defined. - if (!kwargs) { kwargs = {}; } + 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ }, /** - * 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 @@ }; 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ * 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 @@ 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 @@ { 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, diff -r 38a9047cd5877b9123c06a92c2c53b6b488733cf -r 51f4926f6dd8b837c02dd8559587342542cdd7f2 static/scripts/viz/visualization.js --- a/static/scripts/viz/visualization.js +++ b/static/scripts/viz/visualization.js @@ -505,9 +505,6 @@ // 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 @@ 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); Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org