RelLumFlicker = {
const RelLum = [];
const grps = data_clean
.filter((d) => d.Experiment === "MinFlicker" && d.Calib === "Calibrated")
.groupby("SubjectName", "Calib")
.objects({ grouped: true });
for (const sid of grps.keys()) {
const grp_data = grps.get(sid);
for (const ct of grp_data.keys()) {
const grp_calib = grp_data.get(ct);
const rperc_from_xg = [];
const bperc_of_r = [];
const rperc_of_b = [];
const bperc_from_gp = [];
const bperc_from_gp_using_rp = [];
for (const st of ["RedPurple", "GrayGreen", "GreenPurple"]) {
for (let c = 0; c < grp_calib.length; c += 2) {
let w1 = grp_calib[c].Weight;
let w2 = grp_calib[c + 1].Weight;
let stype = grp_calib[c].StimType;
if (stype !== st) {
continue;
}
if (stype === "RedPurple") {
// "first" side was red, "second" was purple
// w1 = red, w2 = purple
const r1 = (w1 - 0.38 * w2) / w2;
bperc_of_r.push(r1);
const r2 = w2 / (w1 - 0.38 * w2);
rperc_of_b.push(r2);
// w2*X = w1*G
// w2*(R + G + B) = w1*G
// w2*(R + B) = (w1 - w2)*G
// w2*(R + (w1_RP - 0.38*w2_RP)*R/w2_RP) = (w1 - w2)*G
// R*(w2 + (w1_RP - 0.38*w2_RP)/w2_RP) = (w1 - w2)*G
// R = G*(w1 - w2)/(w2 + (w1_RP - 0.38*w2_RP)/w2_RP)
} else if (stype === "GrayGreen") {
// "first" side was green, "second" was gray
// w1 = green, w2 = gray
const ratio = (w1 - w2) / (w2 + d3.mean(bperc_of_r));
rperc_from_xg.push(ratio);
// w2*P = w1*G
// w2*(0.38*R + B) = w1*G
// w2*B = w1*G - w2*0.38*R
// w2*B = w1*G - w2*0.38*(G*(w1_XG - w2_XG)/(w2_XG + (w1_RP - 0.38*w2_RP)/w2_RP))
// w2*B = G*(w1 - w2*0.38*(w1_XG - w2_XG)/(w2_XG + (w1_RP - 0.38*w2_RP)/w2_RP))
// w2*B = G*(w1 - w2*0.38*rperc)
// B = G*(w1 - w2*0.38*rperc)/w2
// w2*B = w1*G - w2*0.38*R
// w2*B = w1*G - w2*0.38*B*w2_RP/(w1_RP - 0.38*w2_RP)
// w2*B + w2*0.38*B*w2_RP/(w1_RP - 0.38*w2_RP) = w1*G
// B = G*w1/(w2 + w2*0.38*w2_RP/(w1_RP - 0.38*w2_RP))
} else if (stype === "GreenPurple") {
// "first" side was green, "second" was purple
// w1 = green, w2 = purple
const r1 = (w1 - w2 * 0.38 * d3.mean(rperc_from_xg)) / w2;
bperc_from_gp.push(r1);
const r2 = w1 / (w2 + w2 * 0.38 * d3.mean(rperc_of_b));
bperc_from_gp_using_rp.push(r2);
}
}
}
let rY = 0;
let gY = 0;
let bY = 0;
if (ct === "Calibrated") {
rY = grp_calib[0].monXYZ[0].Y;
gY = grp_calib[0].monXYZ[1].Y;
bY = grp_calib[0].monXYZ[2].Y;
} else {
rY = monXYZ_sRGB.Y;
gY = monXYZ_sRGB.Y;
bY = monXYZ_sRGB.Y;
}
for (let c = 0; c < rperc_from_xg.length; c++) {
const bmean = d3.mean([bperc_from_gp[c], bperc_from_gp_using_rp[c]]);
RelLum.push({
calib: ct,
id: sid,
r_from_xg: rperc_from_xg[c],
b_from_gp: bperc_from_gp[c],
b_from_gp_using_rp: bperc_from_gp_using_rp[c],
b_avg_est: bmean,
b_of_r: bperc_of_r[c],
r_of_b: rperc_of_b[c],
rb_ratio: rperc_from_xg[c] / bmean,
gr_ratio: 1.0 / rperc_from_xg[c],
rb_ratio_mon: rY / bY,
gr_ratio_mon: gY / rY
});
}
}
}
const ToPlot = aq
.from(RelLum)
.filter((d) => d.calib === "Calibrated")
.groupby("id")
.derive({
tot: (d) => d.r_from_xg + 1.0 + d.b_avg_est
})
.derive({
r_rel: (d) => d.r_from_xg / d.tot,
g_rel: (d) => 1.0 / d.tot,
b_rel: (d) => d.b_avg_est / d.tot
})
.rollup({
r_rel_mean: (d) => op.mean(d.r_rel),
g_rel_mean: (d) => op.mean(d.g_rel),
b_rel_mean: (d) => op.mean(d.b_rel)
})
.fold(["r_rel_mean", "g_rel_mean", "b_rel_mean"], { as: ["xs", "vals"] })
.derive({
xs: (d) => op.replace(d.xs, "r_rel_mean", 0)
})
.derive({
xs: (d) => op.replace(d.xs, "g_rel_mean", 1)
})
.derive({
xs: (d) => op.replace(d.xs, "b_rel_mean", 2)
})
.derive({
xs: (d) => +d.xs
});
return { RelVals: aq.from(RelLum), ToPlot: ToPlot };
}