From 82b2520a6bb66033c6b3eae107cefd22c8b5f39a Mon Sep 17 00:00:00 2001 From: Joshua Gould Date: Tue, 7 Jun 2016 15:27:17 -0400 Subject: [PATCH] profile chart beta --- src/tools/chart_tool2.js | 1355 +++++++++++++++++++++----------------- 1 file changed, 763 insertions(+), 592 deletions(-) diff --git a/src/tools/chart_tool2.js b/src/tools/chart_tool2.js index 661c970..2bd6076 100644 --- a/src/tools/chart_tool2.js +++ b/src/tools/chart_tool2.js @@ -4,25 +4,25 @@ * @param chartOptions.getVisibleTrackNames * {Function} */ -morpheus.ChartTool2 = function(chartOptions) { +morpheus.ChartTool2 = function (chartOptions) { var _this = this; this.getVisibleTrackNames = chartOptions.getVisibleTrackNames; this.project = chartOptions.project; var project = this.project; this.$el = $('
' - + '
' - + '
' - + '
' - + '
'); + + '
' + + '
' + + '
' + + '
'); var formBuilder = new morpheus.FormBuilder({ - vertical : true + vertical: true }); this.formBuilder = formBuilder; formBuilder.append({ - name : 'chart_type', - type : 'select', - options : [ 'boxplot', 'row scatter', 'column scatter' ] + name: 'chart_type', + type: 'select', + options: ['boxplot', 'row scatter', 'column scatter', 'row profile', 'column profile'] }); var rowOptions = []; var columnOptions = []; @@ -30,70 +30,70 @@ morpheus.ChartTool2 = function(chartOptions) { var numericColumnOptions = []; var options = []; var numericOptions = []; - var updateOptions = function() { + var updateOptions = function () { var dataset = project.getFullDataset(); - rowOptions = [ { - name : '(None)', - value : '' - } ]; - columnOptions = [ { - name : '(None)', - value : '' - } ]; - numericRowOptions = [ { - name : '(None)', - value : '' - } ]; - numericColumnOptions = [ { - name : '(None)', - value : '' - } ]; - options = [ { - name : '(None)', - value : '' - } ]; - numericOptions = [ { - name : '(None)', - value : '' - } ]; + rowOptions = [{ + name: '(None)', + value: '' + }]; + columnOptions = [{ + name: '(None)', + value: '' + }]; + numericRowOptions = [{ + name: '(None)', + value: '' + }]; + numericColumnOptions = [{ + name: '(None)', + value: '' + }]; + options = [{ + name: '(None)', + value: '' + }]; + numericOptions = [{ + name: '(None)', + value: '' + }]; morpheus.MetadataUtil.getMetadataNames(dataset.getRowMetadata()) - .forEach( - function(name) { - var dataType = morpheus.VectorUtil - .getDataType(dataset.getRowMetadata() - .getByName(name)); - if (dataType === 'number' - || dataType === '[number]') { - numericRowOptions.push({ - name : name + ' (row)', - value : name + '_r' - }); - } - rowOptions.push({ - name : name + ' (row)', - value : name + '_r' - }); - }); + .forEach( + function (name) { + var dataType = morpheus.VectorUtil + .getDataType(dataset.getRowMetadata() + .getByName(name)); + if (dataType === 'number' + || dataType === '[number]') { + numericRowOptions.push({ + name: name + ' (row)', + value: name + '_r' + }); + } + rowOptions.push({ + name: name + ' (row)', + value: name + '_r' + }); + }); morpheus.MetadataUtil.getMetadataNames(dataset.getColumnMetadata()) - .forEach( - function(name) { - var dataType = morpheus.VectorUtil - .getDataType(dataset.getColumnMetadata() - .getByName(name)); - if (dataType === 'number' - || dataType === '[number]') { - numericColumnOptions.push({ - name : name + ' (column)', - value : name + '_c' - }); - } - columnOptions.push({ - name : name + ' (column)', - value : name + '_c' - }); - }); + .forEach( + function (name) { + var dataType = morpheus.VectorUtil + .getDataType(dataset.getColumnMetadata() + .getByName(name)); + if (dataType === 'number' + || dataType === '[number]') { + numericColumnOptions.push({ + name: name + ' (column)', + value: name + '_c' + }); + } + columnOptions.push({ + name: name + ' (column)', + value: name + '_c' + }); + }); options = options.concat(rowOptions.slice(1)); options = options.concat(columnOptions.slice(1)); @@ -104,78 +104,79 @@ morpheus.ChartTool2 = function(chartOptions) { updateOptions(); formBuilder.append({ - name : 'group_columns_by', - type : 'select', - options : options + name: 'group_columns_by', + type: 'select', + options: options }); formBuilder.append({ - name : 'group_rows_by', - type : 'select', - options : options + name: 'group_rows_by', + type: 'select', + options: options }); formBuilder.append({ - name : 'axis_label', - type : 'select', - options : rowOptions + name: 'axis_label', + type: 'select', + options: rowOptions }); formBuilder.append({ - name : 'show_points', - type : 'checkbox', - value : true + name: 'show_points', + type: 'checkbox', + value: true }); formBuilder.append({ - name : 'color', - type : 'select', - options : options + name: 'color', + type: 'select', + options: options }); formBuilder.append({ - name : 'size', - type : 'select', - options : numericOptions + name: 'size', + type: 'select', + options: numericOptions }); function setVisibility() { + // 'boxplot', 'row scatter', 'column scatter', 'row profile', 'column profile' var chartType = formBuilder.getValue('chart_type'); - var isBoxplot = chartType === 'boxplot'; - // formBuilder.setVisible('points', isBoxplot); - formBuilder.setVisible('group_rows_by', isBoxplot); - formBuilder.setVisible('group_columns_by', isBoxplot); - if (!isBoxplot) { + + formBuilder.setVisible('group_rows_by', chartType === 'boxplot'); + formBuilder.setVisible('group_columns_by', chartType === 'boxplot'); + if (chartType !== 'boxplot') { formBuilder.setOptions('axis_label', - chartType === 'row scatter' ? rowOptions : columnOptions, - true); + (chartType === 'row scatter' || chartType === 'column profile') ? rowOptions : columnOptions, + true); formBuilder.setOptions('color', - chartType === 'row scatter' ? columnOptions : rowOptions, - true); + (chartType === 'row scatter' || chartType === 'column profile') ? columnOptions : rowOptions, + true); formBuilder.setOptions('size', - chartType === 'row scatter' ? numericColumnOptions - : numericRowOptions, true); + (chartType === 'row scatter' || chartType === 'row profile') ? numericColumnOptions + : numericRowOptions, true); } else { formBuilder.setOptions('color', options, true); formBuilder.setOptions('size', numericOptions, true); } - formBuilder.setVisible('axis_label', !isBoxplot); + formBuilder.setVisible('axis_label', chartType !== 'boxplot'); } - formBuilder.$form.find('select').on('change', function() { + + formBuilder.$form.find('select').on('change', function () { setVisibility(); _this.draw(); }); - formBuilder.$form.find('input').on('click', function() { + formBuilder.$form.find('input').on('click', function () { _this.draw(); }); setVisibility(); // chart types: boxplot, scatter // add: tooltip, color, size, allow boxplot and scatter of attributes? - var draw = function() { + var draw = function () { _.debounce(_this.draw(), 100); }; - var trackChanged = function() { + var trackChanged = function () { updateOptions(); setVisibility(); formBuilder.setOptions('group_columns_by', options, true); @@ -191,94 +192,96 @@ morpheus.ChartTool2 = function(chartOptions) { formBuilder.$form.appendTo($configPane); this.$el.appendTo($dialog); $dialog.dialog({ - close : function(event, ui) { + close: function (event, ui) { project.off('trackChanged.chart', trackChanged); project.getRowSelectionModel().off('selectionChanged.chart', draw); project.getColumnSelectionModel().off('selectionChanged.chart', - draw); + draw); _this.$el.empty(); }, - resizable : true, - height : 600, - width : 900 + + resizable: true, + height: 600, + width: 900 }); + this.$dialog = $dialog; this.draw(); }; -morpheus.ChartTool2.getPlotlyDefaults = function() { +morpheus.ChartTool2.getPlotlyDefaults = function () { var layout = { - autosize : false, - paper_bgcolor : 'rgb(255,255,255)', - plot_bgcolor : 'rgb(229,229,229)', - showlegend : false, - margin : { - l : 80, - r : 0, - t : 10, - b : 14, - autoexpand : true + autosize: false, + paper_bgcolor: 'rgb(255,255,255)', + plot_bgcolor: 'rgb(229,229,229)', + showlegend: false, + margin: { + l: 80, + r: 0, + t: 10, + b: 14, + autoexpand: true }, - xaxis : { - zeroline : false, - titlefont : { - size : 12 + xaxis: { + zeroline: false, + titlefont: { + size: 12 }, - gridcolor : 'rgb(255,255,255)', - showgrid : true, - showline : false, - showticklabels : true, - tickcolor : 'rgb(127,127,127)', - ticks : 'outside', - type : 'linear' + gridcolor: 'rgb(255,255,255)', + showgrid: true, + showline: false, + showticklabels: true, + tickcolor: 'rgb(127,127,127)', + ticks: 'outside', + type: 'linear' }, - yaxis : { - zeroline : false, - titlefont : { - size : 12 + yaxis: { + zeroline: false, + titlefont: { + size: 12 }, - gridcolor : 'rgb(255,255,255)', - showgrid : true, - showline : false, - showticklabels : true, - tickcolor : 'rgb(127,127,127)', - ticks : 'outside', - type : 'linear' + gridcolor: 'rgb(255,255,255)', + showgrid: true, + showline: false, + showticklabels: true, + tickcolor: 'rgb(127,127,127)', + ticks: 'outside', + type: 'linear' } }; var config = { - showLink : false, - displaylogo : false, - staticPlot : false, - showHints : true, - modeBarButtonsToRemove : [ 'sendDataToCloud' ] + showLink: false, + displaylogo: false, + staticPlot: false, + showHints: true, + modeBarButtonsToRemove: ['sendDataToCloud'] }; return { - layout : layout, - config : config + layout: layout, + config: config }; }; -morpheus.ChartTool2.getVectorInfo = function(value) { +morpheus.ChartTool2.getVectorInfo = function (value) { var field = value.substring(0, value.length - 2); var isColumns = value.substring(value.length - 2) === '_c'; return { - field : field, - isColumns : isColumns + field: field, + isColumns: isColumns }; }; morpheus.ChartTool2.prototype = { - annotate : function(options) { + annotate: function (options) { var _this = this; var formBuilder = new morpheus.FormBuilder(); formBuilder.append({ - name : 'annotation_name', - type : 'text', - required : true + name: 'annotation_name', + type: 'text', + required: true }); formBuilder.append({ - name : 'annotation_value', - type : 'text', - required : true + name: 'annotation_value', + type: 'text', + required: true }); // formBuilder.append({ // name : 'annotate', @@ -288,78 +291,78 @@ morpheus.ChartTool2.prototype = { // value : 'Rows' // }); morpheus.FormBuilder - .showOkCancel({ - title : 'Annotate Selection', - content : formBuilder.$form, - okCallback : function() { - var dataset = options.dataset; - var eventData = options.eventData; - var array = options.array; - var value = formBuilder.getValue('annotation_value'); - var annotationName = formBuilder - .getValue('annotation_name'); - // var annotate = formBuilder.getValue('annotate'); - var isRows = true; - var isColumns = true; - var existingRowVector = null; - var rowVector = null; - if (isRows) { - existingRowVector = dataset.getRowMetadata() - .getByName(annotationName); - rowVector = dataset.getRowMetadata().add( - annotationName); - } - var existingColumnVector = null; - var columnVector = null; - if (isColumns) { - existingColumnVector = dataset.getColumnMetadata() - .getByName(annotationName); - columnVector = dataset.getColumnMetadata().add( - annotationName); - } - - for (var p = 0, nselected = eventData.points.length; p < nselected; p++) { - var item = array[eventData.points[p].pointNumber]; - if (isRows) { - if (_.isArray(item.row)) { - item.row.forEach(function(r) { - rowVector.setValue(r, value); - }); - - } else { - rowVector.setValue(item.row, value); - } + .showOkCancel({ + title: 'Annotate Selection', + content: formBuilder.$form, + okCallback: function () { + var dataset = options.dataset; + var eventData = options.eventData; + var array = options.array; + var value = formBuilder.getValue('annotation_value'); + var annotationName = formBuilder + .getValue('annotation_name'); + // var annotate = formBuilder.getValue('annotate'); + var isRows = true; + var isColumns = true; + var existingRowVector = null; + var rowVector = null; + if (isRows) { + existingRowVector = dataset.getRowMetadata() + .getByName(annotationName); + rowVector = dataset.getRowMetadata().add( + annotationName); + } + var existingColumnVector = null; + var columnVector = null; + if (isColumns) { + existingColumnVector = dataset.getColumnMetadata() + .getByName(annotationName); + columnVector = dataset.getColumnMetadata().add( + annotationName); + } - } - if (isColumns) { - columnVector.setValue(item.column, value); - } - } - if (isRows) { - morpheus.VectorUtil - .maybeConvertStringToNumber(rowVector); - _this.project.trigger('trackChanged', { - vectors : [ rowVector ], - render : existingRowVector != null ? [] - : [ morpheus.VectorTrack.RENDER.TEXT ], - columns : false - }); - } - if (isColumns) { - morpheus.VectorUtil - .maybeConvertStringToNumber(columnVector); - _this.project.trigger('trackChanged', { - vectors : [ columnVector ], - render : existingColumnVector != null ? [] - : [ morpheus.VectorTrack.RENDER.TEXT ], - columns : true + for (var p = 0, nselected = eventData.points.length; p < nselected; p++) { + var item = array[eventData.points[p].pointNumber]; + if (isRows) { + if (_.isArray(item.row)) { + item.row.forEach(function (r) { + rowVector.setValue(r, value); }); + + } else { + rowVector.setValue(item.row, value); } + } - }); + if (isColumns) { + columnVector.setValue(item.column, value); + } + } + if (isRows) { + morpheus.VectorUtil + .maybeConvertStringToNumber(rowVector); + _this.project.trigger('trackChanged', { + vectors: [rowVector], + render: existingRowVector != null ? [] + : [morpheus.VectorTrack.RENDER.TEXT], + columns: false + }); + } + if (isColumns) { + morpheus.VectorUtil + .maybeConvertStringToNumber(columnVector); + _this.project.trigger('trackChanged', { + vectors: [columnVector], + render: existingColumnVector != null ? [] + : [morpheus.VectorTrack.RENDER.TEXT], + columns: true + }); + } + } + }); }, - _createScatter : function(options) { + _createScatter: function (options) { var dataset = options.dataset; var colorByVector = options.colorByVector; var colorModel = options.colorModel; @@ -368,7 +371,7 @@ morpheus.ChartTool2.prototype = { var heatmap = this.heatmap; var myPlot = options.myPlot; - var isColumnScatter = options.isColumnScatter; + var isColumnChart = options.isColumnChart; // scatter var x = []; var y = []; @@ -381,31 +384,31 @@ morpheus.ChartTool2.prototype = { y.push(dataset.getValue(options.rowIndexOne, j)); x.push(dataset.getValue(options.rowIndexTwo, j)); array.push({ - row : [ options.rowIndexOne, options.rowIndexTwo ], - column : j + row: [options.rowIndexOne, options.rowIndexTwo], + column: j }); if (colorByVector) { var colorByValue = colorByVector.getValue(j); color.push(colorModel.getMappedValue(colorByVector, - colorByValue)); + colorByValue)); } if (sizeByVector) { var sizeByValue = sizeByVector.getValue(j); size.push(sizeFunction(sizeByValue)); } var obj = { - j : j + j: j }; - obj.toString = function() { - var trackNames = _this.getVisibleTrackNames(!isColumnScatter); + obj.toString = function () { + var trackNames = _this.getVisibleTrackNames(!isColumnChart); var s = []; for (var i = 0; i < trackNames.length; i++) { var v = dataset.getColumnMetadata() - .getByName(trackNames[i]); + .getByName(trackNames[i]); if (v) { morpheus.HeatMapTooltipProvider.vectorToString(v, - this.j, s, '
'); + this.j, s, '
'); } } @@ -417,62 +420,199 @@ morpheus.ChartTool2.prototype = { // TODO add R^2 var trace = { - x : x, - y : y, - marker : { - color : color, - size : size, - symbol : 'circle-open' + x: x, + y: y, + marker: { + color: color, + size: size, + symbol: 'circle-open' }, - text : text, - mode : 'markers', - type : 'scatter' // scattergl + text: text, + mode: 'markers', + type: 'scatter' // scattergl }; var selection = null; var _this = this; var config = $ - .extend( - true, - {}, - options.config, + .extend( + true, + {}, + options.config, { - modeBarButtonsToAdd : [ [ { - name : 'annotate', - title : 'Annotate Selection', - attr : 'dragmode', - val : 'annotate', - icon : { - 'width' : 1792, - 'path' : 'M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z', - 'ascent' : 1792, - 'descent' : 0 + modeBarButtonsToAdd: [[{ + name: 'annotate', + title: 'Annotate Selection', + attr: 'dragmode', + val: 'annotate', + icon: { + 'width': 1792, + 'path': 'M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z', + 'ascent': 1792, + 'descent': 0 }, - click : function() { + click: function () { if (!selection) { morpheus.FormBuilder - .showInModal({ - title : 'Annotate Selection', - html : 'Please select points in the chart', - close : 'Close' - }); + .showInModal({ + title: 'Annotate Selection', + html: 'Please select points in the chart', + close: 'Close' + }); } else { _this.annotate({ - array : array, - eventData : selection, - dataset : dataset - }); + array: array, + eventData: selection, + dataset: dataset + }); } } - } ] ] + }]] }); - Plotly.newPlot(myPlot, [ trace ], options.layout, config); + Plotly.newPlot(myPlot, [trace], options.layout, config); + myPlot.on('plotly_selected', function (eventData) { + selection = eventData; + }); + + }, + _createProfile: function (options) { + var dataset = options.dataset; + // only allow coloring by row + var colorByVector = options.colorByVector; + var colorModel = options.colorModel; + var sizeByVector = options.sizeByVector; + var sizeFunction = options.sizeFunction; + var axisLabelVector = options.axisLabelVector; + var isColumnChart = options.isColumnChart; + var heatmap = this.heatmap; + var myPlot = options.myPlot; + + var traces = []; + var ticktext = []; + var tickvals = []; + console.log(dataset.getRowCount(), dataset.getColumnCount()); + for (var j = 0, ncols = dataset.getColumnCount(); j < ncols; j++) { + ticktext.push(axisLabelVector != null ? axisLabelVector.getValue(j) : '' + j); + tickvals.push(j); + } + for (var i = 0, nrows = dataset.getRowCount(); i < nrows; i++) { + // each row is a new trace + var x = []; + var y = []; + var text = []; + var size = sizeByVector ? [] : 6; + var color = colorByVector ? colorModel.getMappedValue(colorByVector, + colorByVector.getValue(i)) : undefined; + + for (var j = 0, ncols = dataset.getColumnCount(); j < ncols; j++) { + x.push(j); + y.push(dataset.getValue(i, j)); - myPlot.on('plotly_selected', function(eventData) { + if (sizeByVector) { + var sizeByValue = sizeByVector.getValue(j); + size.push(sizeFunction(sizeByValue)); + } + var obj = { + i: i, + j: j + }; + obj.toString = function () { + var trackNames = _this.getVisibleTrackNames(!isColumnChart); + var s = []; + + for (var i = 0; i < trackNames.length; i++) { + var v = dataset.getColumnMetadata() + .getByName(trackNames[i]); + if (v) { + morpheus.HeatMapTooltipProvider.vectorToString(v, + this.j, s, '
'); + } + + } + return s.join(''); + + }; + text.push(obj); + } + var trace = { + x: x, + y: y, + name: colorByVector ? colorByVector.getValue(i) : '', + tickmode: 'array', + marker: { + size: size, + symbol: 'circle' + }, + text: text, + mode: 'markers+lines', + type: 'scatter' // scattergl + }; + traces.push(trace); + } + + var selection = null; + var _this = this; + options.layout.xaxis.tickvals = tickvals; + options.layout.xaxis.ticktext = ticktext; + options.layout.xaxis.tickmode = 'array'; + + var config = $ + .extend( + true, + {}, + options.config, + { + modeBarButtonsToAdd: [[{ + name: 'annotate', + title: 'Annotate Selection', + attr: 'dragmode', + val: 'annotate', + icon: { + 'width': 1792, + 'path': 'M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z', + 'ascent': 1792, + 'descent': 0 + }, + click: function () { + if (!selection) { + morpheus.FormBuilder + .showInModal({ + title: 'Annotate Selection', + html: 'Please select points in the chart', + close: 'Close' + }); + } else { + _this.annotate({ + eventData: selection, + dataset: dataset + }); + } + } + }]] + }); + var $parent = $(myPlot).parent(); + options.layout.width = $parent.width(); + options.layout.height = this.$dialog.height() - 30; + Plotly.newPlot(myPlot, traces, options.layout, config); + myPlot.on('plotly_selected', function (eventData) { selection = eventData; }); + function resize() { + var width = $parent.width(); + var height = _this.$dialog.height() - 30; + Plotly.relayout(myPlot, { + width: width, + height: height + }); + } + + this.$dialog.on('dialogresize', resize); + $(myPlot).on('remove', function () { + _this.$dialog.off('dialogresize'); + }); + }, - _createBoxPlot : function(options) { + _createBoxPlot: function (options) { var array = options.array; // array of items var points = options.points; var colorByVector = options.colorByVector; @@ -488,7 +628,7 @@ morpheus.ChartTool2.prototype = { var sizeFunction = options.sizeFunction; var sizeByGetter = options.sizeByGetter; var size = sizeFunction ? [] : 6; - var scale = d3.scale.linear().domain([ 0, 1 ]).range([ -0.3, -1 ]); + var scale = d3.scale.linear().domain([0, 1]).range([-0.3, -1]); for (var k = 0, nitems = array.length; k < nitems; k++) { var item = array[k]; y.push(dataset.getValue(item.row, item.column)); @@ -498,26 +638,26 @@ morpheus.ChartTool2.prototype = { if (colorByVector) { var colorByValue = colorByGetter(item); color.push(colorModel.getMappedValue(colorByVector, - colorByValue)); + colorByValue)); } if (sizeFunction) { var sizeByValue = sizeByGetter(item); size.push(sizeFunction(sizeByValue)); } var obj = { - row : item.row, - column : item.column + row: item.row, + column: item.column }; - obj.toString = function() { + obj.toString = function () { var s = []; var trackNames = _this.getVisibleTrackNames(true); for (var trackIndex = 0; trackIndex < trackNames.length; trackIndex++) { var v = dataset.getColumnMetadata().getByName( - trackNames[trackIndex]); + trackNames[trackIndex]); if (v) { morpheus.HeatMapTooltipProvider.vectorToString(v, - this.column, s, '
'); + this.column, s, '
'); } } @@ -526,10 +666,10 @@ morpheus.ChartTool2.prototype = { for (var trackIndex = 0; trackIndex < trackNames.length; trackIndex++) { var v = dataset.getRowMetadata().getByName( - trackNames[trackIndex]); + trackNames[trackIndex]); if (v) { morpheus.HeatMapTooltipProvider.vectorToString(v, - this.row, s, '
'); + this.row, s, '
'); } } @@ -541,73 +681,73 @@ morpheus.ChartTool2.prototype = { } - var traces = [ { - name : '', - y : y, - type : 'box', - boxpoints : false - } ]; + var traces = [{ + name: '', + y: y, + type: 'box', + boxpoints: false + }]; if (points) { traces.push({ - name : '', - x : x, - y : y, - hoverinfo : 'y+text', - mode : 'markers', - type : 'scatter', - text : text, - marker : { - symbol : 'circle-open', - size : size, - color : color + name: '', + x: x, + y: y, + hoverinfo: 'y+text', + mode: 'markers', + type: 'scatter', + text: text, + marker: { + symbol: 'circle-open', + size: size, + color: color } }); } var selection = null; var _this = this; var config = $ - .extend( - true, - {}, - options.config, + .extend( + true, + {}, + options.config, { - modeBarButtonsToAdd : [ [ { - name : 'annotate', - title : 'Annotate Selection', - attr : 'dragmode', - val : 'annotate', - icon : { - 'width' : 1792, - 'path' : 'M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z', - 'ascent' : 1792, - 'descent' : 0 + modeBarButtonsToAdd: [[{ + name: 'annotate', + title: 'Annotate Selection', + attr: 'dragmode', + val: 'annotate', + icon: { + 'width': 1792, + 'path': 'M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z', + 'ascent': 1792, + 'descent': 0 }, - click : function() { + click: function () { if (!selection) { morpheus.FormBuilder - .showInModal({ - title : 'Annotate Selection', - html : 'Please select points in the chart', - close : 'Close' - }); + .showInModal({ + title: 'Annotate Selection', + html: 'Please select points in the chart', + close: 'Close' + }); } else { _this.annotate({ - array : array, - eventData : selection, - dataset : dataset - }); + array: array, + eventData: selection, + dataset: dataset + }); } } - } ] ] + }]] }); Plotly.newPlot(myPlot, traces, options.layout, config); - myPlot.on('plotly_selected', function(eventData) { + myPlot.on('plotly_selected', function (eventData) { selection = eventData; }); }, - draw : function() { + draw: function () { var _this = this; this.$chart.empty(); var plotlyDefaults = morpheus.ChartTool2.getPlotlyDefaults(); @@ -618,19 +758,19 @@ morpheus.ChartTool2.prototype = { var points = this.formBuilder.getValue('show_points'); var groupColumnsBy = this.formBuilder.getValue('group_columns_by'); - var titleBy = this.formBuilder.getValue('axis_label'); + var axisLabel = this.formBuilder.getValue('axis_label'); var colorBy = this.formBuilder.getValue('color'); var sizeBy = this.formBuilder.getValue('size'); var groupRowsBy = this.formBuilder.getValue('group_rows_by'); var chartType = this.formBuilder.getValue('chart_type'); var dataset = this.project.getSelectedDataset({ - emptyToAll : false + emptyToAll: false }); this.dataset = dataset; if (dataset.getRowCount() * dataset.getColumnCount() === 0) { $('

Please select rows and columns in the heat map.

') - .appendTo(this.$chart); + .appendTo(this.$chart); return; } if ((dataset.getRowCount() * dataset.getColumnCount()) > 100000) { @@ -638,56 +778,90 @@ morpheus.ChartTool2.prototype = { } var grid = []; - var rowIds = [ undefined ]; - var columnIds = [ undefined ]; + var rowIds = [undefined]; + var columnIds = [undefined]; var items = []; var heatmap = this.heatmap; var colorByInfo = morpheus.ChartTool2.getVectorInfo(colorBy); var sizeByInfo = morpheus.ChartTool2.getVectorInfo(sizeBy); - if (chartType === 'row scatter' || chartType === 'column scatter') { + var colorModel = !colorByInfo.isColumns ? this.project.getRowColorModel() + : this.project.getColumnColorModel(); + var axisLabelInfo = morpheus.ChartTool2.getVectorInfo(axisLabel); + var axisLabelVector = axisLabelInfo.isColumns ? dataset.getColumnMetadata().getByName(axisLabelInfo.field) : dataset.getRowMetadata().getByName( + axisLabelInfo.field); + var sizeByVector = sizeByInfo.isColumns ? dataset.getColumnMetadata().getByName(sizeByInfo.field) : dataset.getRowMetadata().getByName( + sizeByInfo.field); + var colorByVector = colorByInfo.isColumns ? dataset.getColumnMetadata().getByName(colorByInfo.field) : dataset.getRowMetadata().getByName( + colorByInfo.field); - var titleInfo = morpheus.ChartTool2.getVectorInfo(titleBy); + var sizeByScale = null; + if (sizeByVector) { + var minMax = morpheus.VectorUtil.getMinMax(sizeByVector); + sizeByScale = d3.scale.linear().domain( + [minMax.min, minMax.max]).range([3, 16]) + .clamp(true); + } + if (chartType === 'row profile' || chartType === 'column profile') { + var $chart = $('
'); + var myPlot = $chart[0]; + $chart.appendTo(this.$chart); + if (chartType === 'column profile') { + dataset = new morpheus.TransposedDatasetView(dataset); + } + this + ._createProfile({ + isColumnChart: chartType === 'column profile', + axisLabelVector: axisLabelVector, + colorByVector: colorByVector, + colorModel: colorModel, + sizeByVector: sizeByVector, + sizeFunction: sizeByScale, + myPlot: myPlot, + dataset: dataset, + config: config, + layout: $ + .extend( + true, + {}, + layout, + { + showlegend: true, + width: chartWidth, + height: chartHeight, + margin: { + b: 80 + }, + yaxis: {}, + xaxis: {} + }) + }); + } + if (chartType === 'row scatter' || chartType === 'column scatter') { + var transpose = chartType === 'column scatter'; - var isColumnScatter = chartType === 'column scatter'; - if (isColumnScatter) { + if (transpose) { dataset = new morpheus.TransposedDatasetView(dataset); } - if (dataset.getRowCount() > 15) { + if (dataset.getRowCount() > 20) { $('

Maximum chart size exceeded.

') - .appendTo(this.$chart); + .appendTo(this.$chart); return; } - // title vector is always rows - var titleVector = dataset.getRowMetadata().getByName( - titleInfo.field); - // color vector is always columns - var colorByVector = dataset.getColumnMetadata().getByName( - colorByInfo.field); - var colorModel = isColumnScatter ? this.project.getRowColorModel() - : this.project.getColumnColorModel(); - - // size by vector is always columns - var sizeByVector = dataset.getColumnMetadata().getByName( - sizeByInfo.field); + // rowIndexOne is along rows of chart (y axis), rowIndexTwo along x // axis - var sizeByScale = null; - if (sizeByVector) { - var minMax = morpheus.VectorUtil.getMinMax(sizeByVector); - sizeByScale = d3.scale.linear().domain( - [ minMax.min, minMax.max ]).range([ 3, 16 ]) - .clamp(true); - } + + // draw grid for (var rowIndexOne = 0, nrows = dataset.getRowCount(); rowIndexOne < nrows; rowIndexOne++) { for (var rowIndexTwo = 0; rowIndexTwo < nrows; rowIndexTwo++) { if (rowIndexOne > rowIndexTwo) { continue; } var $chart = $('
'); + + 'px;height:' + chartHeight + + 'px;position:absolute;left:' + + (rowIndexTwo * chartWidth) + 'px;top:' + + (rowIndexOne * chartHeight) + 'px;">'); var myPlot = $chart[0]; $chart.appendTo(this.$chart); @@ -695,284 +869,281 @@ morpheus.ChartTool2.prototype = { var array = []; for (var j = 0, ncols = dataset.getColumnCount(); j < ncols; j++) { array.push({ - row : rowIndexTwo, - column : j + row: rowIndexTwo, + column: j }); } this - ._createBoxPlot({ - array : array, - points : points, - colorByVector : colorByVector, - colorModel : colorModel, - colorByGetter : function(item) { - return colorByVector - .getValue(item.column); - }, - sizeByGetter : function(item) { - return sizeByVector - .getValue(item.column); + ._createBoxPlot({ + array: array, + points: points, + colorByVector: colorByVector, + colorModel: colorModel, + colorByGetter: function (item) { + return colorByVector + .getValue(item.column); + }, + sizeByGetter: function (item) { + return sizeByVector + .getValue(item.column); + }, + sizeFunction: sizeByScale, + myPlot: myPlot, + dataset: dataset, + config: config, + transposed: isColumns, + layout: $ + .extend( + true, + {}, + layout, + { + width: chartWidth, + height: chartHeight, + margin: { + b: 80 }, - sizeFunction : sizeByScale, - myPlot : myPlot, - dataset : dataset, - config : config, - transposed : isColumns, - layout : $ - .extend( - true, - {}, - layout, - { - width : chartWidth, - height : chartHeight, - margin : { - b : 80 - }, - xaxis : { - title : titleVector == null ? '' - : titleVector - .getValue(rowIndexTwo), - showticklabels : false - } - }) - }); + xaxis: { + title: axisLabelVector == null ? '' + : axisLabelVector + .getValue(rowIndexTwo), + showticklabels: false + } + }) + }); } else { this - ._createScatter({ - isColumnScatter : isColumnScatter, - rowIndexOne : rowIndexOne, - rowIndexTwo : rowIndexTwo, - colorByVector : colorByVector, - colorModel : colorModel, - colorByGetter : function(item) { - return colorByVector - .getValue(item.column); + ._createScatter({ + isColumnChart: transpose, + rowIndexOne: rowIndexOne, + rowIndexTwo: rowIndexTwo, + colorByVector: colorByVector, + colorModel: colorModel, + colorByGetter: function (item) { + return colorByVector + .getValue(item.column); + }, + sizeByVector: sizeByVector, + sizeFunction: sizeByScale, + myPlot: myPlot, + dataset: dataset, + config: config, + layout: $ + .extend( + true, + {}, + layout, + { + width: chartWidth, + height: chartHeight, + margin: { + b: 80 }, - sizeByVector : sizeByVector, - sizeFunction : sizeByScale, - myPlot : myPlot, - dataset : dataset, - config : config, - layout : $ - .extend( - true, - {}, - layout, - { - width : chartWidth, - height : chartHeight, - margin : { - b : 80 - }, - yaxis : { - title : titleVector == null ? '' - : titleVector - .getValue(rowIndexOne), - }, - xaxis : { - title : titleVector == null ? '' - : titleVector - .getValue(rowIndexTwo) - } - }) - }); + yaxis: { + title: axisLabelVector == null ? '' + : axisLabelVector + .getValue(rowIndexOne), + }, + xaxis: { + title: axisLabelVector == null ? '' + : axisLabelVector + .getValue(rowIndexTwo) + } + }) + }); } - } } - return; - } - - // boxplot - for (var i = 0, nrows = dataset.getRowCount(); i < nrows; i++) { - for (var j = 0, ncols = dataset.getColumnCount(); j < ncols; j++) { - items.push({ - row : i, - column : j - }); + } else if (chartType === 'boxplot') { + for (var i = 0, nrows = dataset.getRowCount(); i < nrows; i++) { + for (var j = 0, ncols = dataset.getColumnCount(); j < ncols; j++) { + items.push({ + row: i, + column: j + }); + } } - } - var colorByInfo = morpheus.ChartTool2.getVectorInfo(colorBy); - var colorByVector = colorByInfo.isColumns ? dataset.getColumnMetadata() - .getByName(colorByInfo.field) : dataset.getRowMetadata() - .getByName(colorByInfo.field); - - var colorModel = !colorByInfo.isColumns ? this.project - .getRowColorModel() : this.project.getColumnColorModel(); - var colorByGetter = colorByInfo.isColumns ? function(item) { - return colorByVector.getValue(item.column); - } : function(item) { - return colorByVector.getValue(item.row); - }; - var sizeByVector = sizeByInfo.isColumns ? dataset.getColumnMetadata() - .getByName(sizeByInfo.field) : dataset.getRowMetadata() - .getByName(sizeByInfo.field); - var sizeByGetter = sizeByInfo.isColumns ? function(item) { - return sizeByVector.getValue(item.column); - } : function(item) { - return sizeByVector.getValue(item.row); - }; - var sizeByScale = null; - if (sizeByVector) { - var minMax = morpheus.VectorUtil.getMinMax(sizeByVector); - sizeByScale = d3.scale.linear().domain([ minMax.min, minMax.max ]) - .range([ 3, 16 ]).clamp(true); - } - if (groupColumnsBy || groupRowsBy) { - var rowIdToArray = new morpheus.Map(); - if (groupRowsBy) { - var groupRowsByInfo = morpheus.ChartTool2 - .getVectorInfo(groupRowsBy); - var vector = groupRowsByInfo.isColumns ? dataset - .getColumnMetadata().getByName(groupRowsByInfo.field) + var colorByInfo = morpheus.ChartTool2.getVectorInfo(colorBy); + var colorByVector = colorByInfo.isColumns ? dataset.getColumnMetadata() + .getByName(colorByInfo.field) : dataset.getRowMetadata() + .getByName(colorByInfo.field); + + var colorModel = !colorByInfo.isColumns ? this.project + .getRowColorModel() : this.project.getColumnColorModel(); + var colorByGetter = colorByInfo.isColumns ? function (item) { + return colorByVector.getValue(item.column); + } : function (item) { + return colorByVector.getValue(item.row); + }; + var sizeByVector = sizeByInfo.isColumns ? dataset.getColumnMetadata() + .getByName(sizeByInfo.field) : dataset.getRowMetadata() + .getByName(sizeByInfo.field); + var sizeByGetter = sizeByInfo.isColumns ? function (item) { + return sizeByVector.getValue(item.column); + } : function (item) { + return sizeByVector.getValue(item.row); + }; + var sizeByScale = null; + if (sizeByVector) { + var minMax = morpheus.VectorUtil.getMinMax(sizeByVector); + sizeByScale = d3.scale.linear().domain([minMax.min, minMax.max]) + .range([3, 16]).clamp(true); + } + if (groupColumnsBy || groupRowsBy) { + var rowIdToArray = new morpheus.Map(); + if (groupRowsBy) { + var groupRowsByInfo = morpheus.ChartTool2 + .getVectorInfo(groupRowsBy); + var vector = groupRowsByInfo.isColumns ? dataset + .getColumnMetadata().getByName(groupRowsByInfo.field) : dataset.getRowMetadata().getByName( - groupRowsByInfo.field); + groupRowsByInfo.field); - var getter = groupRowsByInfo.isColumns ? function(item) { - return vector.getValue(item.column); - } : function(item) { - return vector.getValue(item.row); - }; + var getter = groupRowsByInfo.isColumns ? function (item) { + return vector.getValue(item.column); + } : function (item) { + return vector.getValue(item.row); + }; - for (var i = 0, nitems = items.length; i < nitems; i++) { - var item = items[i]; - var value = getter(item); - var array = rowIdToArray.get(value); - if (array == undefined) { - array = []; - rowIdToArray.set(value, array); + for (var i = 0, nitems = items.length; i < nitems; i++) { + var item = items[i]; + var value = getter(item); + var array = rowIdToArray.get(value); + if (array == undefined) { + array = []; + rowIdToArray.set(value, array); + } + array.push(item); } - array.push(item); + } else { + rowIdToArray.set(undefined, items); } - } else { - rowIdToArray.set(undefined, items); - } - if (groupColumnsBy) { - var name = groupColumnsBy.substring(0, + if (groupColumnsBy) { + var name = groupColumnsBy.substring(0, groupColumnsBy.length - 2); - var isColumns = groupColumnsBy + var isColumns = groupColumnsBy .substring(groupColumnsBy.length - 2) === '_c'; - var vector = isColumns ? dataset.getColumnMetadata().getByName( + var vector = isColumns ? dataset.getColumnMetadata().getByName( name) : dataset.getRowMetadata().getByName(name); - var getter = isColumns ? function(item) { - return vector.getValue(item.column); - } : function(item) { - return vector.getValue(item.row); - }; + var getter = isColumns ? function (item) { + return vector.getValue(item.column); + } : function (item) { + return vector.getValue(item.row); + }; + + var columnIdToIndex = new morpheus.Map(); + var rowIndex = 0; + rowIdToArray.forEach(function (array, id) { + grid[rowIndex] = []; + for (var i = 0, nitems = array.length; i < nitems; i++) { + var item = array[i]; + var value = getter(item); + var columnIndex = columnIdToIndex.get(value); + if (columnIndex === undefined) { + columnIndex = columnIdToIndex.size(); + columnIdToIndex.set(value, columnIndex); + } + if (grid[rowIndex][columnIndex] === undefined) { + grid[rowIndex][columnIndex] = []; + } - var columnIdToIndex = new morpheus.Map(); - var rowIndex = 0; - rowIdToArray.forEach(function(array, id) { - grid[rowIndex] = []; - for (var i = 0, nitems = array.length; i < nitems; i++) { - var item = array[i]; - var value = getter(item); - var columnIndex = columnIdToIndex.get(value); - if (columnIndex === undefined) { - columnIndex = columnIdToIndex.size(); - columnIdToIndex.set(value, columnIndex); - } - if (grid[rowIndex][columnIndex] === undefined) { - grid[rowIndex][columnIndex] = []; + grid[rowIndex][columnIndex].push(item); } - - grid[rowIndex][columnIndex].push(item); - } - rowIds[rowIndex] = id; - rowIndex++; - }); - columnIdToIndex.forEach(function(index, id) { - columnIds[index] = id; - }); + rowIds[rowIndex] = id; + rowIndex++; + }); + columnIdToIndex.forEach(function (index, id) { + columnIds[index] = id; + }); + + } else { + var rowIndex = 0; + rowIdToArray.forEach(function (array, id) { + grid[rowIndex] = [array]; + rowIds[rowIndex] = id; + rowIndex++; + }); + } } else { - var rowIndex = 0; - rowIdToArray.forEach(function(array, id) { - grid[rowIndex] = [ array ]; - rowIds[rowIndex] = id; - rowIndex++; - }); + grid = [[items]]; } - } else { - grid = [ [ items ] ]; - } - - var gridRowCount = rowIds.length; - var gridColumnCount = columnIds.length; + var gridRowCount = rowIds.length; + var gridColumnCount = columnIds.length; + + for (var i = 0; i < gridRowCount; i++) { + var rowId = rowIds[i]; + var yrange = [Number.MAX_VALUE, -Number.MAX_VALUE]; + if (chartType === 'boxplot') { + for (var j = 0; j < gridColumnCount; j++) { + var array = grid[i][j]; + if (array) { + for (var k = 0, nitems = array.length; k < nitems; k++) { + var item = array[k]; + var value = dataset.getValue(item.row, item.column); + if (!isNaN(value)) { + yrange[0] = Math.min(yrange[0], value); + yrange[1] = Math.max(yrange[1], value); + } - for (var i = 0; i < gridRowCount; i++) { - var rowId = rowIds[i]; - var yrange = [ Number.MAX_VALUE, -Number.MAX_VALUE ]; - if (chartType === 'boxplot') { - for (var j = 0; j < gridColumnCount; j++) { - var array = grid[i][j]; - if (array) { - for (var k = 0, nitems = array.length; k < nitems; k++) { - var item = array[k]; - var value = dataset.getValue(item.row, item.column); - if (!isNaN(value)) { - yrange[0] = Math.min(yrange[0], value); - yrange[1] = Math.max(yrange[1], value); } - } } + // for now increase range by 1% + var span = yrange[1] - yrange[0]; + var delta = (span * 0.01); + yrange[1] += delta; + yrange[0] -= delta; } - // for now increase range by 1% - var span = yrange[1] - yrange[0]; - var delta = (span * 0.01); - yrange[1] += delta; - yrange[0] -= delta; - } - for (var j = 0; j < gridColumnCount; j++) { - var array = grid[i][j]; - var columnId = columnIds[j]; - if (array) { + for (var j = 0; j < gridColumnCount; j++) { + var array = grid[i][j]; + var columnId = columnIds[j]; + if (array) { - var $chart = $('
'); - $chart.appendTo(this.$chart); - var myPlot = $chart[0]; - if (chartType === 'boxplot') { - - this._createBoxPlot({ - layout : $.extend(true, {}, layout, { - width : chartWidth, - height : chartHeight, - yaxis : { - range : yrange, - title : rowId, - }, - xaxis : { - title : columnId, - showticklabels : false - } - }), - array : array, - points : points, - sizeByGetter : sizeByGetter, - sizeFunction : sizeByScale, - colorModel : colorModel, - colorByVector : colorByVector, - colorByGetter : colorByGetter, - myPlot : myPlot, - dataset : dataset, - config : config - }); - } + $chart.appendTo(this.$chart); + var myPlot = $chart[0]; + if (chartType === 'boxplot') { + + this._createBoxPlot({ + layout: $.extend(true, {}, layout, { + width: chartWidth, + height: chartHeight, + yaxis: { + range: yrange, + title: rowId, + }, + xaxis: { + title: columnId, + showticklabels: false + } + }), + array: array, + points: points, + sizeByGetter: sizeByGetter, + sizeFunction: sizeByScale, + colorModel: colorModel, + colorByVector: colorByVector, + colorByGetter: colorByGetter, + myPlot: myPlot, + dataset: dataset, + config: config + }); + } + } } } } } -}; \ No newline at end of file +}; -- GitLab