Summary
This method returns the average of multiple collected item values. A common use case is ECG triplicate readings, but it will apply to any similar use case. It also can be used to average an arbitrary number of values as long as the FormData conforms to the conventions used by this method.
Form Setup
This method expects that 3 forms contain data collected using the same study event. It will look for Complete and uncanceled FormData. In each form, the method will find the first occurrence of the Item matching the name specified in the method configuration.
Formal Expression
Variables:
INCLUDE_NONCONFORMANT_DATA: If true, data looked up which is nonconformant can be used in the calculation. If false, then only Complete forms will be considered
REQUIRE_VALUE_FOR_EACH_FORM: if false, then the average of 2 data items will be returned. If true, the method will only return a value if a value is found for every form specified.
STUDY_EVENT_NAME: Name of the study event used in collection of the desired ECG data. This can be hardcoded OR dynamically retrieved if you’re looking for the same study event of the item that the method is attached to.
TIMEPOINT: Timepoint of the forms. If not present, by default the timepoint of the itemData to which this method is attached will be dynamically retrieved and used.
ITEM_NAME_TO_AVERAGE: Name of the Item containing data to be averaged. This can be hard coded OR dynamically calculated using a naming convention for the method that this is attached to.
BASELINE_FORM_NAMES = the names of the forms containing the data to be averaged.
Here is an example showing this method applied to ECG QTcF values:
var INCLUDE_NONCONFORMANT_DATA = true; var REQUIRE_VALUE_FOR_EACH_FORM = false; // if false, this will average as many values that are found, even if that is less than expected var STUDY_EVENT_NAME = formJson.form.studyEventName; // study event where the forms can be found. Can be dynamic (default) or hard coded // logger('STUDY_EVENT_NAME '+STUDY_EVENT_NAME); var BASELINE_FORM_NAMES = ['ECG 1','ECG 2','ECG 3']; // name of the forms containing data var thisItemName = itemJson.item.name; // logger('thisItemName '+thisItemName+' first ['+thisItemName.split(' ')[0]+']'); // var ITEM_NAME_TO_AVERAGE = 'PR'; // you can optionally hardcode this if you don't want to leverage convention var ITEM_NAME_TO_AVERAGE = thisItemName.split(' ')[0]; var TIMEPOINT = null; var thisTimepoint = formJson.form.timepoint; if (!TIMEPOINT && thisTimepoint) { // logger('Found timepoint. Setting TIMEPOINT to '+thisTimepoint); TIMEPOINT = thisTimepoint; } var ret = 0; var itemsFound = 0; var valueTotal = 0; for (var i = 0; i < BASELINE_FORM_NAMES.length; i++) { var baselineForms = null; if (TIMEPOINT) { // logger('looking up form timepoint '+TIMEPOINT); baselineForms = findFormData(STUDY_EVENT_NAME, BASELINE_FORM_NAMES[i], TIMEPOINT); } else { // logger('looking up form without timepoint, since none found'); baselineForms = findFormData(STUDY_EVENT_NAME, BASELINE_FORM_NAMES[i]); } baselineCompletedForms = collectCompleted(baselineForms, INCLUDE_NONCONFORMANT_DATA); // logger('baselineCompletedForms.length '+baselineCompletedForms.length); if (baselineCompletedForms != null && 1 === baselineCompletedForms.length) { var item = findFirstItemByName(baselineCompletedForms[0], ITEM_NAME_TO_AVERAGE); itemsFound++; valueTotal += Number(item.value); // logger('itemsFound now '+itemsFound+' adding item.value '+item.value+'for valueTotal'+valueTotal); } else { // logger('rats. baselineCompletedForms.length '+baselineCompletedForms.length); } } if (!REQUIRE_VALUE_FOR_EACH_FORM || BASELINE_FORM_NAMES.length === itemsFound) { ret = Math.round(valueTotal / itemsFound).toString(); } return ret; function collectCompleted(formDataArray, INCLUDE_NONCONFORMANT_DATA) { if (formDataArray == null) { return []; } var keepers = []; for (var i = formDataArray.length - 1; i >= 0; i--) { var formData = formDataArray[i]; if (formData.form.canceled == false && formData.form.itemGroups[0].canceled == false && (formData.form.dataCollectionStatus == 'Complete' || (INCLUDE_NONCONFORMANT_DATA == true && formData.form.dataCollectionStatus == 'Nonconformant') )) { // logger('keeping 1 canceled '+formData.form.canceled+' formData.dataCollectionStatus '+formData.form.dataCollectionStatus); keepers.push(formData); } else { // logger('Skipping 1 canceled '+formData.form.canceled+' formData.dataCollectionStatus '+formData.form.dataCollectionStatus); } } return keepers; }