morpheus.MatchesOnTopSortKey = function (project, modelIndices, name) { var modelHighlight = {}; var p = project; var viewIndices = []; for (var i = 0, length = modelIndices.length; i < length; i++) { modelHighlight[modelIndices[i]] = true; viewIndices.push(i); } this.comparator = function (i1, i2) { var a = modelHighlight[i1] === undefined ? 0 : 1; var b = modelHighlight[i2] == undefined ? 0 : 1; return (a > b ? -1 : (a === b ? 0 : 1)); }; this.indices = viewIndices; this.name = name; }; morpheus.MatchesOnTopSortKey.prototype = { init: function () { }, getSortOrder: function () { return 2; }, getComparator: function () { return this.comparator; }, getValue: function (i) { return i; }, toString: function (i) { return this.name; } }; morpheus.SortKey = function (field, sortOrder) { if (typeof sortOrder === 'string') { sortOrder = morpheus.SortKey.SortOrder[sortOrder.toUpperCase()]; } this.field = field; this.sortOrder = sortOrder; this.v = null; this.c = null; this.setSortOrder(sortOrder); }; morpheus.SortKey.SortOrder = { ASCENDING: 0, DESCENDING: 1, UNSORTED: 2, CUSTOM: 3, TOP_N: 4 }; morpheus.SortKey.ASCENDING_COMPARATOR = function (a, b) { // we want NaNs to end up at the bottom var aNaN = (a == null || _.isNumber(a) && isNaN(a) || a.length === 0); var bNaN = (b == null || _.isNumber(b) && isNaN(b) || b.length === 0); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } if (a.toLowerCase) { a = a.toLowerCase(); } if (b.toLowerCase) { b = b.toLowerCase(); } return (a === b ? 0 : (a < b ? -1 : 1)); }; morpheus.SortKey.DESCENDING_COMPARATOR = function (a, b) { var aNaN = (a == null || _.isNumber(a) && isNaN(a) || a.length === 0); var bNaN = (b == null || _.isNumber(b) && isNaN(b)) || b.length === 0; if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } return (a === b ? 0 : (a < b ? 1 : -1)); }; morpheus.SortKey.NUMBER_ASCENDING_COMPARATOR = function (a, b) { // we want NaNs to end up at the bottom var aNaN = (a == null || isNaN(a)); var bNaN = (b == null || isNaN(b)); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } return (a === b ? 0 : (a < b ? -1 : 1)); }; morpheus.SortKey.NUMBER_DESCENDING_COMPARATOR = function (a, b) { var aNaN = (a == null || isNaN(a)); var bNaN = (b == null || isNaN(b)); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } return (a === b ? 0 : (a < b ? 1 : -1)); }; morpheus.SortKey.STRING_ASCENDING_COMPARATOR = function (a, b) { a = (a == null || a.toLowerCase === undefined) ? null : a.toLowerCase(); b = (b == null || b.toLowerCase === undefined) ? null : b.toLowerCase(); return (a === b ? 0 : (a < b ? -1 : 1)); }; morpheus.SortKey.STRING_DESCENDING_COMPARATOR = function (a, b) { a = (a == null || a.toLowerCase === undefined) ? null : a.toLowerCase(); b = (b == null || b.toLowerCase === undefined) ? null : b.toLowerCase(); return (a === b ? 0 : (a < b ? 1 : -1)); }; morpheus.SortKey.ELEMENT_ASCENDING_COMPARATOR = function (obj1, obj2) { var a = +obj1; var b = +obj2; var aNaN = isNaN(a); var bNaN = isNaN(b); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } if (a === b) { if (obj1.toObject && obj2.toObject) { var a1 = obj1.toObject(); var b1 = obj2.toObject(); for (var name in a1) { a = a1[name]; b = b1[name]; var c = (a === b ? 0 : (a < b ? -1 : 1)); if (c !== 0) { return c; } } } } return (a === b ? 0 : (a < b ? -1 : 1)); }; morpheus.SortKey.ELEMENT_DESCENDING_COMPARATOR = function (obj1, obj2) { // we want NaNs to end up at the bottom var a = +obj1; var b = +obj2; var aNaN = isNaN(a); var bNaN = isNaN(b); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } if (a === b) { if (obj1.toObject && obj2.toObject) { var a1 = obj1.toObject(); var b1 = obj2.toObject(); for (var name in a1) { a = a1[name]; b = b1[name]; var c = (a === b ? 0 : (a < b ? 1 : -1)); if (c !== 0) { return c; } } } } return (a === b ? 0 : (a < b ? 1 : -1)); }; morpheus.SortKey.BOX_PLOT_SUMMARY_FUNCTION = function (array) { var box = array.box; if (box == null) { var v = morpheus.VectorUtil.arrayAsVector(array); box = morpheus .BoxPlotItem(this.indices != null ? new morpheus.SlicedVector( v, this.indices) : v); array.box = box; } return box.q3; }; morpheus.SortKey.ARRAY_MAX_SUMMARY_FUNCTION = function (array) { var a = 0; if (array != null) { var aPosMax = -Number.MAX_VALUE; var aNegMax = Number.MAX_VALUE; for (var i = 0, length = array.length; i < length; i++) { var value = array[i]; if (!isNaN(value)) { if (value >= 0) { aPosMax = value > aPosMax ? value : aPosMax; } else { aNegMax = value < aNegMax ? value : aNegMax; } } } if (aPosMax !== -Number.MAX_VALUE) { a = aPosMax; } if (aNegMax !== Number.MAX_VALUE) { a = Math.abs(aNegMax) > a ? aNegMax : a; } } return a; }; morpheus.SortKey.ARRAY_ASCENDING_COMPARATOR = function (summary) { return function (a, b) { var aNaN = a == null; var bNaN = b == null; if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } a = summary(a); b = summary(b); aNaN = isNaN(a); bNaN = isNaN(b); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } return (a === b ? 0 : (a < b ? -1 : 1)); }; }; morpheus.SortKey.ARRAY_DESCENDING_COMPARATOR = function (summary) { return function (a, b) { var aNaN = a == null; var bNaN = b == null; if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } a = summary(a); b = summary(b); aNaN = isNaN(a); bNaN = isNaN(b); if (aNaN && bNaN) { return 0; } if (aNaN) { return 1; } if (bNaN) { return -1; } return (a === b ? 0 : (a < b ? 1 : -1)); }; }; morpheus.SortKey.reverseComparator = function (c) { return function (a, b) { return c(b, a); }; }; morpheus.SortKey.prototype = { init: function (dataset) { this.v = dataset.getRowMetadata().getByName(this.field); if (!this.v) { this.v = {}; this.v.getValue = function () { return 0; }; this.c = this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING ? morpheus.SortKey.ASCENDING_COMPARATOR : morpheus.SortKey.DESCENDING_COMPARATOR; } else { var dataType = morpheus.VectorUtil.getDataType(this.v); if (dataType === 'number') { this.c = this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING ? morpheus.SortKey.NUMBER_ASCENDING_COMPARATOR : morpheus.SortKey.NUMBER_DESCENDING_COMPARATOR; } else if (dataType === '[number]') { var summary = this.v.getProperties().get( morpheus.VectorKeys.ARRAY_SUMMARY_FUNCTION) || morpheus.SortKey.ARRAY_MAX_SUMMARY_FUNCTION; this.c = this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING ? morpheus.SortKey .ARRAY_ASCENDING_COMPARATOR(summary) : morpheus.SortKey.ARRAY_DESCENDING_COMPARATOR(summary); } else { this.c = this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING ? morpheus.SortKey.ASCENDING_COMPARATOR : morpheus.SortKey.DESCENDING_COMPARATOR; } } }, getComparator: function () { return this.c; }, getValue: function (i) { return this.v.getValue(i); }, setSortOrder: function (sortOrder) { this.sortOrder = sortOrder; }, getSortOrder: function () { return this.sortOrder; }, toString: function () { return this.field; } }; /** * @param modelIndices * Selected rows or columns * @param isColumnSort - * sort columns by selected rows. */ morpheus.SortByValuesKey = function (modelIndices, sortOrder, isColumnSort) { this.field = 'selection'; this.bothCount = 10; this.modelIndices = modelIndices; this.sortOrder = sortOrder; this.isColumnSort = isColumnSort; this.setSortOrder(sortOrder); }; morpheus.SortByValuesKey.prototype = { init: function (dataset, visibleModelIndices) { // isColumnSort-sort columns by selected rows // dataset is transposed if !isColumnSort this.dataset = morpheus.DatasetUtil.slicedView(dataset, null, this.modelIndices); this.rowView = new morpheus.DatasetRowView(this.dataset); this.summaryFunction = this.modelIndices.length > 1 ? morpheus.Median : function (row) { return row.getValue(0); }; if (this.sortOrder === morpheus.SortKey.SortOrder.TOP_N) { var pairs = []; var missingIndices = []; for (var i = 0, nrows = visibleModelIndices.length; i < nrows; i++) { var index = visibleModelIndices[i]; var value = this.summaryFunction(this.rowView.setIndex(index)); if (!isNaN(value)) { pairs.push({ index: index, value: value }); } else { missingIndices.push(index); } } // sort values in descending order pairs .sort(function (a, b) { return (a.value < b.value ? 1 : (a.value === b.value ? 0 : -1)); }); var modelIndexToValue = []; var nInGroup = Math.min(pairs.length, this.bothCount); var counter = 0; var topIndex = 0; var half = Math.floor(pairs.length / 2); var topPairs = pairs.slice(0, half); var bottomPairs = pairs.slice(half); var bottomIndex = bottomPairs.length - 1; var ntop = topPairs.length; var npairs = pairs.length; while (counter < npairs) { for (var i = 0; i < nInGroup && topIndex < ntop; i++, topIndex++, counter++) { modelIndexToValue[topPairs[topIndex].index] = counter; } var indexCounterPairs = []; for (var i = 0; i < nInGroup && bottomIndex >= 0; i++, bottomIndex--, counter++) { indexCounterPairs.push([bottomPairs[bottomIndex].index, counter]); } for (var i = indexCounterPairs.length - 1, j = 0; i >= 0; i--, j++) { var item_i = indexCounterPairs[i]; var item_j = indexCounterPairs[j]; modelIndexToValue[item_i[0]] = item_j[1]; } } // add on missing for (var i = 0, length = missingIndices.length; i < length; i++, counter++) { modelIndexToValue[missingIndices[i]] = counter; } this.modelIndexToValue = modelIndexToValue; } else { delete this.modelIndexToValue; } }, getComparator: function () { return this.c; }, getValue: function (i) { return this.modelIndexToValue ? this.modelIndexToValue[i] : this .summaryFunction(this.rowView.setIndex(i)); }, setSortOrder: function (sortOrder) { if (typeof sortOrder === 'string') { sortOrder = morpheus.SortKey.SortOrder[sortOrder.toUpperCase()]; } this.sortOrder = sortOrder; if (this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING) { this.c = morpheus.SortKey.ELEMENT_ASCENDING_COMPARATOR; } else if (this.sortOrder === morpheus.SortKey.SortOrder.DESCENDING) { this.c = morpheus.SortKey.ELEMENT_DESCENDING_COMPARATOR; } else { this.c = morpheus.SortKey.NUMBER_ASCENDING_COMPARATOR; } }, getSortOrder: function () { return this.sortOrder; }, toString: function () { return 'values'; } }; /** * @param modelIndices * Array of model indices * @param nvisible * The number of visible indices at the time this sort key was * created. Used by dendrogram to determine if dendrogram should be * shown. * @param name * This sort key name */ morpheus.SpecifiedModelSortOrder = function (modelIndices, nvisible, name) { this.nvisible = nvisible; var modelIndexToValue = []; for (var i = 0, length = modelIndices.length; i < length; i++) { modelIndexToValue[modelIndices[i]] = i; } this.modelIndexToValue = modelIndexToValue; this.name = name; this.c = morpheus.SortKey.ASCENDING_COMPARATOR; }; morpheus.SpecifiedModelSortOrder.prototype = { init: function (dataset) { }, getComparator: function (a, b) { return this.c; }, getValue: function (i) { return this.modelIndexToValue[i]; }, setSortOrder: function (sortOrder) { this.sortOrder = sortOrder; this.c = this.sortOrder === morpheus.SortKey.SortOrder.ASCENDING ? morpheus.SortKey.NUMBER_ASCENDING_COMPARATOR : morpheus.SortKey.NUMBER_DESCENDING_COMPARATOR; }, getSortOrder: function () { return this.sortOrder; }, getName: function () { return this.name; } }; morpheus.SortKey.keepExistingSortKeys = function (newSortKeys, existingSortKeys) { // keep MatchesOnTopSortKey and dendrogram // var existingOnTopSortKey = null; var existingSpecifiedSortKey = null; for (var i = 0, length = existingSortKeys.length; i < length; i++) { var key = existingSortKeys[i]; // if (key instanceof morpheus.MatchesOnTopSortKey) { // existingOnTopSortKey = key; // } if (key instanceof morpheus.SpecifiedModelSortOrder && key.name === 'dendrogram') { existingSpecifiedSortKey = key; } } if (existingSpecifiedSortKey) { var newSortKeysHasTopSortKey = false; var newSortKeysHasSpecifiedSortKey = false; for (var i = 0, length = newSortKeys.length; i < length; i++) { var key = newSortKeys[i]; // if (key instanceof morpheus.MatchesOnTopSortKey) { // newSortKeysHasTopSortKey = true; // } if (key instanceof morpheus.SpecifiedModelSortOrder && key.name === 'dendrogram') { newSortKeysHasSpecifiedSortKey = true; } } // if (existingOnTopSortKey && !newSortKeysHasTopSortKey) { // newSortKeys.splice(0, 0, existingOnTopSortKey); // } if (existingSpecifiedSortKey && !newSortKeysHasSpecifiedSortKey) { newSortKeys.splice(newSortKeys.length, 0, existingSpecifiedSortKey); } } return newSortKeys; }; /** * Group by key * * @param values */ morpheus.SpecifiedGroupByKey = function (clusterIds) { this.clusterIds = clusterIds; this.c = function (a, b) { return (a === b ? 0 : // Values are equal (a < b ? -1 : // (-0.0, 0.0) or (!NaN, NaN) 1)); }; }; morpheus.SpecifiedGroupByKey.prototype = { init: function (dataset) { }, getComparator: function (a, b) { return this.c; }, getValue: function (i) { return this.clusterIds[i]; }, setSortOrder: function (sortOrder) { }, getSortOrder: function () { }, getName: function () { return 'Dendrogram Cut'; } };