I've got a few nice charts now but here I might have bitten off more than I can chew. I know you wouldn't normally consider a PieChart where negative groupings are involved but bear with me.
I've got a column of values I want to display in a PieChart.
The PieChart should have 2 elements, 1. Average value of positive numbers 2. Average value of negative numbers
The Text element of the pie slices should note 1. Positive Avg £?? (?%) 2. Negative Avg £?? (?%)
What I can't quite get to grips with is how the PieChart deals with negative values. My Pie chart has no slice for the negative element. So thinking about it, could I incorporate a -1 multiplier on the negative numbers only.
I'm thinking, would extracting the positive and negative numbers into seperate arrays, adjusting the negative array with the miltiplier then reincorporating the two arrays back into my piechart offer a reasonable solution? If it's not too onerous I would appreciate some guidance on process here.
I was just expecting, for example, Average Negative Value say 20, average Positive value 60. and the percentages shown as 25% and 75%. It's the relationship of these two numbers to each other I'm interested in.
The above is as far as I've got just using total values. I also need some help with how to extract and use the average values.
<div id="paybacksplit"></div>
<pre id="data">
Trade,Payback
1,85
2,74
3,-90
4,77
5,93
6,85
7,95
8,98
9,98
10,-88
11,10
12,98
13,93
14,65
15,76
16,81
17,0
18,0
19,96
20,-9
21,96
22,94
23,96
24,94
25,-88
26,8
27,85
28,88
29,90
</pre>
var pbschart = new dc.PieChart("#paybacksplit");
var trades = d3.csvParse(d3.select('pre#data').text());
trades.forEach(function(x) {
x.Payback = +x.Payback;
});
var ndx = crossfilter(trades),
tradeDimension = ndx.dimension(function(d) {
if (d.Payback >= 0)
return "Profitable";
else
return "Losing";
});
paybackSumGroup = tradeDimension.group().reduceSum(function(d) {return d.Payback;});
pbschart
.width(768)
.height(480)
.slicesCap(2)
.innerRadius(2)
.dimension(tradeDimension)
.group(paybackSumGroup)
.legend(dc.legend().highlightSelected(true))
.on('pretransition', function(chart) {
chart.selectAll('text.pie-slice').text(function(d) {
return d.data.key + ' £ '+ d.data.value + dc.utils.printSingleValue((d.endAngle - d.startAngle) / (2*Math.PI) * 100) + '%';
})
});
pbschart.render();
jsfiddle is here
What happened next;
Gordons response helped but I'm not yet adept enough to figure out the next stage which was to return the average values.
However since the data is coming from my own data I just restructured the output to provide a column with Profit/Loss for each item and a second column with the values (with the negative values converted to positive values).
With my limited dc.js knowledge it was easier to rejig my database output. What I ended up with is
<div id="paybacksplit2"></div>
<!-- here's a way to load data from a jsfiddle, to avoid CORS
problems - see http://stackoverflow.com/a/22896088/676195
-->
<pre id="data">
Trade,Payback
Prof,85
Prof,74
Loss,90
Prof,77
Prof,93
Prof,85
Prof,95
Prof,98
Prof,98
Loss,88
Prof,10
Prof,98
Prof,93
Prof,65
Prof,76
Prof,81
Prof,0
Prof,0
Prof,96
Loss,9
Prof,96
Prof,94
Prof,96
Prof,94
Loss,88
Prof,8
Prof,85
Prof,88
Prof,90
</pre>
and
var pbschart2 = new dc.PieChart("#paybacksplit2");
var numberFormat = d3.format("(.2f");
var trades = d3.csvParse(d3.select('pre#data').text());
trades.forEach(function(x) {
x.payback = +x.Payback
x.trade = x.Trade
;
});
var ndx = crossfilter(trades),
tradeDimension = ndx.dimension(function(d) {return d.trade;});
paybackSumGroup = tradeDimension.group().reduceSum(function(d) {return d.payback;});
var nameDim = ndx.dimension(function(d) { return d.trade; })
var totalValGroup = nameDim.group().reduce(reduceAddVal, reduceRemoveVal, reduceInitialVal);
var result = totalValGroup.top(Infinity);
console.log(result);
function reduceAddVal(p, v) {
++p.count;
p.totalVal += v.payback;
p.average = p.totalVal / p.count;
return p;
}
function reduceRemoveVal(p, v) {
--p.count;
p.totalVal -= v.payback;
p.average = p.totalVal / p.count;
return p;
}
function reduceInitialVal() {
return {
count: 0,
totalVal: 0,
average: 0
};
}
pbschart2
.width(768)
.height(200)
.slicesCap(2)
.dimension(nameDim)
.group(totalValGroup)
.valueAccessor(function (p) {
return p.value.average;
})
.legend(dc.legend().highlightSelected(true))
.on('pretransition', function(chart) {
chart.selectAll('text.pie-slice').text(function(d) {
return ' £ '+ numberFormat(d.data.value.average);
})
});
pbschart2.render();
which gave me the following;
Which is more or less what I was after.
Updated fiddle here
Maybe in time I can do more in dc.js but since I have the option to define my own data extract this was the easiest option for me at the moment.
Thanks Gordon, I'm getting there bit by bit!