Combine force directed graph with donut chart D3JS - d3.js

i want to combine two charts together.
First force directed graph with donut chart. Every node in force directed graph after clik will show context menu by donut chart. I prepared two charts, but I do not know how to combine them.
Code for force directed:
// Graph 2 - context menu donut chart
var dataset = [
{
size: 2,
label: "Item 1"
},
{
size: 1,
label: "Item 2"
},
{
size: 65,
label: "Item 3"
},
{
size: 45,
label: "Item 4"
},
{
size: 50,
label: "Item 5"
}
];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return Object.keys(dataset).length; }); // zde je nutné zadat celkovou populaci - početz prvků v
// Menu
// Arc setting
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
// Graph space
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Prepare graph and load data
var g = svg.selectAll(".arc")
.data(pie(dataset))
.enter().append("g")
.attr("class", "arc");
// Add colors
var path = g.append("path")
.attr("d", arc)
.attr("fill", function (d) { return color(d.data.size);})
// Add labels
var asdfd = g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.data.label; });
var oldColor;
// Add hover action
path.on("mouseenter", function(d,i) {
console.log("mousein"+ d.data.label)
var thisPath = d3.select(this);
oldColor = thisPath.attr("fill"); // save old color
thisPath
.attr("fill", "blue")
.attr("cursor", "pointer")
.attr("class", "on");
})
path.on("mouseout", function(d) {
d3.select(this)
.attr("fill", oldColor)
.attr("class", "off");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Result of combination should be like on this picture:
Thank you for yor ideas!
EDIT: I maybe solve this, buth there is some small performace problem, can anyone help me how to finish this, graph is lagging, and I have problem with arrow between nodes. Thnaks for help !
var json = {
"nodes": [{
"id": -1146034065,
"name": "/",
"group": 0
}, {
"id": -990073683,
"name": "/blog/",
"group": 0
}, {
"id": -1724280020,
"name": "/menu/",
"group": 0
}, {
"id": 1176095248,
"name": "/napojovy-listek/",
"group": 0
}, {
"id": -2085082741,
"name": "/fotogalerie/",
"group": 0
}, {
"id": 883542796,
"name": "/rezervace/",
"group": 0
}, {
"id": 369131020,
"name": "/kontakt/",
"group": 0
}, {
"id": -1276353015,
"name": "/en/",
"group": 0
}, {
"id": -1557747058,
"name": "/o-nas/",
"group": 404
}, {
"id": 890427810,
"name": "/en/about-us/",
"group": 0
}, {
"id": -978700858,
"name": "/en/menu-2/",
"group": 0
}, {
"id": 1436673749,
"name": "/en/napojovy-listek/",
"group": 0
}, {
"id": -489730654,
"name": "/en/photograph/",
"group": 0
}, {
"id": -1461616187,
"name": "/en/reservation/",
"group": 0
}, {
"id": 1520755615,
"name": "/en/contact/",
"group": 0
}, {
"id": 37644686,
"name": "/en//kontakt/",
"group": 0
}, {
"id": 1131720527,
"name": "/en//o-nas/",
"group": 404
}],
"links": [{
"source": -990073683,
"target": -1146034065,
"value": 1
}, {
"source": -1724280020,
"target": -1146034065,
"value": 1
}, {
"source": 1176095248,
"target": -1146034065,
"value": 1
}, {
"source": -2085082741,
"target": -1146034065,
"value": 1
}, {
"source": 883542796,
"target": -1146034065,
"value": 1
}, {
"source": 369131020,
"target": -1146034065,
"value": 1
}, {
"source": -1276353015,
"target": -1146034065,
"value": 1
}, {
"source": -1557747058,
"target": -1146034065,
"value": 1
}, {
"source": 890427810,
"target": -990073683,
"value": 1
}, {
"source": -978700858,
"target": -1724280020,
"value": 1
}, {
"source": 1436673749,
"target": 1176095248,
"value": 1
}, {
"source": -489730654,
"target": -2085082741,
"value": 1
}, {
"source": -1461616187,
"target": 883542796,
"value": 1
}, {
"source": 1520755615,
"target": 369131020,
"value": 1
}, {
"source": 37644686,
"target": -1276353015,
"value": 1
}, {
"source": 1131720527,
"target": -1276353015,
"value": 1
}, {
"source": -1146034065,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": -1146034065,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": -1146034065,
"target": -1724280020,
"count": 3,
"value": 1
}, {
"source": -1146034065,
"target": 1176095248,
"count": 3,
"value": 1
}, {
"source": -1146034065,
"target": -2085082741,
"count": 3,
"value": 1
}, {
"source": -1146034065,
"target": 883542796,
"count": 3,
"value": 1
}, {
"source": -1146034065,
"target": 369131020,
"count": 3,
"value": 1
}, {
"source": -1146034065,
"target": -1276353015,
"count": 1,
"value": 1
}, {
"source": -1146034065,
"target": -1557747058,
"count": 2,
"value": 1
}, {
"source": -990073683,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": -2085082741,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": 883542796,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": 369131020,
"count": 1,
"value": 1
}, {
"source": -990073683,
"target": 890427810,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": -2085082741,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": 883542796,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": 369131020,
"count": 1,
"value": 1
}, {
"source": -1724280020,
"target": -978700858,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": -2085082741,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": 883542796,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": 369131020,
"count": 1,
"value": 1
}, {
"source": 1176095248,
"target": 1436673749,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": -2085082741,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": 883542796,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": 369131020,
"count": 1,
"value": 1
}, {
"source": -2085082741,
"target": -489730654,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": -2085082741,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": 883542796,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": 369131020,
"count": 1,
"value": 1
}, {
"source": 883542796,
"target": -1461616187,
"count": 1,
"value": 1
}, {
"source": 369131020,
"target": -1146034065,
"count": 1,
"value": 1
}, {
"source": 369131020,
"target": -990073683,
"count": 1,
"value": 1
}, {
"source": 369131020,
"target": -1724280020,
"count": 1,
"value": 1
}, {
"source": 369131020,
"target": 1176095248,
"count": 1,
"value": 1
}, {
"source": 369131020,
"target": -2085082741,
"count": 1,
"value": 1
}
]
}
var width = 960,
height = 700
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["a"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");
var edges = [];
var fill = d3.scale.category10();
json.links.forEach(function (e) {
// Get the source and target nodes
var sourceNode = json.nodes.filter(function (n) {
return n.id === e.source;
})[0],
targetNode = json.nodes.filter(function (n) {
return n.id === e.target;
})[0],
count = e.count;
// Add the edge to the array
edges.push({
source: sourceNode,
target: targetNode,
count: count,
type: "a"
});
});
var force = d3.layout.force()
.gravity(0.01)
.distance(500)
.charge(-300)
.linkDistance(300)
.size([width, height])
.nodes(json.nodes)
.links(edges)
.start();
var link = svg.append("g").selectAll("link")
.data(edges)
.enter().append("path")
.attr("class", "link")
//.attr("marker-end", function(d) { return "url(#" + d.targetNode + ")"; })
.style("stroke-width", function (d) {
return Math.sqrt(d.count * 1, 5);
});
// Přidáme k uzlu kontextové menu a zvýrazníme sousedy
var node = svg.selectAll("node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.style("fill", function (d) {
return fill(d.group);
})
.call(force.drag).on("mouseover", fade(.1)).on("mouseout", fade(1))
.on("click", function (d, i) {
svg.selectAll(".node").style("fill", function (d) { return fill(d.group);});
d3.select(".menu").remove();
var thisNode = d3.select(this);
thisNode.attr('r', 25).style("fill", "lightcoral");
var menuDataSet = [{
size: 2,
label: "Item 1"
}, {
size: 1,
label: "Item 2"
}, {
size: 65,
label: "Item 3"
}, {
size: 45,
label: "Item 4"
}, {
size: 50,
label: "Item 5"
}];
// Barvy menu
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return Object.keys(menuDataSet).length;
}); // zde je nutné zadat celkovou populaci - početz prvků v
// Menu
var widthMenu = 180,
heightMenu = 180,
radiusMenu = Math.min(widthMenu, heightMenu) / 2;
// Arc setting
var arc = d3.svg.arc()
.innerRadius(radiusMenu - 70)
.outerRadius(radiusMenu - 25);
// Graph space
var svgMenu = thisNode.append("svg")
.attr("width", widthMenu)
.attr("height", heightMenu)
.attr("class","menu")
.attr("x", -90)
.attr("y", -90)
.append("g")
.attr("transform", "translate(" + widthMenu / 2 + "," + heightMenu / 2 + ")");
// Prepare graph and load data
var g = svgMenu.selectAll(".arc")
.data(pie(menuDataSet))
.enter().append("g")
.attr("class", "arc");
// Add colors
var path = g.append("path")
.attr("d", arc)
.attr("fill", function (d) {
return color(d.data.size);
})
// Add labels
var asdfd = g.append("text")
.attr("transform", function (d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function (d) {
return d.data.label;
});
// Add hover action
path.on("mouseenter", function (d, i) {
var thisPath = d3.select(this);
thisPath.attr("fill", "blue")
.attr("cursor", "pointer")
.attr("class", "on");
})
path.on("mouseout", function (d) {
d3.select(this)
.attr("fill", function (d) {
return color(d.data.size);
})
.attr("class", "off");
});
});
/*
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
*/
node.append("circle").attr("r", 10);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function (d) {
return d.name
});
// přidá popisky k hranám
var labels = svg.selectAll('text')
.data(edges)
.enter().append('text')
.attr("x", function (d) {
return (d.source.y + d.target.y) / 2;
})
.attr("y", function (d) {
return (d.source.x + d.target.x) / 2;
})
.attr("text-anchor", "middle")
.text(function (d) {
return d.count;
});
force.on("tick", function () {
link.attr("d", function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}
);
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
labels.attr("x", function (d) {
return (d.source.x + d.target.x + 10) / 2;
})
.attr("y", function (d) {
return (d.source.y + d.target.y + 10) / 2;
})
});
function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}
var linkedByIndex = {};
edges.forEach(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}
function fade(opacity) {
return function (d) {
// přidá popisky k hranám
var labels = svg.selectAll('text')
.data(edges)
.enter().append('text')
.attr("x", function (o) {
return (o.source.y + o.target.y) / 2;
})
.attr("y", function (o) {
return (o.source.x + o.target.x) / 2;
})
.attr("text-anchor", "middle")
.text(function (o) {
return o.count;
});
node.style("stroke-opacity", function (o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style("stroke-opacity", function (o) {
return o.source === d || o.target === d ? 1 : opacity;
});
};
}
body {
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
stroke-dasharray: 0,4 1;
}
text {
font: 10px sans-serif;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Related

d3.js - force layout not show nodes and links

Below example converted from this v3 version, it try to use force layout to draw some nodes and links, but it can not show the nodes or links!
console.log("--------")
console.clear();
var w = 600,
h = 600,
nodeCircles,
linkLines,
root;
var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(w / 2, h / 2))
.on('tick',tick)
var zoomer = d3.zoom()
.scaleExtent([0.9,3])
.on("zoom", zoom);
function zoom(event) {
vis.attr("transform",
"translate(" + event.translate + ")"
+ " scale(" + event.scale + ")" );
}
var graph = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("class", "graph")
.call(zoomer);
var rect = graph.append("rect")
.attr("width", w)
.attr("height", h)
.attr('fill','none')
.attr('stroke','black')
.style("pointer-events", "all");
var vis = graph.append("svg:g")
.attr("class", "plotting-area");
function update() {
var nodes = d3.hierarchy(root)
const links = d3.tree()
.size([h, w])(nodes)
.links();
nodes = flatten(root)
force
.nodes(nodes)
.on("tick", tick);
force.force("link")
.links(links);
// Update the links…
linkLines = vis.selectAll("line.link")
.data(links, function (d) {
return d.target.index;
});
linkLines.enter().insert("svg:line", ".node")
.attr("class", "link")
.attr('stroke','black')
linkLines.exit().remove();
nodeCircles = vis.selectAll("circle.node")
.data(nodes, function (d) {
return d.id;
})
.attr("fill", color)
.attr('stroke','black')
nodeCircles.enter().append("svg:circle")
.attr("class", "node")
.attr("r", function (d) {
return d.children ? 4.5 : Math.sqrt(d.size) / 10;
})
.style("fill", color);
nodeCircles.exit().remove();
}
function color(d) {
return d.children ? "#c6dbef" : d.group;
}
function tick() {
linkLines.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
nodeCircles.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
}
function readfile(json) {
root = json;
root.fixed = true;
root.x = w / 2;
root.y = h/2;
update();
};
function flatten(root) {
var nodes = [],
i = 0;
function recurse(node) {
if (node.children) node.size = node.children.reduce(function (p, v) {
return p + recurse(v);
}, 0);
if (!node.id) node.id = ++i;
nodes.push(node);
return node.size;
}
root.size = recurse(root);
return nodes;
}
var data = {
"dist": 0.00193506541936,
"name": "N3",
"children": [ {
"dist": 0.00488832259274,
"name": "N4",
"children": [ {
"dist": 0.00421186204991,
"name": "N5",
"children": [ {
"dist": 0.0163437491651,
"name": "N6",
"children": [{
"dist": 0.417946674158,
"group": "blue",
"name": "CHEMBL1644419",
"size": 2000.0000000000866
}, {
"dist": 0.00543077796308,
"name": "N8",
"children": [{
"dist": 0.0297671023157,
"name": "N9",
"children": [{
"dist": 0.359033872667,
"group": "red",
"name": "ASD03540222",
"size": 2000.0000000000866
}, {
"dist": 0.362485114675,
"group": "red",
"name": "ASD01150858",
"size": 2000.0000000000866
}]
},{
"dist": 0.0224504491652,
"name": "N12",
"children": [{
"dist": 0.00178517153851,
"name": "N13",
"children": [{
"dist": 0.364388220986,
"group": "blue",
"name": "CHEMBL197161",
"size": 2000.0000000000866
}, {
"dist": 0.0425243314393,
"name": "N15",
"children": [{
"dist": 0.336193167816,
"group": "blue",
"name": "CHEMBL1644268",
"size": 2000.0000000000866
}, {
"dist": 0.325677335782,
"group": "red",
"name": "CHEMBL593637",
"size": 2000.0000000000866
}]
}]
}, {
"dist": 0.0246952948163,
"name": "N18",
"children": [{
"dist": 0.358771918732,
"group": "blue",
"name": "CHEMBL569878",
"size": 2000.0000000000866
}, {
"dist": 0.36317930078,
"group": "blue",
"name": "CHEMBL434267",
"size": 2000.0000000000866
}]
}]
}]
}]
}, {
"dist": 0.00389420127272,
"name": "N21",
"children": [{
"dist": 0.010842478752,
"name": "N22",
"children": [{
"dist": 0.415105380276,
"group": "blue",
"name": "CHEMBL1275732",
"size": 2000.0000000000866
}, {
"dist": 0.0337121910412,
"name": "N24",
"children": [{
"dist": 0.0664262587727,
"name": "N25",
"children": [{
"dist": 0.315587114957,
"group": "red",
"name": "ASD00170175",
"size": 2000.0000000000866
}, {
"dist": 0.310918909139,
"group": "red",
"name": "CHEMBL292368",
"size": 2000.0000000000866
}]
}, {
"dist": 0.376684365543,
"group": "red",
"name": "ASD00170052",
"size": 2000.0000000000866
}]
}]
}, {
"dist": 0.00704072756384,
"name": "N29",
"children": [{
"dist": 0.0103358142929,
"name": "N30",
"children": [{
"dist": 0.412662682696,
"group": "blue",
"name": "CHEMBL14370",
"size": 2000.0000000000866
}, {
"dist": 0.427337317304,
"group": "blue",
"name": "CHEMBL94700",
"size": 2000.0000000000866
}]
}, {
"dist": 0.0142382687979,
"name": "N33",
"children": [{
"dist": 0.403816741996,
"group": "blue",
"name": "CHEMBL545557",
"size": 2000.0000000000866
}, {
"dist": 0.0752386947609,
"name": "N35",
"children": [{
"dist": 0.316746014667,
"group": "blue",
"name": "CHEMBL506342",
"size": 2000.0000000000866
}, {
"dist": 0.314832932701,
"group": "red",
"name": "CHEMBL1256402",
"size": 2000.0000000000866
}]
}]
}]
}]
} ]
}]
} ] };
readfile(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>

Fixing the axis-scale range that is presented

I have an value that is the count of total minutes that I am presenting within my time series. While the minutes are used for plotting, I would like to change the axis tick labels to present the hours that this data fits closest to. The way I approached this was to add a .tickFormat() that converts the minutes to hours and then return d3.timeFormat() with the hour format and a new date set to 0 that is set with the hours. While the axis tick labels are close, they aren't correct. There seems to be a slight offset, duplication of values and the scale not starting at 0 (Starts at 12). Should I use a different function call to correct the scale?.
This is the code in question:
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
console.log(hours)
console.log(new Date(0).setMinutes(hours))
return d3.timeFormat("%I")( new Date(0).setHours(hours))
}));
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script>
var data = [
{ "x": "2020-04-26", "y": 461.0, "label": "7:41" },
{ "x": "2020-04-27", "y": 421.0, "label": "7:01" },
{ "x": "2020-04-28", "y": 519.0, "label": "8:39" },
{ "x": "2020-04-29", "y": 502.0, "label": "8:22" },
{ "x": "2020-04-30", "y": 511.0, "label": "8:31" },
{ "x": "2020-05-01", "y": 513.0, "label": "8:33" },
{ "x": "2020-05-02", "y": 496.0, "label": "8:16" },
{ "x": "2020-05-03", "y": 480.0, "label": "8:00" },
{ "x": "2020-05-04", "y": 364.0, "label": "6:04" },
{ "x": "2020-05-05", "y": 498.0, "label": "8:18" },
{ "x": "2020-05-06", "y": 467.0, "label": "7:47" },
{ "x": "2020-05-07", "y": 477.0, "label": "7:57" },
{ "x": "2020-05-08", "y": 431.0, "label": "7:11" },
{ "x": "2020-05-09", "y": 419.0, "label": "6:59" },
{ "x": "2020-05-10", "y": 471.0, "label": "7:51" },
{ "x": "2020-05-11", "y": 391.0, "label": "6:31" },
{ "x": "2020-05-12", "y": 481.0, "label": "8:01" },
{ "x": "2020-05-13", "y": 494.0, "label": "8:14" },
{ "x": "2020-05-14", "y": 506.0, "label": "8:26" },
{ "x": "2020-05-15", "y": 464.0, "label": "7:44" },
{ "x": "2020-05-16", "y": 474.0, "label": "7:54" },
{ "x": "2020-05-17", "y": 383.0, "label": "6:23" },
{ "x": "2020-05-18", "y": 385.0, "label": "6:25" },
{ "x": "2020-05-19", "y": 470.0, "label": "7:50" },
{ "x": "2020-05-20", "y": 465.0, "label": "7:45" },
{ "x": "2020-05-21", "y": 574.0, "label": "9:34" },
{ "x": "2020-05-22", "y": 473.0, "label": "7:53" },
{ "x": "2020-05-23", "y": 431.0, "label": "7:11" },
{ "x": "2020-05-24", "y": 497.0, "label": "8:17" },
{ "x": "2020-05-26", "y": 482.0, "label": "8:02" },
{ "x": "2020-05-27", "y": 492.0, "label": "8:12" },
{ "x": "2020-05-28", "y": 494.0, "label": "8:14" },
{ "x": "2020-05-29", "y": 469.0, "label": "7:49" },
{ "x": "2020-05-30", "y": 395.0, "label": "6:35" },
{ "x": "2020-05-31", "y": 427.0, "label": "7:07" },
{ "x": "2020-06-01", "y": 346.0, "label": "5:46" },
{ "x": "2020-06-02", "y": 416.0, "label": "6:56" },
{ "x": "2020-06-03", "y": 461.0, "label": "7:41" },
{ "x": "2020-06-04", "y": 486.0, "label": "8:06" },
{ "x": "2020-06-05", "y": 451.0, "label": "7:31" },
{ "x": "2020-06-06", "y": 533.0, "label": "8:53" },
{ "x": "2020-06-08", "y": 462.0, "label": "7:42" },
{ "x": "2020-06-09", "y": 461.0, "label": "7:41" },
{ "x": "2020-06-10", "y": 477.0, "label": "7:57" },
{ "x": "2020-06-11", "y": 458.0, "label": "7:38" },
{ "x": "2020-06-12", "y": 484.0, "label": "8:04" },
{ "x": "2020-06-13", "y": 389.0, "label": "6:29" },
{ "x": "2020-06-15", "y": 472.0, "label": "7:52" },
{ "x": "2020-06-16", "y": 462.0, "label": "7:42" },
{ "x": "2020-06-17", "y": 486.0, "label": "8:06" },
{ "x": "2020-06-18", "y": 489.0, "label": "8:09" },
{ "x": "2020-06-19", "y": 483.0, "label": "8:03" },
{ "x": "2020-06-20", "y": 426.0, "label": "7:06" },
{ "x": "2020-06-21", "y": 453.0, "label": "7:33" },
{ "x": "2020-06-22", "y": 489.0, "label": "8:09" },
{ "x": "2020-06-23", "y": 467.0, "label": "7:47" },
{ "x": "2020-06-24", "y": 474.0, "label": "7:54" },
{ "x": "2020-06-25", "y": 451.0, "label": "7:31" },
{ "x": "2020-06-26", "y": 450.0, "label": "7:30" },
{ "x": "2020-06-27", "y": 470.0, "label": "7:50" },
{ "x": "2020-06-29", "y": 247.0, "label": "4:07" },
{ "x": "2020-06-30", "y": 502.0, "label": "8:22" },
{ "x": "2020-07-01", "y": 464.0, "label": "7:44" }
]
// D3 date parser
for (var i=0; i < data.length; i++){
var parser = d3.timeParse("%Y-%m-%d")
data[i].date = parser(data[i].x);
}
var margin = { top: 10, right: 30, bottom: 30, left: 60 }
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr( 'preserveAspectRatio',"xMinYMin meet")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // translate(margin left, margin top)
var x = d3.scaleTime()
.domain([d3.min(data, function(d) { return d.date }), d3.max(data, function(d) { return d.date })])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," + (height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d){ return +d.y })])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
console.log(hours)
console.log(new Date(0).setMinutes(hours))
return d3.timeFormat("%I")( new Date(0).setHours(hours))
}));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Asleep (Minutes)");
// Add line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.y) })
);
// Add the scatterplot (data points)
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.delay(function(d,i){ return (i*3)})
.duration(2000)
.attr("cx", function(d){ return x(d.date) })
.attr("cy", function(d){ return y(d.y) });
</script>
While your data is a time, it's not a date. Forcing it to be a date will give you many nasty complications. I just surpassed the d3 and Date logic, leading to a simpler solution:
var data = [{
"x": "2020-04-26",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-04-27",
"y": 421.0,
"label": "7:01"
},
{
"x": "2020-04-28",
"y": 519.0,
"label": "8:39"
},
{
"x": "2020-04-29",
"y": 502.0,
"label": "8:22"
},
{
"x": "2020-04-30",
"y": 511.0,
"label": "8:31"
},
{
"x": "2020-05-01",
"y": 513.0,
"label": "8:33"
},
{
"x": "2020-05-02",
"y": 496.0,
"label": "8:16"
},
{
"x": "2020-05-03",
"y": 480.0,
"label": "8:00"
},
{
"x": "2020-05-04",
"y": 364.0,
"label": "6:04"
},
{
"x": "2020-05-05",
"y": 498.0,
"label": "8:18"
},
{
"x": "2020-05-06",
"y": 467.0,
"label": "7:47"
},
{
"x": "2020-05-07",
"y": 477.0,
"label": "7:57"
},
{
"x": "2020-05-08",
"y": 431.0,
"label": "7:11"
},
{
"x": "2020-05-09",
"y": 419.0,
"label": "6:59"
},
{
"x": "2020-05-10",
"y": 471.0,
"label": "7:51"
},
{
"x": "2020-05-11",
"y": 391.0,
"label": "6:31"
},
{
"x": "2020-05-12",
"y": 481.0,
"label": "8:01"
},
{
"x": "2020-05-13",
"y": 494.0,
"label": "8:14"
},
{
"x": "2020-05-14",
"y": 506.0,
"label": "8:26"
},
{
"x": "2020-05-15",
"y": 464.0,
"label": "7:44"
},
{
"x": "2020-05-16",
"y": 474.0,
"label": "7:54"
},
{
"x": "2020-05-17",
"y": 383.0,
"label": "6:23"
},
{
"x": "2020-05-18",
"y": 385.0,
"label": "6:25"
},
{
"x": "2020-05-19",
"y": 470.0,
"label": "7:50"
},
{
"x": "2020-05-20",
"y": 465.0,
"label": "7:45"
},
{
"x": "2020-05-21",
"y": 574.0,
"label": "9:34"
},
{
"x": "2020-05-22",
"y": 473.0,
"label": "7:53"
},
{
"x": "2020-05-23",
"y": 431.0,
"label": "7:11"
},
{
"x": "2020-05-24",
"y": 497.0,
"label": "8:17"
},
{
"x": "2020-05-26",
"y": 482.0,
"label": "8:02"
},
{
"x": "2020-05-27",
"y": 492.0,
"label": "8:12"
},
{
"x": "2020-05-28",
"y": 494.0,
"label": "8:14"
},
{
"x": "2020-05-29",
"y": 469.0,
"label": "7:49"
},
{
"x": "2020-05-30",
"y": 395.0,
"label": "6:35"
},
{
"x": "2020-05-31",
"y": 427.0,
"label": "7:07"
},
{
"x": "2020-06-01",
"y": 346.0,
"label": "5:46"
},
{
"x": "2020-06-02",
"y": 416.0,
"label": "6:56"
},
{
"x": "2020-06-03",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-06-04",
"y": 486.0,
"label": "8:06"
},
{
"x": "2020-06-05",
"y": 451.0,
"label": "7:31"
},
{
"x": "2020-06-06",
"y": 533.0,
"label": "8:53"
},
{
"x": "2020-06-08",
"y": 462.0,
"label": "7:42"
},
{
"x": "2020-06-09",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-06-10",
"y": 477.0,
"label": "7:57"
},
{
"x": "2020-06-11",
"y": 458.0,
"label": "7:38"
},
{
"x": "2020-06-12",
"y": 484.0,
"label": "8:04"
},
{
"x": "2020-06-13",
"y": 389.0,
"label": "6:29"
},
{
"x": "2020-06-15",
"y": 472.0,
"label": "7:52"
},
{
"x": "2020-06-16",
"y": 462.0,
"label": "7:42"
},
{
"x": "2020-06-17",
"y": 486.0,
"label": "8:06"
},
{
"x": "2020-06-18",
"y": 489.0,
"label": "8:09"
},
{
"x": "2020-06-19",
"y": 483.0,
"label": "8:03"
},
{
"x": "2020-06-20",
"y": 426.0,
"label": "7:06"
},
{
"x": "2020-06-21",
"y": 453.0,
"label": "7:33"
},
{
"x": "2020-06-22",
"y": 489.0,
"label": "8:09"
},
{
"x": "2020-06-23",
"y": 467.0,
"label": "7:47"
},
{
"x": "2020-06-24",
"y": 474.0,
"label": "7:54"
},
{
"x": "2020-06-25",
"y": 451.0,
"label": "7:31"
},
{
"x": "2020-06-26",
"y": 450.0,
"label": "7:30"
},
{
"x": "2020-06-27",
"y": 470.0,
"label": "7:50"
},
{
"x": "2020-06-29",
"y": 247.0,
"label": "4:07"
},
{
"x": "2020-06-30",
"y": 502.0,
"label": "8:22"
},
{
"x": "2020-07-01",
"y": 464.0,
"label": "7:44"
}
]
// D3 date parser
for (var i = 0; i < data.length; i++) {
var parser = d3.timeParse("%Y-%m-%d")
data[i].date = parser(data[i].x);
}
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
}
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr('preserveAspectRatio', "xMinYMin meet")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // translate(margin left, margin top)
var x = d3.scaleTime()
.domain([d3.min(data, function(d) {
return d.date
}), d3.max(data, function(d) {
return d.date
})])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," + (height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return +d.y
})])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
var minutes = d - hours * 60;
return hours.toString().padStart(2, 0) + ":" + minutes.toString().padStart(2, 0).padStart(2, 0);
}));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Asleep (Minutes)");
// Add line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) {
return x(d.date)
})
.y(function(d) {
return y(d.y)
})
);
// Add the scatterplot (data points)
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.delay(function(d, i) {
return (i * 3)
})
.duration(2000)
.attr("cx", function(d) {
return x(d.date)
})
.attr("cy", function(d) {
return y(d.y)
});
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

