Public
Edited
Oct 19, 2022
Fork of Arc diagram
2 forks
Insert cell
Insert cell
// viewof order = {
// const options = [
// {name: "Order by name", value: (a, b) => d3.ascending(a.label, b.label)},
// {name: "Order by group", value: (a, b) => d3.ascending(a.group, b.group)},
// // {name: "Order by degree", value: (a, b) => d3.sum(b.sourceLinks, l => l.value) + d3.sum(b.targetLinks, l => l.value) - d3.sum(a.sourceLinks, l => l.value) - d3.sum(a.targetLinks, l => l.value) || d3.ascending(a.id, b.id)}
// ];
// const form = html`<form style="display: flex; align-items: center; min-height: 33px;"><select name=i>${options.map(o => Object.assign(html`<option>`, {textContent: o.name}))}`;
// const timeout = setTimeout(() => {
// form.i.selectedIndex = 1;
// form.dispatchEvent(new CustomEvent("input"));
// }, 2000);
// form.onchange = () => {
// form.dispatchEvent(new CustomEvent("input")); // Safari
// };
// form.oninput = (event) => {
// if (event.isTrusted) form.onchange = null, clearTimeout(timeout);
// form.value = options[form.i.selectedIndex].value;
// };
// form.value = options[form.i.selectedIndex].value;
// return form;
// }
Insert cell
swatches({ color: color_predicate })
Insert cell
chart = {

const svg = d3.select(DOM.svg(width+margin.left+margin.right,
height+margin.top+100+margin.bottom)).style("width", "100%")

// const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, 400])
.style("width", "100%")
.style("height", "680")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.attr("align", "center")
.attr("justify-content", "center")
.attr("text-anchor", "middle")
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
// .append("g")
svg.append("style").text(`

.hover path {
stroke: #ccc;
}
.hover text {
fill: #ccc;
}
.hover g.primary text {
fill: black;
font-weight: bold;
}
.hover g.secondary text {
fill: #333;
}
.hover path.primary {
stroke: #333;
stroke-opacity: 1;
}
`);

const label = svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(graph.nodes.sort(function(x, y){
return d3.ascending(x.group, y.group);
}))
.join("g")
.attr("transform", d => `translate(${margin.left},${d.y = y(d.label)})`)
.call(g => g.append("text")
.attr("x", -6)
.attr("dy", "0.35em")
.attr("fill", d => d3.lab(color(d.group)).darker(2))
.text(d => d.label))
.call(g => g.append("circle")
.attr("r",3)
.attr("fill", d => color(d.group)));


function zoomed({transform}) {
svg.attr("transform", transform);
}
const path = svg.insert("g", "*")
.attr("fill", "none")
.attr("stroke-opacity", 0.6)
.attr("stroke-width", 1.5)
.selectAll("path")
.data(graph.links)
.join("path")
.attr("stroke", d => color_predicate(d.value))
.attr("d", arc);

const nodes = svg.append("g")
// .selectAll("nodes")
.attr("fill", "none")
.attr("pointer-events", "all")
.selectAll("rect")
.data(graph.nodes.sort(function(x, y){
return d3.ascending(x.group, y.group);
}))
.attr("stroke", d => color_predicate(d.value))
.join("rect")
.attr("width", margin.left + 40)
.attr("height", step)
.attr("y", d => y(d.label) - step / 2)

nodes.on('mouseover', function(d) {
// Highlight selected node
d3.select(this).style("fill", d=>color(d.group));
// Highlight arcs
path
.style('stroke', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? d=> color(d.predicate): d=> color(d.predicate);})
.style('stroke-width', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? 4 : 1;})

label
.style("fill", function (nodeLabeld){
return nodeLabeld.id == d.id ? 'black' : 'black';})
.style('font-weight', function (nodeLabeld) {
return nodeLabeld.id == d.id ? 'bold' : 'normal';})

});
// .on("mouseover", d => {
// svg.classed("hover", true);
// label.classed("primary", n => n === d);
// label.classed("secondary", n => n.sourceLinks.some(l => l.target === d) || n.targetLinks.some(l => l.source === d));
// path.classed("primary", l => l.source === d || l.target === d).filter(".primary").raise();
// })
// .on("mouseout", d => {
// svg.classed("hover", false);
// label.classed("primary", false);
// label.classed("secondary", false);
// path.classed("primary", false).order();
// });
nodes.on('mouseout', function (d) {
nodes.style("fill", d=> color(d.group));
path.style('stroke', d=>color_predicate(d.value));
path.style('stroke-width', 1);
// actor.style('fill','white');
});


// function update() {
// y.domain(graph.nodes.sort(viewof order.value).map(d => d.label));

// const t = svg.transition()
// .duration(750);

// label.transition(t)
// .delay((d, i) => i * 20)
// .attrTween("transform", d => {
// const i = d3.interpolateNumber(d.y, y(d.label));
// return t => `translate(${margin.left},${d.y = i(t)})`;
// });

// path.transition(t)
// .duration(750 + graph.nodes.length * 20)
// .attrTween("d", d => () => arc(d));

// overlay.transition(t)
// .delay((d, i) => i * 20)
// .attr("y", d => y(d.label) - step / 2);
// }

// viewof order.addEventListener("input", update);
// invalidation.then(() => viewof order.removeEventListener("input", update));

return svg.node();
}
Insert cell
function arc(d) {
const y1 = d.source.y;
const y2 = d.target.y;
const r = Math.abs(y2 - y1) / 2;
return `M${margin.left},${y1}A${r},${r} 0,0,${y1 < y2 ? 1 : 0} ${margin.left},${y2}`;
}
Insert cell
y = d3.scalePoint(graph.nodes.map(d => d.label).sort(d3.ascending), [margin.top, height - margin.bottom])
Insert cell
margin = ({top: 10, right: 50, bottom: 10, left: 200})
Insert cell
height = (data.nodes.length - 1) * step + margin.top + margin.bottom
Insert cell
step = 14
Insert cell
color_predicate = d3.scaleOrdinal()
.domain(["Activation", "Inhibition", "IncreaseAmount", "DecreaseAmount", "Associated", "HAS_A_TRIAL"])
.range(["#d5f2bd", "#edc2bb", "#d5f2bd","#edc2bb","#f5d0b0", "#c3c3e3"]);
Insert cell
color = d3.scaleOrdinal(graph.nodes.map(d => d.group).sort(d3.ascending), d3.schemeCategory10)
Insert cell
import {swatches} from "@d3/color-legend"
Insert cell
graph = {
const nodes = data.nodes.map(({id, group, label}) => ({
id,
sourceLinks: [],
targetLinks: [],
group,
label
}));

const nodeById = new Map(nodes.map(d => [d.id, d]));

const links = data.links.map(({source, target, predicate}) => ({
source: nodeById.get(source),
target: nodeById.get(target),
value : predicate
}));

for (const link of links) {
const {source, target, value} = link;
source.sourceLinks.push(link);
target.targetLinks.push(link);
}

return {nodes, links};
}
Insert cell
data = FileAttachment("test.json").json()
Insert cell
d3 = require("d3@5")
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