Using d3.js v3, I've made this bubble chart:
d3.json(JSON_URL, function(data) {
data = JSON.parse(data)
var nodes = pack.nodes(data);
var node = canvas.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + d.x + ","+ d.y + ")" ;});
node.append("circle")
.attr("r", function(d) {return d.r; })
.attr("fill", function (d, i) {return d.children ? "#fff" : color(i)})
.attr("opacity", 0.25)
.attr("stroke-width", "2");
node.append("text")
.text(function(d) {return d.children ? "" : d.name ;})
.attr("text-anchor", "middle")
.attr("class", "nodetext")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;})
.on("click", function(d) { window.open("https://twitter.com/hashtag/" + d.name.trim() + "\?src=hash"); })
.on("mouseover", function(d) {
d3.select(this).attr("r", 10).style("fill", "#2f4cff");
d3.select(this).style("cursor", "pointer");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5.5).style("fill", "#000");
});
//problem here
node.append("text")
.text(function(d) {return d.children ? "" : d.value ;})
.attr("text-anchor", "middle")
.attr("class", "nodevalue")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;});
}) ;
It's all well, expect the fact that the texts for d.value overlap the texts of d.name, while I want them to come under the d.name. The result should be something like this:
I tried to tweak the nodevalue class but it did not affect the positioning of texts.
How can I acheive this?
You can use the y attribute to position vertically your text. Your code is a bit hard to test because we don't have access to your json, so blindly the code for the text part would be :
node.append("text")
.text(function(d) {return d.children ? "" : d.name ;})
.attr("text-anchor", "middle")
.attr("class", "nodetext")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;})
.on("click", function(d) { window.open("https://twitter.com/hashtag/" + d.name.trim() + "\?src=hash"); })
.on("mouseover", function(d) {
d3.select(this).attr("r", 10).style("fill", "#2f4cff");
d3.select(this).style("cursor", "pointer");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5.5).style("fill", "#000");
});
node.append("text")
.text(function(d) {return d.children ? "" : d.value ;})
.attr("text-anchor", "middle")
.attr("class", "nodevalue")
.attr("y", 15) // adding y attribute to offset vertically your text
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;});
Related
I want to write relations between 2 nodes on the links that connect them. This is my code, I do not know why he did not work. Can you help me ?
Thanks a lot.
PS: Sorry for my english.
d3.json("links.json", function(json) {
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", function(d) { return Math.sqrt(d.weight); })
.style("stroke", function(d) { return color(d.group); });
link.append("path")
.attr("fill", "none")
.attr("stroke", "#333S")
.attr("stroke-width", "1.5px");
link.append("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function(d) {
return "translate(" +
((d.source.x + d.target.y)/2) + "," +
((d.source.x + d.target.y)/2) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
console.log(d.relation);
return d.relation;
});
});
This is a links.json example :
{
"nodes":[{"name":"Gaillard Ruzé","group":0},{"name":"Guillaume Budé,Gulielmus Budaeus","group":1}],
"links":[{"source":0,"target":1,"weight":1,"group":15,"relation":"est dédicataire de"}]
}
I'm splitting data into categories e.g. rich poor and all. Using dropdown to get those values to display on a scatterplot. First transition happens, everything works as expected. Text labels are correctly displayed too, however when another option is selected and second transition happened half of circles are disappearing and every other transition is messed up. Only works if option all selected than again, first transition works, after that it is all messed up.
Codepen
function render(someData) {
xScale
.domain([
d3.min(someData, function(d) {
return +d.poorToys;
}),
d3.max(someData, function(d) {
return +d.poorToys;
})
]);
yScale
.domain([
d3.min(someData, function(d) {
return +d.richToys;
}),
d3.max(someData, function(d) {
return +d.richToys;
})+ 20
]);
//Adding circles
var circles = svg.selectAll("circle")
.data(someData, function(d) {
return d.country;
});
I believe a problem starts here.
circles
.enter()
.append("circle")
.attr("cx", function(d) {
if (currentSelection === "rich") {
return width - margin.right;
} else if (currentSelection === "poor") {
return margin.left;
} else if (currentSelection === "all") {}
return xScale(+d.poorToys);
})
.attr("cy", function(d) {
if (currentSelection === "rich") {
return margin.top;
} else if (currentSelection === "poor") {
return height - margin.bottom;
} else if (currentSelection === "all") {}
return yScale(+d.richToys);
})
.attr("r", function(d) {
if (currentSelection === "all") {
return rad;
}
})
.style("fill", "red")
.append("title")
.text(function(d) {
return d.country + " reports books for " + d.poorToys + "% in poor areas and " + d.richToys + "% in rich areas.";
});
circles
.transition()
.duration(2000)
.attr("cx", function(d) {
return xScale(+d.poorToys);
})
.attr("cy", function(d) {
return yScale(+d.richToys);
})
.attr("r", function() {
if (currentSelection !== "all") {
return rad * 1.5;
} else {
return rad;
}
});
circles
.exit()
.transition()
.duration(1000)
.style("opacity", 0)
.remove();
//Update x axis
svg.select(".x.axis")
.transition()
.duration(1000)
.call(xAxis);
//Update y axis
svg.select(".y.axis")
.transition()
.duration(1000)
.call(yAxis);
if (currentSelection !== "all"){
var labels = svg.selectAll("text.labels")
.data(someData, function(d){
return d.country;
});
labels
.enter()
.append("text")
.attr("transform", function(d){
return "translate(" + xScale(+d.poorToys) + "," + yScale(+d.richToys) + ")";
})
.attr("dx", 2)
.attr("dy", 1)
.attr("class", "labels")
.style("fill", "white")
.style("font-size", "5px")
.text(function(d){
return d.country;
});
labels
.transition()
.duration(2000)
.style("opacity", 1);
labels
.exit()
.remove();
} else {
svg.selectAll("text.labels")
.transition()
.duration(1000)
.style("opacity", 0)
.remove();
}
}
You incorrectly give your x axis a class of x_axis on line 57 then later try to select it as x.axis in your render function on line 179.
Once you fix that up, I think it should work as expected.
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + -14 + "," + (height + 30) + ")")
.call(xAxis);
Updated Pen
Apart from the axis problem found by #ksav your main problem is that you don't position the labels. Many labels are present in rich and poor.
var labels = svg.selectAll("text.labels")
.data(someData, function(d){ return d.country; });
labels
.enter()
.append("text")
.attr("x", function(d){ return xScale(+d.poorToys); })
.attr("y", function(d){ return yScale(+d.richToys); })
.attr("dx", 2)
.attr("dy", 1)
.attr("class", "labels")
.attr("opacity", 0)
.style("fill", "white")
.style("font-size", "8px")
.text(function(d){ return d.country; })
.merge(labels)
.transition()
.duration(2000)
.attr("x", function(d){ return xScale(+d.poorToys); })
.attr("y", function(d){ return yScale(+d.richToys); })
.attr("opacity", 1);
Also don't position the circles based on the selection
circles
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(+d.poorToys); })
.attr("cy", function(d) { return yScale(+d.richToys); })
.attr("r", function(d) { return rad; })
.style("fill", "red")
.append("title")
.text(function(d) {
return d.country + " reports books for " + d.poorToys + "% in poor areas and " + d.richToys + "% in rich areas.";
});
I suspect I'm barking up the wrong tree - although I've got no errors in the console to help me out.
I've got this block of code:
var path = svg.data([json]).selectAll("path")
.data(partition.nodes)
.enter()
.append("path")
.attr("display", function(d) {
return d.depth ? null : "none";
})
.attr("d", arc)
.style("stroke", "#fff")
.style("fill", function(d) {
return color((d.children ? d : d.parent).name);
})
.attr("fill-rule", "evenodd")
.style("opacity", 1)
.each(stash);
//>>this section functions ok
path.append("title")
.text(function(d) {
return d.name + ": " + d.amount;
});
//>>this section throws no errors but "foo" does not appear
path.append("text")
.text(function(d) {
return "foo";
})
.style("stroke", "#3b5998")
.style("fill", "#3b5998");
The code snippet beginning path.append("title")... works ok but the final snippet beginning path.append("text")... adds the text foo to the html but it is not visible on the webpage - why is it not visible and how do I add labels?
This is part of this visual:
http://plnkr.co/edit/q9ODd5?p=preview
text cannot be nested with a path. You'll need to add it to the svg instead. Additionally, you'll want to position the text in some way:
svg.append("text")
.text(function(d) {
return "foo";
})
.attr("x", function(){ return 0 })
.attr("y", function(){ return 0 })
.style("stroke", "#3b5998")
.style("fill", "#3b5998");
The working code ended as the following:
var path = svg.data([json]).selectAll(".theArc")
.data(partition.nodes)
.enter()
.append("path")
.attr("class", "theArc") //<<<<<<<<<<new
.attr("id", function(d,i) { return "theArc_"+i; }) //Give each slice a unique ID //<<<<<<<<<<new jq
.attr("display", function(d) {
return d.depth ? null : "none";
})
.attr("d", arc)
.style("stroke", "#fff")
.style("fill", function(d) {
return color((d.children ? d : d.parent).name);
})
.attr("fill-rule", "evenodd")
.style("opacity", 1)
.each(stash);
path
.append("title") //mouseover title showing the figures
.text(function(d) {
return d.name + ": " + d.amount;
});
svg.data([json]).selectAll(".theTxts")
.data(partition.nodes)
.enter()
.append("text")
.attr("class", "theTxts")
.attr("dx", 10) //Move the text from the start angle of the arc
.attr("dy", 18) //Move the text down
.append("textPath")
.attr("xlink:href", function(d, i) {
return "#theArc_" + i;
})
.text(function(d) {
return d.name;
})
.style("stroke", "#3b5998")
.style("fill", "#3b5998");
Actually I've integrated collapsible feature inside bounded force directed graph. But when I tried to put a label on each node, I got unexpected output.
I used bellow code to append labels on node:
node.enter().append("text")
.attr("class","node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.on("click",click)
.text(function(d){return d.name})
.call(force.drag);
And below code I've written inside a tick function:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
What I might be doing wrong?
I need to append the g tag and then circle and text:
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("click", click)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 8.5; });
nodeEnter.append("text")
.attr("dy", ".35em")
.text(function(d) { return d.name; });
node.select("circle")
.style("fill", color);
i have the code below and wonder, why the textpath isn't displayed? Can anyone help?
var areas = svg.append("g").selectAll("path")
.data(chord.groups)
.enter().append("path")
.style("fill", function(d) { return fill(d.index); })
.style("stroke", function(d) { return fill(d.index); })
.attr("class", "bar")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius))
.on("mouseover", fade(.1))
.on("mouseout", fade(1));
svg.selectAll(".bar").append("text")
.style("font-size", "10px")
.attr("fill", "black")
.append("textPath")
.attr("x", 8)
.attr("dy", ".35em")
.style("fill", "#ff00ff")
.attr("xlink:href", function(d, i) { return "#group" + i; })
.text("Textexample");
Thank you very much!
Benjamin