D3 axis incorrect

Adopting this example, I get an axis that is incorrect. The axis shows labels for 50 000, 00 000, 50 000, etc, but my data is from 0 - 513836. This is what the axis looks like:
Here's my code and data:
data = [{
"value": "478176",
"date": "2020-06-28"
}, {
"value": "478278",
"date": "2020-06-29"
}, {
"value": "478559",
"date": "2020-06-30"
}, {
"value": "478559",
"date": "2020-07-01"
}, {
"value": "479175",
"date": "2020-07-02"
}, {
"value": "479175",
"date": "2020-07-03"
}, {
"value": "479175",
"date": "2020-07-04"
}, {
"value": "479379",
"date": "2020-07-05"
}, {
"value": "479633",
"date": "2020-07-06"
}, {
"value": "480010",
"date": "2020-07-07"
}, {
"value": "480531",
"date": "2020-07-08"
}, {
"value": "480794",
"date": "2020-07-09"
}, {
"value": "480794",
"date": "2020-07-10"
}, {
"value": "480794",
"date": "2020-07-11"
}, {
"value": "480995",
"date": "2020-07-12"
}, {
"value": "481161",
"date": "2020-07-13"
}, {
"value": "481161",
"date": "2020-07-14"
}, {
"value": "481934",
"date": "2020-07-15"
}, {
"value": "482218",
"date": "2020-07-16"
}, {
"value": "482218",
"date": "2020-07-17"
}, {
"value": "482218",
"date": "2020-07-18"
}, {
"value": "482851",
"date": "2020-07-19"
}, {
"value": "483331",
"date": "2020-07-20"
}, {
"value": "484302",
"date": "2020-07-21"
}, {
"value": "484569",
"date": "2020-07-22"
}, {
"value": "484734",
"date": "2020-07-23"
}, {
"value": "484734",
"date": "2020-07-24"
}, {
"value": "484734",
"date": "2020-07-25"
}, {
"value": "485123",
"date": "2020-07-26"
}, {
"value": "485597",
"date": "2020-07-27"
}, {
"value": "486763",
"date": "2020-07-28"
}, {
"value": "487392",
"date": "2020-07-29"
}, {
"value": "487392",
"date": "2020-07-30"
}, {
"value": "487392",
"date": "2020-07-31"
}, {
"value": "487392",
"date": "2020-08-01"
}, {
"value": "487392",
"date": "2020-08-02"
}, {
"value": "487909",
"date": "2020-08-03"
}, {
"value": "488496",
"date": "2020-08-04"
}, {
"value": "488496",
"date": "2020-08-05"
}, {
"value": "490538",
"date": "2020-08-06"
}, {
"value": "490538",
"date": "2020-08-07"
}, {
"value": "490538",
"date": "2020-08-08"
}, {
"value": "491490",
"date": "2020-08-09"
}, {
"value": "492511",
"date": "2020-08-10"
}, {
"value": "494185",
"date": "2020-08-11"
}, {
"value": "494730",
"date": "2020-08-12"
}, {
"value": "495052",
"date": "2020-08-14"
}, {
"value": "495052",
"date": "2020-08-15"
}, {
"value": "495610",
"date": "2020-08-16"
}, {
"value": "496394",
"date": "2020-08-17"
}, {
"value": "496394",
"date": "2020-08-18"
}, {
"value": "498006",
"date": "2020-08-19"
}, {
"value": "498631",
"date": "2020-08-20"
}, {
"value": "498631",
"date": "2020-08-21"
}, {
"value": "498631",
"date": "2020-08-22"
}, {
"value": "499186",
"date": "2020-08-23"
}, {
"value": "499561",
"date": "2020-08-24"
}, {
"value": "500491",
"date": "2020-08-25"
}, {
"value": "500491",
"date": "2020-08-26"
}, {
"value": "501295",
"date": "2020-08-27"
}, {
"value": "501295",
"date": "2020-08-28"
}, {
"value": "501295",
"date": "2020-08-29"
}, {
"value": "501748",
"date": "2020-08-30"
}, {
"value": "502284",
"date": "2020-08-31"
}, {
"value": "503353",
"date": "2020-09-01"
}, {
"value": "503719",
"date": "2020-09-02"
}, {
"value": "504046",
"date": "2020-09-03"
}, {
"value": "504046",
"date": "2020-09-04"
}, {
"value": "504046",
"date": "2020-09-05"
}, {
"value": "504204",
"date": "2020-09-06"
}, {
"value": "504697",
"date": "2020-09-07"
}, {
"value": "505659",
"date": "2020-09-08"
}, {
"value": "506346",
"date": "2020-09-12"
}, {
"value": "507109",
"date": "2020-09-14"
}, {
"value": "508650",
"date": "2020-09-16"
}, {
"value": "509708",
"date": "2020-09-17"
}, {
"value": "509708",
"date": "2020-09-18"
}, {
"value": "509708",
"date": "2020-09-19"
}, {
"value": "510154",
"date": "2020-09-20"
}, {
"value": "510226",
"date": "2020-09-21"
}, {
"value": "511136",
"date": "2020-09-22"
}, {
"value": "511252",
"date": "2020-09-23"
}, {
"value": "511253",
"date": "2020-09-24"
}, {
"value": "511253",
"date": "2020-09-25"
}, {
"value": "511253",
"date": "2020-09-26"
}, {
"value": "511363",
"date": "2020-09-27"
}, {
"value": "511467",
"date": "2020-09-28"
}, {
"value": "511467",
"date": "2020-09-29"
}, {
"value": "512016",
"date": "2020-09-30"
}, {
"value": "512016",
"date": "2020-10-01"
}, {
"value": "512016",
"date": "2020-10-02"
}, {
"value": "512016",
"date": "2020-10-03"
}, {
"value": "512610",
"date": "2020-10-04"
}, {
"value": "512889",
"date": "2020-10-05"
}, {
"value": "513552",
"date": "2020-10-06"
}, {
"value": "513836",
"date": "2020-10-07"
}];
parseDate = d3.timeParse("%Y-%m-%d");
line = d3.line()
.defined(d => !isNaN(d.value))
.x(d => x(parseDate(d.date)))
.y(d => y(parseInt(d.value)));
margin = ({
top: 20,
right: 30,
bottom: 30,
left: 40
});
height = 500;
width = 500;
x = d3.scaleUtc()
.domain(d3.extent(data, d => parseDate(d.date)))
.range([margin.left, width - margin.right]);
y = d3.scaleLinear()
.domain([0, d3.max(data, d => parseInt(d.value))]).nice()
.range([height - margin.bottom, margin.top]);
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));
svg = d3.select("body").append("svg")
//.attr("viewBox", [0, 0, width, height]);
.attr("width", "100%")
.attr("height", "100%");
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", line);
<script src="https://d3js.org/d3.v6.min.js"></script>

