From f98eda52a1d1b25d02c4b6fe8bb6bfa9e55fdf73 Mon Sep 17 00:00:00 2001
From: Jaden Diefenbaugh <blakcap@users.noreply.github.com>
Date: Thu, 2 Mar 2017 11:27:12 +0100
Subject: [PATCH] add experimentsService to handle experiment data

---
 .../app/controllers/reportController.js       |   7 +-
 .../app/services/experimentsService.js        | 183 ++++++++++++++++++
 2 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 beat/web/reports/static/reports/app/services/experimentsService.js

diff --git a/beat/web/reports/static/reports/app/controllers/reportController.js b/beat/web/reports/static/reports/app/controllers/reportController.js
index 1187c3c6d..d3fcede13 100644
--- a/beat/web/reports/static/reports/app/controllers/reportController.js
+++ b/beat/web/reports/static/reports/app/controllers/reportController.js
@@ -21,7 +21,7 @@
  */
 //This controller retrieves data from the reportFactory/experimentFactory through the REST API and associates it with the $scope
 //The $scope is ultimately bound to the report view
-angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', 'experimentFactory', 'plotterFactory', 'dataFactory', '$q', 'GroupsService', function ($scope, reportFactory, experimentFactory, plotterFactory, dataFactory, $q, GroupsService){
+angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', 'experimentFactory', 'plotterFactory', 'dataFactory', '$q', 'GroupsService', 'ExperimentsService', function ($scope, reportFactory, experimentFactory, plotterFactory, dataFactory, $q, GroupsService, ExperimentsService){
 	$scope.q = $q;
 	$scope.user;
 	$scope.report_id;
