Showing Date range in d3.js graph axis - d3.js

Right now for showing time on a line chart, I'm doing:
d3.svg.axis().scale(x).orient('bottom').ticks(numTicks, 1)
.tickFormat(d3.time.format('%a %d'))
which shows me dates like: Tue 12 on x-axis.
However, now I want to show the date range (something like: Tue 12-Tue 19) on the axis, but not getting how to do this.

Finally I had to do something like this:
var xAxis = d3.svg.axis().scale(x).orient('bottom').ticks(numTicks, 1)
.tickFormat(function(d,i) {return dateRanges[i]}).tickSize(6).tickPadding(8);
where dateRanges = an array containing all the dateRange string

Related

d3 time axis NaN error

I'm attempting to make a simple line chart in d3 v5 and I'm having trouble with the x axis.
Here's a sample of my data
{
"2015-05-02":"1",
"2015-05-03":"2",
"2015-05-04":"1",
"2015-05-13":"3",
"2015-05-15":"2",
"2015-05-16":"2",
"2015-05-20":"1",
"2015-05-26":"11",
"2015-05-27":"1",
"2015-05-28":"7",
"2015-05-29":"260",
}
Here I try to parse my keys as date objects
//attempting to parse dates
//the dates are strings (eg. 2015-02-18)
dates = d3.keys(data);
$.each(dates, function(thisDate){
var formatDate = d3.timeParse("%Y-%m-%d");
dates[thisDate] = formatDate(dates[thisDate]);
});
After looping through my dates, they are date objects that look like this:
Wed Feb 18 2015 00:00:00 GMT-0600 (Central Standard Time)
Then I set my mins and maxs:
minDate = d3.min(dates); //Wed Feb 18 2015 00:00:00 GMT-0600 (Central Standard Time)
maxDate = d3.max(dates); //Sat Dec 09 2017 00:00:00 GMT-0600 (Central Standard Time)
And set my scale like this:
//x scale
var xScale = d3.scaleTime()
.domain([minDate,maxDate])
.range(0,width);
Then I tried to display my axis like this
//x axis
var xAxis = d3.axisBottom(xScale);
svg.append('g')
.call(xAxis);
It's currently giving me this error when I try to call the x axis:
Error: <path> attribute d: Expected number, "MNaN,6V0.5HNaNV6".
My path wants numbers? But I just made them javascript date objects. I used to dabble in d3 v3, but I'm pretty rusty. Any links to good v5 examples would also be much appreciated.
Thanks!
I forgot the square brackets on my range...
//x scale
var xScale = d3.scaleTime()
.domain([minDate,maxDate])
.range(0,width);
Should have been
//x scale
var xScale = d3.scaleTime()
.domain([minDate,maxDate])
.range([0,width]);
Shout out to this post for the answer: D3.js error using timescale (path is NaN)
Now on to the next problem...
why don't you parse the dates like this
var formatDate = d3.timeParse("%Y-%m-%d");
var dates = d3.keys(data).map( d => formatDate(d) );
var xScale = d3.scaleTime()
.domain(d3.extent(dates))
.range([0,width]);
var data = {
"2015-05-02":"1",
"2015-05-03":"2",
"2015-05-04":"1",
"2015-05-13":"3",
"2015-05-15":"2",
"2015-05-16":"2",
"2015-05-20":"1",
"2015-05-26":"11",
"2015-05-27":"1",
"2015-05-28":"7",
"2015-05-29":"260"
};
var width = 500;
var formatDate = d3.timeParse("%Y-%m-%d");
var dates = d3.keys(data).map( d => formatDate(d) );
var xScale = d3.scaleTime()
.domain(d3.extent(dates))
.range([0,width]);
console.log('xScale-domain', xScale.domain());
<script src="http://d3js.org/d3.v5.min.js" charset="utf-8"></script>

dc.js access data points in multiple charts when click datapoint in first chart

