Commit ccf5d869 authored by Klaas Winter's avatar Klaas Winter
Browse files

Added PCA support. Closes #5.

PCA support is added. This means that support is now available for
showing both PCA and CA next to each other. When filtering is applied,
both PCA and CA are updated, but on the variables that were used to
initialise them. To achieve this, the DimRedPlot service is now
responsible for performing PCA and CA, such that it also knows which
analyses have been performed. The effect of this change is also that
some of the logic from plotctrl has been moved into the DimRedPlot
service, which is good since controllers shouldn't have too much logic
anyways.
parent 4b4b4328
This diff is collapsed.
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
*/ */
angular.module('contigBinningApp.controllers') angular.module('contigBinningApp.controllers')
.controller('DimRedCtrl', function ($scope, $modal, Analytics, R, DimRedPlot, DataSet) { .controller('DimRedCtrl', function ($scope, $modal, R, DimRedPlot, DataSet) {
'use strict'; 'use strict';
...@@ -105,10 +105,15 @@ angular.module('contigBinningApp.controllers') ...@@ -105,10 +105,15 @@ angular.module('contigBinningApp.controllers')
$scope.selectedDimRedMethod = $scope.dimRedMethods[0]; $scope.selectedDimRedMethod = $scope.dimRedMethods[0];
$scope.selectedVariables = []; $scope.selectedVariables = [];
$scope.$watch('selectedDimRedMethod', function (newMethod) { $scope.changeDimRedMethod = function (newMethod) {
// Somehow, if I do not do this, selectedDimRedMethod won't be updated until after the function has finished
$scope.selectedDimRedMethod = newMethod;
if (newMethod === undefined) { return; } if (newMethod === undefined) { return; }
setVariables(); setVariables();
}); $scope.selectedVariables = [];
updateSelectedVariables([]);
};
$scope.$on('DimRedPlot::variablesSelected', function (e, dimRedMethod) { $scope.$on('DimRedPlot::variablesSelected', function (e, dimRedMethod) {
/*jslint unparam: true*/ /*jslint unparam: true*/
...@@ -139,17 +144,6 @@ angular.module('contigBinningApp.controllers') ...@@ -139,17 +144,6 @@ angular.module('contigBinningApp.controllers')
updateSelectedVariables(variables); updateSelectedVariables(variables);
}); });
function updateCaOnTnf() {
$scope.selectedVariables = _.filter($scope.variables, function (variable) {
return variable.group === "Tetra nucleotide frequencies";
});
updateSelectedVariables($scope.selectedVariables);
if ($scope.selectedVariables.length > 2) {
$scope.reduceDimensionality();
}
}
/*jslint unparam: true */ /*jslint unparam: true */
$scope.$on('DataSet::schemaLoaded', function (e, schema) { $scope.$on('DataSet::schemaLoaded', function (e, schema) {
$scope.dataAvailable = true; $scope.dataAvailable = true;
...@@ -158,19 +152,17 @@ angular.module('contigBinningApp.controllers') ...@@ -158,19 +152,17 @@ angular.module('contigBinningApp.controllers')
}); });
/*jslint unparam: false */ /*jslint unparam: false */
$scope.$on('DataSet::filtered', updateCaOnTnf);
/*jslint unparam: true */ /*jslint unparam: true */
$scope.$on('Analytics::dimRedMethodsAvailable', function (e, methods) { $scope.$on('DimRedPlot::dimRedMethodsAvailable', function (e, methods) {
// ICoVeR: For now we only suppor CA on (T|P)NF, so we filter out all // ICoVeR: For now we only suppor CA on (T|P)NF, so we filter out all
// other dim. red. methods. // other dim. red. methods.
$scope.dimRedMethods = _.filter(methods, function (m) { return m.name === "ca"; }); $scope.dimRedMethods = _.filter(methods, function (m) { return m.name === "ca" || m.name === "pca"; });
$scope.selectedDimRedMethod = $scope.dimRedMethods[0]; $scope.selectedDimRedMethod = $scope.dimRedMethods[0];
setVariables(); setVariables();
}); });
/*jslint unparam: false */ /*jslint unparam: false */
$scope.$on('Analytics::dimensionalityReduced', function () { $scope.$on('DimRedPlot::dimensionalityReduced', function () {
$scope.configurationInvalid = $scope.configurationInvalid =
$scope.selectedVariables.length === 0 $scope.selectedVariables.length === 0
|| $scope.selectedDimRedMethod === undefined; || $scope.selectedDimRedMethod === undefined;
...@@ -202,6 +194,6 @@ angular.module('contigBinningApp.controllers') ...@@ -202,6 +194,6 @@ angular.module('contigBinningApp.controllers')
DataSet.get(vars, function () { return; }); DataSet.get(vars, function () { return; });
$scope.configurationInvalid = true; $scope.configurationInvalid = true;
Analytics.reduce(drMethod, vars); DimRedPlot.reduce(drMethod, vars);
}; };
}); });
...@@ -42,8 +42,8 @@ angular.module('contigBinningApp.controllers') ...@@ -42,8 +42,8 @@ angular.module('contigBinningApp.controllers')
} }
/*jslint unparam: true */ /*jslint unparam: true */
$scope.$on("Analytics::dimensionalityReduced", function (ev, method, session) { $scope.$on("DimRedPlot::dimensionalityReduced", function (ev, data) {
session.getObject(updateState); updateState(data);
}); });
/*jslint unparam: false */ /*jslint unparam: false */
......
...@@ -48,84 +48,19 @@ angular.module('contigBinningApp.controllers') ...@@ -48,84 +48,19 @@ angular.module('contigBinningApp.controllers')
switchOptions(); switchOptions();
}; };
// Makes sure that the labels of points are no longer than 80px $scope.$on("DimRedPlot::dimensionalityReduced", function () {
function createWrappedLabels(points) { $scope.analyses = DimRedPlot.analyses;
var testText = d3.select("body").append("div").style("float", "left");
$scope.dimredplotWidth = "col-lg-" + (12 / $scope.analyses.length);
testText.style("font-size", "8px");
if ($scope.analyses.length > 1) {
function wrap(d, i) { if (!$scope.hideOptions) {
/*jslint unparam:true*/ switchOptions();
var textLength,
string,
desiredStringLength,
label = d.id;
if (d.label !== undefined) {
label = d.label;
} }
testText.text(label);
textLength = testText.node().offsetWidth;
string = label;
desiredStringLength = Math.ceil(80 / textLength * string.length);
string = string.slice(0, desiredStringLength);
testText.text(string);
textLength = testText.node().clientWidth;
while (textLength > 80 && string.length > 0) {
string = string.slice(0, -1);
testText.text(string);
textLength = testText.node().clientWidth;
}
d.wrappedLabel = string;
} }
points.forEach(wrap); $scope.$apply();
testText.remove();
}
function updatePlot(data) {
$scope.$apply(function () {
var index;
DimRedPlot.addProcessedData(data.method[0], data.processedData);
if (data.variableProjections !== undefined) {
createWrappedLabels(data.variableProjections);
}
if (data.individualProjections !== undefined) {
createWrappedLabels(data.individualProjections);
}
index = _.findIndex($scope.analyses, {'method': data.method});
if (index === -1) {
data.plotIdx = $scope.analyses.length;
$scope.analyses.push(data);
} else {
data.plotIdx = index;
$scope.analyses[index] = data;
}
$scope.dimredplotWidth = "col-lg-" + (12 / $scope.analyses.length);
if ($scope.analyses.length > 1) {
if (!$scope.hideOptions) {
switchOptions();
}
}
});
$scope.$broadcast("DimRedPlot::resize", $scope.analyses.length); $scope.$broadcast("DimRedPlot::resize", $scope.analyses.length);
}
$scope.$on("Analytics::dimensionalityReduced", function (ev, method, session) {
/*jslint unparam: true */
session.getObject(updatePlot);
}); });
}); });
...@@ -27,8 +27,7 @@ angular.module('contigBinningApp.services') ...@@ -27,8 +27,7 @@ angular.module('contigBinningApp.services')
'use strict'; 'use strict';
var d = { var d = {
clusterMethods: [], clusterMethods: []
dimRedMethods: []
}; };
/*jslint unparam: true */ /*jslint unparam: true */
...@@ -38,14 +37,6 @@ angular.module('contigBinningApp.services') ...@@ -38,14 +37,6 @@ angular.module('contigBinningApp.services')
return methods; return methods;
}, []); }, []);
$rootScope.$broadcast("Analytics::clusterMethodsAvailable", d.clusterMethods); $rootScope.$broadcast("Analytics::clusterMethodsAvailable", d.clusterMethods);
d.dimRedMethods = _.reduce(_.keys(appConfig.dimred), function (methods, method) {
var cfg = appConfig.dimred[method];
cfg.name = method;
methods.push(cfg);
return methods;
}, []);
$rootScope.$broadcast("Analytics::dimRedMethodsAvailable", d.dimRedMethods);
}); });
/*jslint unparam: false */ /*jslint unparam: false */
...@@ -54,10 +45,6 @@ angular.module('contigBinningApp.services') ...@@ -54,10 +45,6 @@ angular.module('contigBinningApp.services')
return d.clusterMethods; return d.clusterMethods;
}, },
dimRedMethods: function () {
return d.dimRedMethods;
},
cluster: function (method, variables, args, id) { cluster: function (method, variables, args, id) {
var fnArgs = { var fnArgs = {
vars: variables, vars: variables,
...@@ -73,19 +60,6 @@ angular.module('contigBinningApp.services') ...@@ -73,19 +60,6 @@ angular.module('contigBinningApp.services')
ocpu.call("cluster." + method, fnArgs, function () { ocpu.call("cluster." + method, fnArgs, function () {
$rootScope.$broadcast("Analytics::dataUpdated", id); $rootScope.$broadcast("Analytics::dataUpdated", id);
}); });
},
reduce: function (method, variables) {
var fnArgs = {
vars: variables
};
if (DataSet.rows()) {
fnArgs.rows = DataSet.rows();
}
ocpu.call("dimred." + method, fnArgs, function (session) {
$rootScope.$broadcast("Analytics::dimensionalityReduced", method, session);
});
} }
}; };
......
/*jslint white: false, indent: 2, nomen: true */ /*jslint white: false, indent: 2, nomen: true */
/*global angular, _, list, d3 */ /*global angular, _, list, d3, ocpu */
/* /*
ICoVeR - Interactive Contig-bin Verification and Refinement ICoVeR - Interactive Contig-bin Verification and Refinement
...@@ -27,6 +27,8 @@ angular.module('contigBinningApp.services') ...@@ -27,6 +27,8 @@ angular.module('contigBinningApp.services')
'use strict'; 'use strict';
var d = { var d = {
dimRedMethods: [],
analyses: [],
processedData: {}, processedData: {},
selections: { selections: {
variable: {}, variable: {},
...@@ -54,6 +56,107 @@ angular.module('contigBinningApp.services') ...@@ -54,6 +56,107 @@ angular.module('contigBinningApp.services')
} }
}; };
// Makes sure that the labels of points are no longer than 80px
function createWrappedLabels(points) {
var testText = d3.select("body").append("div").style("float", "left");
testText.style("font-size", "8px");
function wrap(d, i) {
/*jslint unparam:true*/
var textLength,
string,
desiredStringLength,
label = d.id;
if (d.label !== undefined) {
label = d.label;
}
testText.text(label);
textLength = testText.node().offsetWidth;
string = label;
desiredStringLength = Math.ceil(80 / textLength * string.length);
string = string.slice(0, desiredStringLength);
testText.text(string);
textLength = testText.node().clientWidth;
while (textLength > 80 && string.length > 0) {
string = string.slice(0, -1);
testText.text(string);
textLength = testText.node().clientWidth;
}
d.wrappedLabel = string;
}
points.forEach(wrap);
testText.remove();
}
function processDimRedResults(variables) {
return function (data) {
var index;
d.addProcessedData(data.method[0], data.processedData);
if (data.variableProjections !== undefined) {
createWrappedLabels(data.variableProjections);
}
if (data.individualProjections !== undefined) {
createWrappedLabels(data.individualProjections);
}
// Add a list of variables for automatic redoing of dim. red.
data.usedVariables = variables;
index = _.findIndex(d.analyses, {'method': data.method});
if (index === -1) {
data.plotIdx = d.analyses.length;
d.analyses.push(data);
} else {
data.plotIdx = index;
d.analyses[index] = data;
}
$rootScope.$broadcast("DimRedPlot::dimensionalityReduced", data);
};
}
$rootScope.$on("App::configurationLoaded", function (ev, appConfig) {
/*jslint unparam: true */
d.dimRedMethods = _.reduce(_.keys(appConfig.dimred), function (methods, method) {
var cfg = appConfig.dimred[method];
cfg.name = method;
methods.push(cfg);
return methods;
}, []);
$rootScope.$broadcast("DimRedPlot::dimRedMethodsAvailable", d.dimRedMethods);
});
d.reduce = function (method, variables) {
var fnArgs = {
vars: variables
};
if (DataSet.rows()) {
fnArgs.rows = DataSet.rows();
}
ocpu.call("dimred." + method, fnArgs, function (session) {
session.getObject(processDimRedResults(variables));
});
};
$rootScope.$on('DataSet::filtered', function () {
d.analyses.forEach(function (analysis) {
d.reduce(analysis.method[0], analysis.usedVariables);
});
});
function resetStates() { function resetStates() {
d.selections.individual = {}; d.selections.individual = {};
d.influences.individual = {}; d.influences.individual = {};
...@@ -347,7 +450,7 @@ angular.module('contigBinningApp.services') ...@@ -347,7 +450,7 @@ angular.module('contigBinningApp.services')
// If this brushing is done outside of dimredplot we need to set the selection // If this brushing is done outside of dimredplot we need to set the selection
// type to BAR. // type to BAR.
if (_.findIndex(Analytics.dimRedMethods(), "name", method) === -1) { if (_.findIndex(d.dimRedMethods, "name", method) === -1) {
_.forEach(d.selections.individual, function (val, key) { _.forEach(d.selections.individual, function (val, key) {
d.selections.individual[key] = list.selected.NONE; d.selections.individual[key] = list.selected.NONE;
}); });
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
class="col-sm-3 no-left-padding adjusted-right-padding"> class="col-sm-3 no-left-padding adjusted-right-padding">
<select class="form-control input-sm" <select class="form-control input-sm"
ng-model="selectedDimRedMethod" ng-model="selectedDimRedMethod"
ng-change="changeDimRedMethod(selectedDimRedMethod)"
ng-options="method.name for method in dimRedMethods"> ng-options="method.name for method in dimRedMethods">
</select> </select>
</div> </div>
......
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