Show time durations on a d3 axis - javascript

I am currently creating a d3 axis using d3.time.scale.utc(). My input for the axis is a series of time offsets in minutes (with decimal values). For example:
var minuteOffsets = [0.03, 1.65, 3.22, ..., 89.91, 90.01];
I want to display these time offsets in mm:ss format on the axis. The axis labels can be at standard intervals, like so:
+------+------+-- ... --+------+------+-- ... --+------+
00:00 00:30 01:00 59:30 60:00 60:30 90:00 90:30
Note specifically that the minute value should show values >60. The seconds value has the normal range 0-59.
When I tried using .tickFormat(d3.time.format('%M:%S')), it wraps the minute value back to 00:00 after the 45:00 label. I also had a look at duration from moment.js, but I can't figure out how exactly to incorporate that into my code.

Based on the comment by Lars Kotthoff, I changed my scale to be a linear scale, instead of a time scale. Then I added a custom tickFormat function to do the necessary formatting.
I used MomentJS to first create a duration from the minute values, and then used the library moment-duration-format to produce the tick label in mm:ss format.
var axis = d3.svg.axis().tickFormat(function (d) {
return moment.duration(d, 'minutes')
.format('mm:ss', { trim: false });
});
This helps to avoid explicitly writing code for extracting the minute and second components, and then formatting them into a string.

Related

D3js Changing ticks on Zoomable Time axis

Background
I have a zoomable time graph which I build incorporating the following code:
var x = d3.time.scale().range([0, 100]);
var xAxis = d3.svg.axis()
.scale(x)
.tickFormat(customformatter);
When the appropriate interval is years, it shows ticks of years. Months shows months, etc.
Problem
This works wonderfully, generating great ticks until I zoom down into weeks, at which point I need to be able to dictate what day of the week ticks show for (Sunday, monday, etc.). I am aware of the multiformat custom generator for tickFormat in which you can specify the format given the appropriate interval. That will not change the ticks, however. Is there a way to set the start of the weeks' rules while maintaining the tick generation that otherwise exists at the year, month, day (etc.) level? Can the default start date be set to some other day of the week for the d3 library?
This is hardly a recommendable answer to my own question, but if anyone is desperate one way is to override the source code in /src/time/week.js:
d3_time.week = d3_time.sunday;
d3_time.weeks = d3_time.sunday.range;
d3_time.weeks.utc = d3_time.sunday.utc.range;
d3_time.weekOfYear = d3_time.sundayOfYear;
Just swap out 'sunday' for another day of the week.

d3js: time scaling and "1901"

I'm working with a time-based scatterplot and am using data which only parses times by month, hour and day. On my axis labels, I'm getting "1901". D3 seems to be choosing a year and displaying it. How can I easily get rid of this? I don't want any year displayed:
1901 example http://lmnts.lmnarchitects.com/wp-content/uploads/2014/04/2014-04-01-09_31_30-127.0.0.1_8020_Climate3_seattle-winter-temps.html.jpg
you need to set the tickFormat of your axis to display only months and days. The tickFormat receives a function that takes a date and returns a string. You can use d3.time.format to set the tick format:
var axis = d3.svg.axis()
// ... set more attributes
.tickFormat(d3.time.format('%b %d')); // Abbreviated month and decimal day (Apr 01)
Regards,

DC.js X-axis hour labels appear as thousandths

Using dc.js to build some charts. The localHour attribute contains numbers between 0 and 23. However, when using this on my axis, all numbers are reported as thousandths instead of the standard hour. 04 PM also appears at the origin.
How can I fix this?
var hourDim = ndx.dimension(function(d){ return d.hour; });
var num = hourDim.group().reduceSum(dc.pluck('count'));
var mainChart = dc.lineChart("#main");
mainChart
.width(500).height(200)
.dimension(hourDim)
.group(num)
.x(d3.time.scale().domain([0,24]))
.yAxisLabel("Count per Hour")
What's actually going on here is that your "hour" measurements are being interpretted as milliseconds. Milliseconds are the default Javascript time unit if you don't specify otherwise. Specifically, you're getting milliseconds after the Javascript zero time, which is sometime on Dec 31 1969 or Jan 1 1970 depending on timezone adjustment, and apparently starts at 4pm in your timezone. The rest is just default formatting trying to make things look nice.
Unless you're doing other things that require the hours to be treated as timestamps, it is probably easiest to leave the hours as plain numbers, using a linear scale instead of a time scale.
If you're fine with plain old "1", "2", "3" on the axis labels, that's all you have to do.
If you want those numbers to look like hours, you need to set a tickFormat function on the chart axis.
You could just do something like
mainChart.x(d3.scale.linear().domain([0,24])
.tickFormat(function(h){return h + ":00";})
);
But that causes problems if the axis decides to put ticks at fractional values -- you'll get something that looks like 1.5:00 instead of 1:30. You could fix that with some math and number formatting functions, but at that point you're doing enough work to make it worth using proper date-time formatting.
To get proper hour:minute axis labels, you can use a d3 time formatting function to specify the format, but you're also going to have to translate the number of hours into a valid date-time object.
var msPerHour = 1000*60*60;
var timeFormat = d3.time.format.utc("%H:%M");
mainChart.x(d3.scale.linear().domain([0,24])
.tickFormat(function(h){
return timeFormat(new Date(msPerHour*h) );
})
);
Note that I've specified the time format function to use UTC time instead of local time, so that it treats zero as midnight. It still thinks it's midnight, Jan 1 1970, but you're also specifying the formatting to only include hours and minutes so that shouldn't be an issue.