Understanding why strings break this 3d.js force.graph code

I am running this code in a jupyter notebook. First, I create this HTML element:
%%html
<div id="d3-example"></div>
<style>
.node {stroke: #fff; stroke-width: 1.5px;}
.link {stroke: #999; stroke-opacity: .6;}
</style>
Then I run this javascript:
%%javascript
// We load the d3.js library from the Web.
require.config({paths:
{d3: "http://d3js.org/d3.v3.min"}});
require(["d3"], function(d3) {
// The code in this block is executed when the
// d3.js library has been loaded.
// First, we specify the size of the canvas
// containing the visualization (size of the
// <div> element).
var width = 300, height = 300;
// We create a color scale.
var color = d3.scale.category10();
// We create a force-directed dynamic graph layout.
var force = d3.layout.force()
.charge(-120)
.linkDistance(1)
.size([width, height]);
// In the <div> element, we create a <svg> graphic
// that will contain our interactive visualization.
var svg = d3.select("#d3-example").select("svg")
if (svg.empty()) {
svg = d3.select("#d3-example").append("svg")
.attr("width", width)
.attr("height", height);
}
// We load the JSON file.
d3.json("graph2.json", function(error, graph) {
if (error) throw error;
// In this block, the file has been loaded
// and the 'graph' object contains our graph.
// We load the nodes and links in the
// force-directed graph.
force.nodes(graph.nodes)
.links(graph.links)
.start();
// We create a <line> SVG element for each link
// in the graph.
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link");
// We create a <circle> SVG element for each node
// in the graph, and we specify a few attributes.
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5) // radius
.style("fill", function(d) {
// The node color depends on the club.
return color(d.club);
})
.call(force.drag);
// The name of each node is the node number.
node.append("title")
.text(function(d) { return d.name; });
// We bind the positions of the SVG elements
// to the positions of the dynamic force-directed
// graph, at each time step.
force.on("tick", function() {
link.attr("x1", function(d){return d.source.x})
.attr("y1", function(d){return d.source.y})
.attr("x2", function(d){return d.target.x})
.attr("y2", function(d){return d.target.y});
node.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y});
});
});
});
And this is the content of the json file:
{
"nodes": [
{
"name": 0,
"club": "Mr. Hi"
},
{
"name": 1,
"club": "Mr. Hi"
},
{
"name": 2,
"club": "Mr. Hi"
},
{
"name": 3,
"club": "Mr. Hi"
},
{
"name": 4,
"club": "Mr. Hi"
},
{
"name": 5,
"club": "Mr. Hi"
},
{
"name": 6,
"club": "Mr. Hi"
},
{
"name": 7,
"club": "Mr. Hi"
},
{
"name": 8,
"club": "Mr. Hi"
},
{
"name": 9,
"club": "Officer"
},
{
"name": 10,
"club": "Mr. Hi"
},
{
"name": "11",
"club": "Mr. Hi"
},
{
"name": "12",
"club": "Mr. Hi"
},
{
"name": "13",
"club": "Mr. Hi"
},
{
"name": "14",
"club": "Officer"
},
{
"name": "15",
"club": "Officer"
},
{
"name": "16",
"club": "Mr. Hi"
},
{
"name": "17",
"club": "Mr. Hi"
},
{
"name": "18",
"club": "Officer"
},
{
"name": "19",
"club": "Mr. Hi"
},
{
"name": "20",
"club": "Officer"
},
{
"name": "21",
"club": "Mr. Hi"
},
{
"name": "22",
"club": "Officer"
},
{
"name": "23",
"club": "Officer"
},
{
"name": "24",
"club": "Officer"
},
{
"name": "25",
"club": "Officer"
},
{
"name": "26",
"club": "Officer"
},
{
"name": "27",
"club": "Officer"
},
{
"name": "28",
"club": "Officer"
},
{
"name": "29",
"club": "Officer"
},
{
"name": "30",
"club": "Officer"
},
{
"name": "31",
"club": "Officer"
},
{
"name": "32",
"club": "Officer"
},
{
"name": "33",
"club": "Officer"
}
],
"links": [
{
"source": 0,
"target": 1
},
{
"source": 0,
"target": 2
},
{
"source": 0,
"target": 3
},
{
"source": 0,
"target": 4
},
{
"source": 0,
"target": 5
},
{
"source": 0,
"target": 6
},
{
"source": 0,
"target": 7
},
{
"source": 0,
"target": 8
},
{
"source": 0,
"target": 10
},
{
"source": 0,
"target": 11
},
{
"source": 0,
"target": 12
},
{
"source": 0,
"target": 13
},
{
"source": 0,
"target": 17
},
{
"source": 0,
"target": 19
},
{
"source": 0,
"target": 21
},
{
"source": 0,
"target": 31
},
{
"source": 1,
"target": 2
},
{
"source": 1,
"target": 3
},
{
"source": 1,
"target": 7
},
{
"source": 1,
"target": 13
},
{
"source": 1,
"target": 17
},
{
"source": 1,
"target": 19
},
{
"source": 1,
"target": 21
},
{
"source": 1,
"target": 30
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 7
},
{
"source": 2,
"target": 8
},
{
"source": 2,
"target": 9
},
{
"source": 2,
"target": 13
},
{
"source": 2,
"target": 27
},
{
"source": 2,
"target": 28
},
{
"source": 2,
"target": 32
},
{
"source": 3,
"target": 7
},
{
"source": 3,
"target": 12
},
{
"source": 3,
"target": 13
},
{
"source": 4,
"target": 6
},
{
"source": 4,
"target": 10
},
{
"source": 5,
"target": 6
},
{
"source": 5,
"target": 10
},
{
"source": 5,
"target": 16
},
{
"source": 6,
"target": 16
},
{
"source": 8,
"target": 30
},
{
"source": 8,
"target": 32
},
{
"source": 8,
"target": 33
},
{
"source": 9,
"target": 33
},
{
"source": 13,
"target": 33
},
{
"source": 14,
"target": 32
},
{
"source": 14,
"target": 33
},
{
"source": 15,
"target": 32
},
{
"source": 15,
"target": 33
},
{
"source": 18,
"target": 32
},
{
"source": 18,
"target": 33
},
{
"source": 19,
"target": 33
},
{
"source": 20,
"target": 32
},
{
"source": 20,
"target": 33
},
{
"source": 22,
"target": 32
},
{
"source": 22,
"target": 33
},
{
"source": 23,
"target": 25
},
{
"source": 23,
"target": 27
},
{
"source": 23,
"target": 29
},
{
"source": 23,
"target": 32
},
{
"source": 23,
"target": 33
},
{
"source": 24,
"target": 25
},
{
"source": 24,
"target": 27
},
{
"source": 24,
"target": 31
},
{
"source": 25,
"target": 31
},
{
"source": 26,
"target": 29
},
{
"source": 26,
"target": 33
},
{
"source": 27,
"target": 33
},
{
"source": 28,
"target": 31
},
{
"source": 28,
"target": 33
},
{
"source": 29,
"target": 32
},
{
"source": 29,
"target": 33
},
{
"source": 30,
"target": 32
},
{
"source": 30,
"target": 33
},
{
"source": 31,
"target": 32
},
{
"source": 31,
"target": 33
},
{
"source": 32,
"target": 33
}
]
}
​I want to customize the code and use it to visualize a different file. But I don't fully understand the code. I changed the values in the links section to strings. And that breaks the code. I want to use strings for my other graph. But I don't see how the javascript code depends on integers. For some reason, it breaks and no graph is displayed.

