d3 time axis NaN error - d3.js

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>

Related

line graph renders wrongly and problem with the X axis (time), cannot brush the graph - time series dc.js

I'm creating a dashboard for a scanning tool. I have created a bunch of graphs but got stuck with plotting a line chart to show kind of like a time series ( like how many records are populated at that particular scan time). I'm using dc.js and have tried a couple of ways, but the line does not render correctly and the axis has weird thing going with it.
I cannot brush the graph too, it is throwing "coordinate-grid-mixin.js:1083 Uncaught TypeError: undefined is not a function".
I have a UNIX timestamp, which I'm converting to datetime and then I'm using these to plot the line chart.
//Converting the timestamp
var dateFormatSpecifier = "%m/%d/%Y";
var day_FormatSpecifier = "%d %b %y";
var dateFormat = d3.timeFormat(dateFormatSpecifier);
var dayFormat = d3.timeFormat(day_FormatSpecifier)
var dateFormatParser = d3.timeParse(dateFormatSpecifier);
var numberFormat = d3.format(".2f");
facts.forEach(function(d) {
console.log('Before Change : ' + d.timestamp);
d.date = new Date(d.timestamp * 1000);
d.month = d3.timeMonth(d.date);
d.day = d3.timeDay(d.date);
d.date = dateFormat(d.date);
d.day = dayFormat(d.day)
console.log('After Change : ' + d.date + ' ' + d.month + ' '+ d.day);
// console.log('After Change Month: ' + d.month);
});
//Plotting
var dateDim = data.dimension(function(d) { return (d.day);});
var groupForSNR = dateDim.group().reduceCount(item => 1);
var time_chart = dc.lineChart("#time-chart");
var minDate = dateDim.bottom(1)[0].date;
console.log('min : ' + minDate);
var maxDate = dateDim.top(1)[0].date;
console.log('max : ' + maxDate);
var xmin = dayFormat(new Date(1559890800*1000))
console.log('xmin : ' + xmin);
var xmax = dayFormat(new Date(1561878000*1000))
console.log('xmin : ' + xmax);
time_chart
.height(150)
.transitionDuration(500)
.margins({top: 10, right: 10, bottom: 20, left: 40})
.dimension(dateDim)
.group(groupForSNR)
.brushOn(true)
.elasticY(true)
.y(d3.scaleLinear().domain([0,100]))
.x(d3.scaleOrdinal().domain(xmin, xmax))
.xUnits(d3.timeDay);
time_chart.xAxis().ticks(15);
time_chart.yAxis().ticks(10);
-
".x(d3.scaleTime().domain(xmin, xmax))" is not even displaying anything.
Thanks for your effort.
Your syntax is slightly off, and you always want to work with JavaScript Date objects when using D3 time scales. Only the ticks and labels (output) will be formatted as strings, all input will be Dates.
.domain() always takes an array.
You want
var minDate = dateDim.bottom(1)[0].day; // Date object
var maxDate = dateDim.top(1)[0].day;
.x(d3.scaleTime().domain([minDate, maxDate]))
Not sure if these are the only problems - everything else looks okay but it's hard to tell without trying.
Just keep studying, look very closely at what the examples are doing, you'll pick it up quickly!
EDIT: you will find examples where the dates are formatted as strings with an ordinal scale on input. There are only particular cases where is this a good idea, and I don't think this is one of them.

D3js first tick label is missing

I don't understand why the first label (2000) is missing. I compared it to many examples without finding why.
let xAxisScale = d3
.scaleTime()
.domain([min, max]) // 2000, 2013
.range([0, width]);
xAxis = d3
.axisBottom()
.tickFormat(d3.timeFormat('%Y'))
.tickPadding(5)
.ticks(d3.timeYear)
.scale(xAxisScale);
gx = innerSpace
.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
Do you see any errors ?
Thanks !
This problem may be due to small variations in min date. It depends on the way you construct min date.
For example, new Date('2000-01-01') does not include year 2000 if your time zone is >0. You can write new Date('2000-01-01T00:00:00Z') to use UTC.
Also, if you use new Date(YYYY, MM, DD), you should take into account, that month starts from zero, while day starts from one.
Read about correct way of dealing with that problem here: http://bl.ocks.org/jebeck/9671241
Next to your nice answer I tried different ways to get a datetime without utc / gmt problems but didn't find a nice solution of dealing with it for all web explorer without using library.
The best solution I find is to use the library momentjs because momentjs will nicely handle the timezone :
const minMoment = moment(`01/01/${minDate}`, 'DD/MM/YYYY', true);
const maxMoment = moment(`01/01/${maxDate}`, 'DD/MM/YYYY', true);
this.xAxisScale = d3
.scaleTime()
.domain([minMoment.toDate(), maxMoment.toDate()])
.range([0, width]);

dc.js time series format

