Public
Edited
Jan 20, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
setup = {
const margin = { top: 10, right: 250, bottom: 10, left: 300 }
const leafSet = new Set();
graph.links.map(d => leafSet.add(d.source));
const nodeIds = Array.from(leafSet);
const parentSet = new Set();
graph.links.map(d => parentSet.add(d.target));
const parentIds = Array.from(parentSet);

const height = nodeIds.length * 10
const width = 200
const y1 = d3
.scaleBand()
.domain(parentIds)
.range([0, height]),
y2 = d3
.scaleBand()
.domain(nodeIds)
.range([0, height]),
axis1 = d3.axisLeft(y1)
.tickFormat(function(d) {
return graph.nodes[d].name;
}),
axis2 = d3.axisRight(y2)
.tickFormat(function(d) {
return graph.nodes[d].name;
}),
link = d3.linkHorizontal();
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

const g = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

const gAxisLeft = g
.append("g")
.call(axis1);

const gAxisRight = g
.append("g")
.attr("transform", "translate(" + width + ",0)")
.call(axis2);

const matrix = graph.links
.flatMap(({ source, target, value }) => [
[source, target, value]
]);

const edges = g
.append("g")
.selectAll("path")
.data(matrix)
.join("path")
.attr("d", d => (link({
source: [0, y1(d[1]) + y1.bandwidth()/2],
target: [width, y2(d[0]) + y2.bandwidth()/2]
})))
.attr("fill","none")
.attr("stroke","black")
let prev;
update(graph.nodes.map(d => +d.id));

function update(permutation) {
y1.domain(permutation.filter(function(d) {return parentSet.has(d)}));
y2.domain(permutation.filter(function(d) {return leafSet.has(d)}));

const duration = 1000

gAxisLeft
.transition()
.duration(duration)
.call(axis1)
gAxisRight
.transition()
.duration(duration)
.call(axis2)
edges
.transition()
.duration(duration)
.attr("d", d => (link({
source: [0, y1(d[1]) + y1.bandwidth()/2],
target: [width, y2(d[0]) + y2.bandwidth()/2]
})))

prev = permutation;
return permutation;
}

return Object.assign(svg.node(), { update });
}
Insert cell
current = setup.update(permutations[sorting]())
Insert cell
Insert cell
permutations = orders(graph, {distance})
Insert cell
orders = ({ nodes, links }, { distance = "manhattan" }) => {
const n = nodes.length;

const graph = reorder.graph().nodes(nodes).links(links).init();

let dist_adjacency;

const leafOrder = reorder
.optimal_leaf_order()
.distance(reorder.distance[distance]);

function computeLeaforder() {
const adjacency = reorder.graph2mat(graph);
return leafOrder(adjacency);
}

function computeLeaforderDist() {
if (!dist_adjacency) dist_adjacency = reorder.graph2valuemats(graph);
return reorder.valuemats_reorder(dist_adjacency, leafOrder);
}

function computeBarycenter() {
const barycenter = reorder.barycenter_order(graph);
return reorder.adjacent_exchange(graph, ...barycenter);
}

function computeRCM() {
return reorder.reverse_cuthill_mckee_order(graph);
}

function computeSpectral() {
return reorder.spectral_order(graph);
}

const orders = {
none: () => d3.range(n),
name: () =>
d3.range(n).sort((a, b) => d3.ascending(nodes[a].name, nodes[b].name)),
count: () => d3.range(n).sort((a, b) => nodes[b].count - nodes[a].count),
group: () =>
d3
.range(n)
.sort(
(a, b) =>
d3.ascending(nodes[a].group, nodes[b].group) ||
d3.ascending(nodes[a].name, nodes[b].name)
),
leafOrder: computeLeaforder,
//leafOrderDist: computeLeaforderDist,
//barycenter: computeBarycenter,
rcm: computeRCM,
spectral: computeSpectral
};

return orders;
}
Insert cell
orderingsOptions = [
"none",
"name",
"count",
"group",
"leafOrder",
//"leafOrderDist",
//"barycenter",
"rcm",
"spectral"
]
Insert cell
distanceOptions = ({
euclidean: "Euclidean (L2)",
manhattan: "Manhattan (L1)",
minkowski: "Minkowski",
chebyshev: "Chebyshev",
hamming: "Hamming",
jaccard: "Jaccard",
braycurtis: "Braycurtis"
})
Insert cell
reorder = require("reorder.js@2.2.4")
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