Create Bars as Sums of Values - javascript

This one is sort of hard to define, but I'll try my best. Here's one piece of my 1000 line data:
{
"chartData":[
{"vNm":"Cyrus Shadfar","vId":5167,"values":[
{"period":"2014-12-12","id":37419,"amount":99.995},
{"period":"2014-01-09","id":32630,"amount":180.00},
{"period":"2014-08-25","id":35100,"amount":371.25},
{"period":"2014-08-26","id":35102,"amount":393.75},
{"period":"2014-12-08","id":37545,"amount":49.11},
{"period":"2014-09-03","id":35848,"amount":90.00},
{"period":"2014-12-16","id":37673,"amount":69.48},
{"period":"2014-08-27","id":35909,"amount":371.25},
{"period":"2014-06-04","id":34727,"amount":80.00},
{"period":"2014-06-09","id":34810,"amount":90.00},
{"period":"2014-11-17","id":37191,"amount":130.00},
{"period":"2014-03-27","id":33642,"amount":90.00},
{"period":"2014-06-11","id":34300,"amount":90.00},
{"period":"2014-09-16","id":36115,"amount":99.995},
{"period":"2014-06-18","id":34958,"amount":90.00},
{"period":"2014-05-07","id":34428,"amount":90.00},
{"period":"2014-04-10","id":33855,"amount":90.00},
{"period":"2014-10-24","id":36830,"amount":100.00},
{"period":"2014-12-19","id":37424,"amount":100.00},
{"period":"2014-11-26","id":37446,"amount":90.00},
{"period":"2014-02-20","id":32678,"amount":180.00},
{"period":"2014-03-20","id":33360,"amount":90.00},
{"period":"2014-12-12","id":37550,"amount":69.48},
{"period":"2014-04-22","id":34010,"amount":90.00},
{"period":"2014-04-24","id":34068,"amount":90.00},
{"period":"2014-03-13","id":33500,"amount":90.00},
{"period":"2014-07-16","id":35287,"amount":52.505},
{"period":"2014-06-05","id":34726,"amount":90.00},
{"period":"2014-02-24","id":32933,"amount":90.00},
{"period":"2014-11-10","id":37183,"amount":192.50},
{"period":"2014-08-28","id":36015,"amount":202.50},
{"period":"2014-03-20","id":33643,"amount":90.00},
{"period":"2014-06-13","id":34951,"amount":90.00},
{"period":"2014-06-12","id":34381,"amount":80.00},
{"period":"2014-06-20","id":34959,"amount":90.00}
]}
]
}
There are 25 sets exactly like this with different amounts, periods and id's. All I want is for the bars in my graph to be made of the sum of the amounts, instead of the individual amounts, as I have done here:
svg.selectAll(".bars")
.data(data.chartData, function(d){return d.vNm;})
.enter().append("g")
.attr("class", "bars")
.selectAll(".bar")
.data(function(d){return d.values;})
.enter().append("rect")
.attr("x", function(d) {
return x(d.vNm);
})
.attr("width", sizeOfSpace)
.attr("y", function(d){
return y(d.amount)
})
.attr("height", function(d) {
return height - y(d.amount); })
.attr("class", "bar")
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Here's a working fiddle: http://jsfiddle.net/o5fbqqnq/ (rather large, both codewise and visually)

Seems like an easy question, so perhaps I'm misunderstanding it. Why doesn't something like the following work for you?
svg.selectAll(".bar")
.data(data.chartData, function(d){return d.vNm;})
.enter().append("rect")
.attr("x", function(d) {
return x(d.vNm);
})
.attr("width", sizeOfSpace)
.attr("y", function(d) {
return y(d.values.reduce(function(sum, d) {
return sum + d.amount;
}, 0));
})
.attr("height", function(d) {
return height - y(d.values.reduce(function(sum, d) {
return sum + d.amount;
}, 0));
})
.attr("class", "bar")
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
You can obviously optimize the code if your data sets are large.

