diff --git a/app/js/benefitRisk/schemaService.js b/app/js/benefitRisk/schemaService.js index 971eadf41..a8786e22d 100644 --- a/app/js/benefitRisk/schemaService.js +++ b/app/js/benefitRisk/schemaService.js @@ -1,11 +1,11 @@ 'use strict'; -define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { +define(['lodash', 'angular', 'ajv'], function(_, angular, Ajv) { var dependencies = [ 'currentSchemaVersion', 'generateUuid' ]; - var SchemaService = function ( + var SchemaService = function( currentSchemaVersion, generateUuid ) { @@ -28,10 +28,10 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { if (newProblem.schemaVersion === '1.1.0') { newProblem = updateToVersionOnePointTwoPointZero(newProblem); } - + if (newProblem.schemaVersion === currentSchemaVersion) { var error = isInvalidSchema(newProblem); - + if (error) { return { isValid: false, @@ -76,7 +76,7 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { function updateToVersionOnePointZeroPointZero(problem) { var newProblem = angular.copy(problem); - newProblem.criteria = _.mapValues(problem.criteria, _.partial(createNewCriterion, problem)); + newProblem.criteria = _.mapValues(problem.criteria, createNewCriterion); newProblem.performanceTable = createNewPerformanceTable(newProblem); newProblem.schemaVersion = '1.0.0'; return newProblem; @@ -94,7 +94,27 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { function updateToVersionOnePointTwoPointZero(problem) { var newProblem = angular.copy(problem); - newProblem.performanceTable = _.map(newProblem.performanceTable, function (entry) { + newProblem.performanceTable = changePerformanceTypeToArray(newProblem); + newProblem.criteria = removeObsoletePropertiesFromDataSource(newProblem); + newProblem.schemaVersion = '1.2.0'; + return newProblem; + } + + function removeObsoletePropertiesFromDataSource(problem) { + return _.mapValues(problem.criteria, function(criterion) { + criterion.dataSources = _.map(criterion.dataSources, function(dataSource) { + delete dataSource.inputType; + delete dataSource.inputMethod; + delete dataSource.dataType; + delete dataSource.parameterOfInterest; + return dataSource; + }); + return criterion; + }); + } + + function changePerformanceTypeToArray(problem) { + return _.map(problem.performanceTable, function(entry) { if (entry.alternative) { entry.performance.type = [entry.performance.type]; return entry; @@ -102,12 +122,10 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { return entry; } }); - newProblem.schemaVersion = '1.2.0'; - return newProblem; } function putFavorabilityOnCriteria(problem) { - return _.mapValues(problem.criteria, function (criterion, criterionId) { + return _.mapValues(problem.criteria, function(criterion, criterionId) { var newCriterion = angular.copy(criterion); if (problem.valueTree.children[0].criteria) { newCriterion.isFavorable = _.includes(problem.valueTree.children[0].criteria, criterionId); @@ -119,7 +137,7 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { } function createNewPerformanceTable(problem) { - return _.map(problem.performanceTable, function (tableEntry) { + return _.map(problem.performanceTable, function(tableEntry) { var newEntry = angular.copy(tableEntry); if (tableEntry.criterionUri) { newEntry.criterion = tableEntry.criterionUri; @@ -130,46 +148,28 @@ define(['lodash', 'angular', 'ajv'], function (_, angular, Ajv) { }); } - function createNewCriterion(problem, criterion, criterionId) { - var newCriterion = _.pick(criterion, ['title', 'description', 'unitOfMeasurement']); - var dataSource = createDataSource(problem, criterion, criterionId); + function createNewCriterion(criterion) { + var newCriterion = _.pick(criterion, [ + 'title', + 'description', + 'unitOfMeasurement' + ]); + var dataSource = createDataSource(criterion); newCriterion.dataSources = [dataSource]; return newCriterion; } - function createDataSource(problem, criterion, criterionId) { - var dataSource = _.pick(criterion, ['pvf', 'source', 'sourceLink', 'strengthOfEvidence', 'uncertainties', 'scale']); + function createDataSource(criterion) { + var dataSource = _.pick(criterion, [ + 'pvf', + 'source', + 'sourceLink', + 'strengthOfEvidence', + 'uncertainties', + 'scale' + ]); dataSource.id = generateUuid(); - var inputParameters = getInputParameters(problem.performanceTable, criterionId); - return _.merge(dataSource, inputParameters); - } - - function getInputParameters(performanceTable, criterionId) { - var type = findEntryTypeForCriterion(performanceTable, criterionId); - if (isManualDistribution(type)) { - return { - inputType: 'distribution', - inputMethod: 'manualDistribution' - }; - } else if (type === 'dt') { - return { - inputType: 'distribution', - inputMethod: 'assistedDistribution', - dataType: 'continuous' - }; - } - } - - function findEntryTypeForCriterion(performanceTable, criterionId) { - var tableEntry = _.find(performanceTable, function (entry) { - return entry.criterion === criterionId || entry.criterionUri === criterionId; - }); - return tableEntry.performance.type; - } - - function isManualDistribution(type) { - var MANUAL_DISTRIBUTIONS = ['exact', 'dnorm', 'dbeta', 'dgamma']; - return _.includes(MANUAL_DISTRIBUTIONS, type); + return dataSource; } return { diff --git a/app/js/effectsTable/criterionCardDirective.html b/app/js/effectsTable/criterionCardDirective.html index ceeeb7217..ae396c8e1 100644 --- a/app/js/effectsTable/criterionCardDirective.html +++ b/app/js/effectsTable/criterionCardDirective.html @@ -52,22 +52,6 @@
{{criterion.title}}
Reference - - Input type - - - - Input method - - - - Data type - - - - Parameter of interest - - Strength of evidence / Uncertainties @@ -104,13 +88,6 @@
{{criterion.title}}
{{dataSource.source}} - - {{dataSource.inputType ? dataSource.inputType : 'Unknown'}} - {{dataSource.inputType === 'distribution' ? INPUT_METHODS[dataSource.inputMethod] :'NA'}} - {{dataSource.inputType === 'effect' || dataSource.inputMethod === 'assistedDistribution' ? dataSource.dataType - : 'NA'}} - {{(dataSource.inputType && dataSource.inputType !== 'distribution') || dataSource.inputMethod === 'assistedDistribution' - ? PARAMETERS_OF_INTEREST[dataSource.parameterOfInterest] : 'NA'}} SoE: {{dataSource.strengthOfEvidence}}
diff --git a/app/js/effectsTable/criterionCardDirective.js b/app/js/effectsTable/criterionCardDirective.js index 93b2f9770..47963fb15 100644 --- a/app/js/effectsTable/criterionCardDirective.js +++ b/app/js/effectsTable/criterionCardDirective.js @@ -39,19 +39,6 @@ define(['lodash'], function(_) { scope.editDataSource = editDataSource; // init - scope.INPUT_METHODS = { - manualDistribution: 'Manual distribution', - assistedDistribution: 'Assisted distribution' - }; - - scope.PARAMETERS_OF_INTEREST = { - mean: 'Mean', - median: 'Median', - cumulativeProbability: 'Cumulative probability', - eventProbability: 'Event probability', - value: 'value' - }; - setUnit(); scope.$on('elicit.settingsChanged', setUnit); diff --git a/app/js/effectsTable/criterionListDirective.js b/app/js/effectsTable/criterionListDirective.js index a7e55aabd..e0b47fb1a 100644 --- a/app/js/effectsTable/criterionListDirective.js +++ b/app/js/effectsTable/criterionListDirective.js @@ -107,7 +107,6 @@ define(['lodash'], function(_) { //private function initializeCriteriaLists() { if (scope.isInput) { - checkForUnknownCriteria(); checkForMissingFavorability(); } var partition = _.partition(scope.criteria, ['isFavorable', true]); @@ -130,18 +129,6 @@ define(['lodash'], function(_) { scope.errors.push('Missing favorability'); } } - - function checkForUnknownCriteria() { - var error = 'Unknown input type'; - _.pull(scope.errors, error); - if (_.find(scope.criteria, function(criterion) { - return _.find(criterion.dataSources, function(dataSource) { - return !dataSource.inputType; - }); - })) { - scope.errors.push(error); - } - } } }; }; diff --git a/app/js/effectsTable/effectsTable.html b/app/js/effectsTable/effectsTable.html index d836d0d2c..bd6837f7c 100644 --- a/app/js/effectsTable/effectsTable.html +++ b/app/js/effectsTable/effectsTable.html @@ -63,8 +63,7 @@

Effects Table workspace-settings="workspaceSettings" scales="scales[row.dataSource.id][alternative.id]" theoretical-scale="row.dataSource.scale" - alternative-id="alternative.id" - input-type="row.dataSource.inputType"> + alternative-id="alternative.id"> diff --git a/app/js/effectsTable/effectsTableCellDirective.html b/app/js/effectsTable/effectsTableCellDirective.html index ccd41010a..ff579e274 100644 --- a/app/js/effectsTable/effectsTableCellDirective.html +++ b/app/js/effectsTable/effectsTableCellDirective.html @@ -3,8 +3,8 @@ {{effectDataSourceLabel}}
- +
@@ -24,8 +24,8 @@ -
+
-
+
\ No newline at end of file diff --git a/app/js/effectsTable/effectsTableCellDirective.js b/app/js/effectsTable/effectsTableCellDirective.js index 1b3ae2f2b..0fabb6023 100644 --- a/app/js/effectsTable/effectsTableCellDirective.js +++ b/app/js/effectsTable/effectsTableCellDirective.js @@ -1,5 +1,5 @@ 'use strict'; -define([], function() { +define(['lodash'], function(_) { var dependencies = ['$filter']; @@ -11,8 +11,7 @@ define([], function() { 'workspaceSettings': '=', 'scales': '=', 'theoreticalScale': '=', - 'alternativeId': '=', - 'inputType': '=' + 'alternativeId': '=' }, templateUrl: './effectsTableCellDirective.html', link: function(scope) { @@ -21,11 +20,11 @@ define([], function() { scope.$watch('workspaceSettings', init, true); function init() { - scope.uncertainty = scope.effectsTableInfo.distributionType === 'relative' || scope.effectsTableInfo.studyDataLabelsAndUncertainty[scope.alternativeId].hasUncertainty; + scope.uncertainty = _.includes(scope.effectsTableInfo.distributionType , 'relative') || scope.effectsTableInfo.studyDataLabelsAndUncertainty[scope.alternativeId].hasUncertainty; scope.effectsDisplay = scope.workspaceSettings.effectsDisplay; scope.hasStudyData = scope.effectsTableInfo.hasStudyData; - scope.isEffect = scope.inputType === 'effect'; scope.effectDataSourceLabel = scope.effectsTableInfo.studyDataLabelsAndUncertainty ? scope.effectsTableInfo.studyDataLabelsAndUncertainty[scope.alternativeId].label : undefined; + scope.isEffect = _.includes(scope.effectsTableInfo.distributionType , 'exact'); } } diff --git a/app/js/effectsTable/effectsTableService.js b/app/js/effectsTable/effectsTableService.js index b7dc15240..c53500de9 100644 --- a/app/js/effectsTable/effectsTableService.js +++ b/app/js/effectsTable/effectsTableService.js @@ -1,11 +1,11 @@ 'use strict'; -define(['lodash', 'angular'], function(_, angular) { +define(['lodash', 'angular'], function (_, angular) { var dependencies = []; - var EffectsTableService = function() { + var EffectsTableService = function () { function buildEffectsTable(criteria) { var tableRows = addCanBePercentageToCriteria(angular.copy(criteria)); - var useFavorability = _.find(criteria, function(criterion) { + var useFavorability = _.find(criteria, function (criterion) { return criterion.hasOwnProperty('isFavorable'); }); if (useFavorability) { @@ -29,28 +29,28 @@ define(['lodash', 'angular'], function(_, angular) { tableRows = buildTableRows(tableRows); return tableRows; } - + function addCanBePercentageToCriteria(criteria) { - return _.mapValues(criteria, function(criterion) { + return _.mapValues(criteria, function (criterion) { criterion.canBePercentage = canBePercentage(criterion); return criterion; }); } function canBePercentage(criterion) { - return !!_.find(criterion.dataSources, function(dataSource) { + return !!_.find(criterion.dataSources, function (dataSource) { return _.isEqual(dataSource.scale, [0, 1]) || _.isEqual(dataSource.scale, [0, 100]); }); } function buildTableRows(rows) { - return _.reduce(rows, function(accum, row) { + return _.reduce(rows, function (accum, row) { if (row.isHeaderRow) { return accum.concat(row); } var rowCriterion = _.omit(row, ['dataSources']); rowCriterion.numberOfDataSources = row.dataSources.length; - accum = accum.concat(_.map(row.dataSources, function(dataSource, index) { + accum = accum.concat(_.map(row.dataSources, function (dataSource, index) { return { criterion: rowCriterion, isFirstRow: index === 0, @@ -62,7 +62,7 @@ define(['lodash', 'angular'], function(_, angular) { } function createEffectsTableInfo(performanceTable) { - return _.reduce(performanceTable, function(accum, tableEntry) { + return _.reduce(performanceTable, function (accum, tableEntry) { var dataSourceId = tableEntry.dataSource; if (accum[dataSourceId]) { return accum; } if (tableEntry.alternative) { @@ -71,7 +71,7 @@ define(['lodash', 'angular'], function(_, angular) { hasStudyData: true, studyDataLabelsAndUncertainty: _(performanceTable) .filter(['dataSource', dataSourceId]) - .reduce(function(accum, entryForCriterion) { + .reduce(function (accum, entryForCriterion) { accum[entryForCriterion.alternative] = buildLabel(entryForCriterion); return accum; }, {}) @@ -87,79 +87,21 @@ define(['lodash', 'angular'], function(_, angular) { } function isStudyDataAvailable(effectsTableInfo) { - return !!(_.find(effectsTableInfo, function(infoEntry) { + return !!(_.find(effectsTableInfo, function (infoEntry) { return infoEntry.distributionType !== 'relative'; })); } + + function buildLabel(entryForCriterion) { - var label = ''; + var label; var performance = entryForCriterion.performance; - var hasUncertainty = performance.type !== 'empty'; - var parameters = performance.parameters; + var hasUncertainty = determineUncertainty(performance.type); if (performance.input) { - var input = performance.input; - switch (performance.type) { - case 'exact': - hasUncertainty = false; - if (input.events) { - label = input.events + ' / ' + input.sampleSize; - } else if (input.scale === 'percentage') { - label = input.value + '%'; - label = input.lowerBound ? label + ' (' + input.lowerBound + '%; ' + - input.upperBound + '%)' : label; - label = input.sampleSize ? label + ' (' + input.sampleSize + ')' : label; - } else { - label = input.value; - label = input.stdErr ? label + ' (' + input.stdErr + ')' : label; - label = input.lowerBound ? label + ' (' + input.lowerBound + '; ' + - input.upperBound + ')' : label; - label = input.sampleSize ? label + ' (' + input.sampleSize + ')' : label; - } - break; - case 'dt': - label = input.mu + ' (' + roundToThreeDigits(parameters.stdErr) + '), ' + (input.sampleSize); - break; - case 'dnorm': - if (input.events && input.sampleSize) { - label = input.events + ' / ' + input.sampleSize; - } else if (input.value && input.sampleSize && input.scale === 'percentage') { //dichotomous - label = input.value + '% (' + input.sampleSize + ')'; - } else if (input.value && input.sampleSize) { //dichotomous - label = input.value + ' (' + input.sampleSize + ')'; - } else if (input.stdErr) {//with stdErr - label = input.value ? input.value : input.mu; //exact to dist vs manual normal dist - label += ' (' + input.stdErr + ')'; - } else if (input.lowerBound) {//with confidence interval - label = input.value + ' (' + input.lowerBound + '; ' + input.upperBound + ')'; - } - break; - case 'dbeta': - label = input.events + ' / ' + input.sampleSize; - break; - } + label = buildLabelBasedOnInput(performance); } else { - switch (performance.type) { - case 'exact': - hasUncertainty = false; - label = performance.value; - break; - case 'dt': - label = parameters.mu + ' (' + roundToThreeDigits(parameters.stdErr) + '), ' + (parameters.dof + 1); - break; - case 'dnorm': - label = parameters.mu + ' (' + roundToThreeDigits(parameters.sigma) + ')'; - break; - case 'dbeta': - label = (parameters.alpha - 1) + ' / ' + (parameters.beta + parameters.alpha - 2); - break; - case 'dgamma': - label = (parameters.alpha) + ' / ' + (parameters.beta); - break; - case 'dsurv': - label = (parameters.alpha - 0.001) + ' / ' + (parameters.beta - 0.001); - break; - } + label = buildLabelBasedOnParameters(performance); } return { label: label, @@ -167,7 +109,91 @@ define(['lodash', 'angular'], function(_, angular) { }; } - //private + function determineUncertainty(type) { + return !_.includes(type, 'empty') && !_.includes(type, 'exact'); + } + + function buildLabelBasedOnParameters(performance) { + var label = ''; + var parameters = performance.parameters; + if (_.includes(performance.type, 'exact')) { + label = performance.value; + } else if (_.includes(performance.type, 'dt')) { + label = parameters.mu + ' (' + roundToThreeDigits(parameters.stdErr) + '), ' + (parameters.dof + 1); + } else if (_.includes(performance.type, 'dnorm')) { + label = parameters.mu + ' (' + roundToThreeDigits(parameters.sigma) + ')'; + } else if (_.includes(performance.type, 'dbeta')) { + label = (parameters.alpha - 1) + ' / ' + (parameters.beta + parameters.alpha - 2); + } else if (_.includes(performance.type, 'dgamma')) { + label = (parameters.alpha) + ' / ' + (parameters.beta); + } else if (_.includes(performance.type, 'dsurv')) { + label = (parameters.alpha - 0.001) + ' / ' + (parameters.beta - 0.001); + } + return label; + } + + function buildLabelBasedOnInput(performance) { + var label = ''; + var type = performance.type; + var input = performance.input; + if (_.includes(type, 'exact')) { + label = buildExactLabel(input); + } else if (_.includes(type, 'dt')) { + label = buildStudentsTLabel(input); + } else if (_.includes(type, 'dnorm')) { + label = buildNormalLabel(input); + } else if (_.includes(type, 'dbeta')) { + label = buildBetaLabel(input); + } + return label; + } + + function buildBetaLabel(input){ + return input.events + ' / ' + input.sampleSize; + } + + function buildNormalLabel(input) { + var label = ''; + if (input.events && input.sampleSize) { + label = input.events + ' / ' + input.sampleSize; + } else if (input.value && input.sampleSize && input.scale === 'percentage') { //dichotomous + label = input.value + '% (' + input.sampleSize + ')'; + } else if (input.value && input.sampleSize) { //dichotomous + label = input.value + ' (' + input.sampleSize + ')'; + } else if (input.stdErr) {//with stdErr + label = input.value ? input.value : input.mu; //exact to dist vs manual normal dist + label += ' (' + input.stdErr + ')'; + } else if (input.lowerBound) {//with confidence interval + label = input.value + ' (' + input.lowerBound + '; ' + input.upperBound + ')'; + } + return label; + } + + function buildStudentsTLabel(performance) { + return performance.input.mu + ' (' + + roundToThreeDigits(performance.parameters.stdErr) + + '), ' + (performance.input.sampleSize); + } + + function buildExactLabel(input) { + var label = ''; + if (input.events) { + label = input.events + ' / ' + input.sampleSize; + } else if (input.scale === 'percentage') { + label = input.value + '%'; + label = input.lowerBound ? label + ' (' + input.lowerBound + '%; ' + + input.upperBound + '%)' : label; + label = input.sampleSize ? label + ' (' + input.sampleSize + ')' : label; + } else { + label = input.value; + label = input.stdErr ? label + ' (' + input.stdErr + ')' : label; + label = input.lowerBound ? label + ' (' + input.lowerBound + '; ' + + input.upperBound + ')' : label; + label = input.sampleSize ? label + ' (' + input.sampleSize + ')' : label; + } + return label; + } + function roundToThreeDigits(value) { return Math.round(value * 1000) / 1000; } diff --git a/app/js/manualInput/addCriterionController.js b/app/js/manualInput/addCriterionController.js index 3a2aac1a8..bdcb5e0c2 100644 --- a/app/js/manualInput/addCriterionController.js +++ b/app/js/manualInput/addCriterionController.js @@ -37,11 +37,7 @@ define(['lodash'], function(_) { $scope.criterion = { id: generateUuid(), dataSources: [{ - id: generateUuid(), - inputType: 'distribution', - inputMethod: 'assistedDistribution', - dataType: 'dichotomous', - parameterOfInterest: 'eventProbability' + id: generateUuid() }], isFavorable: false }; diff --git a/app/js/manualInput/effectInputHelperDirective.html b/app/js/manualInput/effectInputHelperDirective.html index 3b75cab1d..b9e1eef51 100644 --- a/app/js/manualInput/effectInputHelperDirective.html +++ b/app/js/manualInput/effectInputHelperDirective.html @@ -10,42 +10,39 @@ -
+
-
-
-
diff --git a/app/js/manualInput/effectInputHelperDirective.js b/app/js/manualInput/effectInputHelperDirective.js index 3842fd387..77c0caa03 100644 --- a/app/js/manualInput/effectInputHelperDirective.js +++ b/app/js/manualInput/effectInputHelperDirective.js @@ -26,9 +26,7 @@ define(['lodash'], function(_) { link: function(scope) { // functions scope.keyCheck = keyCheck; - scope.updateUpperBound = updateUpperBound; scope.inputChanged = inputChanged; - scope.confidenceIntervalNEChanged = confidenceIntervalNEChanged; //init var isEscPressed = false; @@ -48,14 +46,6 @@ define(['lodash'], function(_) { } }); - function updateUpperBound() { - var id = scope.inputCell.inputParameters.id; - if (scope.inputCell.isNormal && id === 'exactValueCI' && scope.inputCell.dataType === 'continuous' && scope.inputCell.parameterOfInterest === 'mean') { - var uppperBound = 2 * scope.inputCell.firstParameter - scope.inputCell.secondParameter; - scope.inputCell.thirdParameter = significantDigits(uppperBound); - } - } - function saveState() { $timeout(function() { scope.inputData = scope.inputCell; @@ -66,11 +56,7 @@ define(['lodash'], function(_) { } function initInputParameters() { - if (doInputParametersNeedUpdating(scope.inputDataSource, scope.inputData)) { - scope.inputCell = _.cloneDeep(scope.inputDataSource); - } else { - scope.inputCell = _.cloneDeep(scope.inputData); - } + scope.inputCell = _.cloneDeep(scope.inputData); scope.inputParameterOptions = ManualInputService.getOptions(scope.inputCell); if (!scope.inputCell.inputParameters) { scope.inputCell.inputParameters = _.values(scope.inputParameterOptions)[0]; @@ -80,7 +66,6 @@ define(['lodash'], function(_) { } function inputChanged() { - updateUpperBound(); scope.error = ManualInputService.getInputError(scope.inputCell); } @@ -92,27 +77,6 @@ define(['lodash'], function(_) { scope.$broadcast('doClose.af.dropdownToggle'); } } - - function doInputParametersNeedUpdating(inputDataSource, cell) { - if (!cell.inputParameters) { - return true; - } - var inputType = inputDataSource.inputType; - var inputMethod = inputDataSource.inputMethod; - var dataType = inputDataSource.dataType; - return inputType !== cell.inputType || - (inputType === 'distribution' && inputMethod !== cell.inputMethod) || - (inputType === 'distribution' && inputMethod === 'assistedDistribution' && dataType !== cell.dataType) || - (inputType === 'effect' && dataType !== cell.dataType) || - (inputType === 'effect' && dataType === 'continuous' && - inputDataSource.parameterOfInterest !== cell.parameterOfInterest); - } - - function confidenceIntervalNEChanged() { - if (scope.inputCell.lowerBoundNE || scope.inputCell.upperBoundNE) { - scope.inputCell.isNormal = false; - } - } } }; }; diff --git a/app/js/manualInput/inputDataSourceDirective.html b/app/js/manualInput/inputDataSourceDirective.html index 818c44987..81ed83288 100644 --- a/app/js/manualInput/inputDataSourceDirective.html +++ b/app/js/manualInput/inputDataSourceDirective.html @@ -23,67 +23,4 @@
-
- - - - - -
-
- - - - - -
-
- - - - - - - -
-
- - - - - -
-
- - - - - - - - - - - -
diff --git a/app/js/manualInput/inputDataSourceDirective.js b/app/js/manualInput/inputDataSourceDirective.js index aa2cbf6b5..77b9a6217 100644 --- a/app/js/manualInput/inputDataSourceDirective.js +++ b/app/js/manualInput/inputDataSourceDirective.js @@ -13,29 +13,8 @@ define([], function() { templateUrl: './inputDataSourceDirective.html', link: function(scope) { // functions - scope.dataTypeChanged = dataTypeChanged; - scope.inputTypeChanged = inputTypeChanged; scope.checkSourceLink = checkSourceLink; - function dataTypeChanged() { - switch (scope.source.dataType) { - case 'dichotomous': - scope.source.parameterOfInterest = 'eventProbability'; - break; - case 'continuous': - scope.source.parameterOfInterest = 'mean'; - break; - default: - scope.source.parameterOfInterest = 'value'; - } - } - - function inputTypeChanged() { - if (scope.source.inputType === 'distribution' && scope.source.dataType === 'other') { - scope.source.dataType = 'dichotomous'; - } - } - function checkSourceLink() { var regex = new RegExp(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi); scope.isInvalidSourceLink.isInvalid = scope.source.sourceLink && !scope.source.sourceLink.match(regex); diff --git a/app/js/manualInput/inputKnowledgeService.js b/app/js/manualInput/inputKnowledgeService.js index 38cded93a..8f7280351 100644 --- a/app/js/manualInput/inputKnowledgeService.js +++ b/app/js/manualInput/inputKnowledgeService.js @@ -22,135 +22,54 @@ define(['lodash', 'angular'], function(_, angular) { } }, effect: { - getKnowledge: function(cell) { - return EFFECT_KNOWLEDGE.getKnowledge(cell); + getKnowledge: function() { + return EFFECT_KNOWLEDGE.getKnowledge(); } } }; - var DICHOTOMOUS_EFFECT_DECIMAL = { - id: 'dichotomousDecimal', - label: 'Decimal', - firstParameter: buildPositiveWithMax('Value', 1.0), - fits: function(tableEntry) { - return !tableEntry.performance.input || tableEntry.performance.type === 'empty'; - }, - toString: valueToString, - finishInputCell: finishValueCell, - buildPerformance: function(cell) { - return PerformanceService.buildExactPerformance(cell.firstParameter); - } - }; - - var DICHOTOMOUS_EFFECT_DECIMAL_SAMPLE_SIZE = { - id: 'dichotomousDecimalSampleSize', - label: 'Decimal, sample size', - firstParameter: buildPositiveWithMax('Value', 1.0), - secondParameter: buildIntegerAboveZero('Sample size'), - canBeNormal: true, - fits: function(tableEntry) { - return tableEntry.performance.input && - tableEntry.performance.input.sampleSize && - !isFinite(tableEntry.performance.input.events) && - tableEntry.performance.input.scale !== 'percentage'; - }, - toString: function(cell) { - var proportion = cell.firstParameter; - var sampleSize = cell.secondParameter; - var returnString = proportion + ' (' + sampleSize + ')'; - if (cell.isNormal) { - var sigma = roundedStdErr(proportion, sampleSize); - returnString += '\nNormal(' + proportion + ', ' + sigma + ')'; - } else { - returnString += NO_DISTRIBUTION; - } - return returnString; - }, - finishInputCell: finishProportionSampleSizeCell, - buildPerformance: function(cell) { - var proportion = cell.firstParameter; - var sampleSize = cell.secondParameter; - var input = { - value: proportion, - sampleSize: sampleSize + var EFFECT_KNOWLEDGE = { + getKnowledge: function() { + var options = { + value: buildExactValueKnowledge('Value'), + valueSE: buildExactValueSEKnowledge('Value'), + valueCI: buildExactValueConfidenceIntervalKnowledge('Value'), + valueSampleSize: VALUE_SAMPLE_SIZE, + fraction: FRACTION }; - if (cell.isNormal) { - var sigma = stdErr(proportion, sampleSize); - return PerformanceService.buildNormalPerformance(proportion, sigma, input); - } else { - return PerformanceService.buildExactPerformance(proportion, input); - } + return buildKnowledge(options); } }; - var DICHOTOMOUS_EFFECT_PERCENTAGE = { - id: 'dichotomousPercentage', - label: 'Percentage', - firstParameter: buildPositiveWithMax('Value', 100), - fits: function(tableEntry) { - return tableEntry.performance.input && - !tableEntry.performance.input.sampleSize && - tableEntry.performance.input.scale === 'percentage'; - }, - toString: function(cell) { - return cell.firstParameter + '%' + NO_DISTRIBUTION; - }, - finishInputCell: function(cell, tableEntry) { - var inputCell = angular.copy(cell); - inputCell.firstParameter = tableEntry.performance.input.value; - return inputCell; - }, - buildPerformance: function(cell) { - return PerformanceService.buildExactPerformance(cell.firstParameter / 100, { - value: cell.firstParameter, - scale: 'percentage' - }); - } - }; - - var DICHOTOMOUS_EFFECT_PERCENTAGE_SAMPLE_SIZE = { - id: 'dichotomousPercentageSampleSize', - label: 'Percentage, sample size', - firstParameter: buildPositiveWithMax('Value', 100), + var VALUE_SAMPLE_SIZE = { + id: 'valueSampleSize', + label: 'value, sample size', + firstParameter: buildDefined('Value'), secondParameter: buildIntegerAboveZero('Sample size'), - canBeNormal: true, fits: function(tableEntry) { return tableEntry.performance.input && tableEntry.performance.input.sampleSize && - tableEntry.performance.input.scale === 'percentage'; + !isFinite(tableEntry.performance.input.value) ; }, toString: function(cell) { - var percentage = cell.firstParameter; + var value = cell.firstParameter; var sampleSize = cell.secondParameter; - var returnString = percentage + '% (' + sampleSize + ')'; - if (cell.isNormal) { - var proportion = percentage / 100; - var sigma = roundedStdErr(proportion, sampleSize); - returnString += '\nNormal(' + proportion + ', ' + sigma + ')'; - } else { - returnString += NO_DISTRIBUTION; - } + var returnString = value + ' (' + sampleSize + ')'; return returnString; }, - finishInputCell: finishProportionSampleSizeCell, + finishInputCell: finishValueSampleSizeCell, buildPerformance: function(cell) { - var proportion = cell.firstParameter / 100; + var value = cell.firstParameter; var sampleSize = cell.secondParameter; var input = { - value: cell.firstParameter, - sampleSize: cell.secondParameter, - scale: 'percentage' + value: value, + sampleSize: sampleSize }; - if (cell.isNormal) { - var sigma = stdErr(proportion, sampleSize); - return PerformanceService.buildNormalPerformance(proportion, sigma, input); - } else { - return PerformanceService.buildExactPerformance(proportion, input); - } + return PerformanceService.buildExactPerformance(value, input); } }; - var DICHOTOMOUS_EFFECT_FRACTION = { + var FRACTION = { id: 'dichotomousFraction', label: 'Fraction', firstParameter: { @@ -163,7 +82,6 @@ define(['lodash', 'angular'], function(_, angular) { ] }, secondParameter: buildIntegerAboveZero('Sample size'), - canBeNormal: true, fits: function(tableEntry) { return tableEntry.performance.input && isFinite(tableEntry.performance.input.events) && @@ -171,21 +89,12 @@ define(['lodash', 'angular'], function(_, angular) { }, toString: function(cell) { var sampleSize = cell.secondParameter; - var returnString = cell.firstParameter + ' / ' + sampleSize; - if (cell.isNormal) { - var proportion = cell.firstParameter / sampleSize; - var sigma = roundedStdErr(proportion, sampleSize); - returnString += '\nNormal(' + proportion + ', ' + sigma + ')'; - } else { - returnString += NO_DISTRIBUTION; - } - return returnString; + return cell.firstParameter + ' / ' + sampleSize; }, finishInputCell: function(cell, tableEntry) { var inputCell = angular.copy(cell); inputCell.firstParameter = tableEntry.performance.input.events; inputCell.secondParameter = tableEntry.performance.input.sampleSize; - inputCell.isNormal = tableEntry.performance.type === 'dnorm'; return inputCell; }, buildPerformance: function(cell) { @@ -193,13 +102,7 @@ define(['lodash', 'angular'], function(_, angular) { events: cell.firstParameter, sampleSize: cell.secondParameter }; - if (cell.isNormal) { - var mu = cell.firstParameter / cell.secondParameter; - var sigma = stdErr(mu, cell.secondParameter); - return PerformanceService.buildNormalPerformance(mu, sigma, input); - } else { - return PerformanceService.buildExactPerformance(cell.firstParameter / cell.secondParameter, input); - } + return PerformanceService.buildExactPerformance(cell.firstParameter / cell.secondParameter, input); } }; @@ -283,60 +186,6 @@ define(['lodash', 'angular'], function(_, angular) { } }) }; - var CONTINUOUS_EFFECT_KNOWLEDGE = { - getKnowledge: function(cell) { - return this[cell.parameterOfInterest].getKnowledge(cell); - }, - mean: buildKnowledge({ - exactValue: buildExactValueKnowledge('Mean'), - exactValueSE: _.extend(buildExactValueSEKnowledge('Mean'), { - canBeNormal: true - }), - exactValueCI: _.extend(buildExactValueConfidenceIntervalKnowledge('Mean'), { - canBeNormal: true - }) - }), - median: buildKnowledge({ - exactValue: buildExactValueKnowledge('Median'), - exactValueCI: buildExactValueConfidenceIntervalKnowledge('Median') - }), - cumulativeProbability: buildKnowledge(function() { - var decimal = buildExactValueKnowledge('Decimal', 'decimal'); - decimal.firstParameter.constraints = decimal.firstParameter.constraints.concat( - [ConstraintService.positive(), - ConstraintService.belowOrEqualTo(1)]); - var percentage = buildPercentageKnowledge(); - var decimalCI = addCeilConstraints(buildExactValueConfidenceIntervalKnowledge('Decimal', 'decimalCI'), 1); - var percentageCI = addCeilConstraints(buildPercentageConfidenceIntervalKnowledge('Percentage', 'percentageCI'), 100); - var retval = { - decimal: decimal, - decimalCI: decimalCI, - percentage: percentage, - percentageCI: percentageCI - }; - return retval; - }()) //!! - }; - - var EFFECT_KNOWLEDGE = { - getKnowledge: function(cell) { - return this[cell.dataType].getKnowledge(cell); - }, - dichotomous: buildKnowledge({ - dichotomousDecimal: DICHOTOMOUS_EFFECT_DECIMAL, - dichotomousDecimalSampleSize: DICHOTOMOUS_EFFECT_DECIMAL_SAMPLE_SIZE, - dichotomousPercentage: DICHOTOMOUS_EFFECT_PERCENTAGE, - dichotomousPercentageSampleSize: DICHOTOMOUS_EFFECT_PERCENTAGE_SAMPLE_SIZE, - dichotomousFraction: DICHOTOMOUS_EFFECT_FRACTION - }), - continuous: CONTINUOUS_EFFECT_KNOWLEDGE, - other: buildKnowledge({ - exactValue: buildExactValueKnowledge('Value'), - exactValueSE: buildExactValueSEKnowledge('Value'), - exactValueCI: buildExactValueConfidenceIntervalKnowledge('Value') - }) - }; - var ASSISTED_DISTRIBUTION_KNOWLEDGE = { getKnowledge: function(cell) { return this[cell.dataType].getKnowledge(cell); @@ -505,6 +354,16 @@ define(['lodash', 'angular'], function(_, angular) { return knowledge; } + + function buildExactValueKnowledge(label, id) { + id = id ? id : 'value'; + var knowledge = buildExactKnowledge(id, label); + knowledge.fits = function(tableEntry) { + return !tableEntry.performance.input || tableEntry.performance.type === 'empty'; + }; + return knowledge; + } + function buildExactKnowledge(id, label) { return { id: id, @@ -518,15 +377,6 @@ define(['lodash', 'angular'], function(_, angular) { }; } - function buildExactValueKnowledge(label, id) { - id = id ? id : 'exactValue'; - var knowledge = buildExactKnowledge(id, label); - knowledge.fits = function(tableEntry) { - return !tableEntry.performance.input || tableEntry.performance.type === 'empty'; - }; - return knowledge; - } - function buildExactValueSEKnowledge(label, id) { id = id ? id : 'exactValueSE'; var knowledge = buildExactKnowledge(id, label + ', SE'); @@ -597,35 +447,6 @@ define(['lodash', 'angular'], function(_, angular) { return knowledge; } - function buildPercentageConfidenceIntervalKnowledge(label, id) { - var knowledge = buildExactValueConfidenceIntervalKnowledge(label, id); - knowledge.toString = valueCIPercentToString; - knowledge.buildPerformance = function(cell) { - return PerformanceService.buildExactPercentConfidencePerformance(cell); - }; - knowledge.fits = function(tableEntry) { - return tableEntry.performance.input && - (isFinite(tableEntry.performance.input.lowerBound) || tableEntry.performance.input.lowerBound === 'NE') && - (isFinite(tableEntry.performance.input.upperBound) || tableEntry.performance.input.upperBound === 'NE') && - tableEntry.performance.input.scale === 'percentage'; - }; - return knowledge; - } - - function buildPercentageKnowledge() { - var knowledge = buildExactValueKnowledge('Percentage', 'percentage'); - knowledge.firstParameter.constraints = knowledge.firstParameter.constraints.concat(ConstraintService.positive(), [ConstraintService.belowOrEqualTo(100)]); - knowledge.toString = valuePercentToString; - knowledge.buildPerformance = buildPercentPerformance; - knowledge.fits = function(tableEntry) { - return tableEntry.performance.input && - tableEntry.performance.input.value && - !tableEntry.performance.input.lowerBound && - tableEntry.performance.input.scale === 'percentage'; - }; - return knowledge; - } - // finish cell functions function finishValueCell(cell, tableEntry) { @@ -684,14 +505,13 @@ define(['lodash', 'angular'], function(_, angular) { return inputCell; } - function finishProportionSampleSizeCell(cell, tableEntry) { + function finishValueSampleSizeCell(cell, tableEntry) { if (cell.empty) { return cell; } var inputCell = angular.copy(cell); inputCell.firstParameter = tableEntry.performance.input.value; inputCell.secondParameter = tableEntry.performance.input.sampleSize; - inputCell.isNormal = tableEntry.performance.type === 'dnorm'; return inputCell; } diff --git a/app/js/manualInput/manualInput.html b/app/js/manualInput/manualInput.html index c73c02c1e..5d2ad250a 100644 --- a/app/js/manualInput/manualInput.html +++ b/app/js/manualInput/manualInput.html @@ -142,31 +142,7 @@

Enter data in effects table

{{state.title}}

- - - - - - - - - - - - - - - - - - - - - -
DescriptionUnit of measurementIs favorable?Reference{{alternative.title}}
{{row.criterion.title}}{{row.criterion.description}}{{row.criterion.unitOfMeasurement}}{{row.criterion.isFavorable? 'yes' : 'no'}}{{row.dataSource.source}} - -
+
diff --git a/app/js/manualInput/manualInput.js b/app/js/manualInput/manualInput.js index 713005f7f..a3b9de096 100644 --- a/app/js/manualInput/manualInput.js +++ b/app/js/manualInput/manualInput.js @@ -10,6 +10,7 @@ define([ './effectInputHelperDirective', './inputDataSourceDirective', './inProgressResource', + './manualInputTableDirective', 'angular', 'angular-resource' ], function( @@ -23,6 +24,7 @@ define([ effectInputHelper, inputDataSource, InProgressResource, + manualInputTable, angular ) { return angular.module('elicit.manualInput', ['ngResource', 'elicit.util', 'elicit.effectsTable']) @@ -38,6 +40,7 @@ define([ .directive('effectInputHelper', effectInputHelper) .directive('inputDataSource', inputDataSource) + .directive('manualInputTable', manualInputTable) .service('InProgressResource', InProgressResource); diff --git a/app/js/manualInput/manualInputService.js b/app/js/manualInput/manualInputService.js index 213daa1ff..f591cb852 100644 --- a/app/js/manualInput/manualInputService.js +++ b/app/js/manualInput/manualInputService.js @@ -1,11 +1,11 @@ 'use strict'; -define(['lodash', 'angular'], function(_) { +define(['lodash', 'angular'], function (_) { var dependencies = [ 'InputKnowledgeService', 'generateUuid', 'currentSchemaVersion' ]; - var ManualInputService = function( + var ManualInputService = function ( InputKnowledgeService, generateUuid, currentSchemaVersion @@ -19,12 +19,12 @@ define(['lodash', 'angular'], function(_) { } var error; var inputParameters = _.pick(cell.inputParameters, ['firstParameter', 'secondParameter', 'thirdParameter']); - _.find(inputParameters, function(inputParameter, key) { + _.find(inputParameters, function (inputParameter, key) { if (hasNotEstimableBound(cell, inputParameter)) { return; } var inputValue = cell[key]; - return _.find(inputParameter.constraints, function(constraint) { + return _.find(inputParameter.constraints, function (constraint) { error = constraint(inputValue, inputParameter.label, cell); return error; }); @@ -65,18 +65,21 @@ define(['lodash', 'angular'], function(_) { } function createInputTableRows(dataSources, alternatives, oldInputData) { - return _.reduce(dataSources, function(accum, dataSource) { + return _.reduce(dataSources, function (accum, dataSource) { accum[dataSource.id] = createInputTableCells(dataSource, alternatives, oldInputData); return accum; }, {}); } function createInputTableCells(dataSource, alternatives, oldInputData) { - return _.reduce(alternatives, function(accum, alternative) { + return _.reduce(alternatives, function (accum, alternative) { if (hasOldInputDataAvailable(oldInputData, dataSource.id, alternative.id)) { accum[alternative.id] = oldInputData[dataSource.id][alternative.id]; } else { - accum[alternative.id] = _.pick(dataSource, ['inputType', 'inputMethod', 'dataType', 'parameterOfInterest']); + accum[alternative.id] = { + effect: {}, + distribution: {} + }; } accum[alternative.id].isInvalid = true; return accum; @@ -84,11 +87,11 @@ define(['lodash', 'angular'], function(_) { } function hasOldInputDataAvailable(oldData, dataSourceId, alternativeId) { - return oldData && oldData[dataSourceId] && oldData[dataSourceId][alternativeId] + return oldData && oldData[dataSourceId] && oldData[dataSourceId][alternativeId]; } function getDataSources(criteria) { - return _.reduce(criteria, function(accum, criterion) { + return _.reduce(criteria, function (accum, criterion) { return accum.concat(criterion.dataSources); }, []); } @@ -109,13 +112,13 @@ define(['lodash', 'angular'], function(_) { } function hasFavorableCriterion(workspace) { - return !!_.find(workspace.problem.criteria, function(criterion) { + return !!_.find(workspace.problem.criteria, function (criterion) { return criterion.hasOwnProperty('isFavorable'); }); } function copyOldWorkspaceAlternatives(oldWorkspace) { - return _.map(oldWorkspace.problem.alternatives, function(alternative, alternativeId) { + return _.map(oldWorkspace.problem.alternatives, function (alternative, alternativeId) { return _.extend({}, alternative, { id: generateUuid(), oldId: alternativeId @@ -124,7 +127,7 @@ define(['lodash', 'angular'], function(_) { } function buildCriteria(criteria) { - var newCriteria = _.map(criteria, function(criterion) { + var newCriteria = _.map(criteria, function (criterion) { var newCriterion = _.pick(criterion, [ 'title', 'description', @@ -183,7 +186,7 @@ define(['lodash', 'angular'], function(_) { } function copyOldWorkspaceCriteria(workspace) { - return _.map(workspace.problem.criteria, function(criterion) { + return _.map(workspace.problem.criteria, function (criterion) { var newCrit = _.pick(criterion, ['title', 'description', 'isFavorable']); // omit scales, preferences if (canBePercentage(criterion) && criterion.unitOfMeasurement) { newCrit.unitOfMeasurement = criterion.unitOfMeasurement; @@ -195,13 +198,13 @@ define(['lodash', 'angular'], function(_) { } function canBePercentage(criterion) { - return !_.some(criterion.dataSources, function(dataSource) { + return !_.some(criterion.dataSources, function (dataSource) { return _.isEqual([0, 1], dataSource.scale); }); } function copyOldWorkspaceDataSource(criterion) { - return _.map(criterion.dataSources, function(dataSource) { + return _.map(criterion.dataSources, function (dataSource) { var newDataSource = _.pick(dataSource, [ 'source', 'sourceLink', @@ -219,7 +222,7 @@ define(['lodash', 'angular'], function(_) { } function createInputFromOldWorkspace(criteria, alternatives, oldWorkspace) { - return _.reduce(oldWorkspace.problem.performanceTable, function(accum, tableEntry) { + return _.reduce(oldWorkspace.problem.performanceTable, function (accum, tableEntry) { var dataSources = getDataSources(criteria); var dataSourceForEntry = _.find(dataSources, ['oldId', tableEntry.dataSource]); var alternative = _.find(alternatives, ['oldId', tableEntry.alternative]); @@ -237,50 +240,35 @@ define(['lodash', 'angular'], function(_) { return InputKnowledgeService.finishInputCell(dataSource, tableEntry); } + function findInvalidCell(inputData) { + return _.some(inputData, function (row) { + return _.some(row, 'isInvalid'); + }); + } + function findInvalidRow(inputData) { - return _.find(inputData, function(row) { - if (findDistributionCell(row) || findNormalDistributedCell(row) || findCellThatIsDifferent(row)) { - return; - } - return row; + return _.some(inputData, function (row) { + return !findCellThatIsDifferent(row); }); } function findCellThatIsDifferent(row) { - return _.find(row, function(cell) { - return _.find(row, function(otherCell) { - return compareCells(cell, otherCell); + return _.find(row, function (cell) { + return _.find(row, function (otherCell) { + return compareCells(cell.effect, otherCell.effect); }); }); } - function compareCells(cell, otherCell) { - if (cell.inputParameters && cell.inputParameters.id === 'dichotomousFraction') { - if (otherCell.inputParameters.id === 'dichotomousFraction') { - return cell.firstParameter !== otherCell.firstParameter || cell.secondParameter !== otherCell.secondParameter; + function compareCells(effect, otherEffect) { + if (effect.inputParameters && effect.inputParameters.id === 'dichotomousFraction') { + if (otherEffect.inputParameters.id === 'dichotomousFraction') { + return effect.firstParameter !== otherEffect.firstParameter || effect.secondParameter !== otherEffect.secondParameter; } else { - return cell.firstParameter / cell.secondParameter !== otherCell.firstParameter; + return effect.firstParameter / effect.secondParameter !== otherEffect.firstParameter; } } - return cell.firstParameter !== otherCell.firstParameter; - } - - function findDistributionCell(row) { - return _.find(row, function(cell) { - return cell.inputType !== 'effect'; - }); - } - - function findNormalDistributedCell(row) { - return _.find(row, function(cell) { - return cell.isNormal; - }); - } - - function findInvalidCell(inputData) { - return _.find(inputData, function(row) { - return _.find(row, 'isInvalid'); - }); + return effect.firstParameter !== otherEffect.firstParameter; } return { diff --git a/app/js/mcda-web.js b/app/js/mcda-web.js index f089640c8..5c7a5b7f5 100644 --- a/app/js/mcda-web.js +++ b/app/js/mcda-web.js @@ -75,7 +75,7 @@ define([ app.constant('Tasks', Config.tasks); app.constant('isMcdaStandalone', true); - app.constant('currentSchemaVersion', '1.1.0'); + app.constant('currentSchemaVersion', '1.2.0'); app.config([ '$stateProvider', diff --git a/app/js/misc.js b/app/js/misc.js index 9e0b3a297..74dd5b7ec 100644 --- a/app/js/misc.js +++ b/app/js/misc.js @@ -7,8 +7,6 @@ function exampleProblem() { title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [ 0.0, @@ -23,8 +21,6 @@ function exampleProblem() { title: 'Distal DVT', dataSources: [{ id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [ 0.15, @@ -39,8 +35,6 @@ function exampleProblem() { title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [ 0.0, diff --git a/app/js/subProblem/createSubProblem.html b/app/js/subProblem/createSubProblem.html index f12f6e441..af413e844 100644 --- a/app/js/subProblem/createSubProblem.html +++ b/app/js/subProblem/createSubProblem.html @@ -117,8 +117,7 @@

Criterion and alternative selection

+ theoretical-scale="row.dataSource.scale" alternative-id="alternative.id">
@@ -191,4 +190,4 @@
- + \ No newline at end of file diff --git a/app/lexicon.json b/app/lexicon.json index bcae05133..be2351451 100644 --- a/app/lexicon.json +++ b/app/lexicon.json @@ -39,11 +39,6 @@ "text": "Criterion data can be entered as either study data, or an exact-value distribution.", "link": "/manual.html#mcda-manual-entry" }, - "criterion-data-type": { - "title": "Criterion data type", - "text": "Criterion data can be reported in several ways, either as a proportion (e.g. \"fifty out of a hundred\"), a continuous value (e.g. \"weight increase in grams\") or as survival data (e.g. \"median survival after 20 days)\"", - "link": "/manual.html#mcda-manual-entry" - }, "criterion-source": { "title": "Reference", "text": "An optional indication of where the data for this criterion comes from.", @@ -94,16 +89,6 @@ "text": "The process of manually creating a workspace can be paused at any point. This list shows those unfinished workspaces.", "link": "/manual.html#mcda-preparing-dataset" }, - "input-type": { - "title": "Input type", - "text": "The way the measurements for a data source were entered. Input type is either distribution or effect.", - "link": "/manual.html#mcda-manual-entry" - }, - "input-method": { - "title": "Input method", - "text": "The input method shows whether the distributional parameters were specified directly (manual distribution) or derived from user supplied aggregate study data (assisted distribution).", - "link": "/manual.html#mcda-manual-entry" - }, "matching": { "title": "Matching", "text": "Elicitation of the criteria weights through a series of matching questions. This method sets weights by asking users to specify how much the performance with respect to one criterion needs to improve to compensate for a worsening in the performance with respect to another criterion.", @@ -124,11 +109,6 @@ "text": "A section that allows exploring of the sensitivity of the results by allowing only one thing to change.", "link": "/manual.html#mcda-deterministic-analysis" }, - "parameter-of-interest": { - "title": "Parameter of interest", - "text": "The parameter of interest determines what the measured effect depicts.", - "link": "/manual.html#mcda-manual-entry" - }, "partial-value-function": { "title": "Partial Value Function", "text": "A partial value function indicates how the desirability of a criterion's outcome varies with its value.", diff --git a/frontend-test/unit/manualInputServiceSpec.js b/frontend-test/unit/manualInputServiceSpec.js index 395077004..223a00dda 100644 --- a/frontend-test/unit/manualInputServiceSpec.js +++ b/frontend-test/unit/manualInputServiceSpec.js @@ -1,36 +1,39 @@ 'use strict'; -define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], function(_, angular) { +define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], function (_, angular) { var generateUuidMock = jasmine.createSpy('generateUuid'); var manualInputService; var currentSchemaVersion = '1.1.0'; var inputKnowledgeServiceMock = jasmine.createSpyObj('InputKnowledgeService', ['getOptions', 'inputToString', 'finishInputCell', 'buildPerformance']); - describe('The manualInputService', function() { - beforeEach(angular.mock.module('elicit.manualInput', function($provide) { + + describe('The manualInputService', function () { + beforeEach(angular.mock.module('elicit.manualInput', function ($provide) { $provide.value('generateUuid', generateUuidMock); $provide.value('currentSchemaVersion', currentSchemaVersion); $provide.value('InputKnowledgeService', inputKnowledgeServiceMock); })); - beforeEach(inject(function(ManualInputService) { + + beforeEach(inject(function (ManualInputService) { manualInputService = ManualInputService; })); - describe('getInputError', function() { - it('should run all the constraints of a cell\'s parameters, returning the first error found', function() { + + describe('getInputError', function () { + it('should run all the constraints of a cell\'s parameters, returning the first error found', function () { var cell = { firstParameter: 10, secondParameter: 20, inputParameters: { firstParameter: { constraints: [ - function() { } + function () { } ] }, secondParameter: { constraints: [ - function() { }, - function() { return 'error message'; } + function () { }, + function () { return 'error message'; } ] } } @@ -38,12 +41,14 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f var result = manualInputService.getInputError(cell); expect(result).toBe('error message'); }); - it('should return no error for an empty typed cell', function() { + + it('should return no error for an empty typed cell', function () { var cell = { empty: true }; expect(manualInputService.getInputError(cell)).toBeFalsy(); }); + it('should return no error for bounds that are not estimable', () => { var cell = { lowerBoundNE: true, @@ -65,18 +70,20 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f expect(manualInputService.getInputError(cell)).toBeFalsy(); }); }); - describe('inputToString', function() { - it('should use the inputknowledgeservice for valid inputs', function() { + + describe('inputToString', function () { + it('should use the inputknowledgeservice for valid inputs', function () { inputKnowledgeServiceMock.inputToString.and.returnValue('great success'); expect(manualInputService.inputToString({})).toEqual('great success'); }); - it('should return an invalid input message if the input is invalid', function() { + + it('should return an invalid input message if the input is invalid', function () { var invalidInput = { firstParameter: 10, inputParameters: { firstParameter: { constraints: [ - function() { + function () { return 'error in input'; } ] @@ -87,7 +94,7 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f }); }); - describe('prepareInputData', function() { + describe('prepareInputData', function () { var alternatives = [{ title: 'alternative1', id: 'alternative1' @@ -99,60 +106,65 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f id: 'crit1id', title: 'criterion 1 title', dataSources: [{ - id: 'ds1id', - inputType: 'distribution', - inputMethod: 'assistedDistribution', - dataType: 'other' + id: 'ds1id' }] }, { id: 'crit2id', title: 'criterion 2 title', dataSources: [{ - id: 'ds2id', - inputType: 'effect', - dataType: 'other' + id: 'ds2id' }] }]; - it('should prepare the cells of the table for input', function() { + var emptyCell = { + effect: {}, + distribution: {} + }; + + it('should prepare the cells of the table for input', function () { var result = manualInputService.prepareInputData(criteria, alternatives); var expectedResult = { 'ds1id': { - alternative1: _.extend({}, _.omit(criteria[0].dataSources[0], ['id']), { + alternative1: _.extend({}, emptyCell, { isInvalid: true }), - alternative2: _.extend({}, _.omit(criteria[0].dataSources[0], ['id']), { + alternative2: _.extend({}, emptyCell, { isInvalid: true }) }, 'ds2id': { - alternative1: _.extend({}, _.omit(criteria[1].dataSources[0], ['id']), { + alternative1: _.extend({}, emptyCell, { isInvalid: true }), - alternative2: _.extend({}, _.omit(criteria[1].dataSources[0], ['id']), { + alternative2: _.extend({}, emptyCell, { isInvalid: true }) } }; expect(result).toEqual(expectedResult); }); - it('should preserve data if there is old data supplied and the criterion type has not changed', function() { + + it('should preserve data if there is old data supplied and the criterion type has not changed', function () { var oldInputData = { 'ds2id': { alternative1: { - inputType: 'distribution', - inputMethod: 'manualDistribution' + effect: { + foo: 'foo' + }, + distribution: { + bar: 'bar' + } }, - alternative2: criteria[1].inputMetaData + alternative2: undefined } }; var result = manualInputService.prepareInputData(criteria, alternatives, oldInputData); var expectedResult = { 'ds1id': { - alternative1: _.extend({}, _.omit(criteria[0].dataSources[0], ['id']), { + alternative1: _.extend({}, emptyCell, { isInvalid: true }), - alternative2: _.extend({}, _.omit(criteria[0].dataSources[0], ['id']), { + alternative2: _.extend({}, emptyCell, { isInvalid: true }) }, @@ -160,7 +172,7 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f alternative1: _.extend({}, oldInputData.ds2id.alternative1, { isInvalid: true }), - alternative2: _.extend({}, _.omit(criteria[1].dataSources[0], ['id']), { + alternative2: _.extend({}, emptyCell, { isInvalid: true }) } @@ -169,7 +181,7 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f }); }); - describe('createProblem', function() { + describe('createProblem', function () { var title = 'title'; var description = 'A random description of a random problem'; var alternatives = [{ @@ -177,7 +189,7 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f id: 'alternative1', oldId: 'alternative1Oldid' }]; - it('should create a problem, ready to go to the workspace, removing old ids', function() { + it('should create a problem, ready to go to the workspace, removing old ids', function () { inputKnowledgeServiceMock.buildPerformance.and.returnValue({}); var criteria = [{ title: 'favorable criterion', @@ -317,11 +329,11 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f }); }); - describe('createStateFromOldWorkspace', function() { - beforeEach(function() { + describe('createStateFromOldWorkspace', function () { + beforeEach(function () { generateUuidMock.and.returnValues('uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5', 'uuid6', 'uuid7', 'uuid8', 'uuid9', 'uuid10', 'uuid11', 'uuid12', 'uuid13'); }); - it('should create a new state from an existing workspace', function() { + it('should create a new state from an existing workspace', function () { var workspace = { problem: { criteria: { @@ -530,8 +542,8 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f }); }); - describe('getOptions', function() { - it('should call the inputknowledgeservice', function() { + describe('getOptions', function () { + it('should call the inputknowledgeservice', function () { inputKnowledgeServiceMock.getOptions.and.returnValue('here are some options'); expect(manualInputService.getOptions()).toEqual('here are some options'); }); @@ -578,24 +590,27 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f var inputData = { row1: { col1: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' + effect: { + firstParameter: 50, + inputParameters: { + id: 'value' + } } }, col2: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' + effect: { + firstParameter: 50, + inputParameters: { + id: 'value' + } } }, col3: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' + effect: { + firstParameter: 50, + inputParameters: { + id: 'value' + } } } } @@ -604,82 +619,31 @@ define(['lodash', 'angular', 'angular-mocks', 'mcda/manualInput/manualInput'], f expect(result).toBeTruthy(); }); - it('should return falsy if the values of a row are the same, but atleast one is marked as normally distributed', () => { - var inputData = { - row1: { - col1: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' - } - }, - col2: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' - } - }, - col3: { - inputType: 'effect', - isNormal: true, - firstParameter: 50, - inputParameters: { - id: 'value' - } - } - } - }; - var result = manualInputService.findInvalidRow(inputData); - expect(result).toBeFalsy(); - }); - - it('should return falsy if atleast one cell is a distribution', () => { - var inputData = { - row1: { - col1: { - inputType: 'distribution', - firstParameter: 50, - inputParameters: { - id: 'value' - } - }, - col2: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' - } - } - } - }; - var result = manualInputService.findInvalidRow(inputData); - expect(result).toBeFalsy(); - }); - it('should return falsy if atleast one cell has a different value', () => { var inputData = { row1: { col1: { - inputType: 'distribution', - firstParameter: 50, - inputParameters: { - id: 'value' + effect: { + firstParameter: 50, + inputParameters: { + id: 'value' + } } }, col2: { - inputType: 'effect', - firstParameter: 50, - inputParameters: { - id: 'value' + effect: { + firstParameter: 50, + inputParameters: { + id: 'value' + } } }, col3: { - inputType: 'effect', - firstParameter: 51, - inputParameters: { - id: 'value' + effect: { + firstParameter: 51, + inputParameters: { + id: 'value' + } } } } diff --git a/frontend-test/unit/ordinalSwingSpec.js b/frontend-test/unit/ordinalSwingSpec.js index 4b9ca58a9..e90de4977 100644 --- a/frontend-test/unit/ordinalSwingSpec.js +++ b/frontend-test/unit/ordinalSwingSpec.js @@ -85,8 +85,6 @@ define([ title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.25], type: 'linear', @@ -101,8 +99,6 @@ define([ dataSources: [ { id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -115,8 +111,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', @@ -132,8 +126,6 @@ define([ title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.25], type: 'linear', @@ -148,8 +140,6 @@ define([ dataSources: [ { id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -162,8 +152,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', @@ -182,8 +170,6 @@ define([ title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.25], type: 'linear', @@ -197,8 +183,6 @@ define([ title: 'Distal DVT', dataSources: [{ id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -212,8 +196,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', @@ -246,8 +228,6 @@ define([ title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.25], type: 'linear', @@ -261,8 +241,6 @@ define([ title: 'Distal DVT', dataSources: [{ id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -276,8 +254,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', @@ -297,8 +273,6 @@ define([ title: 'Proximal DVT', dataSources: [{ id: 'proxDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.25], type: 'linear', @@ -312,8 +286,6 @@ define([ title: 'Distal DVT', dataSources: [{ id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -327,8 +299,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', @@ -354,8 +324,6 @@ define([ title: 'Distal DVT', dataSources: [{ id: 'distDvtDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0.15, 0.4], type: 'linear', @@ -369,8 +337,6 @@ define([ title: 'Major bleeding', dataSources: [{ id: 'bleedDS', - inputType: 'distribution', - inputMethod: 'manualDistribution', pvf: { range: [0, 0.1], type: 'linear', diff --git a/frontend-test/unit/schemaServiceSpec.js b/frontend-test/unit/schemaServiceSpec.js index f48e3b090..e64eccb53 100644 --- a/frontend-test/unit/schemaServiceSpec.js +++ b/frontend-test/unit/schemaServiceSpec.js @@ -85,8 +85,6 @@ define(['angular', 'angular-mocks', 'mcda/benefitRisk/benefitRisk'], function (a unitOfMeasurement: 'ms', dataSources: [{ id: 'uuid', - inputType: 'distribution', - inputMethod: 'manualDistribution', uncertainties: 'unc', source: 'source1' }] @@ -97,8 +95,6 @@ define(['angular', 'angular-mocks', 'mcda/benefitRisk/benefitRisk'], function (a unitOfMeasurement: 'ms', dataSources: [{ id: 'uuid', - inputType: 'distribution', - inputMethod: 'manualDistribution', uncertainties: 'unc', source: 'source2' }] @@ -207,8 +203,6 @@ define(['angular', 'angular-mocks', 'mcda/benefitRisk/benefitRisk'], function (a isFavorable: true, dataSources: [{ id: 'uuid', - inputType: 'distribution', - inputMethod: 'manualDistribution', uncertainties: 'unc', source: 'source' }] @@ -220,8 +214,6 @@ define(['angular', 'angular-mocks', 'mcda/benefitRisk/benefitRisk'], function (a isFavorable: true, dataSources: [{ id: 'uuid', - inputType: 'distribution', - inputMethod: 'manualDistribution', uncertainties: 'unc', source: 'source' }] diff --git a/frontend-test/unit/test.json b/frontend-test/unit/test.json index 8216b0375..fb8614d59 100644 --- a/frontend-test/unit/test.json +++ b/frontend-test/unit/test.json @@ -8,10 +8,6 @@ "dataSources": [ { "id": "691d5517-75ec-4ce6-ba85-b87c4203c68d", - "inputType": "distribution", - "inputMethod": "assistedDistribution", - "dataType": "dichotomous", - "parameterOfInterest": "eventProbability", "scale": [ 0, 1 @@ -25,10 +21,6 @@ "dataSources": [ { "id": "a4a850a3-6a9c-4126-9e64-f1581b7f6d56", - "inputType": "distribution", - "inputMethod": "assistedDistribution", - "dataType": "continuous", - "parameterOfInterest": "mean", "scale": [ null, null @@ -42,10 +34,6 @@ "dataSources": [ { "id": "b272b7f4-4ada-4be5-958e-aab281399183", - "inputType": "distribution", - "inputMethod": "manualDistribution", - "dataType": "dichotomous", - "parameterOfInterest": "eventProbability", "scale": [ 0, 1 @@ -59,10 +47,6 @@ "dataSources": [ { "id": "5451502e-dfad-4ef7-b539-4df9ec15f886", - "inputType": "effect", - "inputMethod": "assistedDistribution", - "dataType": "dichotomous", - "parameterOfInterest": "eventProbability", "scale": [ 0, 1 @@ -76,10 +60,6 @@ "dataSources": [ { "id": "cf89ea43-e361-4569-a524-2be8a87de9fc", - "inputType": "effect", - "inputMethod": "assistedDistribution", - "dataType": "continuous", - "parameterOfInterest": "mean", "scale": [ null, null @@ -93,10 +73,6 @@ "dataSources": [ { "id": "43c25068-385b-475d-9fd6-a2f7c2505e2a", - "inputType": "effect", - "inputMethod": "assistedDistribution", - "dataType": "other", - "parameterOfInterest": "value", "scale": [ null, null diff --git a/schema/absoluteEffect.json b/schema/absoluteEffect.json index 8d5abc2b6..a3a6cbb97 100644 --- a/schema/absoluteEffect.json +++ b/schema/absoluteEffect.json @@ -36,7 +36,9 @@ "exact", "dt", "dbeta", - "dgamma" + "dgamma", + "dsurv", + "empty" ] } }, diff --git a/schema/dataSource.json b/schema/dataSource.json index 368989ea3..5d9901bc1 100644 --- a/schema/dataSource.json +++ b/schema/dataSource.json @@ -13,41 +13,6 @@ "description": "identifier of the data source", "type": "string" }, - "inputType": { - "description": "The way the measurements for a data source were entered", - "type": "string", - "enum": [ - "distribution", - "effect" - ] - }, - "inputMethod": { - "description": "Whether the input for a distribution is calculated or entered directly", - "type": "string", - "enum": [ - "assistedDistribution", - "manualDistribution" - ] - }, - "dataType": { - "description": "The type of data entered for the criterion", - "type": "string", - "enum": [ - "continuous", - "dichotomous", - "other" - ] - }, - "parameterOfInterest": { - "description": "Determines what the measured effect depicts ", - "type": "string", - "enum": [ - "eventProbability", - "mean", - "median", - "value" - ] - }, "source": { "description": "Where the data comes from", "type": "string"