最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - D3, variable x axis ticks based on time - Stack Overflow

matteradmin6PV0评论

I'm using D3.js to generate a graph with response times over time. Previously I was using Google Charts but it was too heavy. D3 is nice and lightweight, but there's something I can't manage to do that I could do with Google Charts.

The problem is that those graphs sometimes span over one week, sometimes over one day, sometimes over one hour. For each case I have to manually modify how the ticks in the X axis appear. I'm doing it by paring the first and the last values for the X axis, and checking how much time there's between them, like this:

if (dateDif < 25) { // daily
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%H:%M'))
        .ticks(d3.time.hours, 3)
        .orient("bottom");
}

else if (dateDif <= 170) {  // ~ weekly
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%d/%m %H:%M'))
        .ticks(d3.time.hours, 24)
        .orient("bottom");
} else { // more than weekly
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%d/%m %H:%M'))
        .ticks(d3.time.hours, 96)
        .orient("bottom");
}

But that it's not good, at all, specially when there are just a few values in the chart (they're generated every minute), then no ticks appear (because it falls in the first case, and there are no enough values to span 3 hours).

Do you know of any plugin or method that automagically adapts the X axis for this kind of situations?

I'm using D3.js to generate a graph with response times over time. Previously I was using Google Charts but it was too heavy. D3 is nice and lightweight, but there's something I can't manage to do that I could do with Google Charts.

The problem is that those graphs sometimes span over one week, sometimes over one day, sometimes over one hour. For each case I have to manually modify how the ticks in the X axis appear. I'm doing it by paring the first and the last values for the X axis, and checking how much time there's between them, like this:

if (dateDif < 25) { // daily
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%H:%M'))
        .ticks(d3.time.hours, 3)
        .orient("bottom");
}

else if (dateDif <= 170) {  // ~ weekly
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%d/%m %H:%M'))
        .ticks(d3.time.hours, 24)
        .orient("bottom");
} else { // more than weekly
    xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat(d3.time.format('%d/%m %H:%M'))
        .ticks(d3.time.hours, 96)
        .orient("bottom");
}

But that it's not good, at all, specially when there are just a few values in the chart (they're generated every minute), then no ticks appear (because it falls in the first case, and there are no enough values to span 3 hours).

Do you know of any plugin or method that automagically adapts the X axis for this kind of situations?

Share Improve this question asked Apr 25, 2014 at 16:14 José Tomás TocinoJosé Tomás Tocino 10.1k5 gold badges47 silver badges82 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

d3.svg.axis() is fairly good at handling this type of behavior by default - try removing .tickFormat(...) from your axis, and setting .ticks(n) where n is the desired number of ticks you want on the axis at any scale zoom level - this might be sufficient for what you desire.

Here are a couple of related examples:

http://bl.ocks/mbostock/2983699

http://bl.ocks/mbostock/1166403

You could define a function to get the tickFormat based on the dateDif, so you wouldn't need to have such a large if-else block.

function getFormat() {
  if (dateDif < 25) {
    return d3.time.format('%H:%M');
  } else {
    return d3.time.format('%d/%m %H:%M');
  }
}

Then you can set .ticks() to a number. In the output, roughly that many ticks will be shown. d3 chooses a number of ticks that is close to your requested value, but also makes a few decisions to try to give optimal output.

// approximately 10 ticks will be displayed
xAxis = d3.svg.axis()
    .scale(x)
    .tickFormat(getFormat())
    .ticks(10)
    .orient("bottom");

If you use this method, you lose a little control over the exact number of ticks that will be shown, but you are guaranteed to have ticks displayed, and if you choose a sensible number for your ticks value, the output will probably be satisfactory.

Here's a fiddle using this technique with some contrived data.

Post a comment

comment list (0)

  1. No comments so far