Published
Edited
Aug 17, 2020
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function processNodes(data) {
let nodes = []
let ids_1 = data.map(d=>d['Source'])
let ids_2 = data.map(d=>d['Target'])
let nodeIDs = ids_1.concat(ids_2).filter(onlyUnique)
nodeIDs.sort()
nodeIDs.forEach((d,i) => {
//if(d){
let epoch = data.find(el=>el['Source'] === d | el['Target'] === d)['Time']
nodes.push({
id : d.toString(),
date: epoch,
label: d.toString()
})
//}
})
console.log(nodes)
return nodes
}
Insert cell
Insert cell
function findDegree(links) {

const linksTarget_nested = d3.nest()
.key(function (d) {
return d.target
})
.rollup(function (leaves) {
return leaves.length
})
.entries(links)

const linksSource_nested = d3.nest()
.key(function (d) {
return d.source
})
.rollup(function (leaves) {
return leaves.length
})
.entries(links)

const linksNested = []
linksTarget_nested.forEach(function (d, i) {
linksNested.push({ key: d.key, value: d.value })
})
linksSource_nested.forEach(function (d, i) {
linksNested.push({ key: d.key, value: d.value })
})

const linkAllNodes = d3.nest()
.key(function (d) {
return d.key
})
.rollup(function (leaves) {
return d3.sum(leaves, (d) => d.value)
})
.entries(linksNested)

return linkAllNodes
}
Insert cell
function onlyUnique(value, index, self) {
return self.indexOf(value) === index
}
Insert cell
Insert cell
Insert cell
Insert cell
drawGraph(template_data)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
drawGraph(graph1_data)
Insert cell
function drawGraph(raw) {

// for Observable Cell
const wrapper = html`<div style="text-align: center;"></div>`;
const container = html`<div id="container"></div>`
wrapper.appendChild(container);

const force_data = {
nodes: processNodes(raw),
edges: processLinks(raw)
}
const degreeData = findDegree(force_data.edges)

const setEdgesCurOffset = (edges, offsetDiff = 30) => {
const len = edges.length;
const edgeMap = {};
edges.forEach(edge => {
const { source, target } = edge;
let sourceTarget = `${source}-${target}`;
if (source > target) sourceTarget = `${source}-${target}`;

if (!edgeMap[sourceTarget]) {
edgeMap[sourceTarget] = []
}
edgeMap[sourceTarget].push(edge);
});


for (const key in edgeMap) {
const arcEdges = edgeMap[key];
const { length } = arcEdges;
for (let k = 0; k < length; k++) {
const current = arcEdges[k];
const sign = k % 2 === 0 ? 1 : -1;
if (length % 2 === 1) {
current.curveOffset = sign * Math.ceil(k / 2) * offsetDiff;
} else {
current.curveOffset = sign * (Math.floor((k) / 2) * offsetDiff + offsetDiff / 2);
}
delete current.groupById;
}
}
return edges;
};
// Demo Code
const graph = new G6.Graph({
// container
container,
// graph size
width: width,
height: 600,
// layout method
layout: {
type: 'force',
preventOverlap: true,
nodeStrength: -100
},
defaultNode: {
color: 'black',
style: {
fill: 'transparent',
lineWidth: 1,
}
},
defaultEdge: {
type: 'quadratic'
}
});
const data = force_data;
setEdgesCurOffset(data.edges);

const colors = [
'#BDD2FD',
'#BDEFDB',
'#C2C8D5',
'#FBE5A2',
'#F6C3B7',
'#B6E3F5',
'#D3C6EA',
'#FFD8B8',
'#AAD8D8',
'#FFD6E7',
];
const colorScale = d3.scaleOrdinal()
.domain(d3.range(0,6))
.range(colors)
const widthScale = d3.scaleSqrt()
//.domain([0,d3.max(data.edges, d=> d.weight)])
.domain([0, 150000])
.range([0.5,10])
const radiusScale = d3.scaleSqrt()
//.domain([0,d3.max(degreeData, d=> d.value)])
.domain([0, 220])
.range([1,55])
// process data
data.edges.forEach(function(edge) {
edge.color = colorScale(edge.type)
edge.size = edge.weight < 0 ? 1 : widthScale(edge.weight)
});
data.nodes.forEach(function(node) {
let degree = degreeData.find(d=>d.key === node.id).value
node.size = radiusScale(degree)
if (!node.labelCfg) {
node.labelCfg =
{
style: {
fill: '#000',
fontSize: 8,
}
}
}
if(degree < 50){
node.labelCfg.position = "bottom",
node.labelCfg.offset = 2
} else {
node.labelCfg.position = "center",
node.labelCfg.offset = 0
}
});

// load data
graph.data({
nodes: data.nodes,
edges: data.edges
});
// render
graph.render();

// interactions
graph.on('node:dragstart', function(e) {
graph.layout();
refreshDragedNodePosition(e);
});
graph.on('node:drag', function(e) {
refreshDragedNodePosition(e);
});
graph.on('node:dragend', function(e) {
e.item.get('model').fx = null;
e.item.get('model').fy = null;
});

function refreshDragedNodePosition(e) {
const model = e.item.get('model');
model.fx = e.x;
model.fy = e.y;
}
return wrapper
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more