Related

D3js group bar chart subgroups with 0 value

I'm trying to do something similar to this example but I'm passing a 0 value to one subgroup.
so I have a result like this.
is there a way to make one of the other subgroups have this blank space?, I thought it would be something like this.
svg.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) { return "translate(" + x(d.group) + ",0)"; })
.selectAll("rect")
.data(function(d) { return subgroups.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect")
///.attr("x", function(d) { return xSubgroup(d.key); })//change this line to the next one
.attr("x", function(d) { if (d.value>0){return xSubgroup(d.key); }})
.attr("y", function(d) { return y(d.value); })
.attr("width", xSubgroup.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return color(d.key); });

Adding Label Text on Barchart D3js

I'm trying to figure out the correct way to displays labels that will sit on top of each bar in my bar chart. I'd also like them to display a % after the number.
Here is my Plunker: https://plnkr.co/edit/FbIquWxfLjcRTg7tiX4E?p=preview
I experimented with using this code from the question found in the link below. However, I wasnt able to get it to work properly (meaning the whole chart failed to display)
Adding label on a D3 bar chart
var yTextPadding = 20;
svg.selectAll(".bartext")
.data(data)
.enter()
.append("text")
.attr("class", "bartext")
.attr("text-anchor", "top")
.attr("fill", "white")
.attr("x", function(d,i) {
return x(i)+x.rangeBand()/2;
})
.attr("y", function(d,i) {
return height-y(d)+yTextPadding;
})
.text(function(d){
return d;
});
This is the most straight forward way given your existing code:
// keep a reference to the g holding the rects
var rectG = g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; })
.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter();
// append the rects the same way as before
rectG.append("rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return z(d.key); });
// now add the text to the g
rectG.append("text")
.text(function(d){
return d.value + '%';
})
.attr("x", function(d) { return x1(d.key) + (x1.bandwidth()/2); })
.attr("y", function(d) { return y(d.value); })
.style("text-anchor", "middle");
Updated plunker.

How to add numbers to bars with D3.js?

I've created a chart and it works fine, but I can't find out how to add numbers to columns. Numbers appear only if I hover the columns.
Tried different variants:
svg.selectAll("text").
data(data).
enter().
append("svg:text").
attr("x", function(datum, index) { return x(index) + barWidth; }).
attr("y", function(datum) { return height - y(datum.days); }).
attr("dx", -barWidth/2).
attr("dy", "1.2em").
attr("text-anchor", "middle").
text(function(datum) { return datum.days;}).
attr("fill", "white");
A link to my example: https://jsfiddle.net/rinatoptimus/db98bzyk/5/
Alternate idea to #gerardofurtado is to instead of a rect append a g, then group the text and rect together. This prevents the need for double-data binding.
var bars = svg.selectAll(".bar")
.data(newData)
.enter().append("g")
.attr("class", "bar")
// this might be affected:
.attr("transform", function(d, i) {
return "translate(" + i * barWidth + ",0)";
});
bars.append("rect")
.attr("y", function(d) {
return y(d.days);
})
.attr("height", function(d) {
return height - y(d.days) + 1;
})
.style({
fill: randomColor
}) // color bars
.attr("width", barWidth - 1)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
bars.append("text")
.text(function(d) {
return d.days;
})
.attr("y", function(d) {
return y(d.days);
})
.attr("x", barWidth / 2)
.style("text-anchor", "middle");
Updated fiddle.
When you do this:
svg.selectAll("text")
you are selecting text elements that already exist in your SVG. In an enter selection, it's important selecting something that doesn't exist:
svg.selectAll(".text")
.data(newData)
.enter()
.append("svg:text")
.attr("x", function(datum) {
return x(datum.name) + x.rangeBand()/2
})
.attr("y", function(datum) {
return y(datum.days) - 10;
})
.attr("text-anchor", "middle")
.text(function(datum) {
return datum.days;
})
.attr("fill", "white");
Here is your fiddle: https://jsfiddle.net/c210osht/
You could try using the d3fc bar series component, which allows you to add data-labels via the decorate pattern.
Here's what the code would look like:
var svgBar = fc.seriesSvgBar()
.xScale(xScale)
.yScale(yScale)
.crossValue(function(_, i) { return i; })
.mainValue(function(d) { return d; })
.decorate(function(selection) {
selection.enter()
.append("text")
.style("text-anchor", "middle")
.attr("transform", "translate(0, -10)")
.text(function(d) { return d3.format(".2f")(d); })
.attr("fill", "black");
});
Here's a codepen with the complete example.
Disclosure: I am a core contributor to the d3fc project!

Data missing when using group-element as opposed to dots

I use this code:
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", function(d) { return domainOnlyScale(parseFloat(d.Size)+0.01); } )
.attr("cx", function(d) {return x(d.x+(Math.random() * 0.25) - 0.125); })
.attr("cy", function(d) { return y(d.y+(Math.random() * 0.25) - 0.125); })
.style("fill", function(d) { return color(d.color); })
.style("stroke-width", "1px")
.style("stroke", function(d) { return strokecolor(d.color); });
And everything works. All data points show up. Now I change this part of the code to:
console.log(data); // Shows all data points!
var groupings = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d){return "translate("+(x(d.x+(Math.random() * 0.25) - 0.125))+","+y(d.y+(Math.random() * 0.25) - 0.125)+")"}); //used console.log here)
groupings.append("circle")
.attr("class", "dot")
.attr("r", function(d) { return domainOnlyScale(parseFloat(d.size)+0.01); } )
.style("fill", function(d) { return color(d.color); })
.style("stroke-width", "1px")
.style("stroke", function(d) { return strokecolor(d.color); });
groupings.append("text")
.attr("class", "bubbletext")
.attr("dx", function(d){ return -4 })
.attr("dy", function(d){ return +5 })
.text( function(d) { return d.category.substring(0,1); } );
I used another console.log inside the function of the transform of the groupings-creation, and the data is already filtered there. From a few tries it seems as if the first ~15 entries are missing.
Thanks in advance!
The problem is that you have g elements on the page already. These are getting selected through svg.selectAll("g") and then matched to data. Hence, the enter selection doesn't contain all the elements you expect to be there.
The fix is simple -- assign a class to those g elements you're using here to be able to distinguish them from the rest and select accordingly:
svg.selectAll("g.dot")
.data(data)
.enter()
.append("g")
.attr("class", "dot");

