Transitions with nested data D3.js - d3.js

I've recently begun learning D3.js and I am struggling to create a transition in a scatter plot with the following data:
var data = [
{"year" : "2004", "x":100, "y":300, "size": 2, "type": "A"},
{"year" : "2005", "x":200, "y":200, "size": 2, "type": "A"},
{"year" : "2006", "x":300, "y":100, "size": 2, "type": "A"},
{"year" : "2004", "x":150, "y":250, "size": 2.382450, "type": "B"},
{"year" : "2005", "x":150, "y":250, "size": 3.078548, "type": "B"},
{"year" : "2006", "x":150, "y":250, "size": 4.265410, "type": "B"}];
Where in the scatter plot there are 2 points (type A&B) and they change location (x&y) and size by year. I've created a fiddle where I try to nest the data and plot the points, but making the next step of using transition() function is confusing. More specifically, I am still declaring the whole data, but to make transitions work I only need part of the data.

The key to understand what you want lies here:
There are 2 points and they change location (x&y) and size by year
Therefore, this is clearly a XY problem. Your problem is not "how to transition with nested data". Your problem is "how to transition by year".
My proposed solution involves, first of all, dropping that nested array. You don't need that.
Instead, get all the years in the data...
var years = [...new Set(data.map(function(d) {
return d.year
}))];
..., filter the data by year...
var dataStart = data.filter(function(d) {
return d.year === years[0]
});
... and loop trough the years. Here, I'm using d3.interval():
var counter = 1;
var timer = d3.interval(transition, 1500);
function transition() {
var newData = data.filter(function(d) {
return d.year === years[counter]
});
svg.selectAll("circle").data(newData)
.transition()
.duration(1000)
.attr("cx", function(d) {
console.log(d)
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
counter += 1;
if (counter === 3) {
timer.stop()
}
}
Here is the demo:
var data = [{
"year": "2004",
"x": 100,
"y": 100,
"size": 2,
"type": "A"
}, {
"year": "2005",
"x": 200,
"y": 180,
"size": 2,
"type": "A"
}, {
"year": "2006",
"x": 300,
"y": 50,
"size": 2,
"type": "A"
}, {
"year": "2004",
"x": 150,
"y": 150,
"size": 2.382450,
"type": "B"
}, {
"year": "2005",
"x": 150,
"y": 50,
"size": 3.078548,
"type": "B"
}, {
"year": "2006",
"x": 150,
"y": 100,
"size": 4.265410,
"type": "B"
}];
var width = 400,
height = 200;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var years = [...new Set(data.map(function(d) {
return d.year
}))];
var dataStart = data.filter(function(d) {
return d.year === years[0]
});
var cell = svg.selectAll("circle")
.data(dataStart);
cell.enter()
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
var counter = 1;
var timer = d3.interval(transition, 1500);
function transition() {
var newData = data.filter(function(d) {
return d.year === years[counter]
});
svg.selectAll("circle").data(newData)
.transition()
.duration(1000)
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.size * 10;
});
counter += 1;
if (counter === 3) {
timer.stop()
}
}
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

d3js force directed graph arrows not showing up

