From b126104938d663089f8e54c0a2aa879f05a05e59 Mon Sep 17 00:00:00 2001 From: Joshua Gould Date: Tue, 31 May 2016 11:52:03 -0400 Subject: [PATCH] array color fields --- src/matrix/vector_color_model.js | 179 ++++++++++++++++--------------- src/ui/vector_track.js | 164 +++++++++++++++++++--------- 2 files changed, 206 insertions(+), 137 deletions(-) diff --git a/src/matrix/vector_color_model.js b/src/matrix/vector_color_model.js index 83be991..5a69e3e 100644 --- a/src/matrix/vector_color_model.js +++ b/src/matrix/vector_color_model.js @@ -1,4 +1,4 @@ -morpheus.VectorColorModel = function() { +morpheus.VectorColorModel = function () { this.vectorNameToColorMap = new morpheus.Map(); this.vectorNameToColorScheme = new morpheus.Map(); this.colors = morpheus.VectorColorModel.TWENTY_COLORS; @@ -9,63 +9,63 @@ morpheus.VectorColorModel.FEMALE = '#ff99ff'; morpheus.VectorColorModel.MALE = '#66ccff'; // tableau 20-same as d3 category20 -morpheus.VectorColorModel.TWENTY_COLORS = [ '#1f77b4', '#aec7e8', '#ff7f0e', - '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896', '#9467bd', - '#c5b0d5', '#8c564b', '#c49c94', '#e377c2', '#f7b6d2', '#7f7f7f', - '#c7c7c7', '#bcbd22', '#dbdb8d', '#17becf', '#9edae5' ]; +morpheus.VectorColorModel.TWENTY_COLORS = ['#1f77b4', '#aec7e8', '#ff7f0e', + '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896', '#9467bd', + '#c5b0d5', '#8c564b', '#c49c94', '#e377c2', '#f7b6d2', '#7f7f7f', + '#c7c7c7', '#bcbd22', '#dbdb8d', '#17becf', '#9edae5']; morpheus.VectorColorModel.CATEGORY_20A = morpheus.VectorColorModel.TWENTY_COLORS; -morpheus.VectorColorModel.CATEGORY_20B = [ '#393b79', '#5254a3', '#6b6ecf', - '#9c9ede', '#637939', '#8ca252', '#b5cf6b', '#cedb9c', '#8c6d31', - '#bd9e39', '#e7ba52', '#e7cb94', '#843c39', '#ad494a', '#d6616b', - '#e7969c', '#7b4173', '#a55194', '#ce6dbd', '#de9ed6' ]; -morpheus.VectorColorModel.CATEGORY_20C = [ '#3182bd', '#6baed6', '#9ecae1', - '#c6dbef', '#e6550d', '#fd8d3c', '#fdae6b', '#fdd0a2', '#31a354', - '#74c476', '#a1d99b', '#c7e9c0', '#756bb1', '#9e9ac8', '#bcbddc', - '#dadaeb', '#636363', '#969696', '#bdbdbd', '#d9d9d9' ]; +morpheus.VectorColorModel.CATEGORY_20B = ['#393b79', '#5254a3', '#6b6ecf', + '#9c9ede', '#637939', '#8ca252', '#b5cf6b', '#cedb9c', '#8c6d31', + '#bd9e39', '#e7ba52', '#e7cb94', '#843c39', '#ad494a', '#d6616b', + '#e7969c', '#7b4173', '#a55194', '#ce6dbd', '#de9ed6']; +morpheus.VectorColorModel.CATEGORY_20C = ['#3182bd', '#6baed6', '#9ecae1', + '#c6dbef', '#e6550d', '#fd8d3c', '#fdae6b', '#fdd0a2', '#31a354', + '#74c476', '#a1d99b', '#c7e9c0', '#756bb1', '#9e9ac8', '#bcbddc', + '#dadaeb', '#636363', '#969696', '#bdbdbd', '#d9d9d9']; morpheus.VectorColorModel.CATEGORY_ALL = [].concat( - morpheus.VectorColorModel.CATEGORY_20A, - morpheus.VectorColorModel.CATEGORY_20B, - morpheus.VectorColorModel.CATEGORY_20C); + morpheus.VectorColorModel.CATEGORY_20A, + morpheus.VectorColorModel.CATEGORY_20B, + morpheus.VectorColorModel.CATEGORY_20C); -morpheus.VectorColorModel.TABLEAU10 = [ '#1f77b4', '#ff7f0e', '#2ca02c', - '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', - '#17becf' ]; +morpheus.VectorColorModel.TABLEAU10 = ['#1f77b4', '#ff7f0e', '#2ca02c', + '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', + '#17becf']; morpheus.VectorColorModel.STANDARD_COLORS = { - 'na' : '#c0c0c0', - 'nan' : '#c0c0c0', - '' : '#ffffff', - 'wt' : '#ffffff', - 'n' : '#ffffff', - '0' : '#ffffff', - 'y' : morpheus.VectorColorModel.YES_COLOR, - '1' : morpheus.VectorColorModel.YES_COLOR, - 'male' : morpheus.VectorColorModel.MALE, - 'm' : morpheus.VectorColorModel.MALE, - 'female' : morpheus.VectorColorModel.FEMALE, - 'f' : morpheus.VectorColorModel.FEMALE, - 'kd' : '#C675A8', - 'oe' : '#56b4e9', - 'cp' : '#FF9933', - 'trt_sh.cgs' : '#C675A8', - 'trt_oe' : '#56b4e9', - 'trt_cp' : '#FF9933', - 'a375' : '#1490C1', - 'a549' : '#AAC8E9', - 'hcc515' : '#1C9C2A', - 'hepg2' : '#94DC89', - 'ht29' : '#946DBE', - 'mcf7' : '#C5B2D5', - 'pc3' : '#38C697', - 'asc' : '#FF8000', - 'cd34' : '#FFBB75', - 'ha1e' : '#FB4124', - 'neu' : '#FF9A94', - 'npc' : '#E57AC6', - 'cancer' : '#1490C1', - 'immortalized normal' : '#FF8000' + 'na': '#c0c0c0', + 'nan': '#c0c0c0', + '': '#ffffff', + 'wt': '#ffffff', + 'n': '#ffffff', + '0': '#ffffff', + 'y': morpheus.VectorColorModel.YES_COLOR, + '1': morpheus.VectorColorModel.YES_COLOR, + 'male': morpheus.VectorColorModel.MALE, + 'm': morpheus.VectorColorModel.MALE, + 'female': morpheus.VectorColorModel.FEMALE, + 'f': morpheus.VectorColorModel.FEMALE, + 'kd': '#C675A8', + 'oe': '#56b4e9', + 'cp': '#FF9933', + 'trt_sh.cgs': '#C675A8', + 'trt_oe': '#56b4e9', + 'trt_cp': '#FF9933', + 'a375': '#1490C1', + 'a549': '#AAC8E9', + 'hcc515': '#1C9C2A', + 'hepg2': '#94DC89', + 'ht29': '#946DBE', + 'mcf7': '#C5B2D5', + 'pc3': '#38C697', + 'asc': '#FF8000', + 'cd34': '#FFBB75', + 'ha1e': '#FB4124', + 'neu': '#FF9A94', + 'npc': '#E57AC6', + 'cancer': '#1490C1', + 'immortalized normal': '#FF8000' }; -morpheus.VectorColorModel.getStandardColor = function(value) { +morpheus.VectorColorModel.getStandardColor = function (value) { if (value == null) { return '#ffffff'; } @@ -73,7 +73,7 @@ morpheus.VectorColorModel.getStandardColor = function(value) { return morpheus.VectorColorModel.STANDARD_COLORS[stringValue]; }; -morpheus.VectorColorModel.getColorMapForNumber = function(length) { +morpheus.VectorColorModel.getColorMapForNumber = function (length) { var colors; if (length < 3) { colors = colorbrewer.Set1[3]; @@ -83,77 +83,78 @@ morpheus.VectorColorModel.getColorMapForNumber = function(length) { return colors ? colors : morpheus.VectorColorModel.TWENTY_COLORS; }; morpheus.VectorColorModel.prototype = { - clear : function(vector) { + clear: function (vector) { this.vectorNameToColorMap.remove(vector.getName()); this.vectorNameToColorScheme.remove(vector.getName()); }, - copy : function() { + copy: function () { var c = new morpheus.VectorColorModel(); c.colors = this.colors.slice(0); - this.vectorNameToColorMap.forEach(function(colorMap, name) { + this.vectorNameToColorMap.forEach(function (colorMap, name) { var newColorMap = new morpheus.Map(); newColorMap.setAll(colorMap); // copy existing values c.vectorNameToColorMap.set(name, newColorMap); }); - this.vectorNameToColorScheme.forEach(function(colorScheme, name) { + this.vectorNameToColorScheme.forEach(function (colorScheme, name) { c.vectorNameToColorScheme.set(name, colorScheme - .copy(new morpheus.Project(new morpheus.Dataset('', - 1, 1)))); + .copy(new morpheus.Project(new morpheus.Dataset('', + 1, 1)))); }); return c; }, - clearAll : function() { + clearAll: function () { this.vectorNameToColorMap = new morpheus.Map(); this.vectorNameToColorScheme = new morpheus.Map(); }, - containsDiscreteColor : function(vector, value) { + containsDiscreteColor: function (vector, value) { var metadataValueToColorMap = this.vectorNameToColorMap.get(vector - .getName()); + .getName()); if (metadataValueToColorMap === undefined) { return false; } var c = metadataValueToColorMap.get(value); return c != null; }, - setDiscreteColorMap : function(colors) { + setDiscreteColorMap: function (colors) { this.colors = colors; }, - getContinuousColorScheme : function(vector) { + getContinuousColorScheme: function (vector) { return this.vectorNameToColorScheme.get(vector.getName()); }, - getDiscreteColorScheme : function(vector) { + getDiscreteColorScheme: function (vector) { return this.vectorNameToColorMap.get(vector.getName()); }, - createContinuousColorMap : function(vector) { - var min = morpheus.Min(vector); - var max = morpheus.Max(vector); + createContinuousColorMap: function (vector) { + var minMax = morpheus.VectorUtil.getMinMax(vector); + var min = minMax.min; + var max = minMax.max; var cs = new morpheus.HeatMapColorScheme(new morpheus.Project( - new morpheus.Dataset('', 1, 1)), { - type : 'fixed', - map : [ { - value : min, - color : colorbrewer.Greens[3][0] - }, { - value : max, - color : colorbrewer.Greens[3][2] - } ] - }); + new morpheus.Dataset('', 1, 1)), { + type: 'fixed', + map: [{ + value: min, + color: colorbrewer.Greens[3][0] + }, { + value: max, + color: colorbrewer.Greens[3][2] + }] + }); this.vectorNameToColorScheme.set(vector.getName(), cs); return cs; }, - getContinuousMappedValue : function(vector, value) { + getContinuousMappedValue: function (vector, value) { var cs = this.vectorNameToColorScheme.get(vector.getName()); if (cs === undefined) { cs = this.createContinuousColorMap(vector); } return cs.getColor(0, 0, value); }, - _getColorForValue : function(value) { + _getColorForValue: function (value) { var color = morpheus.VectorColorModel.getStandardColor(value); if (color == null) { // try to reuse existing color map var existingMetadataValueToColorMap = this.vectorNameToColorMap - .values(); + .values(); for (var i = 0, length = existingMetadataValueToColorMap.length; i < length; i++) { color = existingMetadataValueToColorMap[i].get(value); if (color !== undefined) { @@ -163,13 +164,13 @@ morpheus.VectorColorModel.prototype = { } return color; }, - getMappedValue : function(vector, value) { + getMappedValue: function (vector, value) { var metadataValueToColorMap = this.vectorNameToColorMap.get(vector - .getName()); + .getName()); if (metadataValueToColorMap === undefined) { metadataValueToColorMap = new morpheus.Map(); this.vectorNameToColorMap.set(vector.getName(), - metadataValueToColorMap); + metadataValueToColorMap); // set all possible colors var values = morpheus.VectorUtil.getValues(vector); var ncolors = 0; @@ -199,7 +200,7 @@ morpheus.VectorColorModel.prototype = { } } else { var _this = this; - _.each(values, function(val) { + _.each(values, function (val) { _this.getMappedValue(vector, val); }); } @@ -215,14 +216,14 @@ morpheus.VectorColorModel.prototype = { } return color; }, - setMappedValue : function(vector, value, color) { + setMappedValue: function (vector, value, color) { var metadataValueToColorMap = this.vectorNameToColorMap.get(vector - .getName()); + .getName()); if (metadataValueToColorMap === undefined) { metadataValueToColorMap = new morpheus.Map(); this.vectorNameToColorMap.set(vector.getName(), - metadataValueToColorMap); + metadataValueToColorMap); } metadataValueToColorMap.set(value, color); } -}; \ No newline at end of file +}; diff --git a/src/ui/vector_track.js b/src/ui/vector_track.js index ee510e7..4b9ad79 100644 --- a/src/ui/vector_track.js +++ b/src/ui/vector_track.js @@ -354,7 +354,7 @@ morpheus.VectorTrack.prototype = { .isRenderAs(morpheus.VectorTrack.RENDER.BAR))) { if (this.getFullVector().getProperties().has( morpheus.VectorKeys.FIELDS) - || morpheus.VectorUtil.getDataType(this.getFullVector()) === 'number') { + || morpheus.VectorUtil.getDataType(this.getFullVector()) === 'number' || morpheus.VectorUtil.getDataType(this.getFullVector()) === '[number]') { this.settings.discrete = false; this.settings.highlightMatchingValues = false; } @@ -824,7 +824,7 @@ morpheus.VectorTrack.prototype = { var SHOW_SELECTION_ONLY = 'Show Selection Only'; var CLEAR_SELECTION = 'Clear Selection'; var HIGHLIGHT_MATCHING_VALUES = 'Highlight Matching Values'; - var FIELDS = 'Fields...'; + var FIELDS = 'Choose Fields...'; var DELETE = 'Delete...'; var TOOLTIP = 'Show In Tooltip'; var HIDE = 'Hide'; @@ -837,15 +837,16 @@ morpheus.VectorTrack.prototype = { var SORT_SEL_DESC = 'Sort Heat Map Descending'; var SORT_SEL_TOP_N = 'Sort Heat Map Descending/Ascending'; var DISPLAY_BAR = 'Show Bar Chart'; - var DISPLAY_STACKED_BAR = 'Stacked'; + var DISPLAY_STACKED_BAR = 'Show Stacked Bar Chart'; + var DISPLAY_BOX_PLOT = 'Show Box Plot'; var DISPLAY_COLOR = 'Show Color'; + var COLOR_BAR_SIZE = 'Color Bar Size...'; var DISPLAY_TEXT = 'Show Text'; var DISPLAY_SHAPE = 'Show Shape'; var DISPLAY_ARC = 'Show Arc'; var DISPLAY_TEXT_AND_COLOR = 'Show Colored Text'; var DISPLAY_STRUCTURE = 'Show Chemical Structure'; var DISPLAY_CONTINUOUS = 'Continuous'; - var TOGGLE = 'Expand/Collapse'; var positions = this.positions; var heatmap = this.heatmap; @@ -955,6 +956,7 @@ morpheus.VectorTrack.prototype = { name: DISPLAY_BAR, checked: this.isRenderAs(morpheus.VectorTrack.RENDER.BAR) }); + } if (isArray) { sectionToItems.Display.push({ @@ -962,18 +964,28 @@ morpheus.VectorTrack.prototype = { checked: this.settings.stackedBar }); sectionToItems.Display.push({ - name: FIELDS, + name: DISPLAY_BOX_PLOT, + checked: this.isRenderAs(morpheus.VectorTrack.RENDER.BOX_PLOT) }); - } - if (!isArray) { sectionToItems.Display.push({ - name: DISPLAY_COLOR, - checked: this.isRenderAs(morpheus.VectorTrack.RENDER.COLOR) + name: FIELDS, }); + + } + sectionToItems.Display.push({ + name: DISPLAY_TEXT, + checked: this.isRenderAs(morpheus.VectorTrack.RENDER.TEXT) + }); + sectionToItems.Display.push({ + name: DISPLAY_COLOR, + checked: this.isRenderAs(morpheus.VectorTrack.RENDER.COLOR) + }); + if (this.isRenderAs(morpheus.VectorTrack.RENDER.COLOR)) { sectionToItems.Display.push({ - name: DISPLAY_TEXT, - checked: this.isRenderAs(morpheus.VectorTrack.RENDER.TEXT) + name: COLOR_BAR_SIZE }); + } + if (!isArray) { sectionToItems.Display.push({ name: DISPLAY_SHAPE, checked: this.isRenderAs(morpheus.VectorTrack.RENDER.SHAPE) @@ -984,11 +996,6 @@ morpheus.VectorTrack.prototype = { // }); } - // sectionToItems.Display.push({ - // name : DISPLAY_TEXT_AND_COLOR, - // checked : this - // .isRenderAs(morpheus.VectorTrack.RENDER.TEXT_AND_COLOR) - // }); if (!isArray && !isNumber && !this.isColumns && name.toLowerCase().indexOf('smile') !== -1) { @@ -1204,7 +1211,7 @@ morpheus.VectorTrack.prototype = { .set( morpheus.VectorKeys.VISIBLE_FIELDS, visibleFieldIndices); - // remove cached box field + var summaryFunction = fullVector .getProperties() .get( @@ -1220,7 +1227,7 @@ morpheus.VectorTrack.prototype = { .getFullDataset() .getRowMetadata() .add(_this.name); - + // remove cached box field for (var i = 0; i < updatedVector .size(); i++) { var array = fullVector @@ -1258,15 +1265,31 @@ morpheus.VectorTrack.prototype = { close: 'Close', html: formBuilder.$form }); - } else if (item === TOGGLE) { - var dataset = project - .getSortedFilteredDataset(); - project.getRowSelectionModel().getViewIndices() - .forEach(function (index) { - dataset.setState(index, undefined); // FIXME + } else if (item === COLOR_BAR_SIZE) { + var formBuilder = new morpheus.FormBuilder(); + formBuilder.append({ + name: 'size', + type: 'text', + value: _this.settings.colorBarSize, + required: true, + col: 'col-xs-2' + }); + formBuilder.find('size').on( + 'change', + function () { + var val = parseFloat($(this) + .val()); + if (val > 0) { + _this.settings.colorBarSize = val; + _this.setInvalid(true); + _this.repaint(); + } + }); + morpheus.FormBuilder.showInModal({ + title: 'Color Bar Size', + close: 'Close', + html: formBuilder.$form }); - project.setFullDataset( - project.getFullDataset(), true); } else if (item === ANNOTATE_SELECTION) { var formBuilder = new morpheus.FormBuilder(); formBuilder.append({ @@ -1617,7 +1640,7 @@ morpheus.VectorTrack.prototype = { chooser.on('change', function (event) { shapeModel.setMappedValue(_this - .getFullVector(), event.value, + .getFullVector(), event.value, event.shape); _this.setInvalid(true); _this.repaint(); @@ -1643,7 +1666,7 @@ morpheus.VectorTrack.prototype = { }); colorSchemeChooser.on('change', function (event) { colorModel.setMappedValue(_this - .getFullVector(), event.value, + .getFullVector(), event.value, event.color); _this.setInvalid(true); _this.repaint(); @@ -1741,6 +1764,8 @@ morpheus.VectorTrack.prototype = { item = morpheus.VectorTrack.RENDER.SHAPE; } else if (item === DISPLAY_ARC) { item = morpheus.VectorTrack.RENDER.ARC; + } else if (item === DISPLAY_BOX_PLOT) { + item = morpheus.VectorTrack.RENDER.BOX_PLOT; } else { console.log('Unknown item ' + item); } @@ -1764,8 +1789,9 @@ morpheus.VectorTrack.prototype = { var settings = this.settings; var canvasSize = isColumns ? this.getUnscaledHeight() : this .getUnscaledWidth(); - if (settings.colorBarSize > canvasSize) { - settings.colorBarSize = canvasSize >= 5 ? (canvasSize - 1) + var colorBarSize = settings.colorBarSize; + if (colorBarSize > canvasSize) { + colorBarSize = canvasSize >= 5 ? (canvasSize - 1) : canvasSize; } var getColor; @@ -1774,21 +1800,61 @@ morpheus.VectorTrack.prototype = { } else { getColor = _.bind(colorModel.getContinuousMappedValue, colorModel); } - for (var i = start; i < end; i++) { - var value = vector.getValue(i); - var position = positions.getPosition(i); - var size = positions.getItemSize(i); - var color = getColor(vector, value); - context.fillStyle = color; - if (isColumns) { - context.beginPath(); - context.rect(position, offset - settings.colorBarSize, size, - settings.colorBarSize); - context.fill(); - } else { - context.beginPath(); - context.rect(offset, position, settings.colorBarSize, size); - context.fill(); + + if (vector.getProperties().get( + morpheus.VectorKeys.FIELDS) != null) { + var visibleFieldIndices = vector.getProperties().get( + morpheus.VectorKeys.VISIBLE_FIELDS); + if (visibleFieldIndices == null) { + visibleFieldIndices = morpheus.Util.seq(vector.getProperties().get( + morpheus.VectorKeys.FIELDS).length); + } + colorBarSize /= visibleFieldIndices.length; + var nvisibleFieldIndices = visibleFieldIndices.length; + + for (var i = start; i < end; i++) { + var array = vector.getValue(i); + var position = positions.getPosition(i); + var size = positions.getItemSize(i); + var _offset = offset; + if (array != null) { + for (var j = 0; j < nvisibleFieldIndices; j++) { + var value = array[visibleFieldIndices[j]]; + var color = getColor(vector, value); + context.fillStyle = color; + if (isColumns) { + context.beginPath(); + context.rect(position, _offset - colorBarSize, size, + colorBarSize); + context.fill(); + } else { + context.beginPath(); + context.rect(_offset, position, colorBarSize, size); + context.fill(); + } + _offset += colorBarSize; + } + } + + } + + } else { + for (var i = start; i < end; i++) { + var value = vector.getValue(i); + var position = positions.getPosition(i); + var size = positions.getItemSize(i); + var color = getColor(vector, value); + context.fillStyle = color; + if (isColumns) { + context.beginPath(); + context.rect(position, offset - colorBarSize, size, + settings.colorBarSize); + context.fill(); + } else { + context.beginPath(); + context.rect(offset, position, colorBarSize, size); + context.fill(); + } } } }, @@ -1800,8 +1866,9 @@ morpheus.VectorTrack.prototype = { var settings = this.settings; var canvasSize = isColumns ? this.getUnscaledHeight() : this .getUnscaledWidth(); - if (settings.colorBarSize > canvasSize) { - settings.colorBarSize = canvasSize >= 5 ? (canvasSize - 1) + var colorBarSize = settings.colorBarSize; + if (colorBarSize > canvasSize) { + colorBarSize = canvasSize >= 5 ? (canvasSize - 1) : canvasSize; } context.fillStyle = 'black'; @@ -1814,7 +1881,7 @@ morpheus.VectorTrack.prototype = { var value = vector.getValue(i); var position = positions.getPosition(i); var itemSize = positions.getItemSize(i); - var minSize = Math.min(settings.colorBarSize, itemSize); + var minSize = Math.min(colorBarSize, itemSize); var size2 = minSize / 2; var shape = shapeModel.getMappedValue(vector, value); // x and y are at center @@ -2025,6 +2092,7 @@ morpheus.VectorTrack.prototype = { .getVector(this.settings.colorByField) : null; var colorModel = isColumns ? this.project.getColumnColorModel() : this.project.getRowColorModel(); + // TODO cache box values for (var i = start; i < end; i++) { var array = vector.getValue(i); if (array != null) { -- GitLab