Commit a69fdef5 authored by joshua-gould's avatar joshua-gould

similarity matrix

parent 9435b49a
This diff is collapsed.
......@@ -175,8 +175,9 @@ morpheus.HCluster.findClosestPair = function(n, distmatrix, r) {
*
* @param dataset
* @param distanceFunction
* The distance function. Use null to assume dataset is already a
* distance matrix.
* The distance function. Use 0 to assume dataset is already a
* distance matrix, 1 to assume dataset is already a similarity
* matrix.
* @return the distance matrix
*/
morpheus.HCluster.computeDistanceMatrix = function(dataset, distanceFunction) {
......@@ -187,12 +188,18 @@ morpheus.HCluster.computeDistanceMatrix = function(dataset, distanceFunction) {
matrix[i] = new Float32Array(i);
}
// assume dataset is already a distance matrix
if (distanceFunction == null) {
if (distanceFunction === 0) {
for (var i = 1; i < n; i++) {
for (var j = 0; j < i; j++) {
matrix[i][j] = dataset.getValue(i, j);
}
}
} else if (distanceFunction === 1) {
for (var i = 1; i < n; i++) {
for (var j = 0; j < i; j++) {
matrix[i][j] = 1 - dataset.getValue(i, j);
}
}
} else {
var list1 = new morpheus.DatasetRowView(dataset);
var list2 = new morpheus.DatasetRowView(dataset);
......
......@@ -23,7 +23,6 @@ morpheus.HClusterGroupBy = function(dataset, groupByFieldNames,
var subset = morpheus.DatasetUtil.slicedView(dataset,
originalIndicesForGroup, null);
var hcl;
var distanceMatrix = morpheus.HCluster.computeDistanceMatrix(
subset, distanceFunction);
hcl = new morpheus.HCluster(distanceMatrix, linkageMethod);
......
morpheus.HClusterTool = function() {
};
morpheus.HClusterTool.PRECOMPUTED = 'Matrix values (for a precomputed distance matrix)';
morpheus.HClusterTool.PRECOMPUTED_DIST = 'Matrix values (for a precomputed distance matrix)';
morpheus.HClusterTool.PRECOMPUTED_SIM = 'Matrix values (for a precomputed similarity matrix)';
morpheus.HClusterTool.Functions = [ morpheus.Euclidean, morpheus.Jaccard,
new morpheus.OneMinusFunction(morpheus.Cosine),
new morpheus.OneMinusFunction(morpheus.Pearson),
new morpheus.OneMinusFunction(morpheus.Spearman),
morpheus.HClusterTool.PRECOMPUTED ];
morpheus.HClusterTool.PRECOMPUTED_DIST,
morpheus.HClusterTool.PRECOMPUTED_SIM ];
morpheus.HClusterTool.Functions.fromString = function(s) {
for (var i = 0; i < morpheus.HClusterTool.Functions.length; i++) {
if (morpheus.HClusterTool.Functions[i].toString() === s) {
......@@ -30,11 +32,14 @@ morpheus.HClusterTool.createLinkageMethod = function(linkageString) {
};
morpheus.HClusterTool.execute = function(dataset, input) {
// note: in worker here
var linkageMethod = morpheus.HClusterTool
.createLinkageMethod(input.linkage_method);
var f = morpheus.HClusterTool.Functions.fromString(input.metric);
if ((typeof f) === 'string') {
f = null; // precomputed
if (f === morpheus.HClusterTool.PRECOMPUTED_DIST) {
f = 0;
} else if (f === morpheus.HClusterTool.PRECOMPUTED_SIM) {
f = 1;
}
var rows = input.cluster == 'Rows' || input.cluster == 'Rows and columns';
var columns = input.cluster == 'Columns'
......@@ -158,7 +163,7 @@ morpheus.HClusterTool.prototype = {
options.input.selectedRows = selectedRows;
options.input.selectedColumns = selectedColumns;
var dataset = project.getSortedFilteredDataset();
if (options.input.background === false) {
var result = morpheus.HClusterTool.execute(dataset, options.input);
if (result.rowsHcl) {
......
morpheus.SimilarityMatrixTool = function() {
};
morpheus.SimilarityMatrixTool.Functions = [ morpheus.Euclidean,
morpheus.Jaccard, morpheus.Cosine, morpheus.Pearson, morpheus.Spearman ];
morpheus.SimilarityMatrixTool.Functions.fromString = function(s) {
for (var i = 0; i < morpheus.SimilarityMatrixTool.Functions.length; i++) {
if (morpheus.SimilarityMatrixTool.Functions[i].toString() === s) {
return morpheus.SimilarityMatrixTool.Functions[i];
}
}
throw new Error(s + ' not found');
};
morpheus.SimilarityMatrixTool.execute = function(dataset, input) {
var isColumnMatrix = input.compute_matrix_for == 'Columns';
var f = morpheus.SimilarityMatrixTool.Functions.fromString(input.metric);
return morpheus.HCluster.computeDistanceMatrix(
isColumnMatrix ? new morpheus.TransposedDatasetView(dataset)
: dataset, f);
};
morpheus.SimilarityMatrixTool.prototype = {
toString : function() {
return 'Similarity Matrix';
},
init : function(project, form) {
},
gui : function() {
return [ {
name : 'metric',
options : morpheus.SimilarityMatrixTool.Functions,
value : morpheus.SimilarityMatrixTool.Functions[3].toString(),
type : 'select'
}, {
name : 'compute_matrix_for',
options : [ 'Columns', 'Rows' ],
value : 'Columns',
type : 'radio'
} ];
},
execute : function(options) {
var project = options.project;
var controller = options.controller;
var isColumnMatrix = options.input.compute_matrix_for == 'Columns';
var f = morpheus.SimilarityMatrixTool.Functions
.fromString(options.input.metric);
var dataset = project.getSortedFilteredDataset();
var blob = new Blob(
[ 'self.onmessage = function(e) {'
+ 'importScripts(e.data.scripts);'
+ 'self.postMessage(morpheus.SimilarityMatrixTool.execute(morpheus.Dataset.fromJson(e.data.dataset), e.data.input));'
+ '}' ]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
worker.postMessage({
scripts : morpheus.Util.getScriptPath(),
dataset : morpheus.Dataset.toJson(dataset, {
columnFields : [],
rowFields : []
}),
input : options.input
});
worker.onmessage = function(e) {
var name = controller.getName();
var matrix = e.data;
var n = isColumnMatrix ? dataset.getColumnCount() : dataset
.getRowCount();
var d = new morpheus.Dataset({
name : name,
rows : n,
columns : n
});
// set the diagonal
var isDistance = f.toString() === morpheus.Euclidean.toString()
|| f.toString() === morpheus.Jaccard.toString();
for (var i = 1; i < n; i++) {
for (var j = 0; j < i; j++) {
var value = matrix[i][j];
d.setValue(i, j, value);
d.setValue(j, i, value);
}
}
// no need to set diagonal if not distance as array already
// initialized to 0
if (!isDistance) {
for (var i = 0; i < n; i++) {
d.setValue(i, i, 1);
}
}
var metadata = isColumnMatrix ? dataset.getColumnMetadata()
: dataset.getRowMetadata();
d.rowMetadataModel = morpheus.MetadataUtil.shallowCopy(metadata);
d.columnMetadataModel = morpheus.MetadataUtil.shallowCopy(metadata);
var colorScheme;
if (!isDistance) {
colorScheme = {
type : 'fixed',
map : [ {
value : -1,
color : 'blue'
}, {
value : 0,
color : 'white'
}, {
value : 1,
color : 'red'
} ]
};
} else {
colorScheme = {
type : 'fixed',
map : [ {
value : 0,
color : 'white'
}, {
value : morpheus.DatasetUtil.max(d),
color : 'red'
} ]
};
}
new morpheus.HeatMap({
colorScheme : colorScheme,
name : name,
dataset : d,
parent : controller,
inheritFromParentOptions : {
rows : !isColumnMatrix,
columns : isColumnMatrix
}
});
worker.terminate();
window.URL.revokeObjectURL(url);
};
return worker;
}
};
\ No newline at end of file
......@@ -1580,7 +1580,8 @@ morpheus.HeatMap.prototype = {
}
if (this.options.parent && this.options.inheritFromParent) {
if (this.options.parent && this.options.inheritFromParent
&& !this.options.colorScheme) {
heatmap.setColorScheme(this.options.parent.heatmap.getColorScheme()
.copy(this.project));
} else {
......@@ -3260,6 +3261,7 @@ morpheus.HeatMap.prototype = {
};
morpheus.HeatMap.copyFromParent = function(project, options) {
// TODO persist sort order, grouping, dendrogram
project.rowColorModel = options.parent.getProject().getRowColorModel()
.copy();
project.columnColorModel = options.parent.getProject()
......@@ -3269,8 +3271,19 @@ morpheus.HeatMap.copyFromParent = function(project, options) {
.copy();
project.columnShapeModel = options.parent.getProject()
.getColumnShapeModel().copy();
var parentRowTracks = options.parent.rowTracks || [];
var parentColumnTracks = options.parent.columnTracks || [];
if (options.inheritFromParentOptions.rows) { // row similarity matrix
project.columnShapeModel = project.rowShapeModel;
project.columnColorModel = project.rowColorModel;
parentColumnTracks = parentRowTracks.slice().reverse();
}
if (options.inheritFromParentOptions.columns) { // column similarity matrix
project.rowShapeModel = project.columnShapeModel;
project.rowColorModel = project.columnColorModel;
parentRowTracks = parentColumnTracks.slice().reverse();
}
if (options.inheritFromParentOptions.transpose) {
var tmp = project.rowShapeModel;
project.rowShapeModel = project.columnShapeModel;
......@@ -3281,6 +3294,7 @@ morpheus.HeatMap.copyFromParent = function(project, options) {
project.columnColorModel = tmp;
tmp = parentRowTracks.slice().reverse();
// swap tracks
parentRowTracks = parentColumnTracks.slice().reverse();
parentColumnTracks = tmp;
}
......
......@@ -208,6 +208,8 @@ morpheus.HeatMapToolBar = function(controller) {
tool : new morpheus.CollapseDatasetTool()
}, {
tool : new morpheus.CreateAnnotation()
}, {
tool : new morpheus.SimilarityMatrixTool()
}, {
tool : new morpheus.TransposeTool()
}, {
......
......@@ -135,7 +135,7 @@ morpheus.Util.getQueryParams = function(s) {
};
morpheus.Util.getScriptPath = function() {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
for (var i = scripts.length - 1; i >= 0; i--) {
var src = scripts[i].src;
var index = src.lastIndexOf('/');
if (index !== -1) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment