In my d3.js chart, I have data from 2002 to 2023.
I verified this using x.domain()
, which returns:
0: Wed Jul 31 2002 00:00:00 GMT 0200 (Central European Summer Time) {}
1: Mon Jul 31 2023 00:00:00 GMT 0200 (Central European Summer Time) {}
Then I try to create x-axis ticks:
let x = d3.scaleTime()
.rangeRound([0, 600]);
let fiscal_year_ends_month = 10;
d3.axisBottom(x)
.tickFormat(d3.timeFormat("%m/%y")).ticks(data.length < 60 ? d3.timeMonth : d3.timeYear)
.ticks(d3.timeDay.filter(function(d) {
return d.getMonth() === fiscal_year_ends_month;
}))
This is supposed to iterate through all the dates in the range, find the ones that meet the condition that the month is what I input, and create the ticks.
However, it runs for infinity.
Specifically, if I do this:
.ticks(d3.timeDay.filter(function(d) {
console.log(d.getFullYear(), d.getMonth(), d.getDate());
return d.getMonth() === fiscal_year_ends_month;
}))
It appears to start at the end of my x.domain
(2023) and run backwards to infinity. I let it run for a while now and the last output of console.log
was June 10, 322 B.C.:
-322 5 10
Needless to say, my chart of stock market data should not start in the 4th century B.C.
Why isn't the process running only through the dates in my x.domain()
?
CodePudding user response:
The issue can be re-created like this:
.ticks(d3.timeDay.filter(function(d) {
console.log(d.getFullYear(), d.getMonth(), d.getDate());
return false; // <--- generates infinite loop backward in time !!
}))
This suggests an issue in your input data with regards to the month index you are trying to filter on. It also suggests there's a bug in the library that let's this happen...
With fiscal_year_ends_month = 10
I assume you are looking to only have November ticks for each year of data ? There is a d3.timeMonth
interval that you can use for this purpose e.g.:
.ticks(d3.timeMonth.filter(function(d) {
return d.getMonth() === fiscal_year_ends_month;
}));
Working example:
// your constant
const fiscal_year_ends_month = 10;
// sample data
let data = [];
for (let i= 0; i<2370; i ) {
let d = new Date()
data.push({
dt: d.setDate(d.getDate() i),
val: i
});
}
// time scale
let x = d3.scaleTime()
.domain(d3.extent(data, d => d.dt))
.range([0, 540]);
// render
let svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 150)
.append("g")
.attr("transform", "translate(30,30)");
let xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%m/%y"))
.ticks(d3.timeMonth.filter(function(d) {
return d.getMonth() === fiscal_year_ends_month;
}));
svg.append("g")
.attr("transform", "translate(0,90)")
.call(xAxis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>