@@ -148,6 +148,7 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact
 	}
 
 	function getExperimentDataReportNumber(report_number){
+		ExperimentsService.loadExperiments($scope.url_prefix, report_number);
 		experimentFactory.getAllExperimentResults($scope.url_prefix, report_number)
 		.then(function (experiments){
 			mutateSave($scope.report_experiments, experiments);
@@ -192,6 +193,7 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact
 	}
 
 	function getExperimentDataForAuthor(all_experiments){
+		ExperimentsService.loadExperiments($scope.user, $scope.report_id, $scope.url_prefix);
 		experimentFactory.getAllExperimentResultsForAuthor($scope.user, $scope.report_id, $scope.url_prefix)
 		.then(function (experiments){
 			mutateSave($scope.report_experiments, experiments);
@@ -266,6 +268,7 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact
 		plotterFactory.getPlotters($scope.url_prefix)
 		.success(function (plottersData){
 			$scope.report.plotters = plottersData;
+			console.log(plottersData);
 			getPlotterParameterData();
 		})
 		.error(function (error){
@@ -277,6 +280,7 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact
 		plotterFactory.getDefaultPlotters($scope.url_prefix)
 		.success(function (defaultPlottersData){
 			$scope.report.defaultplotters = defaultPlottersData;
+			console.log(defaultPlottersData);
 			checkContent();
 		})
 		.error(function (error){
@@ -288,6 +292,7 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact
 		plotterFactory.getPlotterParameter($scope.url_prefix)
 		.success(function (plotterParameterData){
 			$scope.report.plotterparameter = plotterParameterData;
+			console.log(plotterParameterData);
 			//$scope.report.plotterparameter.push({"name":"Default"});
 			getDefaultPlotters();
 		})
diff --git a/beat/web/reports/static/reports/app/services/experimentsService.js b/beat/web/reports/static/reports/app/services/experimentsService.js
new file mode 100644
index 000000000..8b2bf785e
--- /dev/null
+++ b/beat/web/reports/static/reports/app/services/experimentsService.js
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
+ * Contact: beat.support@idiap.ch
+ *
+ * This file is part of the beat.web module of the BEAT platform.
+ *
+ * Commercial License Usage
+ * Licensees holding valid commercial BEAT licenses may use this file in
+ * accordance with the terms contained in a written agreement between you
+ * and Idiap. For further information contact tto@idiap.ch
+ *
+ * Alternatively, this file may be used under the terms of the GNU Affero
+ * Public License version 3 as published by the Free Software and appearing
+ * in the file LICENSE.AGPL included in the packaging of this file.
+ * The BEAT platform is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero Public License along
+ * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
+ */
+
+/*
+ * ExperimentsService
+ * Desc:
+ * 	Manages the experiments data, including storing it and generating
+ * 	different views of the data
+ */
+angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', 'GroupsService', function(experimentFactory, GroupsService){
+	// holds the raw exp data received from the server
+	const expData = {};
+	// holds the view generated from `getTableablesFromExpName`
+	const tableData = {};
+	// holds the view generated from `getPlottablesFromExpName`
+	const plotData = {};
+
+	// lots of experiments have fields that are differently-named
+	// but mean the same thing.
+	// These fields are the *only* available field in the obj.
+	const getVarProp = (obj, dontLogErrors) => {
+		let keys = Object.keys(obj);
+		if(keys.length !== 1 && !dontLogErrors){
+			console.warn(`Found bad obj for getVarProp:`);
+			console.log(obj);
+		}
+
+		return obj[keys[0]];
+	};
+
+	// analyzer
+	const getAnalyzerFromExpName = (expName) => getVarProp(expData[expName].declaration.analyzers, true).algorithm;
+
+	// get all possible objects that could be shown in a table
+	const getTableablesFromExpName = (expName) => {
+		let currExp = expData[expName];
+
+		console.log(currExp);
+		// get all result objs that have a type that doesnt start with 'plot/'
+		// these results can be displayed in a table
+		let results = Object.entries(getVarProp(currExp.results))
+		// type not starting with plot
+		.filter(([res_name, obj]) => !obj.type.startsWith('plot/'))
+		// after we've filtered fields, make it into an obj
+		.map(([res_name, obj]) => { return {[res_name]: obj}; })
+		// concat objs via reduce
+		.reduce((o, curr) => Object.assign(o, curr), {})
+		;
+
+		// get block parameters
+		let blockVars = Object.entries(currExp.declaration.blocks)
+		// only look at blocks with parameters
+		.filter(([blockName, block]) => block.parameters)
+		// loop through each block
+		.map(([blockName, block]) => {
+			// flatten the block's execution infos
+			return Object.entries(block.parameters)
+			.map(([fieldName, field]) => {
+				return { [`${blockName}.${fieldName}`]: field };
+			})
+			.reduce((o, fieldObj) => Object.assign(o, fieldObj), {})
+			;
+		})
+		// flatten the exp's blocks' params
+		.reduce((o, blockObj) => Object.assign(o, blockObj), {})
+		;
+
+		// get global experiment variables
+		let globalVars = Object.entries(currExp.declaration.globals)
+		// properties that have a '/' in the name
+		.filter(([name, obj]) => name.includes('/'))
+		.map(([algName, alg]) => {
+			// flatten the alg's fields
+			return Object.entries(alg)
+			.map(([fieldName, field]) => {
+				return { [`${algName}.${fieldName}`]: field };
+			})
+			.reduce((o, fieldObj) => Object.assign(o, fieldObj), {})
+			;
+		})
+		// flatten the exp's algs' fields
+		.reduce((o, algObj) => Object.assign(o, algObj), {})
+		;
+
+		// get block timing infos
+		let blockTiming = Object.entries(currExp.execution_info)
+		// loop through each block
+		.map(([blockName, block]) => {
+			// flatten the block's execution infos
+			return Object.entries(block)
+			.map(([fieldName, field]) => {
+				return { [`${blockName}.${fieldName}`]: field };
+			})
+			.reduce((o, fieldObj) => Object.assign(o, fieldObj), {})
+			;
+		})
+		// flatten the exp's execution infos
+		.reduce((o, blockObj) => Object.assign(o, blockObj), {})
+		;
+
+		// get total timing info
+		let expTiming = {
+			'total_execution_time': Object.entries(blockTiming)
+			.filter(([name, val]) => name.includes('linear_execution_time'))
+			.map(([name, val]) => val)
+			.reduce((n, v) => n + v, 0)
+		};
+
+		// concat all objs
+		let allObj = Object.assign({},
+			results,
+			globalVars,
+			blockVars,
+			blockTiming,
+			expTiming
+		);
+
+		return allObj;
+	};
+
+	// get all result objs that have a type that starts with 'plot/'
+	// these results can be displayed in a plot
+	const getPlottablesFromExpName = (expName) => {
+		return Object.entries(getVarProp(expData[expName].results))
+		.filter(([res_name, obj]) => obj.type.startsWith('plot/'))
+		.map(([res_name, obj]) => obj);
+	};
+
+	const loadExperiments = (...args) => {
+		let expFetch;
+		if(args.length === 2){
+			// 2 args -> get exps by report num
+			expFetch = experimentFactory.getAllExperimentResults(...args);
+
+		} else if (args.length === 3){
+			// 3 args -> by report author
+			expFetch = experimentFactory.getAllExperimentResultsForAuthor(...args);
+		}
+
+		return expFetch
+		.then((exps) => {
+			Object.entries(exps)
+			.forEach(([expName, exp]) => {
+				expData[expName] = exp;
+				tableData[expName] = getTableablesFromExpName(expName);
+				plotData[expName] = getPlottablesFromExpName(expName);
+			});
+
+			console.log(expData);
+			console.log(tableData);
+			console.log(plotData);
+
+			return expData;
+		});
+	};
+
+	return {
+		experiments: expData,
+		plottables: plotData,
+		tableables: tableData,
+		getAnalyzerFromExpName,
+		loadExperiments
+	};
+}]);
-- 
GitLab