Change Legends and Node to an circle image - javascript

I'm still new in D3.js , currently I had hand over with the project using D3.js.
May I ask about how to change the colour Scale to image ?
The Nodes and Legends is related, the Node color is based on Legends.
Here with my JSON.
"colourScale":"d3.scaleOrdinal().domain([\"Low\",\"Medium\",\"High\",\"Very High\"]).range([\"#009a44\",\"#eaaa00\",\"#f68d2e\",\"#bc204b\"]);",
and here with my Javascript
// draw nodes
var node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.style("fill", function(d) {
if(d['group']==='Low')
{
return "#009a44";
}
else if(d['group']==='Medium')
{
return "#eaaa00";
}
else if(d['group']==='High')
{
return "#f68d2e";
}
else{
return "#bc204b";
}
})
.style("opacity", options.opacity)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click)
.call(drag);
Here with my screenshot of result.

First of all, I'd recommend you to read the this documentation that could provide you with some insights on how to manage colors with d3.js.
Actually you have all the required information in your JSON. So firstly you should create your scale object. Here is an example using the data provided in your JSON.
var myData = ["Low","Medium","High","Very High"];
// Defining colors
var color = d3.scaleOrdinal()
.domain(myData)
.range(["#009a44","#eaaa00","#f68d2e","#bc204b"]) // Your data
.unknown('black') // Fallback solution
After that you should apply this object to your d3 structure in some similar manner:
d3
... // Here goes your svg structure creation
.style('fill', function(d) { // Applying your original scale
return color(d.group);
});
Here you can find a complete example of your node graph with legend
var myData = ["Low","Medium","High","Very High"];
var graph = {
"nodes": [
{"id": "Myriel", "group": 'Low'},
{"id": "Napoleon", "group": 'Low'},
{"id": "Mlle", "group": 'Medium'},
{"id": "Mme", "group": 'Medium'},
{"id": "CountessdeLo", "group": 'High'},
{"id": "Geborand", "group": 'Very High'},
{"id": "Champtercier", "group": 'Very High'},
{"id": "Cravatte", "group": 'Random'},
],
"links": [
]
}
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
// Defining colors
var color = d3.scaleOrdinal()
.domain(myData)
.range(["#009a44","#eaaa00","#f68d2e","#bc204b"]) // Your data
.unknown('black') // Fallback solution
var linearScale = d3.scaleLinear()
.domain([0, myData.length - 1])
.range([0, 100]);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(graph.nodes)
.enter().append("g")
var circles = node.append("circle")
.attr("r", 20)
.attr("fill", function(d) { return color(d.group); });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.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("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
}
d3.select('#wrapper')
.selectAll('text')
.data(myData)
.enter()
.append('text')
.attr('y', function(d, i) {
return linearScale(i);
})
.text(function(d) {
return d;
})
.style('fill', function(d) {
return color(d);
});
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
text {
font-family: sans-serif;
font-size: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<svg width="960" height="600">
<g id="wrapper" transform="translate(100, 40)">
</g>
</svg>
Please, let me know if my answer is not clear for you or you need some additional information or help.

Related

JS / d3.js: Steps to Highlighting of adjacent links

Good day,
My earlier question for this project would be:
D3.js: Dynamically generate source and target based on identical json values
I am new to d3.js, especially in the data manipulation and node graphs area.. I would like to ask several questions regarding data manipulation with regards to creating node graphs. While carrying out my project, here are several problems I have encountered, leading to several questions:
1) Must the source and target values be unique in nature?
Will the linking work if the source/target values are non-unique?
2) A way to highlight/change attributes of links connected to the current selected node
So far, I am only able to change the current node's properties using:
var simulation = d3.forceSimulation(graphData)
.force("charge", d3.forceManyBody().strength(-300))
.force("link", d3.forceLink().id(function(d) { return d[idSel]; }).distance(70))
.force("x", d3.forceX(width/2))
.force("y", d3.forceY(height/2))
.on("tick", ticked);
var g = svg.append("g"),
link = g.append("g").attr("stroke-width", 1.5).selectAll(".link"),
node = g.append("g").attr("stroke-width", 1.5).selectAll(".node");
simulation.nodes(graphData);
simulation.force("link").links(links);
link = link
.data(links)
.enter().append("line")
.attr("class", "link");
node = node
.data(graphData)
.enter().append("circle")
.attr("class", "node")
.attr("r", 6)
.style("fill", function(d, i) { return colors(d[idSel]); })
.on("click", function (d, i, l) {
//Node Effect - Change only selected node's size
d3.selectAll(".node").attr("r", 6);
d3.select(this).attr("r", 12);
//Link Effect - Highlight adjacent Links
... Need help here ...
});
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; });
}
I have gotten the simulation example from: http://bl.ocks.org/mbostock/1095795
However, I do understand this is inefficient as well, but I have no other way to do it given my limited knowledge on d3..
Is there a good example around for me to learn how to highlight the links as well?
Also, I see that I have to use:
function restart()
{
node.exit().remove();
link.exit().remove();
simulation.nodes(nodes);
simulation.force("link").links(links);
simulation.alpha(1).restart();
}
To restart the simulation, else any errors will result in the program unable to calculate the x/y values. However, when I implement this code as a restart function, the newly created nodes do not have x/y values anymore.. Am i doing something wrong?
So sorry for the vague question.. any guidance is very much appreciated. Thank you SO Community! :)
Answering only the question about how to highlight the links (since you didn't provide the links array, here is an answer based on your previous code):
node.on("click", function(d) {
var thisNode = d.id
d3.selectAll(".circleNode").attr("r", 6);
d3.select(this).attr("r", 12);
link.attr("opacity", function(d) {
return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
});
});
What does this code do?
First, we get the id of the clicked node:
var thisNode = d.id
Then, we scan the links to see if the source or the target has the same id:
(d.source.id == thisNode || d.target.id == thisNode)
If that is true, we set the opacity using a ternary operator:
(condition) ? 1 : 0.1
Here is the demo, click on the nodes:
var nodes = [{
"id": "red",
"value": "1"
}, {
"id": "orange",
"value": "2"
}, {
"id": "yellow",
"value": "3"
}, {
"id": "green",
"value": "1"
}, {
"id": "blue",
"value": "1"
}, {
"id": "violet",
"value": "3"
},{
"id": "white",
"value": "1"
},{
"id": "gray",
"value": "1"
},{
"id": "teal",
"value": "3"
}
];
var links = [];
for (var i = 0; i < nodes.length; i++) {
for (var j = i + 1; j < nodes.length; j++) {
if (nodes[i].value === nodes[j].value) {
links.push({
source: nodes[i].id,
target: nodes[j].id
});
}
}
};
var width = 300,
height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).distance(50))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1)
.attr("stroke", "gray")
.attr("fill", "none");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 6)
.attr("class", "circleNode")
.attr("stroke", "gray")
.attr("fill", function(d) {
return d.id;
});
node.on("click", function(d) {
var thisNode = d.id
d3.selectAll(".circleNode").attr("r", 6);
d3.select(this).attr("r", 12);
link.attr("opacity", function(d) {
return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
});
});
simulation
.nodes(nodes)
.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;
});
}
<script src="https://d3js.org/d3.v4.min.js"></script>

