getExperimentView = async (
q,
indexTypeControl,
searchParamsControl,
indexTypeExperiment,
searchParamsExperiment
) => {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.style("border", "1px solid #ccc");
const view = svg.node();
const controlNodes = await getNodes(q, indexTypeControl, searchParamsControl);
const experimentNodes = await getNodes(
q,
indexTypeExperiment,
searchParamsExperiment
);
const controlIds = controlNodes.map((node) => node.id);
const experimentIds = experimentNodes.map((node) => node.id);
controlNodes.forEach(
(node) => (node.type = experimentIds.includes(node.id) ? 1 : 0)
);
const addedNodes = experimentNodes.filter(
(node) => !controlIds.includes(node.id)
);
const intersectG = svg.append("g").attr("id", "intersect-view");
const addedG = svg.append("g").attr("id", "added-view");
const xDomain = d3.extent(
[].concat(controlNodes, experimentNodes),
(node) => node.distance
);
const xDomainLength = xDomain[1] - xDomain[0] + 0.01;
const xBinLength = Math.floor(width / (R * 2));
const controlHistogram = [];
for (let i = 0; i < xBinLength; i++) controlHistogram.push([]);
controlNodes.forEach((node) => {
const binX = Math.floor(
((node.distance - xDomain[0]) / xDomainLength) * xBinLength
);
controlHistogram[binX].push(node);
});
smoothHistogram(controlHistogram);
smoothHistogram(controlHistogram);
controlHistogram.forEach((row) => row.sort((a, b) => -a.type + b.type));
const experimentHistogram = [];
for (let i = 0; i < xBinLength; i++) experimentHistogram.push([]);
addedNodes.forEach((node) => {
const binX = Math.floor(
((node.distance - xDomain[0]) / xDomainLength) * xBinLength
);
experimentHistogram[binX].push(node);
});
smoothHistogram(experimentHistogram);
smoothHistogram(experimentHistogram);
const id2binPos = {};
controlHistogram.forEach((row, x) => {
row.forEach(({ id }, y) => (id2binPos[id] = { x, y }));
});
experimentHistogram.forEach((row, x) => {
row.forEach(({ id }, y) => (id2binPos[id] = { x, y }));
});
const intersectNodesG = intersectG
.selectAll("g")
.data(controlNodes)
.join("g")
.attr("transform", (node) => {
return `translate(${(2 * id2binPos[node.id].x + 1) * R}, ${
height / 2 - (2 * id2binPos[node.id].y + 1) * R
})`;
});
const addedNodesG = addedG
.selectAll("g")
.data(addedNodes)
.join("g")
.attr("transform", (node) => {
return `translate(${(2 * id2binPos[node.id].x + 1) * R}, ${
height / 2 + (2 * id2binPos[node.id].y + 1) * R
})`;
});
intersectNodesG
.append("circle")
.attr("r", r)
.attr("fill", (node) => colors[node.type]);
addedNodesG.append("circle").attr("r", r).attr("fill", colors[2]);
return view;
}