DC.js barChart not displaying with date axis - dc.js

I'm trying to display a bar chart showing with a count of dates but the bars will not draw and I'm getting a NaN error in the console.
Please can someone tell me where I am going wrong?
var data1=[{budget:1,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"01 February 2017"},
{budget:7,billed:6,fees:1,feeVariance:3,Documents:"URL",date:"01 February 2018"},
{budget:10,billed:1,fees:4,feeVariance:3,Documents:"URL",date:"01 May 2017"},
{budget:14,billed:2,fees:4,feeVariance:2,Documents:"URL",date:"15 May 2017"},
{budget:2,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"02 June 2016"}];
var facts = crossfilter(data1);
var dateDimension = facts.dimension(function(d) { return new Date(d.date); });
var dateGroup = dateDimension.group().reduceCount(function(d){return new Date(d.date);});
var minDate = dateDimension.bottom(1)[0].date;
var maxDate = dateDimension.top(1)[0].date;
dc.barChart("#chart1")
.width(800)
.dimension(dateDimension)
.group(dateGroup)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.months);
dc.renderAll();

you need to firstly determine the date format so dc.js can understand it as a date rather than simply a string.
So firstly, create a variable to set the date format:
var dateFormat = d3.time.format('%d %B %Y');
then a function to make our date and month fields:
data1.forEach(function(d) {
d.date = dateFormat.parse(d.date);
d.month = d3.time.month(d.date);
});
Then change the dimension and group to use d.month
var dateDimension = facts.dimension(function(d) { return d.month; });
var dateGroup = dateDimension.group().reduceCount(function(d){return
d.month;});
This will group by month and provide a count/total by month also.
Here's the full code:
var dateFormat = d3.time.format('%d %B %Y');
var data1=[{budget:1,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"01
February 2017"},
{budget:7,billed:6,fees:1,feeVariance:3,Documents:"URL",date:"01 February 2018"},
{budget:10,billed:1,fees:4,feeVariance:3,Documents:"URL",date:"01 May 2017"},
{budget:14,billed:2,fees:4,feeVariance:2,Documents:"URL",date:"15 May 2017"},
{budget:2,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"02 June 2016"}];
var facts = crossfilter(data1);
data1.forEach(function(d) {
d.date = dateFormat.parse(d.date);
d.month = d3.time.month(d.date);
});
var dateDimension = facts.dimension(function(d) { return d.month; });
var dateGroup = dateDimension.group().reduceCount(function(d){return d.month;});
var minDate = dateDimension.bottom(1)[0].date;
var maxDate = dateDimension.top(1)[0].date;
dc.barChart("#chart1")
.width(800)
.dimension(dateDimension)
.group(dateGroup)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.months);
dc.renderAll();
I've added some extra properties to the chart to ensure all the bars are shown correctly:
.gap(2)
.outerPadding(5)
.centerBar(true)
.elasticX(true)
.xAxisPadding(20)
jsfiddle example:
jsfiddle

Related

How to make columns wide (not pencil-thin) on dc BarChart with time x-axis

