In this Plunkr after you've updated the chart, the percentage that's displayed is completely wrong.
The displayed percentage before the update is however correct and I have no idea as to why this is .
Here's part of the code that isn't behaving as expected.
label.transition()
.duration(750)
.text(function(d) {
return textFormat(100/(d.data.total/d.data["apples" + CAT]))+'%'});
Any help is appreciated!
You only ever calculate d.total for category one. In your update function you need to rerun:
data.forEach(function(d) {
d.total = d3.sum(data, function(d) { return d3.sum([d["apples" + CAT]]); });
});
Related
I've previously made a really neat bar chart using d3 and d3tip with some help from StackOverflow (result here). This time I'm trying to achieve something similar with d3tip whilst using a stacked bar chart. I've managed to create the stacked bar chart using examples found on the web, but I can't manage to get the tip to work (snippet of stacked bar chart here).
As you can see in the snippet I've tried to achieve this using the following code:
svg.selectAll(".g")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.Year);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.N);
})
.attr("height", function(d) {
return height - y(d.N);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Which worked perfectly fine previously. Yet for some reason when I mouseover the bars, nothing is shown. I expected to encounter some problems with the stacked portions, but I don't understand why no tip is shown at all.
The content of the tip is still to be developed (I'm still debating what exactly I want to display) but I believe it should be showing a tip at least. What am I missing here?
Your mouseover is in the wrong place. Before you had a bar chart and now you have a stacked bar chart (obviously), but the data brought back will be different.
For example, your mouseover doesnt do anything, because the place where it's called doesn't do anything.
So I have changed the mouse over to where you need it and the data logged is as follows :
Object {name: "Trek", y0: 43, y1: 86}
So instead of d.Year & d.N, the only data you can bring back is d.name. This is due to the data being brought through making the stacks :
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
So I have updated you tip to this :
return "<strong>Name:</strong> <span style='color: #DA6A26'>" + d.name + "</span>"
And moved your mouseover to line 100 :
.on('mouseover', function(d){
console.log('mouseover');
console.log(d)
tip.show(d);
} )
.on('mouseout', tip.hide);
I have left the logs in there for you so you can see what data is outputted.
Updated plnkr : http://plnkr.co/edit/nrslJjlM37Hu5DR2ZBXw?p=preview
By the way your link to the css file was wrong. So instead of css/style.css it should just be style.css
Now on mouseover, you get name. If you don't want this then you need to bring the correct data through when creating the stacks. I.e on this line :
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
I've setup an example to demonstrate the issue's I've encountered:
To be brief, I'm using d3 to render a map of the united states. I'm appending relevant data attributes to handle click events and identify which state was clicked.
On click events the following is preformed:
I'm grabbing the US County topojson file (which contains ALL US
Counties).
Removing irrelevant counties from the data and rendering them on the
map of the state that was clicked.
I can't seem to figure out what is going on behind the scenes that is causing some of the counties to be drawn while others are ignored.
When I log the data that is returned from the filtered list, I'm displaying the accurate number of counties, but they are only partially drawn on the map. Some states don't return any. Pennsylvania and Texas partially work.
I've checked the data and the comparison operations, but I'm thinking this may have to do with arcs properties being mismatched.
If I utilize the Counties JSON file to render the entire map of the united states they are all present.
If anyone can help shed some light on what might be happening that would be great.
svg {
fill:#cccccc;
height:100%;
width:100%;
}
.subunit{
outline:#000000;
stroke:#FFFFFF;
stroke-width: 1px;
}
.subunit:hover{
fill:#ffffff;
stroke:#FFFFFF;
stroke-width="10";
}
<body>
<script src="http://www.cleanandgreenfuels.org/jquery-1.11.3.min.js"></script>
<script src="http://www.cleanandgreenfuels.org/d3.v3.min.js"></script>
<script src="http://www.cleanandgreenfuels.org/topojson.v1.min.js"></script>
<script>
var width = window.innerWidth;
height = window.innerHeight;
var projection = d3.geo.albers()
.scale(1500)
.translate([width / 2, height / 2]);
//d3.geo.transverseMercator()
//.rotate([77 + 45 / 60, -39 - 20 / 60]);
//.rotate([77+45/60,-40-10/60])
//.scale(500)
//.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width+"px")
.attr("height", height+"px");
d3.json("http://www.cleanandgreenfuels.org/usstates2.json.php", function(error, us, init) {
//svg.append("path")
// .datum(topojson.feature(us, us.objects.counties))
//.attr("d", path);
function init(){
$( document ).ready(function() {
$('.subunit').on('click',function(){
var stateid = $(this).attr("data-stateid");
function clearStates(stateid){
d3.json("http://www.cleanandgreenfuels.org/uscounties2.json.php", function(error, us) {
console.log(us);
console.log("DATA CLICKED ID "+stateid);
test = jQuery.grep(us.objects.counties.geometries, function(n){
return (n.properties.stateid == stateid);
});
us.objects.counties.geometries = test;
console.log(test.length);
console.log(us.objects.counties.geometries.length);
var test = topojson.feature(us, us.objects.counties).features;
console.log(test);
console.log(test.length);
svg.selectAll(".subunit")
.data(test)
.enter().append("path")
.attr("class", function(d) { return "subunit"; })
.attr("d", path)
.attr("data-countyid", function(r){ return r.id; });
});
}
clearStates(stateid);
});
});
}
svg.selectAll(".subunit")
.data(topojson.feature(us, us.objects.us).features)
.enter().append("path")
.attr("class", function(d) { return "subunit"; })
.attr("d", path)
.attr("data-stateid", function(r){ return r.id; });
init();
});
</script>
</body>
It appears as if I was attempting to utilize some outdated features, using topojson.mesh and .datum() to add the new data has resolved this issue, but has introduced a new error.
Now it appears as if the polygons that are rendered must be in sequence to be drawn properly this way.
I think the data going in should be cleaned up to optimize the way d3 is designed to function, but I'd still like to know more about how it is rendering this information that is obtained from the dataset.
function clearStates(stateid){
d3.json("http://www.cleanandgreenfuels.org/uscounties2.json.php", function(error, us) {
console.log(us);
console.log("DATA CLICKED ID "+stateid);
test = jQuery.grep(us.objects.counties.geometries, function(n){
return (n.properties.stateid == stateid);
});
us.objects.counties.geometries = test;
console.log(test.length);
console.log(us.objects.counties.geometries.length);
**var test = topojson.mesh(us, us.objects.counties);**
console.log(test);
console.log(test.length);
**svg.append("path")
.datum(test)
.attr("class", function(d) { return "subunit"; })
.attr("d", path)
.attr("data-countyid", function(r){ return r.id; });**
});
}
I'm using NVD3 ver 3.1.7 for generating pieChart.
Everything works perfect except the chart labels. If the label value is of very low
percentage, it does not appear. I want to make it visible irrespective of its value.
This is my code.
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.showLabels(true);
d3.select("#chart svg")
.datum(data)
.transition().duration(1200)
.call(chart);
return chart;
});
Help would highly be appreciated.
I just managed to resolve this issue.
In nvd3 pieChart, there is a parameter
.labelThreshold(.05)
which sets percentage for chart labels to display or hide. By default this is set to
.02 => 2%.
I increased it to
.05 => 5%
which solved my problem.
You can use this option also.
.labelSunbeamLayout(true)
Please see
http://bl.ocks.org/rkirsling/5001347
It shows some nodes and the edges between them. Can you tell what code to add in that and where so that the edges have labels. You can assume any suitable location for the labels and you can also assume any label text.
Thank you.
You can add labels just as you add the paths for the links themselves. All you need to do is calculate the position according to the positions of the two nodes the link connects. The code would look something like this.
svg.selectAll("text").data(links).enter()
.append("text")
.attr("x", function(d) { return d.source.x + (d.target.x - d.source.x)/2; })
.attr("y", function(d) { return d.source.y + (d.target.y - d.source.y)/2; })
.text(function(d) { return d.something; });
Note that in your tick function, you would also need to update the position of the labels.
I have been using D3 to create fancy animated charts, and the examples are great. However, I'm trying to do something seemingly a lot more basic, and having trouble - binding data to a simple list of DIVs.
I set up enter() to initialize elements at opacity 0, transition() to fade them in, and exit() to fade them out and remove them. enter() and exit() seem to be working fine - however, when an update contains an existing element already in the list, it seems to get partially removed - the containing DIV remains, but the contents disappear. I can't understand why the contents of the element would get changed in this way.
My code is as follows:
var data = [...];
sorted = data.sort(function(a, b) { return d3.descending(a.id, b.id); });
var tweet = tweetsBox
.selectAll('div')
.data(sorted, function(d) { return d.id; });
var enterDiv = tweet.enter()
.append("div")
.attr("class", "tweetdiv")
.style("opacity", 0);
enterDiv.append("div")
.attr("class", "username")
.text(function(d) { return "#" + d.username });
enterDiv.append("div")
.attr("class", "displayname")
.text(function(d) { return d.displayname });
enterDiv.append("div")
.attr("class", "date")
.text(function(d) { return d.date });
enterDiv.append("div")
.attr("class", "text")
.text(function(d) { return d.text });
tweet.transition()
.delay(200)
.style("opacity", 1);
tweet.exit()
.transition()
.duration(200)
.style("opacity", 0)
.remove();
I also set up a jsFiddle here demonstrating the issue.
The problem is that you're selecting the divs you created, but create more than one div per data element. When updating, d3 tries to match the data to the nested divs. As you're already assigning a special class to the top-level divs, the fix is very simple. Replace
.selectAll('div')
with
.selectAll('.tweetdiv')