Not able to render/plot Composite chart dc.js - d3.js

This is a piece of a code in which I am able to get data correctly.But the issue is i am not able to plot chart.
Please refer this link to find chart image which I am getting
// This is where the composite chart code is starting.
CompositeChart: function (chartConfig, chartManager, meta) {
var data = meta.data;
var panelDetails = this.panelDetails(chartConfig.chartName);
var chart = dc.compositeChart(panelDetails.id);
var yAxisGroup = [];
if (chartConfig.xDomainType == "Date" && !(data[0][meta.header[chartConfig.x]] instanceof Date)) {
var dateFormater = d3.time.format("%Y-%m-%d");
data.forEach(function (d, i) {
d[meta.header[chartConfig.x]] = dateFormater.parse(d[meta.header[chartConfig.x]]);
});
}
var xAxis = chartManager.cf.dimension(function (d) {
var val = d[meta.header[chartConfig.x]];
var result = (chartManager.dimValues[chartConfig.x]) ? chartManager.dimValues[chartConfig.x][val] : val;
return result;
});
yAxisGroup = (chartConfig.y);
var temp = yAxisGroup[0];
var temp1 = yAxisGroup[1];
var yDim1 = xAxis.group().reduceSum(function (d) {
var val = d[meta.header[temp]];
var result = (chartManager.dimValues[temp]) ? chartManager.dimValues[temp][val] : val;
return result;
});
var yDim2 = xAxis.group().reduceSum(function (d) {
var val = d[meta.header[temp1]];
var result = (chartManager.dimValues[temp1]) ? chartManager.dimValues[temp1][val] : val;
return result;
});
chart
.width(panelDetails.width)
.height(panelDetails.height)
.margins({
top: 35,
right: 55,
bottom: 30,
left: 45
})
.renderHorizontalGridLines(true)
.shareColors(true)
.compose([
dc.lineChart(chart)
.dimension(xAxis)
.dashStyle([2, 2])
.group(yDim1),
dc.lineChart(chart)
.dimension(xAxis)
.dashStyle([5, 5])
.group(yDim2)
])
.brushOn(false);
this.addXDomain(chartConfig, meta, chart, xAxis);
chart.render();
this.chartStore[chartConfig.chartName] = chart;
},
When I debug the data is fine. I am able to print it on console.But no luck on Chart
I am sharing data of X-Axis while grouping Y-Axis data. Any Solutions?
Note: Console is showing no error or exception.
Can any body help me find the parent chart? Guess that is the problem but I am not sure I need to pass the parent chat in compose function.
Fiddle Link

It's hard to know for sure, but you might try putting your xaxis on the composite chart rather than each composed chart.
Here is a working chart that I've built:
var actuals = dc.barChart(compositeChart)
.gap(65)
.group(group)
.valueAccessor(function (d) {
return d.value.Actual;
});
var budgets = dc.barChart(compositeChart)
.gap(65)
.group(group)
.valueAccessor(function (d) {
return d.value.Budget;
});
compositeChart
.width(1000)
.height(300)
.margins({top: 20, right: 45, bottom: 40, left: 50})
.dimension(monthDimension)
.group(group)
.elasticY(true)
.x(d3.time.scale().domain(timeExtent))
.xUnits(d3.time.months)
.round(d3.time.month.round)
.renderHorizontalGridLines(true)
.compose([budgets, actuals])
.brushOn(true)
.title(function (d) {
return [
"Engagement: " + d.value.engagement,
"Amount:" + d.value.amount
].join("\n");
})
.renderlet(function (chart) {
chart.selectAll("g._1").attr("transform", "translate(" + 20 + ", 0)");
chart.selectAll("g._0").attr("transform", "translate(" + 1 + ", 0)");
});
Note that the budget and actual charts do not define an x or xUnits method. This is left to the composite chart. Not sure that whether this is required or not, but I imagine you need to define x for the composite chart.

Related

Trying to order dates on heatMap after formatting the dates

