Public
Edited
Mar 16, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
FileAttachment("image.png").image()characterization = {
const config = {
height: 520,
width: 960,
units: unitSelection.unit,
label: `${unitSelection.unit === "IP" ? "kBTU/ft²/yr": "kWh/m²/yr"}`
};
const svg = d3.select(DOM.svg(config.width, config.height));
const graph = sankey(sankey_data);
const nodeWidth = graph.nodes[0].x1 - graph.nodes[0].x0;
const node = svg.selectAll("g")
.data(graph.nodes)
.enter().append("g")
.attr('transform', d => `translate(${d.x0}, ${d.y0})`);

node.append("rect")
.attr("height", d => d.y1 - d.y0)
.attr("width", d => d.x1 - d.x0)
.attr("fill", d => color(d.name))
.attr("display", d => d.name === "Nothing" ? "none" : null)
.attr("stroke", "#000")
.append("title")
.html(d => `${d.name}\n${si_to(d.value)} ${config.label}`);

node.append("text")
.style("font", "10px sans-serif")
.attr("x", d => d.x0 < config.width / 2 ? 6 + (d.x1 - d.x0) : - 6)
.attr("y", d => (d.y1 - d.y0) / 2)
.attr("dy", "0.35em")
.attr("text-anchor", d => d.x0 < config.width / 2 ? "start" : "end")
.attr('font-size', 10)
.html(d => d.name);
node.append("text")
.style("font", "12px sans-serif")
.attr("x", d => d.x0 < config.width / 2 ? 6 + (d.x1 - d.x0) : - 6)
.attr("y", d => (d.y1 - d.y0) / 2)
.attr("dy", d => {
// switch(d.name) {
// case "Heating Load":
// return "-1.25em";
// default:
// return "1.85em";
// }
return "1.8em";
})
.attr("text-anchor", d => d.x0 < config.width / 2 ? "start" : "end")
.style("font-weight", "bold")
.html(d => {
switch(d.name) {
case "Natural Gas":
return `EUI: ${_.round(si_to(d.value), 0)} ${config.label}`;
case "Electricity":
return `EUI: ${_.round(si_to(d.value), 0)} ${config.label}`;
case "District Heating":
return `EUI: ${_.round(si_to(d.value), 0)} ${config.label}`;
case "District Cooling":
return `EUI: ${_.round(si_to(d.value), 0)} ${config.label}`;
default:
return "";
}
});
node.attr('cursor', 'move')
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragMove)
.on('end', dragEnd));
const link = svg.append("g")
.attr("fill", "none")
.attr("stroke-opacity", 0.5)
.selectAll("g")
.data(graph.links)
.enter().append("g")
.style("mix-blend-mode", "multiply")
.attr("id", d => d.source.name.replace(" ", "_") + "_" + d.target.name.replace(" ", "_"));

//apply gradients based on input and output
const gradient = link.append("linearGradient")
.attr("id", d => (d.uid = DOM.uid("link")).id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", d => d.source.x1)
.attr("x2", d => d.target.x0);
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", d => color(d.source.name));

gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", d => color(d.target.name));
link.append("path")
.attr("class", "link")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke", d => d.uid)
.attr("display", d=> d.target.name === "Nothing" ? "none": null)
.attr("opacity", d => d.value < 0.02 ? 0 : 1)
.attr("stroke-width", d => Math.max(1, d.width));

//link.append("title")
//.html(d => `${d.source.name} → ${d.target.name}\n${si_to(d.value)} ${config.label}`);
function dragStart (d) {
if (!d.__x) d.__x = d3.event.x;
if (!d.__y) d.__y = d3.event.y;
if (!d.__x0) d.__x0 = d.x0;
if (!d.__y0) d.__y0 = d.y0;
if (!d.__x1) d.__x1 = d.x1;
if (!d.__y1) d.__y1 = d.y1;
}
function dragMove(d) {
d3.select(this)
.attr('transform', function (d) {
const dx = d3.event.x - d.__x;
const dy = d3.event.y - d.__y;
d.x0 = d.__x0 + dx;
d.x1 = d.__x1 + dx;
d.y0 = d.__y0 + dy;
d.y1 = d.__y1 + dy;
if (d.x0 < 0) {
d.x0 = 0;
d.x1 = nodeWidth;
}
if (d.x1 > config.width) {
d.x0 = config.width - nodeWidth;
d.x1 = config.width;
}
if (d.y0 < 0) {
d.y0 = 0;
d.y1 = d.__y1 - d.__y0;
}
if (d.y1 > config.height) {
d.y0 = config.height - (d.__y1 - d.__y0);
d.y1 = config.height;
}
return `translate(${d.x0}, ${d.y0})`;
});
sankey.update(graph);
link.selectAll(".link").attr('d', d3.sankeyLinkHorizontal());
}
function dragEnd(d) {
delete d.__x;
delete d.__y;
delete d.__x0;
delete d.__x1;
delete d.__y0;
delete d.__y1;
}

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ip_to = d => (unitSelection.unit === "SI") ? _.round(d / 3.412 / 0.092903, 2) : _.round(d, 2);
Insert cell
si_to = d => (unitSelection.unit === "IP") ? _.round(d * 3.412 * 0.092903, 2) : _.round(d, 2);
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more