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
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>
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>
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>
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 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; });
});
});