study-overview
Version:
a high-level summary of study accrual and data cleaning metrics
1,255 lines (1,143 loc) • 66 kB
JavaScript
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(require('d3')))
: typeof define === 'function' && define.amd
? define(['d3'], factory)
: ((global = global || self), (global.studyOverview = factory(global.d3)));
})(this, function(d3$1) {
'use strict';
if (typeof Object.assign != 'function') {
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function value(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this); // 2. Let len be ? ToLength(? Get(O, 'length')).
var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
} // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1]; // 5. Let k be 0.
var k = 0; // 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, � kValue, k, O �)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
} // e. Increase k by 1.
k++;
} // 7. Return undefined.
return undefined;
}
});
}
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, 'includes', {
value: function value(valueToFind, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
} // 1. Let O be ? ToObject(this value).
var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0; // 3. If len is 0, return false.
if (len === 0) {
return false;
} // 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
var n = fromIndex | 0; // 5. If n = 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
function sameValueZero(x, y) {
return (
x === y ||
(typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y))
);
} // 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(valueToFind, elementK) is true, return true.
if (sameValueZero(o[k], valueToFind)) {
return true;
} // c. Increase k by 1.
k++;
} // 8. Return false
return false;
}
});
}
if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
value: function value(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
} // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1]; // 5. Let k be 0.
var k = 0; // 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, � kValue, k, O �)).
// d. If testResult is true, return k.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return k;
} // e. Increase k by 1.
k++;
} // 7. Return -1.
return -1;
}
});
}
function defaults() {
return {
site_col: ['site', 'site_name', 'sitename'],
id_col: ['usubjid', 'subjid', 'subjectnameoridentifier'],
visit_col: ['visit', 'avisit', 'visit_name', 'folderinstancename'],
visit_order_col: ['visitnum', 'avisitn', 'visit_number', 'folder_ordinal'],
form_col: ['ecrfpagename'],
form_order_col: ['form_number', 'form_ordinal'],
groups: [
{
value_col: '_site_',
label: 'Site'
},
{
value_col: 'SEX',
label: 'Sex'
},
{
value_col: 'RACE',
label: 'Race'
}
],
modules: [
{
spec: 'participants',
title: 'Participants',
unit: 'participant',
results: [
{
label: '# Participants',
subset: [],
summary: 'count'
},
{
label: 'Screening',
subset: [
{
key: 'SBJTSTAT',
values: ['Ongoing']
},
{
key: 'RFENDY',
values: [
'6',
'15',
'16',
'20',
'21',
'22',
'28',
'29',
'30',
'32',
'42',
'43',
'44',
'47'
]
}
],
summary: 'count',
denominator: '# Participants'
},
{
label: 'Screen Failed',
subset: [
{
key: 'SBJTSTAT',
values: ['Screen Failure']
}
],
summary: 'count',
denominator: '# Participants'
},
{
label: 'Enrolled',
subset: [
{
key: 'SBJTSTAT',
values: ['Ongoing']
}
],
summary: 'count',
denominator: '# Participants'
},
{
label: 'Completed',
subset: [
{
key: 'SBJTSTAT',
values: ['Completed']
}
],
summary: 'count',
denominator: '# Participants'
},
{
label: 'Early Termination',
subset: [
{
key: 'SBJTSTAT',
values: ['Early Termination']
}
],
summary: 'count',
denominator: '# Participants'
}
]
},
{
spec: 'visits',
title: 'Visits',
unit: 'visit',
results: [
{
label: '# Visits',
subset: [],
summary: 'count'
},
{
label: 'Visit Status',
subset: [
{
key: 'visit_status',
values: ['Completed', 'Expected', 'Overdue', 'Missed']
}
],
summary: 'count',
denominator: '# Visits',
by: 'visit_status'
}
]
},
{
spec: 'forms',
title: 'Forms',
unit: 'form',
results: [
{
label: '# Forms',
subset: [
{
key: 'is_partial_entry',
values: ['1']
}
],
summary: 'count'
},
{
label: 'Verified',
subset: [
{
key: 'is_verified',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Needs Verification',
subset: [
{
key: 'needs_verification',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Signed',
subset: [
{
key: 'is_signed',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Needs Signature',
subset: [
{
key: 'needs_signature',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Frozen',
subset: [
{
key: 'is_frozen',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Ready for Freeze',
subset: [
{
key: 'ready_for_freeze',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
},
{
label: 'Locked',
subset: [
{
key: 'is_locked',
values: ['1']
}
],
summary: 'count',
denominator: '# Forms'
}
]
},
{
spec: 'queries',
title: 'Queries',
unit: 'query',
results: [
{
label: '# Queries',
subset: [],
summary: 'count'
},
{
label: 'Open Queries by Age Category',
subset: [
{
key: 'querystatus',
values: ['Open']
}
],
summary: 'count',
denominator: '# Queries',
by: 'queryage'
},
{
label: 'Answered Queries by Marking Group',
subset: [
{
key: 'querystatus',
values: ['Answered']
}
],
summary: 'count',
denominator: '# Queries',
by: 'markinggroup'
}
]
}
]
};
}
function _typeof(obj) {
if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') {
_typeof = function(obj) {
return typeof obj;
};
} else {
_typeof = function(obj) {
return obj &&
typeof Symbol === 'function' &&
obj.constructor === Symbol &&
obj !== Symbol.prototype
? 'symbol'
: typeof obj;
};
}
return _typeof(obj);
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (
Symbol.iterator in Object(iter) ||
Object.prototype.toString.call(iter) === '[object Arguments]'
)
return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError('Invalid attempt to spread non-iterable instance');
}
function clone(obj) {
var copy; // Handle the 3 simple types, and null or undefined
if (null == obj || 'object' != _typeof(obj)) return obj; // Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
} // Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
} // Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
function defaultIsMergeableObject(value) {
return isNonNullObject(value) && !isSpecial(value);
}
function isNonNullObject(value) {
return !!value && _typeof(value) === 'object';
}
function isSpecial(value) {
var stringValue = Object.prototype.toString.call(value);
return stringValue === '[object RegExp]' || stringValue === '[object Date]';
}
function emptyTarget(val) {
return Array.isArray(val) ? [] : {};
}
function cloneUnlessOtherwiseSpecified(value, options) {
return options.clone !== false && options.isMergeableObject(value)
? merge(emptyTarget(value), value, options)
: value;
}
function defaultArrayMerge(target, source, options) {
return target.concat(source).map(function(element) {
return cloneUnlessOtherwiseSpecified(element, options);
});
}
function getMergeFunction(key, options) {
if (!options.customMerge) {
return merge;
}
var customMerge = options.customMerge(key);
return typeof customMerge === 'function' ? customMerge : merge;
}
function getEnumerableOwnPropertySymbols(target) {
return Object.getOwnPropertySymbols
? Object.getOwnPropertySymbols(target).filter(function(symbol) {
return target.propertyIsEnumerable(symbol);
})
: [];
}
function getKeys(target) {
return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target));
}
function mergeObject(target, source, options) {
var destination = {};
if (options.isMergeableObject(target)) {
getKeys(target).forEach(function(key) {
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
});
}
getKeys(source).forEach(function(key) {
if (!options.isMergeableObject(source[key]) || !target[key]) {
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
} else {
destination[key] = getMergeFunction(key, options)(
target[key],
source[key],
options
);
}
});
return destination;
}
function merge(target, source, options) {
options = options || {};
options.arrayMerge = options.arrayMerge || defaultArrayMerge;
options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject;
var sourceIsArray = Array.isArray(source);
var targetIsArray = Array.isArray(target);
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
if (!sourceAndTargetTypesMatch) {
return cloneUnlessOtherwiseSpecified(source, options);
} else if (sourceIsArray) {
return options.arrayMerge(target, source, options);
} else {
return mergeObject(target, source, options);
}
}
merge.all = function mergeAll(array, options) {
if (!Array.isArray(array)) {
throw new Error('first argument should be an array');
}
return array.reduce(function(prev, next) {
return merge(prev, next, options);
}, {});
};
function dataSpecifications() {
this.settings.modules.forEach(function(module) {
module.variables = Array.from(
new Set(
d3.merge(
module.results.map(function(result) {
return result.subset
? result.subset.map(function(subset) {
return subset.key;
})
: [];
})
)
)
);
});
}
function sync(defaults) {
var settings = clone(this.settings); // Merge user settings onto default settings.
this.settings = merge(defaults, settings, {
arrayMerge: function arrayMerge(target, source, options) {
return _toConsumableArray(source); //return target.concat(source).map(function(element) {
// return cloneUnlessOtherwiseSpecified(element, options);
//});
}
}); // Retain user settings.
this.settings.custom = settings; // Connect denominators to corresponding result object.
this.settings.modules.forEach(function(module) {
module.results.forEach(function(result) {
if (result.denominator) {
result.denominator = module.results.find(function(result1) {
return result1.label === result.denominator;
});
}
});
});
dataSpecifications.call(this);
}
function configuration() {
sync.call(this, defaults());
}
function layout() {
this.containers = {
main: d3
.select(this.element)
.append('div')
.datum(this)
.classed('study-overview', true)
.attr(
'id',
'study-overview'.concat(document.querySelectorAll('.study-overview').length)
)
};
this.containers.controls = this.containers.main.append('div').classed('so-controls', true);
this.containers.cards = this.containers.main
.selectAll('div.so-card')
.data(this.settings.modules)
.enter()
.append('div')
.classed('so-card', true);
this.containers.headers = this.containers.cards
.append('div')
.append('h4')
.classed('so-card__header', true)
.text(function(d) {
return d.title;
});
this.containers.tables = this.containers.cards
.append('div')
.append('table')
.classed('so-card__table', true);
}
function styles() {
var styles = [
'.study-overview {' +
' display: flex;' +
' flex-wrap: wrap;' +
' flex-direction: row;' +
'}',
'.so-controls {' + ' width: calc(100% - 36px);' + ' margin: 0px 18px;' + '}',
'.so-control-group {' + ' display: inline-block;' + '}',
'.so-control-group--export {' +
' float: right;' +
' padding: 4px;' +
' border: 2px solid black;' +
' background: #aaa;' +
' color: black;' +
' font-weight: bold;' +
' border-radius: 4px;' +
' cursor: pointer;' +
'}',
'.so-control-group--export:hover {' +
' border: 2px solid #aaa;' +
' background: black;' +
' color: #aaa;' +
'}',
'.so-control-group--export .so-control-group__label {' + ' margin-right: 0px;' + '}',
'.so-control-group__label {' + ' margin-right: 8px;' + '}',
'.so-card {' +
' /*' +
' display: flex;' +
' flex-basis: calc(50% - 40px);' +
' justify-content: top;' +
' flex-direction: column;' +
' */' +
' display: inline-block;' +
' width: calc(50% - 40px);' +
' margin: 18px;' +
' border: 1px solid #aaa;' +
' border-radius: 4px;' +
' overflow-x: auto;' +
'}',
'.so-card > * {' +
' width: 100%;' +
' vertical-align: top;' +
' display: table;' +
'}',
'.so-card__header {' +
' font-size: 24px;' +
' margin: 4px 8px;' +
' padding: 4px 8px;' +
' font-weight: lighter;' +
' border-bottom: 1px solid #aaa;' +
'}',
'.so-card__table {' +
' border-collapse: collapse;' +
' border-spacing: 0;' +
' empty-cells: show;' +
' margin: 4px 8px;' +
' padding: 4px 8px;' +
' width: calc(100% - 16px);' +
'}',
'.so-card__table__header {' + '}',
'.so-card__table__header__cell {' + ' padding: .5em 1em;' + '}',
'.so-card__table__row {' + '}',
'.so-card__table__row:hover {' + ' outline: 1px solid blue;' + '}',
'.so-card__table__row:nth-child(2n) {' + ' background: #f2f2f2;' + '}',
'.so-card__table__row--by-group {' +
' border-top: 2px solid black;' +
' border-bottom: 2px solid black;' +
'}',
'.so-card__table__row__cell {' +
' border-width: 0 0 0 1px;' +
' font-size: inherit;' +
' margin: 0;' +
' overflow: visible;' +
' padding: .5em 1em;' +
'}',
'.so-card__table__row__cell:first-child {' + ' white-space: nowrap;' + '}',
'.so-card__table__row__cell:not(:first-child) {' +
" font-family: 'Lucida Console';" +
' white-space: pre;' +
'}',
'.so-card__table__row--by-value .so-card__table__row__cell:first-child {' +
' padding-left: 3em;' +
'}'
];
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = styles.join('\n');
document.getElementsByTagName('head')[0].appendChild(style);
}
function checkDataSpecification(data) {
var _this = this;
var datasets;
if (Array.isArray(data) && !data[0].hasOwnProperty('data'))
datasets = [
{
data: data
}
];
else datasets = data;
datasets.forEach(function(dataset) {
dataset.variables = Object.keys(dataset.data[0]);
if (dataset.hasOwnProperty('spec'))
dataset.module = _this.settings.modules.find(function(module) {
return module.spec === dataset.spec;
});
else {
var matches = _this.settings.modules.map(function(module) {
var match = JSON.parse(JSON.stringify(module));
match.matching = 0;
match.total = match.variables.length;
match.variables.forEach(function(variable) {
match.matching = match.matching + dataset.variables.includes(variable);
});
match.proportion = match.matching / match.total;
return match;
});
dataset.module = matches.find(function(match) {
return (
match.proportion ===
d3.max(matches, function(match) {
return match.proportion;
})
);
});
dataset.spec = dataset.module ? dataset.module.spec : null;
}
});
this.settings.datasets = datasets.map(function(dataset) {
return dataset.spec;
});
this.settings.modules = this.settings.modules.filter(function(module) {
return _this.settings.datasets.includes(module.spec);
});
return datasets;
}
function standardizeVariable(setting, variables) {
var _this = this;
var variable = variables.find(function(variable) {
return _this.settings[setting].find(function(col) {
return col === variable.toLowerCase();
});
});
return variable;
}
function standardizeData() {
var _this = this;
var dataMappings = Object.keys(this.settings)
.filter(function(key) {
return /col$/.test(key);
})
.map(function(key) {
return {
setting: key,
variable: '_'
.concat(key.replace(/_col$/, ''), '_')
.replace(/^_id_$/, '_participant_')
};
});
this.data.forEach(function(data) {
// Capture available variables.
var variables = Object.keys(data.data[0]); // Standardize variables.
dataMappings.forEach(function(dataMapping) {
data[dataMapping.setting] = standardizeVariable.call(
_this,
dataMapping.setting,
variables
);
}); // Attach variable with standard name to data array.
data.data.forEach(function(d, i) {
dataMappings.forEach(function(dataMapping, j) {
d[dataMapping.variable] = d[data[dataMapping.setting]];
});
}); // Attach available variables to data object.
data.variables = Object.keys(data.data[0]);
});
}
function mergeData() {
var participants = this.data.find(function(dataset) {
return dataset.spec === 'participants';
});
if (participants !== undefined) {
var datasets = this.data
.filter(function(dataset) {
return dataset.spec !== 'participants';
})
.map(function(dataset) {
return dataset.data;
});
participants.data.forEach(function(participant) {
datasets.forEach(function(dataset) {
dataset
.filter(function(d) {
return d._participant_ === participant._participant_;
})
.forEach(function(d) {
Object.assign(d, participant);
});
});
});
}
}
function attachData(data) {
for (var property in data) {
if (!Object.keys(this).includes(property)) this[property] = data[property];
}
}
function summarizeData() {
var _this = this;
var by = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
this.data.forEach(function(data) {
// Match data spec to module.
var module = _this.settings.modules.find(function(module) {
return module.spec === data.spec;
}); // Attach data properties to module.
if (module) {
attachData.call(module, data);
if (by) {
module.byValues = d3
.set(
data.data.map(function(d) {
return d[by];
})
)
.values()
.sort();
data.byValues = module.byValues.slice();
} else {
delete module.byValues;
delete data.byValues;
} // nest by key variable
var nest = function nest(data, key) {
var rollup =
arguments.length > 2 && arguments[2] !== undefined
? arguments[2]
: function(d) {
return d.length;
};
var overall = data.map(function(d) {
var datum = Object.assign({}, d);
datum[key] = '_overall_';
return datum;
});
var nested = d3
.nest()
.key(function(d) {
return d[key];
})
.rollup(rollup)
.entries(key ? data.concat(overall) : overall)
.sort(function(a, b) {
return a.key < b.key ? -1 : 1;
});
return nested;
}; // transpose key values
var transpose = function transpose(data, denominators) {
var transposed = data.reduce(function(acc, cur) {
var denominator = denominators ? denominators[cur.key].numerator : null;
acc[cur.key] = {
numerator: cur.values,
denominator: denominator,
value: denominator
? ''
.concat(d3.format('6,d')(cur.values), ' (')
.concat(d3.format('2%')(cur.values / denominator), ')')
: d3.format('6,d')(cur.values)
};
return acc;
}, {});
return transposed;
};
var summarize = function summarize(data) {
var row =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var col =
arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var denominators =
arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
// summarize by col variable
var colNest = nest(data, col);
var colNestTransposed = transpose(
colNest,
denominators ? denominators.summary.row : null
); // summarize by row variable
var rowNest = row
? nest(data, row, function(d) {
return d;
})
: null;
var rowNestTransposed = row
? rowNest
.map(function(row) {
var nested = nest(row.values, col);
nested.key = row.key;
return nested;
})
.map(function(row) {
var transposed = transpose(row, colNestTransposed);
transposed.key = row.key;
return transposed;
})
: null;
return {
row: colNestTransposed,
rows: rowNestTransposed
};
};
module.results.forEach(function(result) {
result.data = module.data.slice();
result.subset.forEach(function(sub) {
result.data = result.data.filter(function(d) {
return sub.values.includes(d[sub.key]);
});
});
result.summary = summarize(
result.data, // data
result.by, // row
by, // col
result.denominator // denominators
);
});
data.summary = module.results
.map(function(result) {
var summary = [];
if (result.summary.row) {
var obj = {
label: result.label,
value: result.summary.row._overall_.value,
level: 1
};
if (by)
module.byValues.forEach(function(byValue) {
obj[byValue] = result.summary.row[byValue]
? result.summary.row[byValue].value
: null;
});
summary.push(obj);
}
if (result.summary.rows) {
result.summary.rows.forEach(function(row) {
var obj = {
label: row.key,
value: row._overall_.value,
level: 2
};
if (by)
module.byValues.forEach(function(byValue) {
obj[byValue] = row[byValue] ? row[byValue].value : null;
});
summary.push(obj);
});
}
return summary;
})
.reduce(function(acc, cur) {
cur.filter(function(d) {
return d.label !== '_overall_';
}).forEach(function(d) {
return acc.push(d);
});
return acc;
}, []);
} else {
console.warn('Data specification [ '.concat(data.spec, ' ] is invalid.'));
}
});
}
function createTable() {
var _this = this;
var by = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
this.settings.modules.forEach(function(module) {
module.containers = {
card: _this.containers.cards.filter(function(d) {
return d.spec === module.spec;
}),
header: _this.containers.headers.filter(function(d) {
return d.spec === module.spec;
}),
table: _this.containers.tables.filter(function(d) {
return d.spec === module.spec;
})
};
if (by) {
module.containers.header = module.containers.table
.append('thead')
.classed('so-card__table__header', true)
.append('tr')
.selectAll('th')
.data([''].concat(_toConsumableArray(module.byValues || []), ['Overall']))
.enter()
.append('th')
.classed('so-card__table__header__cell', true)
.text(function(d) {
return d;
});
}
if (module.results) {
module.containers.body = module.containers.table.append('tbody');
module.containers.rows = module.containers.body
.selectAll('tr')
.data(module.results)
.enter()
.append('tr')
.classed('so-card__table__row', true);
module.containers.rows.each(function(d) {
var _this2 = this;
//console.log(d);
var row = d3.select(this);
row.selectAll('td')
.data(
d3.merge([
[
{
value: d.label
}
],
[]
.concat(_toConsumableArray(module.byValues || []), [
'_overall_'
])
.map(function(cell) {
return (
d.summary.row[cell] || {
numerator: null,
value: null
}
);
})
])
)
.enter()
.append('td')
.attr('class', function(d, i) {
return 'so-card__table__row__cell '.concat(
i === 0
? 'so-card__table__row__cell-key'
: 'so-card__table__row__cell-value'
);
})
.text(function(di) {
return di.value || '';
});
if (d.summary.rows) {
row.classed('so-card__table__row--by-group', true);
d.summary.rows
.filter(function(row) {
return row.key !== '_overall_';
})
.reverse()
.forEach(function(row) {
var el = document.createElement('tr');
_this2.parentNode.insertBefore(el, _this2.nextSibling);
var byRow = d3
.select(el)
.classed(
'so-card__table__row so-card__table__row--by-value',
true
);
byRow
.selectAll('td')
.data(
d3.merge([
[
{
value: row.key
}
],
[]
.concat(_toConsumableArray(module.byValues || []), [
'_overall_'
])
.map(function(cell) {
return (
row[cell] || {
numerator: null,
value: null
}
);
})
])
)
.enter()
.append('td')
.attr('class', function(di, i) {
return 'so-card__table__row__cell '.concat(
i === 0
? 'so-card__table__row__cell-key'
: 'so-card__table__row__cell-value'
);
})
.text(function(di) {
return di.value || '';
});
});
}
});
}
});
}
function groupBy() {
var studyOverview = this;
this.containers.groupBy = {
main: this.containers.controls
.append('div')
.classed('so-control-group so-control-group--group-by', true)
};
this.containers.groupBy.label = this.containers.groupBy.main
.append('span')
.classed('so-control-group__label', true)
.text('Group by');
this.containers.groupBy.select = this.containers.groupBy.main
.append('select')
.classed('so-control-group__dropdown', true);
this.containers.groupBy.options = this.containers.groupBy.select
.selectAll('option')
.data(
[
{
value_col: null,
label: 'None'
}
].concat(_toConsumableArray(this.settings.groups))
)
.enter()
.append('option')
.classed('so-control-group__dropdown__option', true)
.property('selected', function(d) {
return d.label === 'Site';
})
.text(function(d) {
return d.label;
});
this.containers.groupBy.select.on('change', function() {
var option = d3.select