dc.js barChart first and last bar not displaying fully
Asked Answered
J

2

5

I have a barChart with a d3.time.scale x-axis. I am displaying some data per hour, but the first and last data point bars are always cut in half when using centerBar(true).
(When using centerBar(false) the last bar disappears completely.)

The time window is based upon the data itself and is calculated as follows:

var minDate = dateDim.bottom(1)[0]["timestamp"];
var maxDate = dateDim.top(1)[0]["timestamp"];

.x(d3.time.scale().domain([minDate, maxDate]));

The last line sets the time scale domain to use min and maxDate. This is how it looks: dc.js barChart 1

I have increased the bar width slightly using .xUnits(function(){return 60;}) as the default is so thin that the first bar disappears within the y-axis.

Also I already tried to change the domain by substracting/adding one hour to min/maxDate, but this results in unexpected behaviour of the first bar. enter image description here

I used the following to calculate the offset:

minDate.setHours(minDate.getHours() - 1);
maxDate.setHours(maxDate.getHours() + 1);

Is there a fix or workaround for this to add padding before the first and after the last bar?

Jacobba answered 4/8, 2015 at 11:57 Comment(2)
what unexpected behavior results from increasing the domain? like @Austin, this is how I would expect to fix the problem.Larrainelarrie
It then falsely moves the 9 AM bar data to the 8 AM bar. Imagine the graph above with an 8 AM bar with the current 9 AM data (3) and the 9AM bar is now empty. I think I pinned down the problem but cannot fully explain why it's happening. Please see my last comment on Austin's question.Jacobba
N
6

Subtract an hour from the minDate and add an hour to the maxDate to get an hour worth of padding on each side of your min and max data.

The trick here is to use d3.time.hour.offset and play with offsets until it looks nice.

.x(d3.time.scale().domain([d3.time.hour.offset(minDate, -1), d3.time.hour.offset(maxDate, 2)])); `

See this fiddle http://jsfiddle.net/austinlyons/ujdxhd27/3/

Nameplate answered 4/8, 2015 at 14:30 Comment(8)
In my question I already wrote that I ruled that out because it didn't work. I will edit the question to make this more clear.Jacobba
This method does work, maybe there is an issue with your implementation of adding and subtracting an hour. Can you post a JSFiddle?Nameplate
An issue in my implementation is very likely. I will have another look and build a JSFiddle later. Thanks!Jacobba
Updated my response with a fiddle to help you out.Nameplate
oh wow that's fantastic! I played around with it and ended up using a minute offset. I had used a different way of calculating the offset which let to weird behaviour. See my updated question. Thank you very much that was super helpful. Do you by any chance know why my initial attempt at changing min/maxDate failed?Jacobba
It's possible that the parsing of your datetime didn't work as expected. What do you see when you console.log(minDate)?Nameplate
Before: Tue Aug 04 2015 09:00:00 GMT+0100 (BST) After: Tue Aug 04 2015 08:00:00 GMT+0100 (BST)Jacobba
Ah I found the problem, but cannot fully explain why it's happening. setHours actually returns seconds-from-the-epoch which is a number when I do minDate = minDate.setHours(..). In my code I don't use the assignment and the the console.log somehow logs a correct date object and not the number. But once the variable is used within the domain of the chart I think it does somehow use the seconds representation and it fails. Does that make sense?Jacobba
J
3

The mistake was not realising JavaScript's passing-by-reference when using objects such as Date objects.

In addition to Austin's answer, which did solve the problem by using d3 functionality, I investigated why my initial attempt by modifying the minDate and maxDate variables failed.

The problem is that when creating the variables

var minDate = dateDim.bottom(1)[0]["timestamp"];
var maxDate = dateDim.top(1)[0]["timestamp"];

I created pointers to the actual data instead of creating new objects with the same value as the minDate and maxDate objects. The line

minDate.setHours(minDate.getHours() - 1);

therefore then manipulated the actual underlying data within the date dimension dateDim, which then led to the peculiar behaviour.

The obvious solution would have been to create new Date() objects like this:

var minDate = new Date(dateDim.bottom(1)[0]["timestamp"]);
var maxDate = new Date(dateDim.top(1)[0]["timestamp"]);

and then do the desired manipulations:

minDate.setHours(minDate.getHours() - 1);   
maxDate.setHours(maxDate.getHours() + 1);
Jacobba answered 4/8, 2015 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.