Can I use a timeline with a D3 Force Network?

Can I bring this to life with force diagram?
I have a data set that comprises a series of objects that occur along a time line:
letters
orders
memos
phone calls
twitter messages
invoices
emails
The quantity of objects in the data set is driven by a query that extracts relevant objects from a database.
In a simple example there might be 10 objects for a single date or those ten might be spread over 2 or three days or be weeks apart.
All objects are linked, not necesarily directly, to each other.
A might join to B and to C, but D is linked to A only through a link to C.
The links need to be color coded based on the type of link and the line thickness needs to vary to represent the strngth of the link.
I have several ways of displaying this data using fixed coordinates based on the object date. They do the job but they don't look great.
I have created a D3 force diagram that plots the objects (nodes) and draws the links, but I'm at a complete lost as to how I can incoporate the time element.
Is there a way that I can plot the data so that the objects are roughly positioned along a date line? The positions do not need to be exact but the overall result should give the user a good indication of temproal proximity.
I'd also like the links to be drawn with an open B-spline which is something else that I can't get my head around
See sample data and code.
JSON Data
{
"nodes": [
{ "DocID": "77304", "date": "2001-01-21", "Type": "L" },
{ "DocID": "65884", "date": "2001-01-26", "Type": "F" },
{ "DocID": "77005", "date": "2001-02-02", "Type": "L" },
{ "DocID": "66162", "date": "2001-02-07", "Type": "E" },
{ "DocID": "93085", "date": "2001-03-20", "Type": "L" },
{ "DocID": "93101", "date": "2001-03-21", "Type": "P" },
{ "DocID": "93118", "date": "2001-03-28", "Type": "L" },
{ "DocID": "75890", "date": "2001-04-09", "Type": "L" },
{ "DocID": "93189", "date": "2001-04-11", "Type": "L" },
{ "DocID": "93225", "date": "2001-04-12", "Type": "L" },
{ "DocID": "75535", "date": "2001-04-19", "Type": "L" },
{ "DocID": "74916", "date": "2001-05-07", "Type": "I" },
{ "DocID": "58259", "date": "2001-05-16", "Type": "L" },
{ "DocID": "93565", "date": "2001-05-16", "Type": "O" },
{ "DocID": "95504", "date": "2001-05-17", "Type": "O" },
{ "DocID": "74408", "date": "2001-05-21", "Type": "L" },
{ "DocID": "95521", "date": "2001-05-21", "Type": "L" },
{ "DocID": "74343", "date": "2001-05-22", "Type": "L" }
],
"links": [
{ "source": 0, "target": 5, "strength": 9, "colour": 4 },
{ "source": 1, "target": 7, "strength": 4, "colour": 3 },
{ "source": 2, "target": 17, "strength": 2, "colour": 1 },
{ "source": 3, "target": 2, "strength": 3, "colour": 2 },
{ "source": 4, "target": 8, "strength": 9, "colour": 4 },
{ "source": 5, "target": 8, "strength": 5, "colour": 3 },
{ "source": 6, "target": 2, "strength": 3, "colour": 5 },
{ "source": 7, "target": 11, "strength": 5, "colour": 1 },
{ "source": 8, "target": 12, "strength": 3, "colour": 5 },
{ "source": 9, "target": 13, "strength": 9, "colour": 4 },
{ "source": 10, "target": 9, "strength": 4, "colour": 5 },
{ "source": 11, "target": 7, "strength": 5, "colour": 2 },
{ "source": 12, "target": 11, "strength": 3, "colour": 2 },
{ "source": 13, "target": 9, "strength": 3, "colour": 5 },
{ "source": 14, "target": 9, "strength": 2, "colour": 5 },
{ "source": 15, "target": 11, "strength": 3, "colour": 5 },
{ "source": 16, "target": 9, "strength": 6, "colour": 5 },
{ "source": 17, "target": 13, "strength": 4, "colour": 5 },
{ "source": 1, "target": 14, "strength": 2, "colour": 5 },
{ "source": 9, "target": 7, "strength": 2, "colour": 5 },
{ "source": 2, "target": 5, "strength": 5, "colour": 5 },
{ "source": 11, "target": 9, "strength": 7, "colour": 1 }
]
}
JS Code
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(150)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("Resources/testData.json", function (error, graph) {
if (error) throw error;
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.style("stroke", function (d) { return color(d.colour); })
.attr("class", "link")
.style("stroke-width", function (d) { return d.strength; });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.call(force.drag);
node.append("title")
.text(function (d) { return d.DocID; });
force.on("tick", function () {
link.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; });
node.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
});
});

Resources