Im trying to filter a dataset to only display labels for some select elements. The filter shown here seems to work, except it creates thousands of blank elements, which I obviously want to avoid. This is because the filter comes after the append, but if I move the filter above the append statement , it breaks.
What am i doing wrong here
var labels = svg.selectAll("text.label")
.data(partition.nodes(bp.data.preparedData))
.enter()
.append("text")
.filter(function(d){return d.ci_type === 'type'})
.attr("class", "label")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d, i) { return d.name } );
It sounds like you want to filter your data before passing it to D3. That is, your code would be
var labels = svg.selectAll("text.label")
.data(partition.nodes(bp.data.preparedData).filter(
function(d){return d.ci_type === 'type'}))
.enter()
.append("text")
.attr("class", "label")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d, i) { return d.name } );
Related
I'm following this tutorial for a D3 Circle Pack chart. https://bl.ocks.org/denjn5/6d5ddd4226506d644bb20062fc60b53f
How can I add the text from the ID column of the CSV to each circle?
Instead of creating a circle, you can create a group and have a circle and a text inside it.
So instead of:
// Draw on screen
vSlices.attr('cx', function (d) { return d.x; })
.attr('cy', function (d) { return d.y; })
.attr('r', function (d) { return d.r; });
You would do:
var gNode = vSlices
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
gNode.append("circle").attr("r", function(d) {
return d.r;
});
gNode
.append("text")
.style("font", "10px sans-serif")
.attr("text-anchor", "middle")
.text(function(d) {
return d.data.id;
});
Notice that the translation is being done in the group and the attributes are different.
I hope it helps.
I'm building a d3 pie chart with labels on the centroids just like so many examples. I've checked my code against many of those examples but can't figure out where or how my centroids are being calculated. The labels appear to be arranged around the origin of the svg and not the center of the chart like I'd expect. I feel like there's a grouping issue since the text is added but it's not grouped with the arc. Unfortunately, I have no idea how to fix it.
var arcs = svg.datum(domain)
.selectAll('path')
.data(pie);
arcs.enter()
.append('path')
.attr('fill', function(d, i){
return color[i];
})
.attr('d', arc)
.each(function(d) {
this._current = d;
}) // store the initial angles
.attr('transform', 'translate(' + outerRadius + ", " + outerRadius + ')');
arcs.enter()
.append("text")
.attr("transform", function(d) {
console.log(arc.centroid(d));
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d,i) {
return data[i].playerName+": "+data[i].playerScore;
});
Here's a fiddle with the complete code.
You need to also move the text over to adjust for the radius of the chart:
arcs.enter()
.append("text")
.attr("transform", function(d) {
console.log(arc.centroid(d));
return "translate(" + arc.centroid(d) + ")translate(" + outerRadius + ", " + outerRadius + ")";
})
.attr("text-anchor", "middle")
.text(function(d,i) {
return data[i].playerName+": "+data[i].playerScore;
});
This will shift everything over to match the locations of the arcs' centroids.
I am going to draw a line chart using d3.js. I am plotting time in the x axis and speed in the y axis of different vehicle ids. But one thing I am not getting seconds from my data. the code is rounding seconds to minute. So I am getting wrong chart. I am trying to draw something like http://bl.ocks.org/mbostock/3884955.
Here is my code
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").ticks(d3.time.minutes,5).tickFormat(d3.time.format("%H:%M:%S"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.speed); });
/* var points = popchart.selectAll(".point")
.data(data)
.enter().append("svg:circle")
.attr("stroke", "black")
.attr("fill", function(d, i) { return color(i) })
.attr("cx", function(d, i) { return x(d.time) })
.attr("cy", function(d, i) { return y(d.speed) })
.attr("r", function(d, i) { return 3 }); */
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "time"; }));
var ids = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {time: d.time, speed: +d[name]};
})
};
});
x.domain([d3.min(data,function(d){return d.time}),d3.max(data,function(d){return d.time})]);
y.domain([
d3.min(ids, function(c) { return d3.min(c.values, function(v) { return v.speed; }); }),
d3.max(ids, function(c) { return d3.max(c.values, function(v) { return v.speed; }); })
]);
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Speed (mph)");
var id = svg.selectAll(".id")
.data(ids)
.enter().append("g")
.attr("class", "id");
id.append("path")
.attr("class", "line")
.attr("d", function(d) {return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
id.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.time) + "," + y(d.value.speed) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
Though I am picking time in %H:%M:%S format the second is not coming in the chart. Why is this happening?
The reason you are getting loop is only one, Your data is not sorted according to time values as i am suspecting.In Your code you add the following for sorting the data according to time. And use this sorted data to draw the line chart.
Here is the code
data=data.sort(function(a, b) {
return d3.ascending(a.time,b.time);
});
Then pass this sorted data to draw the line chart. You are done
I forked your plunker, it seems as though some of the tabs in your tsv were actually spaces.
This was, for starters, causing massive problems in your plunk,
so for testing I've changed it to a csv, and moved your script into script.js so that it's a little more testable.
I'll try to have another look soon, but this should make it easier for others to debug also. Let us know if this is more like what you wanted
Plunk: http://plnkr.co/edit/bxncPdugtRTaWTdztraC?p=preview
d3.csv("data.csv", function(error, data) {
...
}
I'm using a range slider to add/remove points from a line which follows an histogram.
Without updating the data, the text labels are shown correctly, when I update the values with the slider I'd like that the text-labels follow the line, so they show the values of the points correctly.
The update for the line works, but I am not able to update the text labels correctly.
Right now the laberls are plotted like so outside of the on-change function:
var SerifText = svg.append("g")
.attr("id", "serif-labels")
.selectAll("text")
.data(histogSerif)
.enter()
.append("text")
.text(function (d) { return d.y >= 1 ? d.y : null; })
.attr("text-anchor", "middle")
.attr("font-size", 10 + "px")
.attr("fill", "#f0027f")
.attr("x", function (d) { return x(d.x)})
.attr("y", function (d) { return y(d.y) - padding; })
.attr("visibility", "hidden"); //the hidden & visible is managed by an external checkbox
And then on the on-change function I put this code:
SerifText.selectAll("text").remove();
/* If I do SerifText.remove() it does remove the text but also the group of course,
but as it is it doesn't work */
SerifText.selectAll("text")
.data(histogSerif)
.enter()
.append("text")
.text(function (d) { return d.y >= 1 ? d.y : null; })
.attr("text-anchor", "middle")
.attr("font-size", 10 + "px")
.attr("fill", "#f0027f")
.attr("x", function (d) { return x(d.x)})
.attr("y", function (d) { return y(d.y) - padding; });
But this doesn't work unfortunately. I'd like also to be able to retain the manage of the visible/hidden status by the external checkbox if possible.
Full code is here
Instead of trying to save a reference to the labels that you are going to delete, and then re-selecting them, how about just use a variable that references the SerifText element selection, e.g.:
var SerifTextGroup = svg.append("g")
.attr("id", "serif-labels");
SerifTextGroup.selectAll("text")
.data(histogSerif)
.enter()
//... and so on
Then the rest of your code should work as written (just change SerifText to SerifTextGroup).
I'm trying to set up a pie on d3.js that will constantly update its data (slices) and change the labels.
The slices of data may vary and are not constant (could be a 2 slices pie and 5 slices, etc.)
I've reviewed several of examples such as:
http://jsfiddle.net/emepyc/VYud2/3/
http://bl.ocks.org/mbostock/3808218
But the thing is, my implementation is quite different since I use both text lables and paths.
The problem: data is not updated and text is not removed.
Here is my code: http://jsfiddle.net/Kitt0s/vfkSs/
function tests (data) {
data = data ? data : { "slice1": Math.floor((Math.random()*10)+1), "slice2": Math.floor((Math.random()*10)+1), "slice3": Math.floor((Math.random()*10)+1), "slice4": Math.floor((Math.random()*10)+1) };
var dataa = d3.entries(data);
var cv_path = cv_svg.selectAll("g.slice")
.data(cv_pie(dataa));
cv_path.enter()
.append("g")
.attr("class", "slice")
.append("path")
.attr("fill", function(d, i) { return cv_color(i); } )
.attr("d", cv_arc)
.each(function(d) { this._current = d; });
cv_path.transition().duration(750).attrTween("d", cv_arcTween);
cv_path.exit().remove();
var cv_text = d3.selectAll(".slice")
.append("text")
.attr("transform", function(d) {
d.innerRadius = 0;
d.outerRadius = cv_r;
return "translate(" + cv_arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.attr("font-weight", "bold")
.attr("fill", "#FFFFFF")
.attr("font-size", "30px")
.text(function(d) { return d.data.key + "(" + d.data.value + ")"; });
cv_text.exit().remove();
}
I've spent an awful lot of time trying to get this right, but still seem to get stuck (every time something else breaks.. :P)
Your help would be highly appreciated!
You were almost there. The key is to treat the text exactly the same as the paths and handle the .exit() selection by removing it. I've modified your jsfiddle here. I've removed the g elements to make it a bit easier to understand.