I have a barchart set-up as follows:
function makeGraphs(recordsJson, factorText) {
// Clean data
var records = jQuery.parseJSON(recordsJson);
let parseDate = d3.timeParse("%Y-%m-%d");
records.forEach(function(d) {
d.date = parseDate(d.date);
d.factor = d.factor == true ? 1 : 0;
});
// Create a Crossfilter instance
var ndx = crossfilter(records);
// Define Dimensions
var dateDim = ndx.dimension(d => d.date);
// Group Data
var dateGroup = dateDim.group();
var factorGroup = dateDim.group().reduceSum(dc.pluck('factor'));
var all = ndx.groupAll();
// Define values (to be used in charts)
var minDate = dateDim.bottom(1)[0]["date"];
var maxDate = dateDim.top(1)[0]["date"];
// Chart
const timeChart = new dc.CompositeChart("#time_chart");
timeChart
.height(300)
.x(d3.scaleTime().domain([minDate,maxDate]))
.yAxisLabel("Number of Lines")
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.compose([
new dc.LineChart(timeChart)
.dimension(dateDim)
.colors('blue')
.group(dateGroup, "Total")
.curve(d3.curveLinear),
new dc.BarChart(timeChart)
.dimension(dateDim)
.colors('red')
.centerBar(true)
.gap(1)
.alwaysUseRounding(true)
.group(factorGroup, factorText)
.xUnits(d3.timeDays)
])
.brushOn(false)
.render();
The barchart is always displayed with pencil-thin columns, representing correctly the count of 'factor' items in that date. This occurs no matter the size of day range I apply.
I have tried .xUnits(d3.timeWeeks) to see if it can be made to display better, to no avail (actually, it still displays daily totals, suggesting I need to construct an aggregate function). However, I really need daily counts.
As advised by Gordon, a CompositeChart needs to have its .xUnit property defined in the main chart section, not under one of its sub-chart types:
timeChart
.height(300)
.x(d3.scaleTime().domain([minDate,maxDate]))
.yAxisLabel("Number of Lines")
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.xUnits(d3.timeDays)
.compose([
new dc.LineChart(timeChart)
.dimension(dateDim)
.colors('blue')
.group(dateGroup, "Total")
.curve(d3.curveLinear),
new dc.BarChart(timeChart)
.dimension(dateDim)
.colors('red')
.centerBar(true)
.gap(1)
.alwaysUseRounding(true)
.group(factorGroup, factorText)
])
.brushOn(false)
.render();
The bar-chart component then displays with a proper width.

d3 Xscale returning nan even on setting scale properly

I am creating a d3 line chart, but my XScale is returning nan.
My lines are in ascending order of timestamp
I am setting x domain as:
var lastIndex = line_data[0].length -1;
var minDate = line_data[0][0]['date'];
var maxDate = line_data[0][lastIndex]['date'];
x.domain([minDate,maxDate]);
later I am trying to access it as:
.x(function(d) { console.log('d for x is',d.date);
console.log(x(d.date));
return x(d.date); })
Why is it returning nan?
Here is my fiddle
https://jsfiddle.net/james222/yw3Le6yb/
You are converting a date to a string when populating line_data.
var parser = d3.time.format("%m/%d/%Y %H:%M:%S");
abc[i]['date'] = parser(dateLabel);
line_data[counter] = abc;
Just use the date here.
abc[i]['date'] = dateLabel;

How to make xscales and xaxis from this data D3 V4

I am working on D3 V4.
I have this data
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
How do I make scaleTime from this?
Also this approach is wrong:
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));
var xScale = d3.scaleTime()
.domain([min,max])
.range([padding, width-padding]);
Since - it can't create correct Date object from this format:
"33:12"
My comments inline:
For D3 V3 time parsing
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
//First convert your data to date object like this:
var myParser = d3.time.format("%M:%S");
//run for loop and use parser to parse the date.
dataset.forEach(function(d){
d.Time = myParser.parse(d.Time);//now its a dateObject
})
//Now get your max and min from the date Object
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));
var xScale = d3.scaleTime()
.domain([min,max])
.range([padding, width-padding]);
For D3 V4 time parsing
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
//First convert your data to date object like this:
var myParser = d3.timeParse("%M:%S");
//run for loop and use parser to parse the date.
console.log(myParser)
dataset.forEach(function(d){
d.Time = myParser(d.Time);//now its a dateObject
})
//Now get your max and min from the date Object
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));

D3 charts change the time format and its display on the axes