I have a force directed graph using version 5 of d3.js and would like to include arrow heads for each link. I've included the code below and posted a jsfiddle. I'm seeking guidance on why the arrow heads (id=end-arrow) are not showing up in the graph. I'm referencing the end-arrow as an attribute in the declaration of link: .attr("marker-end","url(#end-arrow)"), and I don't know how to troubleshoot this.
HTML:
<svg id="viz"></svg>
Javascript with d3.js version 5:
// based on https://bl.ocks.org/mapio/53fed7d84cd1812d6a6639ed7aa83868
var width = 600;
var height = 400;
var border = 1;
var bordercolor="black";
var color = d3.scaleOrdinal(d3.schemeCategory10); // coloring of nodes
var graph = {
"nodes": [
{"id": "4718871", "group": 2, "img": "https://derivationmap.net/static/multiplybothsidesby.png", "width": 298, "height": 30, "linear index": 2},
{"id": "2131616531", "group": 0, "img": "https://derivationmap.net/static/2131616531.png", "width": 103, "height": 30, "linear index": 0},
{"id": "9565166889", "group": 0, "img": "https://derivationmap.net/static/9565166889.png", "width": 24, "height": 23, "linear index": 0},
{"id": "9040079362", "group": 0, "img": "https://derivationmap.net/static/9040079362.png", "width": 18, "height": 30, "linear index": 0},
{"id": "9278347", "group": 1, "img": "https://derivationmap.net/static/declareinitialexpr.png", "width": 270, "height": 30, "linear index": 1},
{"id": "6286448", "group": 4, "img": "https://derivationmap.net/static/declarefinalexpr.png", "width": 255, "height": 30, "linear index": 4},
{"id": "2113211456", "group": 0, "img": "https://derivationmap.net/static/2113211456.png", "width": 121, "height": 34, "linear index": 0},
{"id": "2169431", "group": 3, "img": "https://derivationmap.net/static/dividebothsidesby.png", "width": 260, "height": 30, "linear index": 3},
{"id": "3131111133", "group": 0, "img": "https://derivationmap.net/static/3131111133.png", "width": 121, "height": 34, "linear index": 0}
],
"links": [
{"source": "2169431", "target": "2113211456", "value": 1},
{"source": "2113211456", "target": "6286448", "value": 1},
{"source": "9278347", "target": "3131111133", "value": 1},
{"source": "4718871", "target": "2131616531", "value": 1},
{"source": "9040079362", "target": "4718871", "value": 1},
{"source": "2131616531", "target": "2169431", "value": 1},
{"source": "3131111133", "target": "4718871", "value": 1},
{"source": "9565166889", "target": "2169431", "value": 1}
]
};
var label = {
"nodes": [],
"links": []
};
graph.nodes.forEach(function(d, i) {
label.nodes.push({node: d});
label.nodes.push({node: d});
label.links.push({
source: i * 2,
target: i * 2 + 1
});
});
var labelLayout = d3.forceSimulation(label.nodes)
.force("charge", d3.forceManyBody().strength(-50))
.force("link", d3.forceLink(label.links).distance(0).strength(2));
var graphLayout = d3.forceSimulation(graph.nodes)
.force("charge", d3.forceManyBody().strength(-3000))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("x", d3.forceX(width / 2).strength(1))
.force("y", d3.forceY(height / 2).strength(1))
.force("link", d3.forceLink(graph.links).id(function(d) {return d.id; }).distance(50).strength(1))
.on("tick", ticked);
var adjlist = [];
graph.links.forEach(function(d) {
adjlist[d.source.index + "-" + d.target.index] = true;
adjlist[d.target.index + "-" + d.source.index] = true;
});
function neigh(a, b) {
return a == b || adjlist[a + "-" + b];
}
var svg = d3.select("#viz").attr("width", width).attr("height", height);
// define arrow markers for graph links
svg.append("svg:defs").append("svg:marker")
.attr("id", "end-arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 6)
.attr("markerWidth", 3)
.attr("markerHeight", 3)
.attr("orient", "auto")
.append("svg:line")
.attr("d", "M0,-5L10,0L0,5")
.attr("fill", "black");
// http://bl.ocks.org/AndrewStaroscik/5222370
var borderPath = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", height)
.attr("width", width)
.style("stroke", bordercolor)
.style("fill", "none")
.style("stroke-width", border);
var container = svg.append("g");
svg.call(
d3.zoom()
.scaleExtent([.1, 4])
.on("zoom", function() { container.attr("transform", d3.event.transform); })
);
var link = container.append("g").attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter()
.append("line")
.attr("stroke", "#aaa")
.attr("stroke-width", "1px")
.attr("marker-end","url(#end-arrow)");
var node = container.append("g").attr("class", "nodes")
.selectAll("g")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
node.on("mouseover", focus).on("mouseout", unfocus);
node.call(
d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
var labelNode = container.append("g").attr("class", "labelNodes")
.selectAll("text")
.data(label.nodes)
.enter()
.append("image")
// alternative option, unverified: https://stackoverflow.com/questions/39908583/d3-js-labeling-nodes-with-image-in-force-layout
// I have no idea why the i%2 is needed; without it I get two images per node
// switching between i%2==1 and i%2==0 produces different image locations (?)
.attr("xlink:href", function(d, i) { return i % 2 == 1 ? "" : d.node.img; } )
.attr("x", 0)
.attr("y", 0)
// the following alter the image size
.attr("width", function(d, i) { return d.node.width/2; })
.attr("height", function(d, i) { return d.node.height/2; })
// .append("text")
// .text(function(d, i) { return i % 2 == 0 ? "" : d.node.id; })
// .style("fill", "#555")
// .style("font-family", "Arial")
// .style("font-size", 12)
.style("pointer-events", "none"); // to prevent mouseover/drag capture
node.on("mouseover", focus).on("mouseout", unfocus);
function ticked() {
node.call(updateNode);
link.call(updateLink);
labelLayout.alphaTarget(0.3).restart();
labelNode.each(function(d, i) {
if(i % 2 == 0) {
d.x = d.node.x;
d.y = d.node.y;
} else {
var b = this.getBBox();
var diffX = d.x - d.node.x;
var diffY = d.y - d.node.y;
var dist = Math.sqrt(diffX * diffX + diffY * diffY);
var shiftX = b.width * (diffX - dist) / (dist * 2);
shiftX = Math.max(-b.width, Math.min(0, shiftX));
var shiftY = 16;
this.setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
}
});
labelNode.call(updateNode);
}
function fixna(x) {
if (isFinite(x)) return x;
return 0;
}
function focus(d) {
var index = d3.select(d3.event.target).datum().index;
node.style("opacity", function(o) {
return neigh(index, o.index) ? 1 : 0.1;
});
labelNode.attr("display", function(o) {
return neigh(index, o.node.index) ? "block": "none";
});
link.style("opacity", function(o) {
return o.source.index == index || o.target.index == index ? 1 : 0.1;
});
}
function unfocus() {
labelNode.attr("display", "block");
node.style("opacity", 1);
link.style("opacity", 1);
}
function updateLink(link) {
link.attr("x1", function(d) { return fixna(d.source.x); })
.attr("y1", function(d) { return fixna(d.source.y); })
.attr("x2", function(d) { return fixna(d.target.x); })
.attr("y2", function(d) { return fixna(d.target.y); });
}
function updateNode(node) {
node.attr("transform", function(d) {
return "translate(" + fixna(d.x) + "," + fixna(d.y) + ")";
});
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
if (!d3.event.active) graphLayout.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) graphLayout.alphaTarget(0);
d.fx = null;
d.fy = null;
}
Based on feedback in the d3js Slack channel, there were two issues:
In the definition of the arrow, needed .append("svg:path")
With that fixed, the arrows were too small and were hidden behind the node circles. By making the arrows larger, they were visible.
I've updated http://bl.ocks.org/bhpayne/0a8ef2ae6d79aa185dcf2c3a385daf25 and the revised code is below:
HTML
<svg id="viz"></svg>
Javascript + d3js
// based on https://bl.ocks.org/mapio/53fed7d84cd1812d6a6639ed7aa83868
var width = 600;
var height = 400;
var border = 3;
var bordercolor = "black";
var color = d3.scaleOrdinal(d3.schemeCategory10); // coloring of nodes
var graph = {
"nodes": [{
"id": "4718871",
"group": 2,
"img": "https://derivationmap.net/static/multiplybothsidesby.png",
"width": 298,
"height": 30,
"linear index": 2
},
{
"id": "2131616531",
"group": 0,
"img": "https://derivationmap.net/static/2131616531.png",
"width": 103,
"height": 30,
"linear index": 0
},
{
"id": "9565166889",
"group": 0,
"img": "https://derivationmap.net/static/9565166889.png",
"width": 24,
"height": 23,
"linear index": 0
},
{
"id": "9040079362",
"group": 0,
"img": "https://derivationmap.net/static/9040079362.png",
"width": 18,
"height": 30,
"linear index": 0
},
{
"id": "9278347",
"group": 1,
"img": "https://derivationmap.net/static/declareinitialexpr.png",
"width": 270,
"height": 30,
"linear index": 1
},
{
"id": "6286448",
"group": 4,
"img": "https://derivationmap.net/static/declarefinalexpr.png",
"width": 255,
"height": 30,
"linear index": 4
},
{
"id": "2113211456",
"group": 0,
"img": "https://derivationmap.net/static/2113211456.png",
"width": 121,
"height": 34,
"linear index": 0
},
{
"id": "2169431",
"group": 3,
"img": "https://derivationmap.net/static/dividebothsidesby.png",
"width": 260,
"height": 30,
"linear index": 3
},
{
"id": "3131111133",
"group": 0,
"img": "https://derivationmap.net/static/3131111133.png",
"width": 121,
"height": 34,
"linear index": 0
}
],
"links": [{
"source": "2169431",
"target": "2113211456",
"value": 1
},
{
"source": "2113211456",
"target": "6286448",
"value": 1
},
{
"source": "9278347",
"target": "3131111133",
"value": 1
},
{
"source": "4718871",
"target": "2131616531",
"value": 1
},
{
"source": "9040079362",
"target": "4718871",
"value": 1
},
{
"source": "2131616531",
"target": "2169431",
"value": 1
},
{
"source": "3131111133",
"target": "4718871",
"value": 1
},
{
"source": "9565166889",
"target": "2169431",
"value": 1
}
]
};
var label = {
"nodes": [],
"links": []
};
graph.nodes.forEach(function(d, i) {
label.nodes.push({
node: d
});
label.nodes.push({
node: d
});
label.links.push({
source: i * 2,
target: i * 2 + 1
});
});
var labelLayout = d3.forceSimulation(label.nodes)
.force("charge", d3.forceManyBody().strength(-50))
.force("link", d3.forceLink(label.links).distance(0).strength(2));
var graphLayout = d3.forceSimulation(graph.nodes)
.force("charge", d3.forceManyBody().strength(-3000))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("x", d3.forceX(width / 2).strength(1))
.force("y", d3.forceY(height / 2).strength(1))
.force("link", d3.forceLink(graph.links).id(function(d) {
return d.id;
}).distance(50).strength(1))
.on("tick", ticked);
var adjlist = [];
graph.links.forEach(function(d) {
adjlist[d.source.index + "-" + d.target.index] = true;
adjlist[d.target.index + "-" + d.source.index] = true;
});
function neigh(a, b) {
return a == b || adjlist[a + "-" + b];
}
var svg = d3.select("#viz").attr("width", width).attr("height", height);
// define arrow markers for graph links
svg.append("svg:defs").append("svg:marker")
.attr("id", "end-arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 10)
.attr("markerWidth", 20)
.attr("markerHeight", 20)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L20,0L0,5")
.attr("fill", "#000");
// http://bl.ocks.org/AndrewStaroscik/5222370
var borderPath = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", height)
.attr("width", width)
.style("stroke", bordercolor)
.style("fill", "none")
.style("stroke-width", border);
var container = svg.append("g");
svg.call(
d3.zoom()
.scaleExtent([.1, 4])
.on("zoom", function() {
container.attr("transform", d3.event.transform);
})
);
var link = container.append("g").attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter()
.append("line")
.attr("stroke", "#aaa")
.attr("marker-end", "url(#end-arrow)")
.attr("stroke-width", "1px");
var node = container.append("g").attr("class", "nodes")
.selectAll("g")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 10)
.attr("fill", function(d) {
return color(d.group);
})
node.on("mouseover", focus).on("mouseout", unfocus);
node.call(
d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
var labelNode = container.append("g").attr("class", "labelNodes")
.selectAll("text")
.data(label.nodes)
.enter()
.append("image")
// alternative option, unverified: https://stackoverflow.com/questions/39908583/d3-js-labeling-nodes-with-image-in-force-layout
// I have no idea why the i%2 is needed; without it I get two images per node
// switching between i%2==1 and i%2==0 produces different image locations (?)
.attr("xlink:href", function(d, i) {
return i % 2 == 1 ? "" : d.node.img;
})
.attr("x", 0)
.attr("y", 0)
// the following alter the image size
.attr("width", function(d, i) {
return d.node.width / 2;
})
.attr("height", function(d, i) {
return d.node.height / 2;
})
// .append("text")
// .text(function(d, i) { return i % 2 == 0 ? "" : d.node.id; })
// .style("fill", "#555")
// .style("font-family", "Arial")
// .style("font-size", 12)
.style("pointer-events", "none"); // to prevent mouseover/drag capture
node.on("mouseover", focus).on("mouseout", unfocus);
function ticked() {
node.call(updateNode);
link.call(updateLink);
labelLayout.alphaTarget(0.3).restart();
labelNode.each(function(d, i) {
if (i % 2 == 0) {
d.x = d.node.x;
d.y = d.node.y;
} else {
var b = this.getBBox();
var diffX = d.x - d.node.x;
var diffY = d.y - d.node.y;
var dist = Math.sqrt(diffX * diffX + diffY * diffY);
var shiftX = b.width * (diffX - dist) / (dist * 2);
shiftX = Math.max(-b.width, Math.min(0, shiftX));
var shiftY = 16;
this.setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
}
});
labelNode.call(updateNode);
}
function fixna(x) {
if (isFinite(x)) return x;
return 0;
}
function focus(d) {
var index = d3.select(d3.event.target).datum().index;
node.style("opacity", function(o) {
return neigh(index, o.index) ? 1 : 0.1;
});
labelNode.attr("display", function(o) {
return neigh(index, o.node.index) ? "block" : "none";
});
link.style("opacity", function(o) {
return o.source.index == index || o.target.index == index ? 1 : 0.1;
});
}
function unfocus() {
labelNode.attr("display", "block");
node.style("opacity", 1);
link.style("opacity", 1);
}
function updateLink(link) {
link.attr("x1", function(d) {
return fixna(d.source.x);
})
.attr("y1", function(d) {
return fixna(d.source.y);
})
.attr("x2", function(d) {
return fixna(d.target.x);
})
.attr("y2", function(d) {
return fixna(d.target.y);
});
}
function updateNode(node) {
node.attr("transform", function(d) {
return "translate(" + fixna(d.x) + "," + fixna(d.y) + ")";
});
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
if (!d3.event.active) graphLayout.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) graphLayout.alphaTarget(0);
d.fx = null;
d.fy = null;
}

Inserting nodes locations for network graph D3

I am new to D3 and I am trying to solve a homework.
I am trying plot a network graph by drawing the nodes from this dataset(sample).
{ "nodes": [
{
"id": "site09",
"x": 317.5,
"y": 282.5
},
{
"id": "site01",
"x": 112,
"y": 47
},
{
"id": "site03",
"x": 69.5,
"y": 287
},
{
"id": "site04",
"x": 424.5,
"y": 99.5
} ]
"links": [
{"node01": "site05", "node02": "site08", "amount": 10},
{"node01": "site05", "node02": "site02", "amount": 120},
{"node01": "site05", "node02": "site03", "amount": 50},
I want to plot the location of the circles using x and y from the dataset.
I tried the following but the circles/nodes are not showing.
//importing the json data
d3.json("project.json", function(data) {
console.log(data);
svgCanvas.selectAll("circle")
.data(data).enter() // create place hodlers if the data are new .append("circle") // create one circle for each
.append("svg:circle")
.attr("cx", function(data){
return data.x;})
.attr("cy", function(data){
return data.y;})
.attr("r", function(thisElement, index){
// use the value from data to create the radius
return thisElement["amount"]})
vis.selectAll("circle.nodes")
.data(nodes)
.enter()
.append("svg:circle")
.attr("class", "nodes")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", "10px")
.attr("fill", "black")
})
}
Thank you,

d3js force node xy start position

I have a node with fx/fy parameter on simulation starting. This node is fixed on the correct position. But now I want to define x and y coordinates for one or multiple other nodes (in this example: number 10 in jsfiddle), the purpose is to start the simulation of this "unfixed" nodes on a given position and not 0/0. Why is the node fixed on 0/0?
jsfiddle example: https://jsfiddle.net/6g9howo7/2/
var nodes = [
{
"id" : "1",
"fx" : "225",
"fy" : "225"
},
{
"id" : "2"
},
{
"id" : "3"
},
{
"id" : "4"
},
{
"id" : "5"
},
{
"id" : "6"
},
{
"id" : "7"
},
{
"id" : "8"
},
{
"id" : "9"
},
{
"id" : "10",
"x" : "125",
"y" : "125"
},
{
"id" : "11"
},
{
"id" : "12"
},
{
"id" : "13"
},
{
"id" : "14"
},
{
"id" : "15"
}
]
var links =
[
{
"source" : 1,
"target" : 2
},
{
"source" : 1,
"target" : 3
},
{
"source" : 1,
"target" : 4
},
{
"source" : 1,
"target" : 5
},
{
"source" : 1,
"target" : 6
},
{
"source" : 1,
"target" : 7
},
{
"source" : 1,
"target" : 8
},
{
"source" : 1,
"target" : 9
},
{
"source" : 1,
"target" : 10
},
{
"source" : 10,
"target" : 11
},
{
"source" : 10,
"target" : 12
},
{
"source" : 10,
"target" : 13
},
{
"source" : 10,
"target" : 14
},
{
"source" : 10,
"target" : 15
}
]
var svg = d3.select("svg")
var zoom = d3.zoom()
.on("zoom", zoomed);
//.scaleExtent([1 / 8, 4])
svg
.call(zoom).on("dblclick.zoom", null)
var g = svg.append("g");
function zoomed() {
g.attr("transform", d3.event.transform);
}
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
//.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(10).strength(1))
.force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
//.force("center", d3.forceCenter(1000, 1000));
//.force("y", d3.forceY(500))
//.force("x", d3.forceX(500));
//.force("collide",d3.forceCollide(.5));
//.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/)
.style("stroke", 'red');
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r",3)
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
.on("dblclick", dblclick)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
simulation.nodes(nodes)
// .alphaDecay(0.5)
.velocityDecay(0.1)
.on("tick", ticked);
simulation.force("link")
.links(links);
function ticked() {
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; });
}
function dblclick(d) {
d.fx = null;
d.fy = null;
}
function dragstarted(d) {
//if (!d3.event.active) simulation.alphaTarget(0.3).restart();
simulation.restart();
// simulation.alpha -> redémarre la période de simulation
simulation.alpha(1.0);
d.fx = d.x;
d.fy = d.y;
}
//Grid
var grid = 50;
function dragged(d,i) {
//force.stop();
//var grid = 50;
var gx = Math.round(d3.event.x/grid)*grid;
var gy = Math.round(d3.event.y/grid)*grid;
d.fx = gx;
d.fy = gy;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
// console.log(d);
// d.fx = null;
// d.fy = null;
// d.fixed = true;
}
//Grid
var width = 7000;
var height = 7000;
var lineGraph = g.append("g")
.attr("width", width)
.attr("height", height);
// Using for loop to draw multiple horizontal lines
for (var j=grid; j <= width-grid; j=j+grid) {
lineGraph.append("svg:line")
.attr("x1", grid)
.attr("y1", j)
.attr("x2", width-grid)
.attr("y2", j)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
// Using for loop to draw multiple vertical lines
for (var j=grid; j <= height-grid; j=j+grid) {
lineGraph.append("svg:line")
.attr("x1", j)
.attr("y1", grid)
.attr("x2", j)
.attr("y2", height-grid)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
Your approach is correct, setting x and y defines the start position. However, they have to be numbers, not strings.
Therefore, instead of:
{
"id": "10",
"x": "125",
"y": "125"
}
It should be:
{
"id": "10",
"x": 125,
"y": 125
}
Here is your code with that change:
var nodes = [{
"id": "1",
"fx": "225",
"fy": "225"
}, {
"id": "2"
}, {
"id": "3"
}, {
"id": "4"
}, {
"id": "5"
}, {
"id": "6"
}, {
"id": "7"
}, {
"id": "8"
}, {
"id": "9"
}, {
"id": "10",
"x": 125,
"y": 125
}, {
"id": "11"
}, {
"id": "12"
}, {
"id": "13"
}, {
"id": "14"
}, {
"id": "15"
}]
var links = [{
"source": 1,
"target": 2
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 4
}, {
"source": 1,
"target": 5
}, {
"source": 1,
"target": 6
}, {
"source": 1,
"target": 7
}, {
"source": 1,
"target": 8
}, {
"source": 1,
"target": 9
}, {
"source": 1,
"target": 10
}, {
"source": 10,
"target": 11
}, {
"source": 10,
"target": 12
}, {
"source": 10,
"target": 13
}, {
"source": 10,
"target": 14
}, {
"source": 10,
"target": 15
}]
var svg = d3.select("svg")
var zoom = d3.zoom()
.on("zoom", zoomed);
//.scaleExtent([1 / 8, 4])
svg
.call(zoom).on("dblclick.zoom", null)
var g = svg.append("g");
function zoomed() {
g.attr("transform", d3.event.transform);
}
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
//.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).distance(10).strength(1))
.force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
//.force("center", d3.forceCenter(1000, 1000));
//.force("y", d3.forceY(500))
//.force("x", d3.forceX(500));
//.force("collide",d3.forceCollide(.5));
//.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/ )
.style("stroke", 'red');
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 3)
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
.on("dblclick", dblclick)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) {
return d.id;
});
simulation.nodes(nodes)
// .alphaDecay(0.5)
.velocityDecay(0.1)
.on("tick", ticked);
simulation.force("link")
.links(links);
function ticked() {
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;
});
}
function dblclick(d) {
d.fx = null;
d.fy = null;
}
function dragstarted(d) {
//if (!d3.event.active) simulation.alphaTarget(0.3).restart();
simulation.restart();
// simulation.alpha -> redémarre la période de simulation
simulation.alpha(1.0);
d.fx = d.x;
d.fy = d.y;
}
//Grid
var grid = 50;
function dragged(d, i) {
//force.stop();
//var grid = 50;
var gx = Math.round(d3.event.x / grid) * grid;
var gy = Math.round(d3.event.y / grid) * grid;
d.fx = gx;
d.fy = gy;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
// console.log(d);
// d.fx = null;
// d.fy = null;
// d.fixed = true;
}
//Grid
var width = 7000;
var height = 7000;
var lineGraph = g.append("g")
.attr("width", width)
.attr("height", height);
// Using for loop to draw multiple horizontal lines
for (var j = grid; j <= width - grid; j = j + grid) {
lineGraph.append("svg:line")
.attr("x1", grid)
.attr("y1", j)
.attr("x2", width - grid)
.attr("y2", j)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
// Using for loop to draw multiple vertical lines
for (var j = grid; j <= height - grid; j = j + grid) {
lineGraph.append("svg:line")
.attr("x1", j)
.attr("y1", grid)
.attr("x2", j)
.attr("y2", height - grid)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
html {
width: 100%;
height: 100%;
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display: flex;
font-family: sans-serif;
font-size: 75%;
}
/* SVG styles */
svg {
flex-basis: 100%;
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

d3 update path with maximum value of area

I display a d3.area(). To show the highest value, I draw a horizontal line with d3.line() at the maximum value of the dataset. This value is calculated using:
var max_out = d3.max(data, function(d){ return +d.out; });
To brush through the graph, I use the setup as in this example:
As soon as the area is brushed, I would also like to move the "maximum line" up and down reflecting the new domain instead of using the whole dataset.
Any pointers?
Let's have a line function definition, in the first time only defining the x attribute:
var line = d3.line()
.x(function(d) { return x(d.date); });
Right after you append your area in the main view, add another path, which will be used to draw your horizontal line above the corresponding area:
focus.append("path")
.attr("class", "line");
Notice that I'm giving it a line class for styling.
We're also gonna draw the line, at first simply using the function you are currently using to determine the peak of your data:
.attr("d", line.y(function () {
return y(max);
}));
... and feed our line generator the right data :):
.datum(data)
To summarize, here's what we got on initialization:
// There's your main view's data area
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
// There's your 'peak' horizontal line
var max = d3.max(data, function(d){ return d.price; });
focus.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line.y(function () {
return y(max);
}));
In the functions that trigger a re-drawing of your elements, you simply have to update the d attribute of your path.line element.
We're gonna simply do the following:
Filter out data points that aren't within the updated domain of your x-axis
Evaluate the maximum value of that sub-set (using the method you described)
Let D3 generate the new value for the d attribute and set it.
That translates into the following:
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
See an example in action in the snippet below or on JSFiddle.
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 110, left: 40},
margin2 = {top: 180, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var area = d3.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var area2 = d3.area()
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var line = d3.line()
.x(function(d) { return x(d.date); });
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
var data;
(function (_data) {
data = _data;
data.forEach(function (d) {
d.date = new Date(d.date);
});
data = (function uniqBy(a, key) {
var seen = {};
return a.filter(function(item) {
var k = key(item);
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
});
})(data, function (d) {return d.date;});
data.sort(function(a,b) {
return new Date(a.date).getTime() - new Date(b.date).getTime();
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.price; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
var max = d3.max(data, function(d){ return d.price; });
focus.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line.y(function () {
return y(max);
}));
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
})([{"date":"1999-12-31T23:00:00.000Z","price":1394.46},{"date":"2000-01-31T23:00:00.000Z","price":1366.42},{"date":"2000-02-29T23:00:00.000Z","price":1498.58},{"date":"2000-03-31T22:00:00.000Z","price":1452.43},{"date":"2000-04-30T22:00:00.000Z","price":1420.6},{"date":"2000-05-31T22:00:00.000Z","price":1454.6},{"date":"2000-06-30T22:00:00.000Z","price":1430.83},{"date":"2000-07-31T22:00:00.000Z","price":1517.68},{"date":"2000-08-31T22:00:00.000Z","price":1436.51},{"date":"2000-09-30T22:00:00.000Z","price":1429.4},{"date":"2000-10-31T23:00:00.000Z","price":1314.95},{"date":"2000-11-30T23:00:00.000Z","price":1320.28},{"date":"2000-12-31T23:00:00.000Z","price":1366.01},{"date":"2001-01-31T23:00:00.000Z","price":1239.94},{"date":"2001-02-28T23:00:00.000Z","price":1160.33},{"date":"2001-03-31T22:00:00.000Z","price":1249.46},{"date":"2001-04-30T22:00:00.000Z","price":1255.82},{"date":"2001-05-31T22:00:00.000Z","price":1224.38},{"date":"2001-06-30T22:00:00.000Z","price":1211.23},{"date":"2001-07-31T22:00:00.000Z","price":1133.58},{"date":"2001-08-31T22:00:00.000Z","price":1040.94},{"date":"2001-09-30T22:00:00.000Z","price":1059.78},{"date":"2001-10-31T23:00:00.000Z","price":1139.45},{"date":"2001-11-30T23:00:00.000Z","price":1148.08},{"date":"2001-12-31T23:00:00.000Z","price":1130.2},{"date":"2002-01-31T23:00:00.000Z","price":1106.73},{"date":"2002-02-28T23:00:00.000Z","price":1147.39},{"date":"2002-03-31T22:00:00.000Z","price":1076.92},{"date":"2002-04-30T22:00:00.000Z","price":1067.14},{"date":"2002-05-31T22:00:00.000Z","price":989.82},{"date":"2002-06-30T22:00:00.000Z","price":911.62},{"date":"2002-07-31T22:00:00.000Z","price":916.07},{"date":"2002-08-31T22:00:00.000Z","price":815.28},{"date":"2002-09-30T22:00:00.000Z","price":885.76},{"date":"2002-10-31T23:00:00.000Z","price":936.31},{"date":"2002-11-30T23:00:00.000Z","price":879.82},{"date":"2002-12-31T23:00:00.000Z","price":855.7},{"date":"2003-01-31T23:00:00.000Z","price":841.15},{"date":"2003-02-28T23:00:00.000Z","price":848.18},{"date":"2003-03-31T22:00:00.000Z","price":916.92},{"date":"2003-04-30T22:00:00.000Z","price":963.59},{"date":"2003-05-31T22:00:00.000Z","price":974.5},{"date":"2003-06-30T22:00:00.000Z","price":990.31},{"date":"2003-07-31T22:00:00.000Z","price":1008.01},{"date":"2003-08-31T22:00:00.000Z","price":995.97},{"date":"2003-09-30T22:00:00.000Z","price":1050.71},{"date":"2003-10-31T23:00:00.000Z","price":1058.2},{"date":"2003-11-30T23:00:00.000Z","price":1111.92},{"date":"2003-12-31T23:00:00.000Z","price":1131.13},{"date":"2004-01-31T23:00:00.000Z","price":1144.94},{"date":"2004-02-29T23:00:00.000Z","price":1126.21},{"date":"2004-03-31T22:00:00.000Z","price":1107.3},{"date":"2004-04-30T22:00:00.000Z","price":1120.68},{"date":"2004-05-31T22:00:00.000Z","price":1140.84},{"date":"2004-06-30T22:00:00.000Z","price":1101.72},{"date":"2004-07-31T22:00:00.000Z","price":1104.24},{"date":"2004-08-31T22:00:00.000Z","price":1114.58},{"date":"2004-09-30T22:00:00.000Z","price":1130.2},{"date":"2004-10-31T23:00:00.000Z","price":1173.82},{"date":"2004-11-30T23:00:00.000Z","price":1211.92},{"date":"2004-12-31T23:00:00.000Z","price":1181.27},{"date":"2005-01-31T23:00:00.000Z","price":1203.6},{"date":"2005-02-28T23:00:00.000Z","price":1180.59},{"date":"2005-03-31T22:00:00.000Z","price":1156.85},{"date":"2005-04-30T22:00:00.000Z","price":1191.5},{"date":"2005-05-31T22:00:00.000Z","price":1191.33},{"date":"2005-06-30T22:00:00.000Z","price":1234.18},{"date":"2005-07-31T22:00:00.000Z","price":1220.33},{"date":"2005-08-31T22:00:00.000Z","price":1228.81},{"date":"2005-09-30T22:00:00.000Z","price":1207.01},{"date":"2005-10-31T23:00:00.000Z","price":1249.48},{"date":"2005-11-30T23:00:00.000Z","price":1248.29},{"date":"2005-12-31T23:00:00.000Z","price":1280.08},{"date":"2006-01-31T23:00:00.000Z","price":1280.66},{"date":"2006-02-28T23:00:00.000Z","price":1294.87},{"date":"2006-03-31T22:00:00.000Z","price":1310.61},{"date":"2006-04-30T22:00:00.000Z","price":1270.09},{"date":"2006-05-31T22:00:00.000Z","price":1270.2},{"date":"2006-06-30T22:00:00.000Z","price":1276.66},{"date":"2006-07-31T22:00:00.000Z","price":1303.82},{"date":"2006-08-31T22:00:00.000Z","price":1335.85},{"date":"2006-09-30T22:00:00.000Z","price":1377.94},{"date":"2006-10-31T23:00:00.000Z","price":1400.63},{"date":"2006-11-30T23:00:00.000Z","price":1418.3},{"date":"2006-12-31T23:00:00.000Z","price":1438.24},{"date":"2007-01-31T23:00:00.000Z","price":1406.82},{"date":"2007-02-28T23:00:00.000Z","price":1420.86},{"date":"2007-03-31T22:00:00.000Z","price":1482.37},{"date":"2007-04-30T22:00:00.000Z","price":1530.62},{"date":"2007-05-31T22:00:00.000Z","price":1503.35},{"date":"2007-06-30T22:00:00.000Z","price":1455.27},{"date":"2007-07-31T22:00:00.000Z","price":1473.99},{"date":"2007-08-31T22:00:00.000Z","price":1526.75},{"date":"2007-09-30T22:00:00.000Z","price":1549.38},{"date":"2007-10-31T23:00:00.000Z","price":1481.14},{"date":"2007-11-30T23:00:00.000Z","price":1468.36},{"date":"2007-12-31T23:00:00.000Z","price":1378.55},{"date":"2008-01-31T23:00:00.000Z","price":1330.63},{"date":"2008-02-29T23:00:00.000Z","price":1322.7},{"date":"2008-03-31T22:00:00.000Z","price":1385.59},{"date":"2008-04-30T22:00:00.000Z","price":1400.38},{"date":"2008-05-31T22:00:00.000Z","price":1280},{"date":"2008-06-30T22:00:00.000Z","price":1267.38},{"date":"2008-07-31T22:00:00.000Z","price":1282.83},{"date":"2008-08-31T22:00:00.000Z","price":1166.36},{"date":"2008-09-30T22:00:00.000Z","price":968.75},{"date":"2008-10-31T23:00:00.000Z","price":896.24},{"date":"2008-11-30T23:00:00.000Z","price":903.25},{"date":"2008-12-31T23:00:00.000Z","price":825.88},{"date":"2009-01-31T23:00:00.000Z","price":735.09},{"date":"2009-02-28T23:00:00.000Z","price":797.87},{"date":"2009-03-31T22:00:00.000Z","price":872.81},{"date":"2009-04-30T22:00:00.000Z","price":919.14},{"date":"2009-05-31T22:00:00.000Z","price":919.32},{"date":"2009-06-30T22:00:00.000Z","price":987.48},{"date":"2009-07-31T22:00:00.000Z","price":1020.62},{"date":"2009-08-31T22:00:00.000Z","price":1057.08},{"date":"2009-09-30T22:00:00.000Z","price":1036.19},{"date":"2009-10-31T23:00:00.000Z","price":1095.63},{"date":"2009-11-30T23:00:00.000Z","price":1115.1},{"date":"2009-12-31T23:00:00.000Z","price":1073.87},{"date":"2010-01-31T23:00:00.000Z","price":1104.49},{"date":"2010-02-28T23:00:00.000Z","price":1140.45 }]);
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
}
function type(d) {
d.date = parseDate(d.date);
d.price = +d.price;
return d;
}
.area {
fill: steelblue;
clip-path: url(#clip);
}
.line {
stroke: red;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="250"></svg>
Something like this:
focus.append("line")
.attr("class", "peak")
.style("stroke", "orange")
.attr("stroke-width", 3);
function setPeak(){
var maxY = {
x: null,
y: -1e100
};
data.forEach(function(d){
if (d.date >= x.domain()[0] &&
d.date <= x.domain()[1] &&
d.price > maxY.y){
maxY.y = d.price;
maxY.x = d.date;
}
});
d3.select(".peak")
.attr("x1", x(maxY.x))
.attr("x2", x(maxY.x))
.attr("y1", 0)
.attr("y2", height);
}
setPeak();
Running code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.area {
fill: steelblue;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
</style>
<svg width="400" height="300"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 110,
left: 40
},
margin2 = {
top: 230,
right: 20,
bottom: 30,
left: 40
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([
[0, 0],
[width, height2]
])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([
[0, 0],
[width, height]
])
.extent([
[0, 0],
[width, height]
])
.on("zoom", zoomed);
var area = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) {
return x(d.date);
})
.y0(height)
.y1(function(d) {
return y(d.price);
});
var area2 = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) {
return x2(d.date);
})
.y0(height2)
.y1(function(d) {
return y2(d.price);
});
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
//d3.csv("data.csv", type, function(error, data) {
// if (error) throw error;
var data = [{
"date": "1999-12-31T23:00:00.000Z",
"price": 1394.46
}, {
"date": "2000-01-31T23:00:00.000Z",
"price": 1366.42
}, {
"date": "2000-02-29T23:00:00.000Z",
"price": 1498.58
}, {
"date": "2000-03-31T22:00:00.000Z",
"price": 1452.43
}, {
"date": "2000-04-30T22:00:00.000Z",
"price": 1420.6
}, {
"date": "2000-05-31T22:00:00.000Z",
"price": 1454.6
}, {
"date": "2000-06-30T22:00:00.000Z",
"price": 1430.83
}, {
"date": "2000-07-31T22:00:00.000Z",
"price": 1517.68
}, {
"date": "2000-08-31T22:00:00.000Z",
"price": 1436.51
}, {
"date": "2000-09-30T22:00:00.000Z",
"price": 1429.4
}, {
"date": "2000-10-31T23:00:00.000Z",
"price": 1314.95
}, {
"date": "2000-11-30T23:00:00.000Z",
"price": 1320.28
}, {
"date": "2000-12-31T23:00:00.000Z",
"price": 1366.01
}, {
"date": "2001-01-31T23:00:00.000Z",
"price": 1239.94
}, {
"date": "2001-02-28T23:00:00.000Z",
"price": 1160.33
}, {
"date": "2001-03-31T22:00:00.000Z",
"price": 1249.46
}, {
"date": "2001-04-30T22:00:00.000Z",
"price": 1255.82
}, {
"date": "2001-05-31T22:00:00.000Z",
"price": 1224.38
}, {
"date": "2001-06-30T22:00:00.000Z",
"price": 1211.23
}, {
"date": "2001-07-31T22:00:00.000Z",
"price": 1133.58
}, {
"date": "2001-08-31T22:00:00.000Z",
"price": 1040.94
}, {
"date": "2001-09-30T22:00:00.000Z",
"price": 1059.78
}, {
"date": "2001-10-31T23:00:00.000Z",
"price": 1139.45
}, {
"date": "2001-11-30T23:00:00.000Z",
"price": 1148.08
}, {
"date": "2001-12-31T23:00:00.000Z",
"price": 1130.2
}, {
"date": "2002-01-31T23:00:00.000Z",
"price": 1106.73
}, {
"date": "2002-02-28T23:00:00.000Z",
"price": 1147.39
}, {
"date": "2002-03-31T22:00:00.000Z",
"price": 1076.92
}, {
"date": "2002-04-30T22:00:00.000Z",
"price": 1067.14
}, {
"date": "2002-05-31T22:00:00.000Z",
"price": 989.82
}, {
"date": "2002-06-30T22:00:00.000Z",
"price": 911.62
}, {
"date": "2002-07-31T22:00:00.000Z",
"price": 916.07
}, {
"date": "2002-08-31T22:00:00.000Z",
"price": 815.28
}, {
"date": "2002-09-30T22:00:00.000Z",
"price": 885.76
}, {
"date": "2002-10-31T23:00:00.000Z",
"price": 936.31
}, {
"date": "2002-11-30T23:00:00.000Z",
"price": 879.82
}, {
"date": "2002-12-31T23:00:00.000Z",
"price": 855.7
}, {
"date": "2003-01-31T23:00:00.000Z",
"price": 841.15
}, {
"date": "2003-02-28T23:00:00.000Z",
"price": 848.18
}, {
"date": "2003-03-31T22:00:00.000Z",
"price": 916.92
}, {
"date": "2003-04-30T22:00:00.000Z",
"price": 963.59
}, {
"date": "2003-05-31T22:00:00.000Z",
"price": 974.5
}, {
"date": "2003-06-30T22:00:00.000Z",
"price": 990.31
}, {
"date": "2003-07-31T22:00:00.000Z",
"price": 1008.01
}, {
"date": "2003-08-31T22:00:00.000Z",
"price": 995.97
}, {
"date": "2003-09-30T22:00:00.000Z",
"price": 1050.71
}, {
"date": "2003-10-31T23:00:00.000Z",
"price": 1058.2
}, {
"date": "2003-11-30T23:00:00.000Z",
"price": 1111.92
}, {
"date": "2003-12-31T23:00:00.000Z",
"price": 1131.13
}, {
"date": "2004-01-31T23:00:00.000Z",
"price": 1144.94
}, {
"date": "2004-02-29T23:00:00.000Z",
"price": 1126.21
}, {
"date": "2004-03-31T22:00:00.000Z",
"price": 1107.3
}, {
"date": "2004-04-30T22:00:00.000Z",
"price": 1120.68
}, {
"date": "2004-05-31T22:00:00.000Z",
"price": 1140.84
}, {
"date": "2004-06-30T22:00:00.000Z",
"price": 1101.72
}, {
"date": "2004-07-31T22:00:00.000Z",
"price": 1104.24
}, {
"date": "2004-08-31T22:00:00.000Z",
"price": 1114.58
}, {
"date": "2004-09-30T22:00:00.000Z",
"price": 1130.2
}, {
"date": "2004-10-31T23:00:00.000Z",
"price": 1173.82
}, {
"date": "2004-11-30T23:00:00.000Z",
"price": 1211.92
}, {
"date": "2004-12-31T23:00:00.000Z",
"price": 1181.27
}, {
"date": "2005-01-31T23:00:00.000Z",
"price": 1203.6
}, {
"date": "2005-02-28T23:00:00.000Z",
"price": 1180.59
}, {
"date": "2005-03-31T22:00:00.000Z",
"price": 1156.85
}, {
"date": "2005-04-30T22:00:00.000Z",
"price": 1191.5
}, {
"date": "2005-05-31T22:00:00.000Z",
"price": 1191.33
}, {
"date": "2005-06-30T22:00:00.000Z",
"price": 1234.18
}, {
"date": "2005-07-31T22:00:00.000Z",
"price": 1220.33
}, {
"date": "2005-08-31T22:00:00.000Z",
"price": 1228.81
}, {
"date": "2005-09-30T22:00:00.000Z",
"price": 1207.01
}, {
"date": "2005-10-31T23:00:00.000Z",
"price": 1249.48
}, {
"date": "2005-11-30T23:00:00.000Z",
"price": 1248.29
}, {
"date": "2005-12-31T23:00:00.000Z",
"price": 1280.08
}, {
"date": "2006-01-31T23:00:00.000Z",
"price": 1280.66
}, {
"date": "2006-02-28T23:00:00.000Z",
"price": 1294.87
}, {
"date": "2006-03-31T22:00:00.000Z",
"price": 1310.61
}, {
"date": "2006-04-30T22:00:00.000Z",
"price": 1270.09
}, {
"date": "2006-05-31T22:00:00.000Z",
"price": 1270.2
}, {
"date": "2006-06-30T22:00:00.000Z",
"price": 1276.66
}, {
"date": "2006-07-31T22:00:00.000Z",
"price": 1303.82
}, {
"date": "2006-08-31T22:00:00.000Z",
"price": 1335.85
}, {
"date": "2006-09-30T22:00:00.000Z",
"price": 1377.94
}, {
"date": "2006-10-31T23:00:00.000Z",
"price": 1400.63
}, {
"date": "2006-11-30T23:00:00.000Z",
"price": 1418.3
}, {
"date": "2006-12-31T23:00:00.000Z",
"price": 1438.24
}, {
"date": "2007-01-31T23:00:00.000Z",
"price": 1406.82
}, {
"date": "2007-02-28T23:00:00.000Z",
"price": 1420.86
}, {
"date": "2007-03-31T22:00:00.000Z",
"price": 1482.37
}, {
"date": "2007-04-30T22:00:00.000Z",
"price": 1530.62
}, {
"date": "2007-05-31T22:00:00.000Z",
"price": 1503.35
}, {
"date": "2007-06-30T22:00:00.000Z",
"price": 1455.27
}, {
"date": "2007-07-31T22:00:00.000Z",
"price": 1473.99
}, {
"date": "2007-08-31T22:00:00.000Z",
"price": 1526.75
}, {
"date": "2007-09-30T22:00:00.000Z",
"price": 1549.38
}, {
"date": "2007-10-31T23:00:00.000Z",
"price": 1481.14
}, {
"date": "2007-11-30T23:00:00.000Z",
"price": 1468.36
}, {
"date": "2007-12-31T23:00:00.000Z",
"price": 1378.55
}, {
"date": "2008-01-31T23:00:00.000Z",
"price": 1330.63
}, {
"date": "2008-02-29T23:00:00.000Z",
"price": 1322.7
}, {
"date": "2008-03-31T22:00:00.000Z",
"price": 1385.59
}, {
"date": "2008-04-30T22:00:00.000Z",
"price": 1400.38
}, {
"date": "2008-05-31T22:00:00.000Z",
"price": 1280
}, {
"date": "2008-06-30T22:00:00.000Z",
"price": 1267.38
}, {
"date": "2008-07-31T22:00:00.000Z",
"price": 1282.83
}, {
"date": "2008-08-31T22:00:00.000Z",
"price": 1166.36
}, {
"date": "2008-09-30T22:00:00.000Z",
"price": 968.75
}, {
"date": "2008-10-31T23:00:00.000Z",
"price": 896.24
}, {
"date": "2008-11-30T23:00:00.000Z",
"price": 903.25
}, {
"date": "2008-12-31T23:00:00.000Z",
"price": 825.88
}, {
"date": "2009-01-31T23:00:00.000Z",
"price": 735.09
}, {
"date": "2009-02-28T23:00:00.000Z",
"price": 797.87
}, {
"date": "2009-03-31T22:00:00.000Z",
"price": 872.81
}, {
"date": "2009-04-30T22:00:00.000Z",
"price": 919.14
}, {
"date": "2009-05-31T22:00:00.000Z",
"price": 919.32
}, {
"date": "2009-06-30T22:00:00.000Z",
"price": 987.48
}, {
"date": "2009-07-31T22:00:00.000Z",
"price": 1020.62
}, {
"date": "2009-08-31T22:00:00.000Z",
"price": 1057.08
}, {
"date": "2009-09-30T22:00:00.000Z",
"price": 1036.19
}, {
"date": "2009-10-31T23:00:00.000Z",
"price": 1095.63
}, {
"date": "2009-11-30T23:00:00.000Z",
"price": 1115.1
}, {
"date": "2009-12-31T23:00:00.000Z",
"price": 1073.87
}, {
"date": "2010-01-31T23:00:00.000Z",
"price": 1104.49
}, {
"date": "2010-02-28T23:00:00.000Z",
"price": 1140.45
}];
data = data.map(type);
console.log(data)
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.price;
})]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
focus.append("line")
.attr("class", "peak")
.style("stroke", "orange")
.attr("stroke-width", 3);
//});
function setPeak(){
var maxY = {
x: null,
y: -1e100
};
data.forEach(function(d){
if (d.date >= x.domain()[0] &&
d.date <= x.domain()[1] &&
d.price > maxY.y){
maxY.y = d.price;
maxY.x = d.date;
}
});
d3.select(".peak")
.attr("x1", x(maxY.x))
.attr("x2", x(maxY.x))
.attr("y1", 0)
.attr("y2", height);
}
setPeak();
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
setPeak();
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = new Date(d.date);
d.price = +d.price;
return d;
}
</script>