Changing time scale from days to weeks, how do I update and sum data values?

I am trying to have my barchart in d3.js update it's values when the user changes the time scale from days, to weeks or months. (i.e. when the time scale is changed to weeks, I want all the data values for each day in a given week summed together). For example, here is the default graph with the x-axis time scale in days:
x-Axis in days
When a user changes the time scale to weeks and the x-axis updates, the data values remain grouped by day, as shown here:
x-Axis scale in weeks, but data values remain grouped by day:
What I want is for there to be only one bar for each week number of the year on the x-axis, showing the sum of all the data values the user provided for all 7 days of that week. How do I achieve this?
Does this have to be done on the server-side, or can it be on the client-side with javascript, or is there some easy d3.js way I'm overlooking?
This is what my data looks like:
[{"date":"2013-04-20","load_volume":400},{"date":"2013-04-23","load_volume":400},{"date":"2013-04-24","load_volume":400},{"date":"2013-04-28","load_volume":1732},{"date":"2013-04-30","load_volume":400}]
I figured to achieve this I could convert the date values to weekNumberOfYear format (for e.g., 17 for this week), push them into an array and remove all duplicates, then sum the data values for each of the days in that array. I did this and the data looked like this:
[{"date":"15","load_volume":400},{"date":"16","load_volume":2532},{"date":"17","load_volume":400}]
However, I don't believe this is the correct approach because I always get an "Error: Invalid value for attribute x="NaN"" in the JS console. This I think is because I use the x scale to position the rects on my graph:
.attr("x", function(d) { return padding + x(new Date(d.date)); })
... which would result in x(Wed Dec 31 1969 19:00:00 GMT-0500 (EST)), which throws a NaN error.
I am now trying to format the date into %Y-%m-%d format and have it be the beginning Monday of each week, but I'm wondering if there is an easier solution since I've been at this all day.
Well, I think I've figured it out. I just had to convert the dates to millisecond time and remove the double quotes I had around the date value in the JSON string (the double quotes were giving me a NaN error). I did this with the following function:
function getWeekDate(d) {
d = new Date(d); // get current date
var day = d.getDay();
var diff = d.getDate() - day + (day == 0 ? -6 : 1); // Subtract day number of month from day number of week, and adjust when day is sunday
var date = new Date(d.setDate(diff));
return date.setHours(0);
}
which is adapted from this SO question.
Not sure if D3 has a better way of doing it. If I find out i'll post it here.

HighCharts X-Axis Date Not Working (00:00)

I have a HighChart chart which contains a series which is made up of date/value pairs. Each date in the pairs is different. When there are data pairs which have dates which are not within the same week they dates are displayed as they should (mm/dd/yyyy) but when the data set contains only a view pairs which are all within the same week or days right next to each other instead of displaying dates in the (mm/dd/yyyy) format the chart switches to what looks like a time display and shows 00:00, 08:00, 16:00 instead of the full dates.
I already scoured the HighCharts forum and cannot find nor get an answer to this strange behaviour. Maybe someone here can help.
You can see the chart at http://jsfiddle.net/schleichermann/DkgVr/
This is a foible of the auto-scaling algorithm.
Basically, it starts with the smallest unit and stops looking too soon in some cases (like yours)1.
If you know, in advance, the timescale of interest, you can tweak the xAxis settings to compensate.
In this case adding:
day: '%b %e',
hour: '%b %e',
May be adequate. See: jsfiddle.net/DkgVr/4/ .
Or setting tickInterval: 24 * 3600 * 1000 (one day) might be good enough.
See: jsfiddle.net/DkgVr/5/ .
1 It should probably work largest to smallest. Consider making a feature-request or bug report.

Categories

Resources