d3 force diagrams node positions

I am working with d3 force diagrams at the moment, I am wanting to plot my child nodes around a parent node equally spaced, so for example if I have a parent node, and 4 linked child nodes, I would want each those node positioned at 90 degree intervals? Is that possible?
Here is my current force code,
app.force
.nodes(nodes)
.links(app.edges)
.on("tick", tick)
.start();
function tick(e) {
// console.log(link);
var k = 6 * e.alpha;
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; });
linkText
.attr("x", function(d) {
return ((d.source.x + d.target.x)/2);
})
.attr("y", function(d) {
return ((d.source.y + d.target.y)/2);
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) { return d.y })
}
app.force = d3.layout.force()
.charge(-300)
.linkDistance(85)
.size([width, height]);
//Where we will draw our visualisation
app.svg = d3.select(".visualisation").append("svg")
.attr('width', width)
.attr('height', height);
d3.layout.force() was not created with such customisation in mind. Of course you can set some parameters, but most of the positions are automatic calculated, and changing them can be very difficult (unless you create your own force function). Version 4.x is better in that matter, but not much.
In your specific case, you can set a very high (mathematically speaking, "very low", since it is negative) charge:
var force = d3.layout.force()
.charge(-3000)
But even doing that the angles are not exactly right angles, and they vary: if you click "run snippet" you can get an almost perfect cross, but if you click it again it's not that perfect the next time. And it will not work as expected if you have data with several levels of depth.
Here is a demo:
<script src="https://d3js.org/d3.v2.min.js?2.9.3"></script>
<style>
.link {
stroke: #aaa;
}
.node text {
stroke: #333;
cursor: pointer;
}
.node circle {
stroke: #fff;
stroke-width: 3px;
fill: #555;
}
</style>
<body>
<script>
var width = 400,
height = 300
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.distance(50)
.charge(-3000)
.size([width, height]);
var json = {
"nodes": [{
"name": "node1"
}, {
"name": "node2"
}, {
"name": "node3"
}, {
"name": "node4"
}, {
"name": "node5"
}],
"links": [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}, {
"source": 0,
"target": 4
}]
};
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", 2);
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
return d.name
});
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("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
</script>

How do I have a specific d3 node be an image in a force directed graph?

I have made a force directed graph which looks similar to this.
I would like the Nine Inch Nails node, in the centre, to be an image but the rest of the nodes to just be circles. Following this answer it seemed not too difficult but I just can't get my head around the combonation of svg, defs, patterns and d3.
My code is:
var simulation =
d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(-50))
.force("collide", d3.forceCollide().radius(function (d) { return 15 - d.group}).strength(2).iterations(2))
.force("link", d3.forceLink().id(function(d, i) { return i;}).distance(20).strength(0.9))
.force("center", d3.forceCenter(width/2, height/2))
.force('X', d3.forceX(width/2).strength(0.15))
.force('Y', d3.forceY(height/2).strength(0.15));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "vit-icon")
.attr("width", 48)
.attr("height", 48)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", "http://placekitten.com/g/48/48")
.attr("width", 48)
.attr("height", 48)
.attr("x", width/2)
.attr("y", height/2)
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("id", function(d, i) { return 'c'+i})
.attr("r", radius)
.attr("fill", function(d) {
if(d.group==0) {return "url(#vit-icon)";}
else {return color(d.group); }
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
As I say, it seems straight forward in my mind. Basically what I think I'm trying to do is have the image in the svg pattern, then use an if statement to tell my root node to use the image url rather than fill with colour.
In dev tools I can see inspect the image and it shows the blue area it would take up and the node I want it to be associatated to has the 'url(#vit-icon)' as it's fill attribute. But it is not showing the image or any fill for that node.
What am I doing wrong? Or is this the complete wrong approach?
Thanks.
In your defs, just change:
.attr("x", width/2)
.attr("y", height/2)
To:
.attr("x", 0)
.attr("y", 0);
Here is a demo:
var nodes = [{
"id": 1,
}, {
"id": 2,
}, {
"id": 3,
}, {
"id": 4,
}, {
"id": 5,
}, {
"id": 6,
}, {
"id": 7,
}, {
"id": 8,
}];
var links = [{
source: 1,
target: 2
}, {
source: 1,
target: 3
}, {
source: 1,
target: 4
}, {
source: 2,
target: 5
}, {
source: 2,
target: 6
}, {
source: 1,
target: 7
}, {
source: 7,
target: 8
}];
var index = 10;
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "vit-icon")
.attr("width", 1)
.attr("height", 1)
.append("svg:image")
.attr("xlink:href", "http://66.media.tumblr.com/avatar_1c725152c551_128.png")
.attr("width", 48)
.attr("height", 48)
.attr("x", 0)
.attr("y", 0);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).distance(100))
.force("collide", d3.forceCollide(50))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
link = svg.selectAll(".link")
.data(links, function(d) {
return d.target.id;
})
link = link.enter()
.append("line")
.attr("class", "link");
node = svg.selectAll(".node")
.data(nodes, function(d) {
return d.id;
})
node = node.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("circle")
.attr("r", d=> d.id === 1 ? 24 : 14)
.style("fill", function(d) {
if (d.id === 1) {
return "url(#vit-icon)";
} else {
return "teal"
}
})
simulation
.nodes(nodes)
.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("transform", function(d) {
return "translate(" + d.x + ", " + d.y + ")";
});
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
}
.link {
stroke: #aaa;
}
.node {
pointer-events: all;
stroke: none;
stroke-width: 40px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="300"></svg>

d3 v4 update/merge grouped data

I am trying to update data for a force simulation in D3 v4, similar to this unsuccessful attempt and semi-similar to this successful one. CodePen here
Instead of joining the new nodes it appears to be doubling all the nodes (see pictures). It does not seem to be refreshing the graph correctly either.
(initial graph)
(after adding data)
HTML:
<button onclick="addData()">Add Data</button>
<svg width="960" height="600"></svg>
JavaScript:
function addData() {
graph.nodes.push({"id": "Extra1", "group": 11},{"id": "Extra2", "group": 11})
graph.links.push({"source": "Extra1", "target": "Valjean", "strength": 1},{"source": "Extra1", "target": "Extra2", "strength": 2})
update()
simulation.restart()
}
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var link, linkEnter, nodeWrapper, nodeWrapperEnter;
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
var allLinkG = svg.append("g")
.attr("class", "allLinkG")
var allNodeG = svg.append("g")
.attr("class", "allNodeG")
update()
simulation.restart()
function update(){
link = allLinkG
.selectAll("line")
.data(graph.links, function(d){ return d.id })
link.exit().remove()
linkEnter = link
.enter().append("line");
link = linkEnter.merge(link).attr("class","merged");
nodeWrapper = allNodeG
.selectAll("nodeWrapper")
.data(graph.nodes, function(d) { return d.id; })
nodeWrapper.exit().remove();
nodeWrapperEnter = nodeWrapper.enter()
.append("g").attr("class","nodeWrapper")
.append("circle")
.attr("r", 2.5)
nodeWrapper = nodeWrapperEnter
.merge(nodeWrapper).attr("class","merged");
simulation
.nodes(graph.nodes);
simulation.force("link")
.links(graph.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; });
nodeWrapper
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
Thanks very much for any help.
A few issues here:
Your selectAll is selecting by element type nodeWrapper, you meant by class .nodeWrapper.
You change the class name to "merged" after your .merge, you can't do this as it breaks future selections by .nodeWrapper class.
When you .merge your selection, you are merging circles with gs. You should stay consistent and operate on the gs only.
Quick refactor:
function update() {
link = allLinkG
.selectAll("line")
.data(graph.links, function(d) {
return d.id
})
link.exit().remove()
linkEnter = link
.enter().append("line");
link = linkEnter.merge(link).attr("class", "merged");
nodeWrapper = allNodeG
.selectAll(".nodeWrapper") //<-- class nodeWrapper
.data(graph.nodes, function(d) {
return d.id;
})
nodeWrapperEnter = nodeWrapper.enter()
.append("g").attr("class", "nodeWrapper"); //<-- enter selection should be gs
nodeWrapperEnter //<-- append your circles
.append("circle")
.attr("r", 2.5)
nodeWrapper = nodeWrapperEnter //<-- merge, don't change class
.merge(nodeWrapper);
nodeWrapper.exit().remove(); //<-- and the exit
simulation
.nodes(graph.nodes);
simulation.force("link")
.links(graph.links);
}
Note, I also modified your tick function to operate on the g instead of the circle:
nodeWrapper
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
Full code is here.

Plot a Network with specified coordinates in D3.js

I was using D3.js to plot a network of pie charts using a force-directed layout using the example here. Now I would like to plot the network of pies at pre-calculated coordinates and I am unsure how to proceed. I have added two node attributes (x,y) for plotting, now I need to access them within my javascript.
I would also like to add mouse over labels to my pie charts, so I have added a variable labels, but am unsure about how to access those as well, but if I could get help with the xy coordinates, I bet I could figure out the mouse-over bits.
Thanks in advance!
Here is the html file:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #808080;
stroke-opacity: .6;
}
</style>
</head>
<body>
<script type="text/javascript">
graph = { "nodes":[{"proportions": [
{"group":1, "value": 25 },
{"group":2, "value": 0 },
{"group":3, "value": 0 },
{"group":4, "value": 0 }],"x":-315.838,"y":-500},{"proportions": [
{"group":1, "value": 0 },
{"group":2, "value": 25 },
{"group":3, "value": 0 },
{"group":4, "value": 0 }],"x":500,"y":-315.851},{"proportions": [
{"group":1, "value": 0 },
{"group":2, "value": 0 },
{"group":3, "value": 25 },
{"group":4, "value": 0 }],"x":315.838,"y":500},{"proportions": [
{"group":1, "value": 0 },
{"group":2, "value": 0 },
{"group":3, "value": 0 },
{"group":4, "value": 25 }],"x":-500,"y":315.851}],"links": [{ "source":0, "target":1, "length":900, "width":9},
{ "source":0, "target":3, "length":900, "width":9},
{ "source":1, "target":2, "length":900, "width":9},
{ "source":2, "target":3, "length":900, "width":9}]
}
var labels = ['mycave1','mycave2','mycave3','mycave4'];
var width = 4000,
height = 1000,
radius = 100,
color = d3.scale.category10();
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(0);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.charge(-120)
.linkDistance(4 * radius)
.size([width, height]);
force.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node");
node.selectAll("path")
.data(function(d, i) {return pie(d.proportions); })
.enter()
.append("svg:path")
.attr("d", arc)
.attr("fill", function(d, i) { return color(d.data.group); });;
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("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"});
});
</script>
</body>
</html>
You can reposition the entire pie charts if you define each one as a g element and use the transform:translate attribute. Your code would look something like this:
var pies = svg.selectAll('.pie')
.data(graph.nodes)
.enter()
.append("g")
.attr("class", "node")
.attr('transform', function(d){
return 'translate(' + d.x + ',' + d.y + ')';
});
Here's a fiddle of that in your code: fiddle
Only one node is visible in that because the other nodes have negative x/y attributes and are being translated off the page.
All of the data associated with a node will be visible when you have that node in your selection, while only the data of the individual slice will be visible when you select all of the slices. Also note that g elements don't have x and y attributes, only a transform attribute. Source: MDN

Categories