This is how the xAxis looks after formatting the dates:
Without formatTimeMonth() and only parseTime() the xAxis if ordered correctly.
Formating dates:
var parseTime = d3.timeParse("%m/%d/%Y");
var formatTimeMonth = d3.timeFormat("%b/%Y");
data.forEach(function (d) {
d.Month = formatTimeMonth(parseTime(d.Month));
});
HeatMap:
heatMap
.width(900)
.height(800)
.dimension(dimension)
.group(FTEMonthGroup)
.margins({ left: 200, top: 30, right: 10, bottom: 35 })
.keyAccessor(function (d) { return d.key[0]; })
.valueAccessor(function (d) { return d.key[1]; })
.colorAccessor(function (d) { return +d.value.color; })
.title(function (d) {
return "Manager: " + d.key[1] + "\n" +
"FTE: " + d.value.toolTip + "\n" +
"Date: " + d.key[0] + "";
})
.on('renderlet', function (chart) {
chart.selectAll("g.cols.axis text")
.attr("transform", function () {
var coord = this.getBBox();
var x = coord.x + (coord.width / 2),
y = coord.y + (coord.height / 2);
return "rotate(-45 " + x + " " + y + ")"
})
.style("text-anchor", "right");
});
heatMap.colorCalculator(function (d, i) {
return d.value.color === null ?
'#ccc' : heatMap.colors()(d.value.color);
});
The issue here is that you are specifying the group key as a string. Crossfilter will apply "natural ordering" to keys in groups, so your keys are in alphabetical order.
The best way to format your ticks without changing the order is to revert your keys to dates or date-strings and then use colsLabel:
heatMap.colsLabel(d => formatTimeMonth(parseTime(d.Month)));
This is the equivalent of using
chart.xAxis().tickFormat(...)
on most of the other charts.
(The heatmap is one of a few charts that does not use d3-axis. I don't know if the original author ran into troubles with using the standard component - my guess is that they just found it easier to reinvent the wheel.)

D3 V4 Error: <path> attribute d: Expected number, "MNaN,0LNaN,0LNaN,… scaleLinear().domain().range()

Following Pluralsight D3.js Data Visualization Fundamentals Course.
Get error:
Data is from this Github endpoint
Plunker is here
Code:
var realHeight = document.getElementById('d3Container').offsetHeight;
var realWidth = document.getElementById('d3Container').offsetWidth;
var scale = d3.scaleLinear().domain([130, 350]).range([10, 100]);
var githubUrl = 'https://api.github.com/repos/bsullins/d3js-resources/contents/monthlySalesbyCategoryMultiple.json';
var buildLine = function(ds, dl, idx) {
var minSales = d3.min(ds.monthlySales, function(d) {
return d.month
});
var maxSales = d3.max(ds.monthlySales, function(d) {
return d.month
});
// create scales
var xScale = d3.scaleLinear()
.domain([minSales, maxSales])
.range(0, realWidth);
var yScale = d3.scaleLinear()
.domain([0, maxSales])
.range([realHeight, 0]);
// add scales below in .x and .y
var lineFun = d3.line()
.x(function(d) {
console.log(d.month); // outputs as type numbers in console
// return ((d.month -20130001)/3.25); // hardcoded works
return xScale( d.month );
})
.y(function(d, i) {
// var svgHeight = document.getElementById('d3Container').offsetHeight;
// return ( (svgHeight / ( dl * (1+idx) ) - d.sales) ); // hardcoded works
return yScale( d.sales );
})
.curve(d3.curveLinear);
var svg3 = d3.select('body #d3Container')
.append('svg')
.attrs({
'h': '100%',
'w': '100%',
'fill': 'black'
});
var viz = svg3.append('path')
.attrs({
/** access nested JSON here **/
'd': lineFun(ds.monthlySales),
'stroke': function() {
return (idx + 1 === dl) ? 'royalblue' : 'lime';
},
'stroke-width': 4,
'fill': 'white;'
})
};
var showHeader = function(ds) {
d3.select('body #d3Container')
.append('h2')
.text(ds.category + 'Sales 2013');
};
d3.json(githubUrl, function(error, data) {
if (error) {
return;
} else {
// decode data
var decodedData = JSON.parse(window.atob(data.content));
// pass in functions for each
decodedData.contents.forEach(function(ds, idx) {
showHeader(ds);
buildLine(ds, decodedData.contents.length, idx);
})
}
});
Easiest to work with the plunk.
Can uncomment out the 'hardcoded works' comments to see what it should look like.
In D3 (any version), range() accepts an array.
Your xScale right now has this range:
.range(0, hackWidth);
However, it has to be:
.range([0, hackWidth]);
Here is the updated plunker: https://plnkr.co/edit/DB0VVRsGQO4teIC6ltyQ?p=preview

D3.js Donut Chart change node colors and add text label to middle

My goal is to create an animated donut chart that shows 75% - 90% accuracy rate. For this I've started with the code below, but I'd like to make a few tweaks:
I would like to customize the colors of each node output by the
chart (I've added the variable section_path_fill_colors). Currently the code
just chooses random colors I believe.
I would like to add a static text label in the middle of the donut
75% - 90% (I've added the variable static_label).
Currently the labels are attached to each node.
Can someone help me accomplish this?
UPDATE:
I was able to solve the coloring of nodes with:
var color = d3.scale.ordinal()
.domain(["one", "two", "three"])
.range(["#ffffff" , "#d1d2d4" , "#17afd1"]);
Now just need help setting the static label in the middle
JS:
var static_label = '75% - 90%';
var employees = [
{dept: '', count : 75},
{dept: '', count : 15},
{dept: '', count : 10}
];
var color = d3.scale.ordinal()
.domain(["one", "two", "three"])
.range(["#ffffff" , "#d1d2d4" , "#17afd1"]);
var maxWidth = 200;
var maxHeight = 200;
var outerRadius = 100;
var ringWidth = 20;
function checkEndAll(transition, callback) {
var n = 0;
transition
.each(function() { ++n; })
.each("end", function() {
if (!--n) callback.apply(this, arguments);
});
}
function drawAnimatedRingChart(config) {
var pie = d3.layout.pie().value(function (d) {
return d.count;
});
//var color = d3.scale.category10();
var arc = d3.svg.arc();
function tweenPie(finish) {
var start = {
startAngle: 0,
endAngle: 0
};
var i = d3.interpolate(start, finish);
return function(d) { return arc(i(d)); };
}
arc.outerRadius(config.outerRadius || outerRadius)
.innerRadius(config.innerRadius || innerRadius);
// Remove the previous ring
d3.select(config.el).selectAll('g').remove();
var svg = d3.select(config.el)
.attr({
width : maxWidth,
height: maxHeight
});
// Add the groups that will hold the arcs
var groups = svg.selectAll('g.arc')
.data(pie(config.data))
.enter()
.append('g')
.attr({
'class': 'arc',
'transform': 'translate(' + outerRadius + ', ' + outerRadius + ')'
});
// Create the actual slices of the pie
groups.append('path')
.attr({
'fill': function (d, i) {
return color(i);
}
})
.transition()
.duration(config.duration || 1000)
.attrTween('d', tweenPie)
.call(checkEndAll, function () {
// Finally append the title of the text to the node
groups.append('text')
.attr({
'text-anchor': 'middle',
'transform': function (d) {
return 'translate(' + arc.centroid(d) + ')';
}
})
.text(function (d) {
// Notice the usage of d.data to access the raw data item
return d.data.dept;
});
});
}
// Render the initial ring
drawAnimatedRingChart({
el: '.animated-ring svg',
outerRadius: outerRadius,
innerRadius: outerRadius - ringWidth,
data: employees
});
Just do this:
svg.append('text')
.attr({
x: outerRadius,
y: outerRadius,
'text-anchor': 'middle
})
.text(static_label);

Grouped pie chart segments in d3js using .padAngle()

How would I add padding between some groups of segments in a donut/pie chart using d3?
UPDATE
I am using the d3.svg.arc shape generator and .padAngle(paddingFunction) where paddingFunction is defined as:
var paddingFunction = function(d,i) { return i%1==0 ? 0.1 : 0 };
This image is using the paddingFunction described above.
But if I change the padding function to this:
var paddingFunction = function(d,i) { return i%5==0 ? 0.1 : 0 };
I get this image:
Shouldn't the code return two groups of segments with a gap in-between?
Complete code:
// magic numbers
var t = 2 * Math.PI;
var arcHeight = 100;
var innerRadius = 50;
var hours = 10;
function postion(i,offset) {
offset = offset || 0;
return i*(t / hours) + offset*(t / hours)
}
var paddingFunction = function(d,i) { return i%1==0 ? 0.1 : 0 };
// arc generators
var arc = d3.svg.arc()
.innerRadius(function(d,i) { return innerRadius; })
.outerRadius(function(d,i) { return innerRadius + arcHeight; })
.startAngle(function(d, i){ return postion(d.hour);})
.endAngle(function(d, i){ return postion(d.hour,1);})
.padAngle(paddingFunction);
// data
var data = d3.range(0,hours);
data = data.map(function(d) {
return {
hour: d,
color: Math.random(),
}
});
// Scales
var colorScale = d3.scale.linear()
.domain([0, 1])
.interpolate(d3.interpolateRgb)
.range(["#ffffff", "#ffba19"]);
// render viz
var svg = d3.select("svg")
.append("g")
.attr("transform", "translate(320, 320)");
var select = svg.selectAll(".fore").data(data).enter();
select.append("path")
.classed("fore", true)
.style({
"stroke": "black",
"stroke-width": 1,
"fill": function(d) { return colorScale(d.color); }
})
.attr("d", arc);
UPDATE 2
Seems that I misunderstood how the .padAngle() method works. It adds padding on BOTH sides of a segment, I thought it added a gap between segments.
Is there an alternative method in d3 which adds a gap between segements (whilst recalculating the area of the segments so they all keep their proportions)?
Running code: http://blockbuilder.org/GitNoise/13f38aa8f4f2f06dd869

D3.js Bar graph not displaying properly?

I have a bar graph in my program, but it doesn't seem to be displaying properly. All of the bars seem to be a lot bigger than they are supposed to be. Here's the relevant code:
//Bar Graph
var canvas = d3.select("#canvas");
canvas.width = 500;
canvas.height = 500;
var values = [1, 2, 3]
var colours = ['#FA0', '#0AF', '#AF0']
var data = []
var yOffset = 0
//create scale
yRange2 = d3.scale.linear().range([canvas.height - MARGINS.top,
MARGINS.bottom]).domain([0, 6]);
//Process the data
for (var i = 0; i < values.length; i++) {
var datum = {
value: yRange2(values[i]),
colour: colours[i],
x: 0,
y: yOffset
}
yOffset += datum.value;
data.push(datum)
}
//setup y
yAxis2 = d3.svg.axis()
.scale(yRange2)
.tickSize(5)
.orient("left")
.tickSubdivide(true);
canvas.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis2);
var bars = canvas.selectAll('rect').data(data)
bars
.enter()
.append('rect')
.attr({
width: 30,
x: 60,
y: function (d) {
return d.y
},
height: function (d) {
return d.value;
}
})
.style({
fill: function (d) {
return d.colour
}
})
//updates when slider changes
$("#myRange").change(function () {
slider = $("#myRange").val();
updateXs();
updateLineData();
displayVals();
d3.select(".myLine").transition()
.attr("d", lineFunc(lineData));
});
And here's the full code:
http://jsfiddle.net/tqj5maza/7/
To me, it looks like the bars are starting at the top for some reason, and then going downwards, hence the cutoff. The height for each seems too large, though.
You aren't setting the rects height property correctly. Generally this is height of the plotting area minus y position. The way you have your code structured its:
height: function (d) {
return canvas.height - MARGINS.top - d.value;
}
To fix the overlapping x value, you should set up an x d3.scale but a quick and dirty way would be:
x: function(d,i){
return (i + 1) * 60; //<-- move each bar over 60 pixels
}
Updated code here.

Resources