diff --git a/lib/galaxy/webapps/galaxy/api/datasets.py b/lib/galaxy/webapps/galaxy/api/datasets.py index b68206ac78c..2d49caa9261 100644 --- a/lib/galaxy/webapps/galaxy/api/datasets.py +++ b/lib/galaxy/webapps/galaxy/api/datasets.py @@ -187,7 +187,6 @@ class DatasetsController( BaseAPIController, UsesVisualizationMixin ): when the dataset is not yet indexed and hence using data would be slow because indexes need to be created. """ - # Dataset check. msg = self.check_dataset_state( trans, dataset ) if msg: diff --git a/lib/galaxy/webapps/galaxy/controllers/history.py b/lib/galaxy/webapps/galaxy/controllers/history.py index 5512c6eb893..60140a55565 100644 --- a/lib/galaxy/webapps/galaxy/controllers/history.py +++ b/lib/galaxy/webapps/galaxy/controllers/history.py @@ -1322,4 +1322,3 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI def get_item( self, trans, id ): return self.get_history( trans, id ) - diff --git a/lib/galaxy/webapps/galaxy/controllers/visualization.py b/lib/galaxy/webapps/galaxy/controllers/visualization.py index 5f527b73bc8..11ef4209d8d 100644 --- a/lib/galaxy/webapps/galaxy/controllers/visualization.py +++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py @@ -793,9 +793,23 @@ class VisualizationController( BaseUIController, SharableMixin, UsesAnnotations, hda = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True ) hda_dict = hda.get_api_value() hda_dict[ 'id' ] = dataset_id - if( hda_dict[ 'metadata_column_names' ] == None - and hasattr( hda.datatype, 'column_names' ) ): - hda_dict[ 'metadata_column_names' ] = hda.datatype.column_names + + if( ( hda_dict[ 'metadata_column_names' ] == None ) + and ( hasattr( hda.datatype, 'column_names' ) ) ): + hda_dict[ 'metadata_column_names' ] = hda.datatype.column_names + + # try to get the first line (assuming it's a header) + #TODO: doesn't belong here + try: + with open( hda.file_name ) as infile: + for index, line in enumerate( infile ): + if 'comment_lines' not in hda_dict: + hda_dict[ 'comment_lines' ] = [] + hda_dict[ 'comment_lines' ].append( line ) + if index >= 3: + break + except Exception, exc: + log.error( str( exc ) ) history_id = trans.security.encode_id( hda.history.id ) diff --git a/static/scripts/mvc/visualizations/scatterplotControlForm.js b/static/scripts/mvc/visualizations/scatterplotControlForm.js index ca86751b0fc..76c12db9a69 100644 --- a/static/scripts/mvc/visualizations/scatterplotControlForm.js +++ b/static/scripts/mvc/visualizations/scatterplotControlForm.js @@ -67,8 +67,9 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ //logger : console, className : 'scatterplot-control-form', - dataLoadDelay : 500, - dataLoadSize : 3001, + //NOTE: should include time needed to render + dataLoadDelay : 4000, + dataLoadSize : 5000, loadingIndicatorImage : 'loading_small_white_bg.gif', fetchMsg : 'Fetching data...', @@ -107,6 +108,16 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ } this.log( '\t dataset:', this.dataset ); + // attempt to get possible headers from the data's first line + if( this.dataset.comment_lines && this.dataset.comment_lines.length ){ + //TODO:?? + var firstLine = this.dataset.comment_lines[0], + possibleHeaders = firstLine.split( '\t' ); + if( possibleHeaders.length === this.dataset.metadata_column_types.length ){ + this.possibleHeaders = possibleHeaders; + } + } + // passed from mako helper //TODO: integrate to galaxyPaths //TODO: ?? seems like data loader section would be better @@ -194,16 +205,24 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ // controls for which columns are used to plot datapoints (and ids/additional info to attach if desired) var view = this, allColumns = [], - numericColumns = []; - + numericColumns = [], + usePossibleHeaders = ( this.possibleHeaders && this.$dataControl )? + ( this.$dataControl.find( '#first-line-header-checkbox' ).is( ':checked' ) ):( false ); + // gather column indeces (from metadata_column_types) and names (from metadata_columnnames) _.each( this.dataset.metadata_column_types, function( type, index ){ // use a 1 based index in names/values within the form (will be dec. when parsed out) var oneBasedIndex = index + 1, - // label with the name if available (fall back on 'column ') + // default name is 'column '... name = 'column ' + oneBasedIndex; + + // ...but label with the name if available... if( view.dataset.metadata_column_names ){ name = view.dataset.metadata_column_names[ index ]; + + // ...or, use the first line as headers if the user wants + } else if( usePossibleHeaders ){ + name = view.possibleHeaders[ index ]; } // cache all columns here @@ -218,11 +237,17 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ // render the html var $dataControl = this.$el.find( '.tab-pane#data-control' ); - $dataControl.append( ScatterplotControlForm.templates.dataControl({ + $dataControl.html( ScatterplotControlForm.templates.dataControl({ allColumns : allColumns, - numericColumns : numericColumns + numericColumns : numericColumns, + possibleHeaders : ( this.possibleHeaders )?( this.possibleHeaders.join( ', ' ) ):( '' ), + usePossibleHeaders : usePossibleHeaders })); + if( !this.dataset.metadata_column_names && this.possibleHeaders ){ + $dataControl.find( '#first-line-header' ).show(); + } + // preset to column selectors if they were passed in the config in the query string $dataControl.find( '#X-select' ).val( this.chartConfig.xColumn ); $dataControl.find( '#Y-select' ).val( this.chartConfig.yColumn ); @@ -288,6 +313,7 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ // ------------------------------------------------------------------------- EVENTS events : { 'change #include-id-checkbox' : 'toggleThirdColumnSelector', + 'change #first-line-header-checkbox' : 'rerenderDataControl', 'click #data-control #render-button' : 'renderChart', 'click #chart-control #render-button' : 'changeChartSettings' }, @@ -296,6 +322,10 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ // show/hide the id selector on the data settings panel this.$el.find( 'select[name="ID"]' ).parent().toggle(); }, + + rerenderDataControl : function(){ + this.$dataControl = this._render_dataControl(); + }, showLoadingIndicator : function( message, callback ){ // display the loading indicator over the tab panels if hidden, update message (if passed) @@ -577,10 +607,8 @@ var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({ settings.yLabel = ( chartSettingsYLabel === 'Y' )? ( colSelections.Y.colName ):( chartSettingsYLabel ); - settings.animDuration = 10; - if( this.$chartControl.find( '#animDuration.checkbox-input' ).is( ':checked' ) ){ - settings.animDuration = 500; - } + settings.animDuration = ( this.$chartControl.find( '#animate-chart' ).is( ':checked' ) )? + ( this.chart.defaults.animDuration ):( 0 ); this.log( '\t chartSettings:', settings ); return settings; diff --git a/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js b/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js index 66cb53eecfd..c15ed5a8033 100644 --- a/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js +++ b/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js @@ -1 +1 @@ -var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],d=[];_.each(this.dataset.metadata_column_types,function(h,f){var g=f+1,e="column "+g;if(b.dataset.metadata_column_names){e=b.dataset.metadata_column_names[f]}a.push({index:g,name:e});if(h==="int"||h==="float"){d.push({index:g,name:e})}});var c=this.$el.find(".tab-pane#data-control");c.append(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:d}));c.find("#X-select").val(this.chartConfig.xColumn);c.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){c.find("#include-id-checkbox").attr("checked",true).trigger("change");c.find("#ID-select").val(this.chartConfig.idColumn)}return c},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=10;if(this.$chartControl.find("#animDuration.checkbox-input").is(":checked")){c.animDuration=500}this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]}; \ No newline at end of file +var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4000,dataLoadSize:5000,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split("\t");if(c.length===this.dataset.metadata_column_types.length){this.possibleHeaders=c}}if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],e=[],c=(this.possibleHeaders&&this.$dataControl)?(this.$dataControl.find("#first-line-header-checkbox").is(":checked")):(false);_.each(this.dataset.metadata_column_types,function(i,g){var h=g+1,f="column "+h;if(b.dataset.metadata_column_names){f=b.dataset.metadata_column_names[g]}else{if(c){f=b.possibleHeaders[g]}}a.push({index:h,name:f});if(i==="int"||i==="float"){e.push({index:h,name:f})}});var d=this.$el.find(".tab-pane#data-control");d.html(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:e,possibleHeaders:(this.possibleHeaders)?(this.possibleHeaders.join(", ")):(""),usePossibleHeaders:c}));if(!this.dataset.metadata_column_names&&this.possibleHeaders){d.find("#first-line-header").show()}d.find("#X-select").val(this.chartConfig.xColumn);d.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){d.find("#include-id-checkbox").attr("checked",true).trigger("change");d.find("#ID-select").val(this.chartConfig.idColumn)}return d},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=(this.$chartControl.find("#animate-chart").is(":checked"))?(this.chart.defaults.animDuration):(0);this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]}; \ No newline at end of file diff --git a/static/scripts/packed/templates/compiled/template-visualization-chartControl.js b/static/scripts/packed/templates/compiled/template-visualization-chartControl.js index 3534f473f14..d25863fbea3 100644 --- a/static/scripts/packed/templates/compiled/template-visualization-chartControl.js +++ b/static/scripts/packed/templates/compiled/template-visualization-chartControl.js @@ -1 +1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartControl"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return' checked="true"'}i+='

\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n

\n\n
\n \n
';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n Size of the graphic representation of each data point\n

\n
\n\n
\n \n \n

\n Uncheck this to disable the animations used on the graph\n

\n
\n\n
\n \n
';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n (not including graph margins and axes)\n

\n
\n\n
\n \n
';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n (not including graph margins and axes)\n

\n
\n\n
\n \n \n

\n
\n\n
\n \n \n

\n
\n\n ';return i})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartControl"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return' checked="true"'}i+='

\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n

\n\n
\n \n
';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n Size of the graphic representation of each data point\n

\n
\n\n
\n \n \n

\n Uncheck this to disable the animations used on the chart\n

\n
\n\n
\n \n
';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n (not including chart margins and axes)\n

\n
\n\n
\n \n
';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'
\n
\n

\n (not including chart margins and axes)\n

\n
\n\n
\n \n \n

\n
\n\n
\n \n \n

\n
\n\n ';return i})})(); \ No newline at end of file diff --git a/static/scripts/packed/templates/compiled/template-visualization-dataControl.js b/static/scripts/packed/templates/compiled/template-visualization-dataControl.js index 9a36a2c8d19..079e04ae9d4 100644 --- a/static/scripts/packed/templates/compiled/template-visualization-dataControl.js +++ b/static/scripts/packed/templates/compiled/template-visualization-dataControl.js @@ -1 +1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-dataControl"]=b(function(g,m,f,l,k){f=f||g.helpers;var i="",d,h="function",j=this.escapeExpression,o=this;function e(t,s){var q="",r,p;q+='\n \n ";return q}function c(t,s){var q="",r,p;q+='\n \n ";return q}function n(t,s){var q="",r,p;q+='\n \n ";return q}i+="

\n Use the following controls to change the data used by the chart.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n

\n\n ";i+='\n
\n \n \n
\n
\n \n \n
\n\n ";i+='\n
\n \n \n

\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n

\n
\n \n\n \n
';return i})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-dataControl"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,q=this;function e(v,u){var s="",t,r;s+='\n \n ";return s}function c(v,u){var s="",t,r;s+='\n \n ";return s}function p(v,u){var s="",t,r;s+='\n \n ";return s}function o(s,r){return'checked="true"'}j+="

\n Use the following controls to change the data used by the chart.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n

\n\n ";j+='\n
\n \n \n
\n
\n \n \n
\n\n ";j+='\n
\n \n \n

\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n

\n
\n \n\n ";j+='\n \n\n \n
';return j})})(); \ No newline at end of file diff --git a/static/scripts/packed/utils/LazyDataLoader.js b/static/scripts/packed/utils/LazyDataLoader.js index 05b536f5005..e5c07f8d28a 100644 --- a/static/scripts/packed/utils/LazyDataLoader.js +++ b/static/scripts/packed/utils/LazyDataLoader.js @@ -1 +1 @@ -function LazyDataLoader(c){var a=this,d="loaded.new",b="complete";ERROR_EVENT="error";jQuery.extend(a,LoggableMixin);jQuery.extend(a,{total:undefined,url:undefined,currentIntervalId:undefined,data:[],delay:500,start:0,size:1000,initialize:function(e){jQuery.extend(a,e);if(e.hasOwnProperty("initialize")){e.initialize.call(a,e)}this.log(this+" initialized:",a)},buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})},ajaxErrorFn:function(g,e,f){},load:function(h){this.log(this+".load");if(!a.url){throw (a+" requires a url")}if(this.total===null){this.log("\t total is null (will load all)")}else{this.log("\t total:",this.total)}var g=a.size;if((a.total!==null)&&(a.total0){a.currentIntervalId=setTimeout(function(){f(m,n)},a.delay);a.log("\t currentIntervalId:",a.currentIntervalId)}else{e()}}else{e()}}})}function e(){a.log(a+".loadHelper, has finished:",a.data);$(a).trigger(b,[a.data,a.total]);if(h){h(a.data)}}},toString:function(){return"LazyDataLoader"}});a.initialize(c);return a}; \ No newline at end of file +function LazyDataLoader(c){var a=this,d="loaded.new",b="complete";ERROR_EVENT="error";jQuery.extend(a,LoggableMixin);jQuery.extend(a,{total:undefined,url:undefined,currentIntervalId:undefined,data:[],delay:4000,start:0,size:4000,initialize:function(e){jQuery.extend(a,e);if(e.hasOwnProperty("initialize")){e.initialize.call(a,e)}this.log(this+" initialized:",a)},buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})},ajaxErrorFn:function(g,e,f){},load:function(h){this.log(this+".load");if(!a.url){throw (a+" requires a url")}if(this.total===null){this.log("\t total is null (will load all)")}else{this.log("\t total:",this.total)}var g=a.size;if((a.total!==null)&&(a.total0){a.currentIntervalId=setTimeout(function(){f(m,n)},a.delay);a.log("\t currentIntervalId:",a.currentIntervalId)}else{e()}}else{e()}}})}function e(){a.log(a+".loadHelper, has finished:",a.data);$(a).trigger(b,[a.data,a.total]);if(h){h(a.data)}}},toString:function(){return"LazyDataLoader"}});a.initialize(c);return a}; \ No newline at end of file diff --git a/static/scripts/packed/viz/scatterplot.js b/static/scripts/packed/viz/scatterplot.js index ebe17b7161c..b47c4d85894 100644 --- a/static/scripts/packed/viz/scatterplot.js +++ b/static/scripts/packed/viz/scatterplot.js @@ -1 +1 @@ -function TwoVarScatterplot(d){var b=10,f=7,e=10,c=8,a=5;this.log=function(){if(this.debugging&&console&&console.debug){var g=Array.prototype.slice.call(arguments);g.unshift(this.toString());console.debug.apply(console,g)}};this.log("new TwoVarScatterplot:",d);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:400,height:400,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,d);this.log("intial config:",this.config);this.updateConfig=function(g,h){_.extend(this.config,g);this.log(this+".updateConfig:",this.config)};this.toString=function(){return this.config.id};this.translateStr=function(g,h){return"translate("+g+","+h+")"};this.rotateStr=function(h,g,i){return"rotate("+h+","+g+","+i+")"};this.adjustChartDimensions=function(j,h,g,i){j=j||0;h=h||0;g=g||0;i=i||0;this.svg.attr("width",this.config.width+(this.config.marginRight+h)+(this.config.marginLeft+i)).attr("height",this.config.height+(this.config.marginTop+j)+(this.config.marginBottom+g)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+i,this.config.marginTop+j))};this.preprocessData=function(i,h,g){return(i.length>this.config.maxDataPoints)?(i.slice(0,this.config.maxDataPoints)):(i)};this.findMinMaxes=function(g,i,h){this.xMin=this.config.xMin||(h)?(h[0].min):(d3.min(g));this.xMax=this.config.xMax||(h)?(h[0].max):(d3.max(g));this.yMin=this.config.yMin||(h)?(h[1].min):(d3.min(i));this.yMax=this.config.yMax||(h)?(h[1].max):(d3.max(i))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);var g=d3.max(_.map([this.xMin,this.xMax],function(h){return(String(h)).length}));if(g>=a){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.log("this.config.xLabel:",this.config.xLabel);this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel);this.log("xAxisLabel:",this.xAxisLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var g=this.yAxis.selectAll("text").filter(function(k,j){return j!==0});this.log("yTickLabels:",g);this.yLongestLabel=d3.max(g[0].map(function(k,j){return(d3.select(k).text()).length}))||0;var h=b+(this.yLongestLabel*f)+c+e;this.config.yAxisLabelBumpX=-(h-e);if(this.config.marginLeft2)?(i[2]):(undefined);g=this.preprocessData(g);k=this.preprocessData(k);this.log("xCol len",g.length,"yCol len",k.length);this.findMinMaxes(g,k,j);this.setUpScales();if(!this.svg){this.svg=d3.select("svg").attr("class","chart")}if(!this.content){this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id)}this.adjustChartDimensions();if(!this.xAxis){this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis")}if(!this.xAxisLabel){this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label")}if(!this.yAxis){this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis")}if(!this.yAxisLabel){this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label")}this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(g,k,h)}}; \ No newline at end of file +function TwoVarScatterplot(d){var b=10,f=7,e=10,c=8,a=5;this.log=function(){if(this.debugging&&console&&console.debug){var g=Array.prototype.slice.call(arguments);g.unshift(this.toString());console.debug.apply(console,g)}};this.log("new TwoVarScatterplot:",d);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-40,width:400,height:400,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,d);this.log("intial config:",this.config);this.updateConfig=function(g,h){_.extend(this.config,g);this.log(this+".updateConfig:",this.config)};this.toString=function(){return this.config.id};this.translateStr=function(g,h){return"translate("+g+","+h+")"};this.rotateStr=function(h,g,i){return"rotate("+h+","+g+","+i+")"};this.adjustChartDimensions=function(j,h,g,i){j=j||0;h=h||0;g=g||0;i=i||0;this.svg.attr("width",this.config.width+(this.config.marginRight+h)+(this.config.marginLeft+i)).attr("height",this.config.height+(this.config.marginTop+j)+(this.config.marginBottom+g)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+i,this.config.marginTop+j))};this.preprocessData=function(i,h,g){return(i.length>this.config.maxDataPoints)?(i.slice(0,this.config.maxDataPoints)):(i)};this.findMinMaxes=function(g,i,h){this.xMin=this.config.xMin||(h)?(h[0].min):(d3.min(g));this.xMax=this.config.xMax||(h)?(h[0].max):(d3.max(g));this.yMin=this.config.yMin||(h)?(h[1].min):(d3.min(i));this.yMax=this.config.yMax||(h)?(h[1].max):(d3.max(i))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);var g=d3.max(_.map([this.xMin,this.xMax],function(h){return(String(h)).length}));if(g>=a){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.log("this.config.xLabel:",this.config.xLabel);this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel);this.log("xAxisLabel:",this.xAxisLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var g=this.yAxis.selectAll("text").filter(function(k,j){return j!==0});this.log("yTickLabels:",g);this.yLongestLabel=d3.max(g[0].map(function(k,j){return(d3.select(k).text()).length}))||0;var h=b+(this.yLongestLabel*f)+c+e;this.config.yAxisLabelBumpX=-(h-e);if(this.config.marginLeft2)?(i[2]):(undefined);g=this.preprocessData(g);k=this.preprocessData(k);this.log("xCol len",g.length,"yCol len",k.length);this.findMinMaxes(g,k,j);this.setUpScales();if(!this.svg){this.svg=d3.select("svg").attr("class","chart")}if(!this.content){this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id)}this.adjustChartDimensions();if(!this.xAxis){this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis")}if(!this.xAxisLabel){this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label")}if(!this.yAxis){this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis")}if(!this.yAxisLabel){this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label")}this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(g,k,h)};this.infoHtml=function(g,j,i){var h=$("
");if(i){$("
").text(i).css("font-weight","bold").appendTo(h)}$("
").text(g).appendTo(h);$("
").text(j).appendTo(h);return h.html()};this.infoBox=function(l,k,i,h,g){h=h||0;g=g||20;var j=$("
").addClass("chart-info-box").css({position:"absolute",top:l+h,left:k+g});j.html(i);return j}}; \ No newline at end of file diff --git a/static/scripts/templates/compiled/template-visualization-chartControl.js b/static/scripts/templates/compiled/template-visualization-chartControl.js index b432e4529f3..5a7d556b276 100644 --- a/static/scripts/templates/compiled/template-visualization-chartControl.js +++ b/static/scripts/templates/compiled/template-visualization-chartControl.js @@ -13,19 +13,19 @@ function program1(depth0,data) { foundHelper = helpers.datapointSize; if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); } else { stack1 = depth0.datapointSize; stack1 = typeof stack1 === functionType ? stack1() : stack1; } - buffer += escapeExpression(stack1) + "
\n
\n

\n Size of the graphic representation of each data point\n

\n
\n\n
\n \n \n
\n

\n Size of the graphic representation of each data point\n

\n
\n\n
\n \n \n Uncheck this to disable the animations used on the graph\n

\n
\n\n
\n \n
"; + buffer += " />\n

\n Uncheck this to disable the animations used on the chart\n

\n
\n\n
\n \n
"; foundHelper = helpers.width; if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); } else { stack1 = depth0.width; stack1 = typeof stack1 === functionType ? stack1() : stack1; } - buffer += escapeExpression(stack1) + "
\n
\n

\n (not including graph margins and axes)\n

\n
\n\n
\n \n
"; + buffer += escapeExpression(stack1) + "
\n
\n

\n (not including chart margins and axes)\n

\n
\n\n
\n \n
"; foundHelper = helpers.height; if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); } else { stack1 = depth0.height; stack1 = typeof stack1 === functionType ? stack1() : stack1; } - buffer += escapeExpression(stack1) + "
\n
\n

\n (not including graph margins and axes)\n

\n
\n\n
\n \n \n
\n

\n (not including chart margins and axes)\n

\n
\n\n
\n \n \n "; return buffer;} +function program7(depth0,data) { + + + return "checked=\"true\"";} + buffer += "

\n Use the following controls to change the data used by the chart.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n

\n\n "; buffer += "\n
\n \n \n
\n\n \n
"; + buffer += "\n \n
\n\n "; + buffer += "\n
\n

Possible headers: "; + foundHelper = helpers.possibleHeaders; + if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); } + else { stack1 = depth0.possibleHeaders; stack1 = typeof stack1 === functionType ? stack1() : stack1; } + buffer += escapeExpression(stack1) + "\n

\n \n \n It looks like Galaxy couldn't get proper column headers for this data.\n Would you like to use the column headers above as column names to select columns?\n

\n
\n\n \n
"; return buffer;}); })(); \ No newline at end of file diff --git a/static/scripts/templates/visualization-templates.html b/static/scripts/templates/visualization-templates.html index 05b6e9cfd73..29c248143ca 100644 --- a/static/scripts/templates/visualization-templates.html +++ b/static/scripts/templates/visualization-templates.html @@ -90,6 +90,19 @@
+ {{! if we're using generic column selection names ('column 1') - allow the user to use the first line }} + +
@@ -112,29 +125,29 @@
- - Animate chart transitions?: +

- Uncheck this to disable the animations used on the graph + Uncheck this to disable the animations used on the chart

- +
{{width}}

- (not including graph margins and axes) + (not including chart margins and axes)

- +
{{height}}

- (not including graph margins and axes) + (not including chart margins and axes)

diff --git a/static/scripts/utils/LazyDataLoader.js b/static/scripts/utils/LazyDataLoader.js index a7339dff59c..227b56eb929 100644 --- a/static/scripts/utils/LazyDataLoader.js +++ b/static/scripts/utils/LazyDataLoader.js @@ -81,11 +81,11 @@ function LazyDataLoader( config ){ // it's the responsibility of the code using this to combine them properly data : [], // ms btwn recursive loads - delay : 500, + delay : 4000, // starting line, element, whatever start : 0, // size to fetch per load - size : 1000, + size : 4000, // loader init func: extends loader with config and calls config.init if there //@param {object} config : object containing variables to override (or additional) diff --git a/static/scripts/viz/scatterplot.js b/static/scripts/viz/scatterplot.js index 7064eb71622..3ae8de3698f 100644 --- a/static/scripts/viz/scatterplot.js +++ b/static/scripts/viz/scatterplot.js @@ -90,7 +90,7 @@ function TwoVarScatterplot( config ){ xNumTicks : 10, yNumTicks : 10, xAxisLabelBumpY : 40, - yAxisLabelBumpX : -35, + yAxisLabelBumpX : -40, width : 400, height : 400, //TODO: anyway to make this a sub-obj? @@ -304,75 +304,37 @@ function TwoVarScatterplot( config ){ }; // ........................................................ data points - //TODO: these to config ...somehow - //TODO: use these in renderDatapoints ...somehow - this.glyphEnterState = function( d3Elem ){ - - }; - this.glyphFinalState = function( d3Elem ){ - - }; - this.glyphExitState = function( d3Elem ){ - - }; - - // initial render or complete re-render (REPLACE datapoints) this.renderDatapoints = function( xCol, yCol, ids ){ this.log( this + '.renderDatapoints', arguments ); - var count = 0; - - this.datapoints = this.addDatapoints( xCol, yCol, ids, ".glyph" ); - - // glyphs that need to be removed: transition to from normal state to 'exit' state, remove from DOM - this.datapoints.exit() - .each( function(){ count += 1; } ) - .transition().duration( this.config.animDuration ) - .attr( "cy", this.config.height ) - .attr( "r", 0 ) - .remove(); - this.log( count, ' glyphs removed' ); - - //this.log( this.datapoints.length, ' glyphs in the graph' ); - }; - - // adding points to existing - this.addDatapoints = function( newXCol, newYCol, ids, selectorForExisting ){ - this.log( this + '.addDatapoints', arguments ); - // ADD datapoints to plot that's already rendered - // if selectorForExisting === undefined (as in not passed), addDatapoints won't update existing - // pass in the class ( '.glyph' ) to update exising datapoints - var plot = this, - count = 0, + var count = 0, + plot = this, xPosFn = function( d, i ){ //if( d ){ this.log( 'x.data:', newXCol[ i ], 'plotted:', plot.xScale( newXCol[ i ] ) ); } - return plot.xScale( newXCol[ i ] ); + return plot.xScale( xCol[ i ] ); }, yPosFn = function( d, i ){ //if( d ){ this.log( 'y.data:', newYCol[ i ], 'plotted:', plot.yScale( newYCol[ i ] ) ); } - return plot.yScale( newYCol[ i ] ); + return plot.yScale( yCol[ i ] ); }; - - // select all existing glyphs and compare to incoming data - // enter() will yield those glyphs that need to be added - var newDatapoints = this.content.selectAll( selectorForExisting ); - this.log( 'existing datapoints:', newDatapoints ); - newDatapoints = newDatapoints.data( newXCol ); - - // enter - new data to be added as glyphs: give them a 'entry' position and style + + //this.datapoints = this.addDatapoints( xCol, yCol, ids, ".glyph" ); + var datapoints = this.content.selectAll( '.glyph' ).data( xCol ); + + // enter - NEW data to be added as glyphs: give them a 'entry' position and style count = 0; - newDatapoints.enter() + datapoints.enter() .append( 'svg:circle' ) .each( function(){ count += 1; } ) .classed( "glyph", true ) - .attr( "cx", xPosFn ) - .attr( "cy", yPosFn ) + .attr( "cx", 0 ) + .attr( "cy", this.config.height ) // start all bubbles small... .attr( "r", 0 ); this.log( count, ' new glyphs created' ); - // for all existing glyphs and those that need to be added: transition anim to final state + // for all EXISTING glyphs and those that need to be added: transition anim to final state count = 0; - newDatapoints + datapoints // ...animate to final position .transition().duration( this.config.animDuration ) .each( function(){ count += 1; } ) @@ -381,18 +343,22 @@ function TwoVarScatterplot( config ){ .attr( "r", plot.config.datapointSize ); this.log( count, ' existing glyphs transitioned' ); - // attach ids - if( ids ){ - newDatapoints.attr( 'data', function( d, i ){ return ( ids[ i ] ); } ); - } - - // titles - newDatapoints.attr( 'svg:title', function( d, i ){ - return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ]; - }); - // events - newDatapoints + // glyphs that need to be removed: transition to from normal state to 'exit' state, remove from DOM + datapoints.exit() + .each( function(){ count += 1; } ) + .transition().duration( this.config.animDuration ) + .attr( "cy", this.config.height ) + .attr( "r", 0 ) + .remove(); + this.log( count, ' glyphs removed' ); + + this._addDatapointEventhandlers( datapoints, xCol, yCol, ids ); + }; + + this._addDatapointEventhandlers = function( datapoints, xCol, yCol, ids ){ + var plot = this; + datapoints //TODO: remove magic numbers .on( 'mouseover', function( d, i ){ var datapoint = d3.select( this ); @@ -404,36 +370,42 @@ function TwoVarScatterplot( config ){ plot.content.append( 'line' ) .attr( 'stroke', 'red' ) .attr( 'stroke-width', 1 ) - .attr( 'x1', datapoint.attr( 'cx' ) ).attr( 'y1', datapoint.attr( 'cy' ) ) - .attr( 'x2', 0 ).attr( 'y2', datapoint.attr( 'cy' ) ) - .classed( 'hoverline', true ); - plot.content.append( 'line' ) - .attr( 'stroke', 'red' ) - .attr( 'stroke-width', 1 ) - .attr( 'x1', datapoint.attr( 'cx' ) ).attr( 'y1', datapoint.attr( 'cy' ) ) - .attr( 'x2', datapoint.attr( 'cx' ) ).attr( 'y2', plot.config.height ) + // start not at center, but at the edge of the circle - to prevent mouseover thrashing + .attr( 'x1', datapoint.attr( 'cx' ) - plot.config.datapointSize ) + .attr( 'y1', datapoint.attr( 'cy' ) ) + .attr( 'x2', 0 ) + .attr( 'y2', datapoint.attr( 'cy' ) ) .classed( 'hoverline', true ); - //var datapointWindowPos = $( this ).position(); - //var datapointWindowPos = $( this ).offset(); - //window.dot = this; - ////this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left + datapoint.attr( 'r' ), - //this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left, - // newXCol[ i ], newYCol[ i ], ( ids )?( ids[ i ] ):( undefined ) ); - //$( 'body' ).append( this.popup ); + // if the vertical hoverline + if( datapoint.attr( 'cy' ) < plot.config.height ){ + plot.content.append( 'line' ) + .attr( 'stroke', 'red' ) + .attr( 'stroke-width', 1 ) + .attr( 'x1', datapoint.attr( 'cx' ) ) + .attr( 'y1', datapoint.attr( 'cy' ) + plot.config.datapointSize ) + .attr( 'x2', datapoint.attr( 'cx' ) ) + .attr( 'y2', plot.config.height ) + .classed( 'hoverline', true ); + } + + var datapointWindowPos = $( this ).offset(); + plot.datapointInfoBox = plot.infoBox( + datapointWindowPos.top, datapointWindowPos.left, + plot.infoHtml( xCol[ i ], yCol[ i ], ( ids )?( ids[ i ] ):( undefined ) ) + ); + $( 'body' ).append( plot.datapointInfoBox ); }) .on( 'mouseout', function(){ d3.select( this ) .style( 'fill', 'black' ) .style( 'fill-opacity', 0.2 ); - d3.selectAll( '.hoverline' ).remove(); - //if( this.popup ){ - // this.popup.remove(); - //} + plot.content.selectAll( '.hoverline' ).remove(); + if( plot.datapointInfoBox ){ + plot.datapointInfoBox.remove(); + } }); - - return newDatapoints; - }; + }, this.render = function( columnData, meta ){ this.log( this + '.render', arguments ); @@ -457,7 +429,7 @@ function TwoVarScatterplot( config ){ //this.log( 'xMin, xMax, yMin, yMax:', this.xMin, this.xMax, this.yMin, this.yMax ); this.setUpScales(); - // build the svg dom infrastructure + // find (or build if it doesn't exist) the svg dom infrastructure if( !this.svg ){ this.svg = d3.select( 'svg' ).attr( "class", "chart" ); } if( !this.content ){ this.content = this.svg.append( "svg:g" ).attr( "class", "content" ).attr( 'id', this.config.id ); @@ -485,6 +457,32 @@ function TwoVarScatterplot( config ){ this.renderGrid(); this.renderDatapoints( xCol, yCol, ids ); }; + + this.infoHtml = function( x, y, id ){ + var retDiv = $( '
' ); + if( id ){ + $( '
' ).text( id ).css( 'font-weight', 'bold' ).appendTo( retDiv ); + } + $( '
' ).text( x ).appendTo( retDiv ); + $( '
' ).text( y ).appendTo( retDiv ); + return retDiv.html(); + }; + + //TODO: html for now + this.infoBox = function( top, left, html, adjTop, adjLeft ){ + adjTop = adjTop || 0; + adjLeft = adjLeft || 20; + var infoBox = $( '
' ) + .addClass( 'chart-info-box' ) + .css({ + 'position' : 'absolute', + 'top' : top + adjTop, + 'left' : left + adjLeft + }); + infoBox.html( html ); + return infoBox; + }; + } //============================================================================== diff --git a/templates/visualization/scatterplot.mako b/templates/visualization/scatterplot.mako index 9eb9850f0ad..9016af079e6 100644 --- a/templates/visualization/scatterplot.mako +++ b/templates/visualization/scatterplot.mako @@ -26,6 +26,7 @@ div.tab-pane { padding : 8px; background-color: #ebd9b2; margin-bottom: 16px; + overflow: auto; } #chart-header .subtitle { @@ -182,12 +183,11 @@ svg .glyph { } /* -------------------------------------------- info box */ -.zero-dimensions { - width: 0; - height: 0; - border-top: 8px solid transparent; - border-bottom: 8px solid transparent; - border-right: 8px solid grey; +.chart-info-box { + border-radius: 4px; + padding: 4px; + background-color: white; + border: 1px solid black; } @@ -255,63 +255,3 @@ $(function(){
- - -