morpheus.MetadataUtil = function () { }; morpheus.MetadataUtil.renameFields = function (dataset, options) { _.each(options.rows, function (item) { if (item.renameTo) { var v = dataset.getRowMetadata().getByName(item.field); if (v) { v.setName(item.renameTo); } } }); _.each(options.columns, function (item) { if (item.renameTo) { var v = dataset.getColumnMetadata().getByName(item.field); if (v) { v.setName(item.renameTo); } } }); }; /** * @param options.model * Metadata model * @param options.text * Search text * @param options.isColumns * Whether to search columns * @param options.defaultMatchMode * 'exact' or 'contains' * */ morpheus.MetadataUtil.search = function (options) { var model = options.model; var text = options.text; var isColumns = options.isColumns; text = $.trim(text); if (text === '') { return null; } var tokens = morpheus.Util.getAutocompleteTokens(text); if (tokens.length == 0) { return null; } var indexField = isColumns ? 'COLUMN' : 'ROW'; var fieldNames = morpheus.MetadataUtil.getMetadataNames(model); fieldNames.push(indexField); var predicates = morpheus.Util.createSearchPredicates({ tokens: tokens, fields: fieldNames, defaultMatchMode: options.defaultMatchMode }); var vectors = []; var nameToVector = new morpheus.Map(); for (var j = 0; j < model.getMetadataCount(); j++) { var v = model.get(j); var dataType = morpheus.VectorUtil.getDataType(v); var wrapper = { vector: v, dataType: dataType, isArray: dataType.indexOf('[') === 0 }; nameToVector.set(v.getName(), wrapper); vectors.push(wrapper); } // TODO only search numeric fields for range searches var indices = []; var npredicates = predicates.length; var nfields = vectors.length; for (var i = 0, nitems = model.getItemCount(); i < nitems; i++) { var matches = false; for (var p = 0; p < npredicates && !matches; p++) { var predicate = predicates[p]; var filterColumnName = predicate.getField(); if (filterColumnName != null) { var value = null; if (filterColumnName === indexField) { value = i + 1; if (predicate.accept(value)) { matches = true; break; } } else { var wrapper = nameToVector.get(filterColumnName); if (wrapper) { value = wrapper.vector.getValue(i); if (value != null) { if (wrapper.isArray) { for (var k = 0; k < value.length; k++) { if (predicate.accept(value[k])) { matches = true; break; } } } else { if (predicate.accept(value)) { matches = true; break; } } } } } } else { // try all fields for (var j = 0; j < nfields; j++) { var wrapper = vectors[j]; var value = wrapper.vector.getValue(i); if (value != null) { if (wrapper.isArray) { for (var k = 0; k < value.length; k++) { if (predicate.accept(value[k])) { matches = true; break; } } } else { if (predicate.accept(value)) { matches = true; break; } } } } } } if (matches) { indices.push(i); } } return indices; }; morpheus.MetadataUtil.shallowCopy = function (model) { var copy = new morpheus.MetadataModel(model.getItemCount()); for (var i = 0; i < model.getMetadataCount(); i++) { var v = model.get(i); // copy properties b/c they can be modified via ui var newVector = new morpheus.VectorAdapter(v); newVector.properties = new morpheus.Map(); newVector.getProperties = function () { return this.properties; }; v.getProperties().forEach(function (val, key) { if (!morpheus.VectorKeys.COPY_IGNORE.has(key)) { newVector.properties.set(key, val); } }); copy.vectors.push(newVector); } return copy; }; morpheus.MetadataUtil.autocomplete = function (model) { return function (tokens, cb) { // check for term:searchText var matches = []; var regex = null; var regexMatch = null; var searchModel = model; var token = tokens != null && tokens.length > 0 ? tokens[tokens.selectionStartIndex] : ''; token = $.trim(token); try { if (token !== '') { var field = null; var semi = token.indexOf(':'); if (semi > 0) { // field search? if (token.charCodeAt(semi - 1) !== 92) { // \: var possibleField = $.trim(token.substring(0, semi)); if (possibleField.length > 0 && possibleField[0] === '"' && possibleField[token.length - 1] === '"') { possibleField = possibleField.substring(1, possibleField.length - 1); } var index = morpheus.MetadataUtil.indexOf(searchModel, possibleField); if (index !== -1) { token = $.trim(token.substring(semi + 1)); searchModel = new morpheus.MetadataModelColumnView( model, [index]); } } } var set = new morpheus.Set(); // regex used to determine if a string starts with substring `q` regex = new RegExp(morpheus.Util.escapeRegex(token), 'i'); regexMatch = new RegExp('(' + morpheus.Util.escapeRegex(token) + ')', 'i'); // iterate through the pool of strings and for any string that // contains the substring `q`, add it to the `matches` array var max = 10; var vectors = []; var isArray = []; for (var j = 0; j < searchModel.getMetadataCount(); j++) { var v = searchModel.get(j); var dataType = morpheus.VectorUtil.getDataType(v); if (dataType === 'string' || dataType === '[string]') { // skip // numeric // fields vectors.push(v); isArray.push(dataType === '[string]'); } } var nfields = vectors.length; loop: for (var i = 0, nitems = searchModel.getItemCount(); i < nitems; i++) { for (var j = 0; j < nfields; j++) { var v = vectors[j]; var val = v.getValue(i); if (val != null) { if (isArray[j]) { for (var k = 0; k < val.length; k++) { var id = new morpheus.Identifier([val[k], v.getName()]); if (!set.has(id) && regex.test(val[k])) { set.add(id); if (set.size() === max) { break loop; } } } } else { var id = new morpheus.Identifier([val, v.getName()]); if (!set.has(id) && regex.test(val)) { set.add(id); if (set.size() === max) { break loop; } } } } } } set.forEach(function (id) { var array = id.getArray(); var field = array[1]; var val = array[0]; var quotedField = field; if (quotedField.indexOf(' ') !== -1) { quotedField = '"' + quotedField + '"'; } var quotedValue = val; if (quotedValue.indexOf(' ') !== -1) { quotedValue = '"' + quotedValue + '"'; } matches.push({ value: quotedField + ':' + quotedValue, label: '' + field + ':' + '' + val.replace(regexMatch, '$1') + '' }); }); } } catch (x) { } // field names if (regex == null) { regex = new RegExp('.*', 'i'); } for (var j = 0; j < searchModel.getMetadataCount(); j++) { var v = searchModel.get(j); var dataType = morpheus.VectorUtil.getDataType(v); var field = v.getName(); if (dataType === 'number' || dataType === 'string' || dataType === '[string]') { if (regex.test(field)) { var quotedField = field; if (quotedField.indexOf(' ') !== -1) { quotedField = '"' + quotedField + '"'; } matches.push({ value: quotedField + ':', label: '' + (regexMatch == null ? field : field.replace(regexMatch, '$1')) + ':' + (dataType === 'number' ? ('min..max') : ''), show: true }); } } } cb(matches); }; }; morpheus.MetadataUtil.getMetadataNames = function (metadataModel) { var names = []; for (var i = 0, count = metadataModel.getMetadataCount(); i < count; i++) { names.push(metadataModel.get(i).getName(i)); } names.sort(function (a, b) { a = a.toLowerCase(); b = b.toLowerCase(); return (a < b ? -1 : (a === b ? 0 : 1)); }); return names; }; morpheus.MetadataUtil.getVectors = function (metadataModel, names) { var vectors = []; names.forEach(function (name) { var v = metadataModel.getByName(name); if (!v) { throw name + ' not found. Available fields are ' + morpheus.MetadataUtil.getMetadataNames(metadataModel); } vectors.push(v); }); return vectors; }; morpheus.MetadataUtil.indexOf = function (metadataModel, name) { for (var i = 0, length = metadataModel.getMetadataCount(); i < length; i++) { if (name === metadataModel.get(i).getName()) { return i; } } return -1; }; morpheus.MetadataUtil.DEFAULT_STRING_ARRAY_FIELDS = ['target', 'moa']; morpheus.MetadataUtil.DEFAULT_HIDDEN_FIELDS = new morpheus.Set(); ['pr_analyte_id', 'pr_gene_title', 'pr_gene_id', 'pr_analyte_num', 'pr_bset_id', 'pr_lua_id', 'pr_pool_id', 'pr_is_bing', 'pr_is_inf', 'pr_is_lmark', 'qc_slope', 'qc_f_logp', 'qc_iqr', 'bead_batch', 'bead_revision', 'bead_set', 'det_mode', 'det_plate', 'det_well', 'mfc_plate_dim', 'mfc_plate_id', 'mfc_plate_name', 'mfc_plate_quad', 'mfc_plate_well', 'pert_dose_unit', 'pert_id_vendor', 'pert_mfc_desc', 'pert_mfc_id', 'pert_time', 'pert_time_unit', 'pert_univ_id', 'pert_vehicle', 'pool_id', 'rna_plate', 'rna_well', 'count_mean', 'count_cv', 'provenance_code'].forEach(function (name) { morpheus.MetadataUtil.DEFAULT_HIDDEN_FIELDS.add(name); }); morpheus.MetadataUtil.maybeConvertStrings = function (metadata, metadataStartIndex) { for (var i = metadataStartIndex, count = metadata.getMetadataCount(); i < count; i++) { morpheus.VectorUtil.maybeConvertStringToNumber(metadata.get(i)); } morpheus.MetadataUtil.DEFAULT_STRING_ARRAY_FIELDS.forEach(function (field) { if (metadata.getByName(field)) { morpheus.VectorUtil.maybeConvertToStringArray(metadata .getByName(field), ','); } }); }; morpheus.MetadataUtil.copy = function (src, dest) { if (src.getItemCount() != dest.getItemCount()) { throw 'Item count not equal in source and destination. ' + src.getItemCount() + ' != ' + dest.getItemCount(); } var itemCount = src.getItemCount(); var metadataColumns = src.getMetadataCount(); for (var j = 0; j < metadataColumns; j++) { var srcVector = src.get(j); var destVector = dest.getByName(srcVector.getName()); if (destVector == null) { destVector = dest.add(srcVector.getName()); } for (var i = 0; i < itemCount; i++) { destVector.setValue(i, srcVector.getValue(i)); } } }; morpheus.MetadataUtil.addVectorIfNotExists = function (metadataModel, name) { var v = metadataModel.getByName(name); if (!v) { v = metadataModel.add(name); } return v; }; morpheus.MetadataUtil.getMatchingIndices = function (metadataModel, tokens) { var indices = {}; for (var itemIndex = 0, nitems = metadataModel.getItemCount(); itemIndex < nitems; itemIndex++) { var matches = false; for (var metadataIndex = 0, metadataCount = metadataModel .getMetadataCount(); metadataIndex < metadataCount && !matches; metadataIndex++) { var vector = metadataModel.get(metadataModel .getColumnName(metadataIndex)); var value = vector.getValue(itemIndex); for (var i = 0, length = tokens.length; i < length; i++) { if (tokens[i] == value) { matches = true; break; } } } if (matches) { indices[itemIndex] = 1; } } return indices; };