d3.js barchart plugin animation methods

I am having issues trying to build this jquery based d3.js barchart plugin.
the bars are displaced to the left, not sure why
the bars are not updating to new data.
I've tried to get the bars to animate - but not had any success.
http://jsfiddle.net/NYEaX/161/
Here is the animate bars function
animateBars: function(data){
var svg = d3.select(methods.el["selector"] + " .barchart");
var bars = svg.selectAll(".bar")
.data(data);
bars
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return methods.x(d.letter); })
.attr("width", methods.x.rangeBand())
.attr("y", function(d) { return methods.y(d.frequency); })
.attr("height", function(d) { return methods.height - methods.y(d.frequency); })
.transition()
.duration(300)
bars
.transition()
.duration(300)
bars.exit()
.transition()
.duration(300)
}
I fixed the transition for new bars in your jsfiddle. I hope it reveals the functionality of transitions:
http://jsfiddle.net/NYEaX/893/
How it works: After it sets the initial height and y value, it adds a transition to the end height and y value.
bars
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return methods.x(d.letter); })
.attr("width", methods.x.rangeBand())
.attr("y", function(d) { return methods.y(0); })
.attr("height", function(d) { return methods.height - methods.y(0); })
.transition().duration(1000)
.attr("y", function(d) { return methods.y(d.frequency); })
.attr("height", function(d) { return methods.height - methods.y(d.frequency); });

Categories

Resources