function comparisionCard(
data,
{
config,
_staticsFunctions = {},
_comparisonFunctions = {},
colorScale = d3.scaleOrdinal(d3.schemeAccent),
width = 400
}
) {
let div = d3
.create("div")
.style("display", "flex")
.style("width", "${width}px")
.style("overflow-x", "auto")
.style("overflow-y", "hidden");
let staticsFunction = {
mean: d3.mean,
deviation: d3.deviation,
min: d3.min,
max: d3.max,
..._staticsFunctions
};
let comparisonFunction = {
anova: anova,
..._comparisonFunctions
};
if (data.size >= 2) {
let pData = processData(data, config);
generateCard(pData);
} else {
let dummyData = new Map();
dummyData.set(0, []);
dummyData.set(1, []);
let pData = processData(dummyData, config);
generateCard(pData);
}
function generateCard(data) {
let divs = div
.selectAll("vContainer")
.data(data)
.join("div")
.attr("class", "vContainer")
.style("margin", "10px")
.style(
"background",
(d) =>
`linear-gradient(to right, ${colorScale(d.g1)} 50%, ${colorScale(
d.g2
)} 50%)`
)
.style("padding-right", "10px")
.style("padding-left", "10px")
.style("border-radius", "20px")
.style("border-style", "solid");
let counts = divs
.append("div")
.style("display", "flex")
.style("justify-content", "space-between");
counts
.append("div")
.style("text-align", "right")
//.style("width", "50%")
.style("display", "inline-block")
.style("margin-right", "10px")
.text((d) => "Count:" + d.g1Count);
counts
.append("div")
.style("text-align", "right")
//.style("width", "50%")
.style("display", "inline-block")
.style("margin-left", "10px")
.text((d) => "Count:" + d.g2Count);
let varDivs = divs
.selectAll(".var")
.data((d) => d.vars)
.join("div")
.attr("class", "var");
varDivs.append("span").text((d) => d.name + " :");
let uls = varDivs.append("ul").style("margin-top", "0px");
uls
.selectAll(".statistics")
.data((d) => d.statistics)
.join("li")
.attr("class", "statistics")
.text((d) => d.name + " diff: " + d.value?.toFixed(2));
uls
.selectAll(".comparision")
.data((d) => d.comparision)
.join("li")
.attr("class", "comparision")
.text((d) => d.name + ": " + d.value?.toFixed(2));
}
function processData(data, config) {
let keys = Array.from(data.keys());
let indexCombination = keys.flatMap((v, i) =>
keys.slice(i + 1).map((w) => [v, w])
);
let outData = [];
indexCombination.forEach(([ix1, ix2]) => {
let varData = [];
config.forEach((variable) => {
let calculatedDiffs = [];
variable.statistics.forEach((statistic) => {
let varValue0 = computeStatistic(
data.get(ix1),
variable.var,
statistic
);
let varValue1 = computeStatistic(
data.get(ix2),
variable.var,
statistic
);
let result = varValue0 - varValue1;
calculatedDiffs.push({ name: statistic, value: result });
});
let calculateTests = [];
variable.comparison.forEach((test) => {
let result = computeTest(
[data.get(ix1), data.get(ix2)],
variable.var,
test
);
calculateTests.push({ name: test, value: result });
});
varData.push({
name: variable.name,
statistics: calculatedDiffs,
comparision: calculateTests
});
});
outData.push({
g1: ix1,
g1Count: data.get(ix1).length,
g2: ix2,
g2Count: data.get(ix2).length,
vars: varData
});
});
return outData;
}
function computeStatistic(data, varName, statistic) {
return staticsFunction[statistic](data.map((d) => d[varName]));
}
function computeTest(datas, varName, test) {
let samples0 = datas[0].map((d) => d[varName]);
let samples1 = datas[1].map((d) => d[varName]);
samples0 = samples0.filter((d) => d !== undefined && d !== null);
samples1 = samples1.filter((d) => d !== undefined && d !== null);
return comparisonFunction[test](samples0, samples1);
}
function anova(samples0, samples1) {
if (samples0 < 1 && samples1 < 1) {
return undefined;
}
let group0 = Array(samples0.length).fill(0);
let group1 = Array(samples1.length).fill(1);
let samples = samples0.concat(samples1);
let group = group0.concat(group1);
let result = _anova.default(samples, group);
console.log(result);
return result.pValue;
}
return div.node();
}