Im trying to change the time format of the data set of the charts
https://jsfiddle.net/d0ogL90d/2/
I'v tried to do the follwoing but exception is throwing:
var xExtents = d3.extent(d3.merge(dataset), function (d) {
return return d3.time.format('%A %m/%d/%y')(new Date(d.x));
});
if d.x is been returned then it display date but not in the desired format
I also tried to change the data array by:
function createADateArray(){
var arr = [];
temparr = [];
var date = new Date();
arr.push(temparr);
temparr = [];
for(i=1; i < 6; i++){
var date2 = date.setDate(date.getDate() + 1);
var cdate = d3.time.format('%A %m/%d/%y')(new Date(date2))
var obj = {
'x': cdate,
'y': i
}
temparr.push(obj);
}
arr.push(temparr);
// }
return arr;
}
The data is correct anf with the desired format but again exception is throwing
*desired format:
Tue
Jan 10
To create your date entries in your data, just add 1 day offsets to your now var using d3.time.day.offset(now, offset++)
Try these mods which are working for me, at least the date format of the X-axis labels:
var now = d3.time.hour.utc(new Date);
function createADateArray(){
var arr = [];
temparr = [];
// var date = new Date();
//for(j=0; j< 4; j++){
/*for(i=0; i < 1000; i++){
var obj = {
'x': i,
'y': i
}
temparr.push(obj);
arr.push(temparr);
}*/
temparr = [];
// for(i=1004; i < 2000; i++){
var offset = 0;
for(i=1004; i < 1010; i++){
//var date2 = date.setDate(date.getDate() + 1);
//date = new Date(date2);
var obj = {
// 'x': date,
'x': d3.time.day.offset(now, offset++),
'y': i
}
temparr.push(obj);
}
arr.push(temparr);
// }
return arr;
}
...
// d3.time.format("%A %B");
var dateFormat = d3.time.format("%a %b %e %I%p");
var xScale = d3.time.scale()
// .domain([new Date(xExtents[0]), d3.time.day.offset(new Date(xExtents[xExtents.length - 1]), 1)])
.domain(xExtents)
.range([padding, w - padding * 6]);
...
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(dateFormat);
// .ticks(1000);
you can use .tickFormat(d3.time.format("%A %Y-%m-%d"))
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height)
.tickFormat(d3.time.format("%A %Y-%m-%d"))
.ticks(5);
http://codepen.io/anon/pen/mVMjvm?editors=101

Error with .compose using dc.js

I am trying to create a composite of 2 line charts with dc.js.
But I get this error everytime:
Uncaught TypeError: timeChart.width(...).height(...).x(...).elasticY(...).margins(...).dimension(...).compose is not a function
it is a time series where I want to plot netCommercialPosition and netCommercialPosition as two seperate line. It works when I stack them but not when i want to use .compose.
I have followed several examples such as:
Dual Y axis line chart in dc.js
http://dc-js.github.io/dc.js/examples/series.html
So hopefully I use the .compose element correctly
my data set is a json with the following structure:
[{"CFTC_Commodity_Code": 1, "Net_Commmercial_Position": -113520, "Report_Date_as_MM_DD_YYYY": "14/07/2015", "Net_Fund_Position": -12246, "Price": 583.5, "Net_ Commmercial_Position": 3877, " },{…}]
here is my code:
d3.json("/donorschoose/COT", function (error, dataset1){
var ymdFormat = d3.time.format("%d/%m/%Y");
dataset1.forEach(function(p) {
p.Report_Date_as_MM_DD_YYYY = ymdFormat.parse(p.Report_Date_as_MM_DD_YYYY);
});
var COTProjects = dataset1;
var ndx = crossfilter(COTProjects);
var all = ndx.groupAll();
FilterDimension = ndx.dimension(function (d) {
return d.CFTC_Commodity_Code;
});
var dateDim = ndx.dimension(function(d) { return d.Report_Date_as_MM_DD_YYYY; });
var Prices = dateDim.group().reduceSum(function(d) {return d.Price; });
var netFundPosition = dateDim.group().reduceSum(function(d) {return d.Net_Fund_Position; });
var netCommercialPosition = dateDim.group().reduceSum(function(d) {return d.Net_Commmercial_Position; });
var minDate = dateDim.bottom(1)[0]["Report_Date_as_MM_DD_YYYY"];
var maxDate = dateDim.top(1)[0]["Report_Date_as_MM_DD_YYYY"];
var timeChart = dc.lineChart("#time-chart");
actualValuesChart = dc.lineChart(timeChart)
.group(netFundPosition)
normValuesChart = dc.lineChart(timeChart)
.group(netCommercialPosition)
timeChart
.width(650)
.height(260)
.x(d3.time.scale().domain([minDate, maxDate]))
.elasticY(true)
.margins({top: 0, right: 5, bottom: 20, left: 40})
.dimension(dateDim)
.compose([actualValuesChart,normValuesChart])
.transitionDuration(500)
.yAxis().ticks(4);
.brushOn(false)
FilterDimension.filter(1)
dc.renderAll();
});
Any help appreciated
thanks in advance
I found the solution, my problem was that I was trying to call compose() from a lineChart object instead of a compositeChart object.
dc.js-s doc

Resources