Using different dimensions of the same dataset, there are three dc.js Line Charts on screen.
When user clicks a datapoint on any lineChart, I wish to locate and return the data values for that corresponding point from all other charts, including the one clicked on.
I am also attempting (on mouseover) to change the circle fill color to red for the datapoint being hovered, as well as for the corresponding datapoint (same "x" value) for all other charts.
I am using the .filter() method but haven't been successful getting the desired data. The error message is: "Uncaught TypeError: myCSV[i].filter is not a function"
Full jsFiddle demo/example
lc1.on('renderlet', function(lc1) {
var allDots1 = lc1.selectAll('circle.dot');
var allDots2 = lc2.selectAll('circle.dot');
var allDots3 = lc3.selectAll('circle.dot');
allDots1.on('click', function(d) {
var d2find = d.x;
var d2find2 = d3.select(this).datum();
console.log(myCSV);
alert('Captured:'+"\nX-axis (Date): "+d2find2.x +"\nY-axis (Value): "+ d2find2.y +"\nDesired: display corresponding values from all three charts for this (date/time) datapoint");
allDots2.filter(d=>d.x == d2find2).attr('fill','red');
findAllPoints(d2find2);
});//END allDots1.on(click);
function findAllPoints(datum) {
var objOut = {};
var arrLines=['car','bike','moto'];
for (var i = 0; i < 3; i++) {
thisSrx = arrLines[i];
console.log('thisSrx: '+thisSrx);
console.log(myCSV[i].date)
console.log(datum.x);
//loop thru myCSV obj, compare myCSV[i].date to clicked "x" val
//build objOut with data from each graph at same "X" (d/t) as clicked
objOut[i] = myCSV[i].filter(e => e.date === datum.x)[0][thisSrx];
}
$('#msg').html( JSON.stringify(objOut) );
console.log( JSON.stringify(objOut) );
}//END fn findAllPoints()
});//END lc1.on(renderlet)
myCSV contains all three data points, so I don't see the need to loop through the three charts independently - findAllPoints is going to find the same array entry for all three data series anyway.
The main problem you have here is that date objects don't compare equal if they have the same value. This is because == (and ===) evaluate object identity if the operands are objects:
> var d1 = new Date(), d2 = new Date(d1)
undefined
> d1
Mon Feb 13 2017 09:03:53 GMT-0500 (EST)
> d2
Mon Feb 13 2017 09:03:53 GMT-0500 (EST)
> d1==d2
false
> d1.getTime()===d2.getTime()
true
There are two ways to deal with this.
Approach 1: use second event argument
If the items in all the charts match up item by item, you can just use the index.
All d3 callbacks pass both the datum and the index. So you can modify your callback like this:
allDots1.on('click', function(d,i) {
// ...
allDots2.filter((d,j)=> j===i).attr('fill','red').style('fill-opacity', 1);
alert(JSON.stringify(myCSV[i]));
});
http://jsfiddle.net/gordonwoodhull/drbtmL77/7/
Approach 2: compare by date
If the different charts might have different data indices, you probably want to compare by date, but use Date.getTime() to get an integer you can compare with ===:
allDots1.on('click', function(d) {
var d2find = d.x;
// ...
allDots2.filter(d=> d.x.getTime()===d2find.getTime()).attr('fill','red').style('fill-opacity', 1);
var row = myCSV.filter(r=>r.date.getTime()===d2find.getTime())
alert(JSON.stringify(row));
});
http://jsfiddle.net/gordonwoodhull/drbtmL77/10/
Note that in either case, you're going to need to also change the opacity of the dot in the other charts, because otherwise they don't show until they are hovered.
Not sure when you want to reset this - I guess it might make more sense to show the corresponding dots on mouseover and hide them on mouseout. Hopefully this is enough to get you started!

How to render/ format axes each 6 month with d3.scaleTime?

I am trying to make chart like this, using d3.js v.4. But data that i have is twice each year, differ with the given example. How to render axes for every 6 month? My data is every February, and August for each year (2008-2015).
set your x line with scaleTime and startDate and endDate
when you create an axis you can pass an interval with filter to tick func.
If needed you can also format the axis tick with tickFormat.
Here the example using coffeescript
timeParse= d3.timeParse('%m-%Y');
startDate= timeParse('02-2008');
endDate= timeParse('08-2015');
x= d3.scaleTime()
.domain d3.extent d3.timeMonth.range startDate, endDate, 6
.range [0, 700];
xAxis= d3.axisBottom(x)
.ticks d3.timeMonth.filter (xDate)->
# january is 00
# console.log 'getMonth: ', xDate.getMonth();
if xDate.getMonth() is 1 or xDate.getMonth() is 7
true;
else
false;
.tickFormat d3.timeFormat '%b %Y';
svg.append 'g'
.attr 'class', 'axis-group'
.attr 'transform', "translate(0, 300)"
.call xAxis;
output:
Note the that the stop range are excluded as describe here
Reference:
Month Axis

D3 - get selected Date range on brushend

I am new to d3 and using brushing on grouped bar chart
http://fiddle.jshell.net/CjaD3/21/
I am trying to get the range selected. I am listing to the "brushend" event and calling a function brushend(). Its getting called but returning me the x-axis coordinates in numbers ([42, 318]). I want in Date dormat like 'Sat 25' to 'Mon 27'
Thanks for your help.
This is where you would usually use a the invert method of your x-scale. Unfortunately, that method doesn't exist for ordinal scales. Luckily, Jason Davies, patch is still around. I don't like messing with the source, so I adapted it for your function:
function brushend() {
console.log("brushend");
var b = brush.empty() ? contextXScale.domain() : brush.extent();
console.log(b);
var d = mini_x0.domain(),
r = mini_x0.range(),
startDate = d[d3.bisect(r, b[0]) - 1],
finDate = d[d3.bisect(r, b[1]) - 1];
console.log([startDate, finDate]);
}
Updated fiddle.

D3 x-axis date not showing for Sundays

I'm using the code below to display the day of the week and the month value for my data. D3 displays the date as expected e.g. "Sat 18" but for Sunday it shows the month instead e.g. "Oct 19"!
Can't figure out why this is happening. The code is:
var xScale = d3.time.scale()
.domain([new Date($scope.dataset[0][0].time),d3.time.day.offset(new Date($scope.dataset[0][$scope.dataset[0].length-2].time),2)])
.rangeRound([0, w-0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(d3.time.days,1);
Any ideas why this is happening? the sample dataset looks like this:
{time: "2014-10-19",y: 0,y0: 0}
By default, D3 will apply some adaptive formatting to the date tick values (see "This set of time intervals is somewhat arbitrary and additional values may be added in the future" section), but you can override this with a specific date format, for example:
.ticks(d3.time.days,1)
.tickFormat(d3.time.format('%a %e'));
You can find the remainder of the formatting options here.

Resources