UI: add peek-based column selection control; Scatterplot: use peek-based control for selection of x, y, id axes

This commit is contained in:
Carl Eberhard
2014-02-17 12:11:04 -05:00
parent 7951cec806
commit 9e32945972
8 changed files with 451 additions and 105 deletions
@@ -1,55 +1,24 @@
<p class="help-text">
Use the following controls to change the data used by the chart.
Use the following control to change which columns are used by the chart. Click any cell
from the last three rows of the table to select the column for the appropriate data.
Use the 'Draw' button to render (or re-render) the chart with the current settings.
</p>
{{! column selector containers }}
<div class="column-select">
<label>Data column for X: </label>
<select name="xColumn">
{{#each numericColumns}}
<option value="{{index}}">{{name}}</option>
{{/each}}
</select>
</div>
<div class="column-select">
<label>Data column for Y: </label>
<select name="yColumn">
{{#each numericColumns}}
<option value="{{index}}">{{name}}</option>
{{/each}}
</select>
<ul class="help-text" style="margin-left: 8px">
<li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>
<li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>
<li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.
It may be useful to select unique or categorical identifiers here (such as gene ids).
</li>
</ul>
<div class="column-selection">
<pre class="peek">{{{ peek }}}</pre>
</div>
{{! optional id column }}
<div id="include-id">
<label for="include-id-checkbox">Include a third column as data point IDs?</label>
<input type="checkbox" name="include-id" id="include-id-checkbox" />
<p class="help-text-small">
These will be displayed (along with the x and y values) when you hover over
a data point.
</p>
</div>
<div class="column-select" style="display: none">
<label for="ID-select">Data column for IDs: </label>
<select name="idColumn">
{{#each allColumns}}
<option value="{{index}}">{{name}}</option>
{{/each}}
</select>
</div>
{{! if we're using generic column selection names ('column 1') - allow the user to use the first line }}
<div id="first-line-header" style="display: none;">
<p>Possible headers: {{ possibleHeaders }}
</p>
<label for="first-line-header-checkbox">Use the above as column headers?</label>
<input type="checkbox" name="include-id" id="first-line-header-checkbox"
{{#if usePossibleHeaders }}checked="true"{{/if}}/>
<p class="help-text-small">
It looks like Galaxy couldn't get proper column headers for this data.
Would you like to use the column headers above as column names to select columns?
</p>
</div>
<p class="help-text help-text-small">
<b>Note</b>: If it can be determined from the dataset's filetype that column is not numeric, that
column choice may be disabled for either the x or y axis.
</p>
<button class="render-button btn btn-primary active">Draw</button>
@@ -78,73 +78,62 @@ var ScatterplotConfigEditor = Backbone.View.extend( LoggableMixin ).extend({
return this;
},
/** get an object with arrays keyed with possible column types (numeric, text, all)
* and if metadata_column_types is set on the dataset, add the indeces of each
* column into the appropriate array.
* Used to disable certain columns from being selected for x, y axes.
*/
_getColumnIndecesByType : function(){
//TODO: not sure these contraints are necc. now
var types = {
numeric : [],
text : [],
all : []
};
_.each( this.dataset.metadata_column_types || [], function( type, i ){
if( type === 'int' || type === 'float' ){
types.numeric.push( i );
} else if( type === 'str' || type === 'list' ){
types.text.push( i );
}
types.all.push( i );
});
if( types.numeric.length < 2 ){
types.numeric = [];
}
//console.log( 'types:', JSON.stringify( types ) );
return types;
},
/** controls for which columns are used to plot datapoints (and ids/additional info to attach if desired) */
_render_dataControl : function( $where ){
//TODO: better handling of missing column names, column types
$where = $where || this.$el;
var editor = this,
dataset = this.dataset,
column_names = dataset.metadata_column_names || [],
config = this.model.get( 'config' );
//console.log( 'metadata_column_types:', this.dataset.metadata_column_types );
//console.log( 'metadata_column_names:', this.dataset.metadata_column_names );
//TODO: to peek based control
var numericColumns = [],
allColumns = _.map( dataset.metadata_column_types, function( type, i ){
// save column data for select rendering, adding metadata name if available in dataset
var column = { index: i, type: type, name: ( column_names[ i ] || ( 'column ' + ( i + 1 )) ) };
// also add column to numerics if numeric type
if( ( column.type === 'int' ) || ( column.type === 'float' ) ){
numericColumns.push( column );
}
return column;
});
if( numericColumns.length < 2 ){
numericColumns = allColumns;
}
//console.log( 'allColumns:', allColumns );
//console.log( 'numericColumns:', numericColumns );
//column_names = dataset.metadata_column_names || [],
config = this.model.get( 'config' ),
columnTypes = this._getColumnIndecesByType();
// render the html
var $dataControl = $where.find( '.tab-pane#data-control' );
$dataControl.html( ScatterplotConfigEditor.templates.dataControl({
allColumns : allColumns,
numericColumns : numericColumns
peek : this.dataset.peek
}));
//TODO: column selection boilerplate
// preset to column selectors if they were passed in the config in the query string; set up events
var newConfig = {
xColumn : ( _.isFinite( config.xColumn ) )? ( config.xColumn ): ( numericColumns[0].index ),
yColumn : ( _.isFinite( config.yColumn ) )? ( config.yColumn ): ( numericColumns[1].index ),
idColumn : allColumns[0].index
};
// use an idColumn from the config or attempt to get one different from the numeric
if( _.isFinite( config.idColumn ) ){
newConfig.idColumn = config.idColumn;
} else {
if( allColumns.length > 2 ){
var uniqueCol = _.find( allColumns, function( column, i ){
return i !== newConfig.xColumn && i !== newConfig.yColumn;
});
newConfig.idColumn = uniqueCol.index;
}
}
config = this.model.set( 'config', newConfig, { silent: true }).get( 'config' );
$dataControl.find( '.peek' ).peekControl({
controls : [
{ label: 'X Column', id: 'xColumn', selected: config.xColumn, disabled: columnTypes.text },
{ label: 'Y Column', id: 'yColumn', selected: config.yColumn, disabled: columnTypes.text },
{ label: 'ID Column', id: 'idColumn', selected: config.idColumn }
]
//renameColumns : true
$dataControl.find( '[name="xColumn"]' ).val( config.xColumn ).on( 'change', function(){
editor.model.set( 'config', { xColumn: Number( $( this ).val() ) });
}).on( 'peek-control.change', function( ev, data ){
//console.info( 'new selection:', data );
editor.model.set( 'config', data );
}).on( 'peek-control.rename', function( ev, data ){
//console.info( 'new column names', data );
});
$dataControl.find( '[name="yColumn"]' ).val( config.yColumn ).on( 'change', function(){
editor.model.set( 'config', { yColumn: Number( $( this ).val() ) });
});
$dataControl.find( 'select[name="idColumn"]' ).val( config.idColumn ).on( 'change', function(){
editor.model.set( 'config', { idColumn: Number( $( this ).val() ) });
});
if( config.idColumn !== undefined ){
$dataControl.find( '#include-id-checkbox' ).prop( 'checked', true ).trigger( 'change' );
}
$dataControl.find( '[title]' ).tooltip();
return $dataControl;
File diff suppressed because one or more lines are too long
@@ -87,7 +87,7 @@ $(function(){
model : model,
dataset : hdaJson
}).render();
//window.editor = editor;
window.editor = editor;
$( '.chart-header h2' ).click( function(){
var returned = prompt( 'Enter a new title:' );