xy2_
xy2_

Reputation: 7162

d3 scale, put ticks every Nth day evenly spaced

I want to create a tick on my chart every Nth day, with the number of days configurable. If the user chooses "30 days", then the scale should show a tick every 30 days.

To do so, what I've tried is to pass an interval with d3.timeDay. The issue is that D3 docs tell me the dates are not uniformly spaced. Furthermore, it doens't work above 30 days.

d3.timeDay.every(30).range(new Date(2015, 0, 1), new Date(2015, 2, 1));
// returns
[
  2015-01-01,
  2015-01-31,
  2015-02-01,
]

How can I get uniformly spaced dates (and ticks?)

    const dom = [new Date(2019, 1, 1), new Date(2020, 1, 1)]

    const width = 600
    const height = 200
    const x = d3.scaleTime()
      .domain(dom)
      .range([0, width])

    d3.select("body")
      .append("svg")
      .attr("viewBox", [0, 0, width, height])
      .append("g")
      .call(d3.axisBottom(x)
        .ticks(d3.timeDay.every(30))
        .tickFormat(d3.timeFormat("%d-%m-%Y")))
<script src="https://d3js.org/d3.v6.min.js"></script>

Upvotes: 0

Views: 1088

Answers (1)

xy2_
xy2_

Reputation: 7162

I managed to do it with d3.count(), filtering every date that comes and checking the spacing against the first date. Feel free to answer if there's a better solution.

    const dom = [new Date(2019, 1, 1), new Date(2020, 1, 1)]

    const width = 600
    const height = 200
    const x = d3.scaleTime()
      .domain(dom)
      .range([0, width])

    d3.select("body")
      .append("svg")
      .attr("viewBox", [0, 0, width, height])
      .append("g")
      .call(d3.axisBottom(x)
        .ticks(d3.timeDay.filter(d => d3.timeDay.count(dom[0], d) % 30 === 0))
        .tickFormat(d3.timeFormat("%d-%m-%Y")))
<script src="https://d3js.org/d3.v6.min.js"></script>

Upvotes: 4

Related Questions