根据数据范围动态设置D3刻度

Mat*_*nis 1 javascript d3.js

有没有办法ticks根据当前数据集在D3轴上动态设置.我遇到的问题是我的时间范围(x轴)可能有很大差异.对于某些数据集,它需要几年的时间,对于其他数据集需要几个月,在某些情况下只需几毫秒.我目前有这套ticks:

.ticks(d3.time.month, 3)
Run Code Online (Sandbox Code Playgroud)

......每三个月显示一次.对于跨越数月或数年的数据,这是一个不错的季度轴.但是,如果数据的范围仅为几周,几天甚至几秒,则我的轴标签上不会显示任何内容.

mee*_*mit 6

从我(相当广泛的)经验来看,没有自动神奇的方法来做到这一点.但是,"硬"方式是非常有效的,在这种方式中,您明确指定您希望在任何时间范围内发生的事情.

基本上,你知道图表的全部时间跨度 - 假设它被调用timeSpan并且它以毫秒为单位 - 所以你可以创建一个大的if ... else块来响应它.例如

var interval, count;
if (timeSpan <= 3600000) { // 1 hour or less
  interval = d3.time.minute;
  count = 15; // every 15 minutes
}
else if (timeSpan <= 8.64e7) { // 24 hours {
  interval = d3.time.hour;
  count = 1;
}
else if (timeSpan <= 7 * 8.64e7) { // 7 days {
  interval = d3.time.day;
  count = 1;
}
// etc....

timeAxis.ticks(interval, count);
Run Code Online (Sandbox Code Playgroud)

在许多情况下,这对我来说非常有效.您可以根据需要通过添加更多条件来扩展它.此外,您的图表可能有两个轴 - 一个用于主要标记,标记为刻度线,另一个用于辅助刻度线或网格线.然后你可以引入另一个变量,secondaryInterval并以相同的方式将其用于if ... else块.同样,您可能会发现您还需要以.tickFormat()不同的方式指定,timeSpan并且也可以在此代码中使用.

var interval, count, format;
if (timeSpan <= 3600000) { // 1 hour or less
  interval = d3.time.minute;
  count = 15; // every 15 minutes
  format = d3.time.format("%H:%M");
}
// etc....
timeAxis
  .ticks(interval, count)
  .tickFormat(format);
Run Code Online (Sandbox Code Playgroud)

此外,如果您的图表具有响应性,这意味着有时它的宽度为900像素,而其他图表宽度为200像素,您可能还需要根据密度调整刻度.在这种情况下,您需要计算密度值,如"每像素毫秒数":

msPerPixel = timeSpan / chartWidth
Run Code Online (Sandbox Code Playgroud)

对于任何给定的timeSpan,msPerPixel根据浏览器(或图表的)宽度,可以更小或更大,并且您可以使用msPerPixel上面的条件逻辑来显示更多或更少的刻度,具体取决于msPerPixel大于某个常量.

希望有所帮助.祝好运.

  • @Mark我发现让d3决定滴答声永远不会让你得到你想要的东西,也不适用于所有时间范围.当涉及`.tickFormat`时尤其如此.D3为同一个图表中的每个刻度线选择不同的刻度线格式(如标记为2月的刻度线旁边标有2015的刻度线),这是整洁但通常无益的.此外,d3不会将图表的宽度计入刻度选择中,因此无法确保刻度标签不会重叠,也不会根据宽度选择更多或更少的刻度.最重要的是,要明确这一点并不难,而且看起来值得. (3认同)