I'm new to dc.js and I've been trying to create a time series data along with other charts I would eventually cross-filter as well. The graph plots just fine but the data doesn't show up. here is what the data looks like:
month,day_of_week,hour,day,date,geo
Jan,Thursday,2,1,1/1/15,"33.87865278,-87.32532778"
Jan,Thursday,22,1,1/1/15,"34.91044167,-86.90870833"
Jan,Thursday,1,1,1/1/15,"32.14200556,-85.75845556"
.
.
.
Dec,Saturday,0,4,12/19/15,"31.43981389,-85.5103"
I've tried to plot a time series based on the 'date' column and my approach is as follows:
d3.csv("hwy.csv", function(data) {
drawMarkerSelect(data);
var dateFormat = d3.time.format('%m/%d/%Y');
data.forEach(function (d) {
d.dates = dateFormat.parse(d.date);
d.dateRange = d3.time.month(d.dates);
});
});
function drawMarkerSelect(data) {
var xf = crossfilter(data);
var all = xf.groupAll();
trialChart = dc.lineChart(".trial .trial-line");
var trial = xf.dimension(function(d){ return d.dateRange; });
var trialGroup = trial.group();
trialChart
.dimension(trial)
.group(trialGroup)
.height(120)
.width(900)
.x(d3.time.scale().domain([new Date(2014, 12, 01), new Date(2015, 11, 31)]))
.xUnits(d3.time.months);
---Other Charts here as well ---
dc.renderAll();
As of now, this code returns empty chart with x and y bars. I want the total count of cases for each day on y axis and the corresponding date on the x axis.
Your time and support is appreciated!

D3 scatterplot using time scale on x-axis -- not working in Firefox

I've created a pretty simple scatterplot showing a person's weightlifting progress over time. The x-axis is a time scale in days (there's one circle for each day) and the y-axis is the number of pounds lifted that day.
The scatterplot works in Chrome, but not Firefox. It has something to do with using a date object as the x-position of the circles.
Take a look at the chart in Chrome
Here are two rows of my dataset, to show how it is formatted (the date is the first item of each row):
["2011-09-16",150,"Cottage cheese and 1 apple",170,16,"4 Chicken breast strips",130,17,"Hibachi grill: onion soup, salad, 2 shrimp pieces, vegetables. 12 oz chicken, rice",880,99,"Small hard frozen yogurt",300,6,"Cottage cheese, greek yogurt, a bunch of icebreaker sours",230,26,1710,164,175,"Back/biceps, 31 pushups",135,0,0],
["2011-09-17",150,"15 peanuts",80,4,"Dim Sum",1000,40,"Azn salad, 2 serv chicken breast",490,57,"8.8 oz mixx",264,9,"(No Data)",0,0,1833.6875,109.55,174.2," ",135,0,0],
Here's how I draw the circles, and some relevant functions/variables I used to format the dates:
//Width and height
var w = 4200;
var h = 200;
var padding = 35;
var mindate = new Date("2011-9-15");
var maxdate = new Date("2012-5-29");
//Create scale functions
var xScale = d3.time.scale()
.domain([mindate, maxdate])
.range([padding, w - padding * 2]);
var format = d3.time.format("%Y-%m-%d");
var dateFn = function(d) {return format.parse(d[0])};
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(dateFn(d));
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", 6)
.attr("fill", "gray")
.attr("opacity", .5)
Like I said, it works exactly how I want in Chrome, but in Firefox, all the circles are on top of one another with cx=0. Any ideas would be appreciated. I asked my local d3 expert, and he showed me a project he did which also fails in Firefox due to drawing circles using date objects. He just gave up. a link to his project
The problem isn't the way you're parsing the dates, but the way you're setting up the scale.
var mindate = new Date("2011-9-15");
var maxdate = new Date("2012-5-29");
This is the code that works properly only in Chrome because you're relying on its date parsing by using the constructor rather than parsing explicitly like you're doing for the rest of the dates.
The fix is simple -- just parse the dates you're using to set the scale domain as well:
var format = d3.time.format("%Y-%m-%d"),
mindate = format.parse("2011-09-15"),
maxdate = format.parse("2012-05-29");

How to draw two line on the same xScale but different time frame

There ara array about two month .like this
[
[{time:new Date("11/1/13"),data:1},{time:new Date("11/2/13"),data:31},...{time:new Date("11/30/13"),data:4}],
[{time:new Date("10/1/13"),data:2},{time:new Date("10/2/13"),data:45},...{time:new Date("10/30/13"),data:14}]
]
I want to compare the data between two month on the same extent of Xcale .
I don't know how to deal with Xcale.
var xScale = d3.time.scale()
.domain([??])//how to set the domain
.range([0,300])
.nice();
Naming your two arrays data:
var data = [
[{time:new Date("11/1/13"),data:1},{time:new Date("11/2/13"),data:31},...{time:new Date("11/30/13"),data:4}],
[{time:new Date("10/1/13"),data:2},{time:new Date("10/2/13"),data:45},...{time:new Date("10/30/13"),data:14}]
]
Temporally combine the arrays with merge merge, extract the date object with map, and get the range with extent:
var xScale = d3.time.scale()
.domain(d3.extent(d3.merge(data).map(function(d){ return d.time; }))
.range([0,300])

Resources