1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/d6d0c963712a/ changeset: d6d0c963712a user: jgoecks date: 2012-09-25 15:18:00 summary: Viz framework: (a) improvements in setting dataset type when returning infomation; (b) transition Circster to use GenomeDataManager rather than custom data structures. affected #: 7 files diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 lib/galaxy/visualization/data_providers/genome.py --- a/lib/galaxy/visualization/data_providers/genome.py +++ b/lib/galaxy/visualization/data_providers/genome.py @@ -113,7 +113,7 @@ class GenomeDataProvider( BaseDataProvider ): """ Base class for genome data providers. """ - data_type = None + dataset_type = None """ Mapping from column name to payload data; this mapping is used to create @@ -179,12 +179,21 @@ """ Returns data for complete genome. """ - dataset_summary = [] + genome_data = [] for chrom_info in chroms_info[ 'chrom_info' ]: - summary = self.get_data( chrom_info[ 'chrom' ], 0, chrom_info[ 'len' ], **kwargs ) - dataset_summary.append( summary ) + chrom = chrom_info[ 'chrom' ] + chrom_len = chrom_info[ 'len' ] + chrom_data = self.get_data( chrom, 0, chrom_len, **kwargs ) + if chrom_data: + chrom_data[ 'region' ] = "%s:%i-%i" % ( chrom, 0, chrom_len ) + chrom_data[ 'dataset_type' ] = self.dataset_type + genome_data.append( chrom_data ) - return dataset_summary + return { + 'data': genome_data, + 'dataset_type': self.dataset_type + } + def get_filters( self ): """ @@ -316,7 +325,7 @@ class TabixDataProvider( FilterableMixin, GenomeDataProvider ): - data_type = 'tabix' + dataset_type = 'tabix' """ Tabix index data provider for the Galaxy track browser. @@ -358,7 +367,7 @@ # class IntervalDataProvider( GenomeDataProvider ): - data_type = 'interval_index' + dataset_type = 'interval_index' """ Processes interval data from native format to payload format. @@ -444,7 +453,7 @@ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ] """ - data_type = 'interval_index' + dataset_type = 'interval_index' def get_iterator( self, chrom, start, end ): raise Exception( "Unimplemented Method" ) @@ -541,7 +550,7 @@ for large datasets. """ - data_type = 'interval_index' + dataset_type = 'interval_index' def get_iterator( self, chrom=None, start=None, end=None ): # Read first line in order to match chrom naming format. @@ -581,7 +590,7 @@ col_name_data_attr_mapping = { 'Qual' : { 'index': 6 , 'name' : 'Qual' } } - data_type = 'bai' + dataset_type = 'bai' def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ): """ @@ -687,7 +696,7 @@ for large datasets. """ - data_type = 'tabix' + dataset_type = 'tabix' def get_iterator( self, chrom, start, end ): # Read first line in order to match chrom naming format. @@ -721,7 +730,7 @@ Summary tree data provider for the Galaxy track browser. """ - data_type = 'summary_tree' + dataset_type = 'summary_tree' CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance @@ -765,7 +774,13 @@ if results == "detail" or results == "draw": return results else: - return results, stats[ level ][ "max" ], stats[ level ]["avg" ], stats[ level ][ "delta" ] + return { + 'dataset_type': self.dataset_type, + 'data': results, + 'max': stats[ level ][ "max" ], + 'avg': stats[ level ][ "avg" ], + 'delta': stats[ level ][ "delta" ] + } def has_data( self, chrom ): """ @@ -788,7 +803,7 @@ is reported in 1-based, closed format, i.e. SAM/BAM format. """ - data_type = 'bai' + dataset_type = 'bai' def get_filters( self ): """ @@ -970,7 +985,7 @@ class SamDataProvider( BamDataProvider ): - data_type = 'bai' + dataset_type = 'bai' def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ): """ Create SamDataProvider. """ @@ -987,7 +1002,7 @@ BBI data provider for the Galaxy track browser. """ - data_type = 'bigwig' + dataset_type = 'bigwig' def valid_chroms( self ): # No way to return this info as of now @@ -1122,7 +1137,7 @@ """ col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } } - data_type = 'interval_index' + dataset_type = 'interval_index' def write_data_to_file( self, regions, filename ): source = open( self.original_dataset.file_name ) @@ -1201,7 +1216,7 @@ for large datasets. """ - data_type = 'interval_index' + dataset_type = 'interval_index' def get_iterator( self, chrom, start, end ): """ diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 lib/galaxy/web/api/datasets.py --- a/lib/galaxy/web/api/datasets.py +++ b/lib/galaxy/web/api/datasets.py @@ -139,12 +139,15 @@ 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, resolution=kwargs[ 'resolution' ], detail_cutoff=0, draw_cutoff=0 ) + summary = indexer.get_data( chrom, low, high, + resolution=kwargs[ 'resolution' ], + level=kwargs.get( 'level', None ), + detail_cutoff=0, draw_cutoff=0 ) 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 ) frequencies, max_v, avg_v, delta = summary - return { 'dataset_type': indexer.data_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta } + return { 'dataset_type': indexer.dataset_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta } 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) @@ -153,14 +156,13 @@ 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.data_type, 'data': None } + return { 'dataset_type': indexer.dataset_type, 'data': None } if summary == "draw": kwargs["no_detail"] = True # meh extra_info = "no_detail" elif summary != "detail": - frequencies, max_v, avg_v, delta = summary - return { 'dataset_type': indexer.data_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta } + return summary # Get data provider. data_provider = data_provider_registry.get_data_provider( trans, original_dataset=dataset, source='data' ) @@ -171,7 +173,7 @@ # Get and return data from data_provider. result = data_provider.get_data( chrom, int( low ), int( high ), int( start_val ), int( max_vals ), **kwargs ) - result.update( { 'dataset_type': data_provider.data_type, 'extra_info': extra_info } ) + result.update( { 'dataset_type': data_provider.dataset_type, 'extra_info': extra_info } ) return result def _raw_data( self, trans, dataset, **kwargs ): diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 lib/galaxy/web/controllers/visualization.py --- a/lib/galaxy/web/controllers/visualization.py +++ b/lib/galaxy/web/controllers/visualization.py @@ -760,7 +760,7 @@ original_dataset=dataset, source='index' ) # HACK: pass in additional params, which are only used for summary tree data, not BBI data. - track[ 'genome_wide_data' ] = { 'data': data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 ) } + track[ 'preloaded_data' ] = data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 ) return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome ) diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 static/scripts/viz/circster.js --- a/static/scripts/viz/circster.js +++ b/static/scripts/viz/circster.js @@ -1,4 +1,4 @@ -define( ["libs/d3", "viz/visualization"], function( d3, visualization ) { +define( ["libs/underscore", "libs/d3", "viz/visualization"], function(_, d3, visualization) { // General backbone style inheritence var Base = function() { this.initialize && this.initialize.apply(this, arguments); }; Base.extend = Backbone.Model.extend; @@ -48,7 +48,8 @@ // Compute radius start based on model, will be centered // and fit entirely inside element by default. init_radius_start = ( Math.min(width, height)/2 - - this.model.get('tracks').length * (this.dataset_arc_height + this.track_gap) ); + this.model.get('tracks').length * (this.dataset_arc_height + this.track_gap) ), + tracks = this.model.get('tracks'); // Set up SVG element. var svg = d3.select(self.$el[0]) @@ -59,26 +60,37 @@ // Set up zooming, dragging. .append('svg:g') .call(d3.behavior.zoom().on('zoom', function() { + // Do zoom. svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); - var utils = new SVGUtils(); - var visible_elts = d3.selectAll('path').filter(function(d, i) { + + // Update visible elements with more data. + var utils = new SVGUtils(), + tracks_and_chroms_to_update = {}; + + tracks.each(function(t) { + tracks_and_chroms_to_update[t.id] = []; + }); + + d3.selectAll('path.chrom-data').filter(function(d, i) { return utils.is_visible(this, svg); + }).each(function(d, i) { + var elt_data = $.data(this, "chrom_data"); + tracks_and_chroms_to_update[elt_data.track.id].push(elt_data.chrom); }); - visible_elts.each(function(d, i) { - // TODO: redraw visible elements. - }); + + // TODO: update tracks and chroms. + //console.log(tracks_and_chroms_to_update); })) .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .append('svg:g'); // -- Render each dataset in the visualization. -- - this.model.get('tracks').each(function(track, index) { - var dataset = track.get('genome_wide_data'), - radius_start = init_radius_start + index * (dataset_arc_height + self.track_gap), - track_renderer_class = (dataset instanceof visualization.GenomeWideBigWigData ? + tracks.each(function(track, index) { + var radius_start = init_radius_start + index * (dataset_arc_height + self.track_gap), + track_renderer_class = (track.get('track_type') === 'LineTrack' ? CircsterBigWigTrackRenderer : CircsterSummaryTreeTrackRenderer ); @@ -160,12 +172,17 @@ render_data: function(svg) { var self = this, chrom_arcs = this.chroms_layout(), - dataset = this.options.track.get('genome_wide_data'), + track = this.options.track, r_start = this.options.radius_start, r_end = this.options.radius_end, + + genome_wide_data = track.get_genome_wide_data(this.options.genome), // Merge chroms layout with data. - layout_and_data = _.zip(chrom_arcs, dataset.get('data')), + layout_and_data = _.zip(chrom_arcs, genome_wide_data), + + // Get min, max in data. + bounds = this.get_bounds(genome_wide_data), // Do dataset layout for each chromosome's data using pie layout. chroms_data_layout = _.map(layout_and_data, function(chrom_info) { @@ -173,7 +190,7 @@ data = chrom_info[1]; return self.render_chrom_data(svg, chrom_arc, data, r_start, r_end, - dataset.get('min'), dataset.get('max')); + bounds.min, bounds.max); }); return chroms_data_layout; @@ -187,7 +204,7 @@ /** * Renders quantitative data with the form [x, value] and assumes data is equally spaced across - * chromosome. + * chromosome. Attachs a dict with track and chrom name information to DOM element. */ render_quantitative_data: function(svg, chrom_arc, data, inner_radius, outer_radius, min, max) { // Radius scaler. @@ -212,14 +229,25 @@ .angle(line.angle()); // Render data. - var parent = svg.datum(data); - - parent.append("path") - .attr("class", "chrom-data") - .attr("d", area); - } + var parent = svg.datum(data), + path = parent.append("path") + .attr("class", "chrom-data") + .attr("d", area); -}) + // Attach dict with track and chrom info for path. + $.data(path[0][0], "chrom_data", { + track: this.options.track, + chrom: chrom_arc.data.chrom + }); + }, + + /** + * Returns an object with min, max attributes denoting the minimum and maximum + * values for the track. + */ + get_bounds: function() {} + +}); /** * Layout for summary tree data in a circster visualization. @@ -235,7 +263,19 @@ return null; } - return this.render_quantitative_data(svg, chrom_arc, chrom_data[0], inner_radius, outer_radius, min, max); + return this.render_quantitative_data(svg, chrom_arc, chrom_data.data, inner_radius, outer_radius, min, max); + }, + + get_bounds: function(data) { + // Get max across data. + var max_data = _.map(data, function(d) { + if (!d || typeof d === 'string') { return 0; } + return d.max; + }); + return { + min: 0, + max: (max_data && typeof max_data !== 'string' ? _.max(max_data) : 0) + }; } }); @@ -252,6 +292,27 @@ if (data.length === 0) { return; } return this.render_quantitative_data(svg, chrom_arc, data, inner_radius, outer_radius, min, max); + }, + + get_bounds: function(data) { + // Set max across dataset by extracting all values, flattening them into a + // single array, and getting the min and max. + var values = _.flatten( _.map(data, function(d) { + if (d) { + // Each data point has the form [position, value], so return all values. + return _.map(d.data, function(p) { + return p[1]; + }); + } + else { + return 0; + } + }) ); + + return { + min: _.min(values), + max: _.max(values) + }; } }); diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 static/scripts/viz/trackster/tracks.js --- a/static/scripts/viz/trackster/tracks.js +++ b/static/scripts/viz/trackster/tracks.js @@ -3550,8 +3550,7 @@ 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.hda_ldda, dataset_id: - track.dataset_id }, function(result) { + high: track.view.max_high, hda_ldda: track.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)) ) { diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 static/scripts/viz/visualization.js --- a/static/scripts/viz/visualization.js +++ b/static/scripts/viz/visualization.js @@ -1,4 +1,4 @@ -define( ["mvc/data", "viz/trackster/util" ], function(data, util) { +define( ["mvc/data", "viz/trackster/util" ], function(data_mod, util_mod) { /** * Model, view, and controller objects for Galaxy visualization framework. @@ -138,7 +138,6 @@ dataset: null, filters_manager: null, data_type: "data", - genome_wide_summary_data: null, data_mode_compatible: function(entry, mode) { return true; }, can_subset: function(entry) { return false; } }), @@ -150,7 +149,7 @@ data_is_ready: function() { var dataset = this.get('dataset'), ready_deferred = $.Deferred(), - ss_deferred = new util.ServerStateDeferred({ + ss_deferred = new util_mod.ServerStateDeferred({ ajax_settings: { url: this.get('dataset').url(), data: { @@ -176,7 +175,6 @@ var dataset = this.get('dataset'), params = { query: query, - dataset_id: dataset.id, hda_ldda: dataset.get('hda_ldda'), data_type: 'features' }; @@ -188,22 +186,17 @@ */ load_data: function(region, mode, resolution, extra_params) { // Setup data request params. - var params = { + var dataset = this.get('dataset'), + params = { "data_type": this.get('data_type'), "chrom": region.get('chrom'), "low": region.get('start'), "high": region.get('end'), "mode": mode, - "resolution": resolution - }, - dataset = this.get('dataset'); - - // ReferenceDataManager does not have dataset. - if (dataset) { - params.dataset_id = dataset.id; - params.hda_ldda = dataset.get('hda_ldda'); - } - + "resolution": resolution, + "hda_ldda": dataset.get('hda_ldda') + }; + $.extend(params, extra_params); // Add track filters to params. @@ -533,69 +526,53 @@ model: BrowserBookmark }); -var GenomeWideBigWigData = Backbone.Model.extend({ - defaults: { - data: null, - min: 0, - max: 0 - }, - - initialize: function(options) { - // Set max across dataset by extracting all values, flattening them into a - // single array, and getting the min and max. - var values = _.flatten( _.map(this.get('data'), function(d) { - if (d.data.length !== 0) { - // Each data point has the form [position, value], so return all values. - return _.map(d.data, function(p) { - return p[1]; - }); - } - else { - return 0; - } - }) ); - this.set('max', _.max(values)); - this.set('min', _.min(values)); - } -}); - -/** - * Genome-wide summary tree dataset. - */ -var GenomeWideSummaryTreeData = Backbone.RelationalModel.extend({ - defaults: { - data: null, - min: 0, - max: 0 - }, - - initialize: function(options) { - // Set max across dataset. - var max_data = _.max(this.get('data'), function(d) { - if (!d || typeof d === 'string') { return 0; } - return d[1]; - }); - this.attributes.max = (max_data && typeof max_data !== 'string' ? max_data[1] : 0); - } -}); - /** * A track of data in a genome visualization. */ // TODO: rename to Track and merge with Trackster's Track object. -var BackboneTrack = data.Dataset.extend({ +var BackboneTrack = data_mod.Dataset.extend({ initialize: function(options) { // Dataset id is unique ID for now. this.set('id', options.dataset_id); - // Create genome-wide dataset if available. - var genome_wide_data = this.get('genome_wide_data'); - if (genome_wide_data) { - var gwd_class = (this.get('track_type') === 'LineTrack' ? - GenomeWideBigWigData : GenomeWideSummaryTreeData); - this.set('genome_wide_data', new gwd_class(genome_wide_data)); + // Set up data manager. + var data_manager = new GenomeDataManager({ + dataset: this + }); + this.set('data_manager', data_manager); + + // If there's preloaded data, add it to data manager. + var preloaded_data = this.get('preloaded_data'); + if (preloaded_data) { + // Increase size to accomodate all preloaded data. + data_manager.set('num_elements', preloaded_data.data.length); + + // Put data into manager. + _.each(preloaded_data.data, function(entry) { + data_manager.set_data(entry.region, entry); + }); } + }, + + /** + * Returns an array of data with each entry representing one chromosome/contig + * of data. + */ + get_genome_wide_data: function(genome) { + var self = this, + data_manager = this.get('data_manager'); + + // Map chromosome data into track data. + return _.map(genome.get('chroms_info').chrom_info, function(chrom_info) { + return data_manager.get_elt( + new GenomeRegion({ + chrom: chrom_info.chrom, + start: 0, + end: chrom_info.len + }) + ); + }); } }); @@ -716,7 +693,7 @@ }, id = $(this).val(); if ($(this).attr("name") !== "id") { - data['hda_ldda'] = 'ldda'; + data.hda_ldda = 'ldda'; } requests[requests.length] = $.ajax({ url: add_track_async_url + "/" + id, @@ -754,8 +731,6 @@ GenomeRegion: GenomeRegion, GenomeRegionCollection: GenomeRegionCollection, GenomeVisualization: GenomeVisualization, - GenomeWideBigWigData: GenomeWideBigWigData, - GenomeWideSummaryTreeData: GenomeWideSummaryTreeData, ReferenceTrackDataManager: ReferenceTrackDataManager, TrackBrowserRouter: TrackBrowserRouter, TrackConfig: TrackConfig, diff -r 36ca2ecd42fdbc581b0caa253b66a136aa0f848a -r d6d0c963712a9f85a6a2baede6ec402285088823 templates/visualization/circster.mako --- a/templates/visualization/circster.mako +++ b/templates/visualization/circster.mako @@ -23,6 +23,7 @@ require.config({ baseUrl: "${h.url_for('/static/scripts')}", shim: { + "libs/underscore": { exports: "_" }, "libs/d3": { exports: "d3" } } }); 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.