Json d3 access each object

{
"name": "Max",
"value": 107,
"children": [
{
"name": "Don",
"value": 60,
"children" [
{"name": "CC", "value": 25},
{"name": "Jim", "value": 35}
]
},
{
"name": "David",
"value": 47,
"children": [
{"name": "Jeff", "value": 32},
{"name": "Buffy", "value": 15}
]
}
]
}
How can I access the inner most child name with d3?
I tried doing :
.text(function (d) { return d.children ? null : d.name; });
But it didn't work....
When I do
.text(function (d) { return d.name });
it only shows the name of the outer loop --> Don, David.
d3.json('flare.json', function (data) {
var canvas = d3.select('p1')
.append('svg')
.attr('width', 800)
.attr('height', 800)
var color = d3.scale.category20c();
var data1 = data.children;
canvas.selectAll('text')
.data(data1)
.enter()
.append('text')
.attr('x', function (d) { return 2; })
.attr('y', function (d, i) { return i * 15; })
.attr('fill', 'black')
.style('font-size', '12px')
.text(function (d) { return d.children ? null: d.name; })
Data I had before ↓ ↓
{
"name": "Don",
"value": 75,
"children" [
{"name": "CC", "value": 25},
{"name": "Jim", "value": 35}
]
}
When the data was in this single nested format, my code worked perfectly, but when I did double nest on it, it no longer works
You need a recursive function for this --
function getNames(d) {
return d.children ? d.children.map(getNames) : d.name;
}
This will return a nested list with the names of the elements that have no children.

Resources