x 轴上的 d3.js nvd3 日期:仅显示一些日期 [英] d3.js nvd3 date on x axis: only some dates are show

查看:20
本文介绍了x 轴上的 d3.js nvd3 日期:仅显示一些日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 xAxis 上显示日期时遇到一个奇怪的问题.我正在生成这样的数据:

for (i=0;i<12;i++){日期=新日期(2013,i,1);idea.values[i] = {"y" : Math.round(2*i*getRandom(1,2)), "x": date};}

在我的 lineChart 中,我想像这样创建 x 轴:

chart.xAxis.tickSize(12).tickFormat(函数(d){var date = new Date(d);testarr.push(日期);return d3.time.format('%b %y')(日期);});

现在,如果我查看图表,只有几个日期可见.这就是我为调试问题创建数组testarr"的原因.testarr 的内容是8 个日期而不是 12 个(我生成了 12 个)

现在更奇怪的是:将完全相同的数据放入 MultiBarChart 并使用完全相同的 chart.xAxis.... 函数,测试数组内容为 12 个值

我很无语,希望有人能帮帮我.

谢谢你们!

完整代码如下:

对于线图:线图结果

如果我不注释掉

//x: function(d,i) { return i},

部分,轴处处显示Jan70.

对于下面的 MultiBarChart 代码:MultiBar 结果

解决方案

折线图轴,与所有线性轴一样,使用刻度线来显示线上的关键点,但不是每个可能的值.在许多情况下,如果图表显示所有数据,刻度会靠得很近,以至于标签会重叠并变得不可读.人们希望能够根据与相邻刻度线的距离来估计在线上的位置.

相比之下,条形图的 x 值被假定为不同的类别,可能没有自然顺序.它们可以是苹果"、橙子"和香蕉".无法根据相邻标签(苹果"和香蕉")的值来估计中间值(橙子"),因此默认情况下会显示所有标签,即使它们最终重叠且不可读.

但是您的折线图呢,其中只有 12 个日期值,所以您有空间容纳所有标签而不重叠?告诉轴它应该包含多少刻度的常规 d3 方法是 axis.ticks().我看到你试图做类似的事情,但 axis.tickSize() 方法控制每个刻度线的 length,而不是有多少.但是,axis.ticks() 不适用于 NVD3——内部方法会覆盖您在轴上设置的任何值.

别担心,还是有办法控制的,只是需要一些额外的代码.axis.tickValues()方法取代 axis.ticks(),因此您可以使用它来覆盖 NVD3 默认值.

您在 axis.tickValues() 中包含的信息是每个刻度的显式值的数组.由于您的 x 轴值是日期,并且每个月都有一个值,因此您有两种创建此数组的方法:

选项 1:直接从您的数据中获取 x 值.

chart.xAxis.tickValues(ideas.values.map( function(d){return d.x;} ) );//Array.map(function) 创建一个新数组,其中每个值都是//在原始数组的相应元素上调用该函数.//因为你的数据在ideas.values中是一个{x:date, y:number}对象的数组,//此方法创建一个包含数据中所有日期的数组.

选项 2: 使用 d3 时间interval 计算日期序列的方法.

chart.xAxis.tickValues(d3.time.month.range(新日期(2013 01"),新日期(2014 01"),1));//d3.time.month.range(startDate, stopDate, step) 创建日期序列//这是确切的月份值,从 startDate 当天或之后的月份开始//并继续到上个月*之前*停止日期//(所以它不会包括 2014 年 1 月.步长值告诉它多少个月//一次跳过;我们每个月都想要,所以 step==1.//年、周、日、时、分、秒也有类似的方法,//以及从一周中的特定日期开始的周版本;//只需用适当的间隔替换d3.time.month.range"中的month".//对于普通数字,使用 d3.range(start, stop, step).

我希望现在一切都有意义了.

I have a strange issue with showing dates on a xAxis. I am generating data like this:

for (i=0;i<12;i++){
    date=new Date(2013,i,1);

    ideas.values[i] = {"y" : Math.round(2*i*getRandom(1,2)), "x": date};
}

In my lineChart I want to create the x-axis like this:

chart.xAxis.tickSize(12)            
           .tickFormat(function(d) {         
             var date = new Date(d);
             testarr.push(date);
             return d3.time.format('%b %y')(date);
            });

Now if I look at the chart, there are only a few Dates visible. This is why I created the array "testarr" for degbugging issues. The content of testarr is 8 Dates instead of 12 (i generated 12)

Now the even more strange thing: Putting the exactly same data in an MultiBarChart and using the EXACT same chart.xAxis.... function, the test arrays content are 12 values

I am speechless and hope that someone can help me out.

Thank you guys!

Complete Code below:

for lineChart: lineChart Result

<script>
var chart;
nv.addGraph(function() {
  chart = nv.models.lineChart()
  .options({
    margin: {left: 100, bottom: 100},
    //x: function(d,i) { return i},
    showXAxis: true,
    showYAxis: true,
    transitionDuration: 250
  })
  ;
  chart.xAxis.tickSize(12)            
                  .tickFormat(function(d) {         
         var date = new Date(d);
          return d3.time.format('%b %y')(date);
                 });

    chart.yAxis
       .axisLabel('y axis')
       .tickFormat(d3.format(''))
       .axisLabelDistance(50);

  d3.select('#chart1 svg')
    .datum(dataForChart)
    .call(chart);

  //TODO: Figure out a good way to do this automatically
  nv.utils.windowResize(chart.update);
  //nv.utils.windowResize(function() { d3.select('#chart1 svg').call(chart) });

  chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });

  return chart;
});

var dataForChart=function(){

       var section1 = new Array();
       section1.key="Section 1";
       section1.values = new Array();
       section1.color="#1F77B4";

       var section2 = new Array();
       section2.key="Section2";
       section2.values = new Array();
       section2.color="#2CA02C";

        for (i=0;i<12;i++){
            date=new Date(2013,i,1);

            section1.values[i] = {"y" : Math.round(2*i*getRandom(1,2)), "x": date};
            section2.values[i] = {"y" : Math.round(6*i+2*getRandom(1,2)), "x": date};
         }

         function getRandom(min, max) 
         {
            return Math.random() * (max - min + 1) + min;
         }

         var dataArray=new Array();
         dataArray.push(section1);
         dataArray.push(section2);

       return dataArray;
};    

</script>

if I do not comment out the

//x: function(d,i) { return i},

section, the axis shows Jan70 everywhere.

For MultiBarChart Code below: MultiBar Result

<script>
var chart;
nv.addGraph(function() {
    chart = nv.models.multiBarChart()
      .margin({bottom: 30, top:25})
      .transitionDuration(300)
      .delay(0)
      .groupSpacing(0.2)
      .reduceXTicks(false)
      .showControls(true)
      .showLegend(true)
      .staggerLabels(false)

      ;
    chart.xAxis.tickSize(12)            
             .tickFormat(function(d) {
         console.log(d,arguments);
         var date = new Date(d);
               return d3.time.format('%b %y')(date);
             });

    chart.yAxis
       .axisLabel(dataForChart.ylabel)
       .tickFormat(d3.format(''))
       .axisLabelDistance(50);

    d3.select('#chart1 svg')
        .datum(dataForChart)
       .call(chart);

    nv.utils.windowResize(chart.update);


    chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });

    return chart;
});


var dataForChart=function(){

       var section1 = new Array();
       section1.key="Section 1";
       section1.values = new Array();
       section1.color="#1F77B4";

       var section2 = new Array();
       section2.key="Section2";
       section2.values = new Array();
       section2.color="#2CA02C";

        for (i=0;i<12;i++){
            date=new Date(2013,i,1);

            section1.values[i] = {"y" : Math.round(2*i*getRandom(1,2)), "x": date};
            section2.values[i] = {"y" : Math.round(6*i+2*getRandom(1,2)), "x": date};
         }

         function getRandom(min, max) 
         {
            return Math.random() * (max - min + 1) + min;
         }

         var dataArray=new Array();
         dataArray.push(section1);
         dataArray.push(section2);

       return dataArray;
};    

</script>

解决方案

Line chart axes, like all linear axes, use tick marks to show key points on the line, but not every conceivable value. In many cases, if the chart showed every data, the ticks would be so close together that the labels would overlap and become unreadable. People are expected to be able to estimate the position on the line based on the distance to adjacent tick marks.

In contrast, the x-values for the bar chart are assumed to be distinct categories, which might not have a natural order. They could be "apples", "oranges", and "bananas". There's no way to estimate a middle value ("oranges") based on the values of adjacent labels ("apples" and "bananas"), so by default all the labels are shown, even if they end up overlapping and unreadable.

But what about your line chart, where you only have 12 date values, so you have room to fit all the labels without overlap? The regular d3 method to tell the axis how many ticks it should include is axis.ticks(). I see you tried to do something similar, but the axis.tickSize() method controls the length of each tick line, not how many there are. However, axis.ticks() doesn't work with NVD3 -- the internal methods over-write any value you set on the axis.

Don't worry, there is still a way to control it, but it requires some extra code. The axis.tickValues() method supercedes axis.ticks(), so you can use it to over-ride the NVD3 default.

The information you include in axis.tickValues() is an array of explicit values for each tick. Since your x-axis values are dates, and you have one value for each month, you have two ways of creating this array:

Option 1: Get the x values directly from your data.

chart.xAxis.tickValues(ideas.values.map( function(d){return d.x;} ) );

//Array.map(function) creates a new array, where each value is the result of
//calling the function on the corresponding element of the original array.
//Since your data is in ideas.values as an array of {x:date, y:number} objects,
//this method creates an array containing all the dates from your data.

Option 2: Use a d3 time interval method to calculate a sequence of dates.

chart.xAxis.tickValues(d3.time.month.range(
                            new Date("2013 01"),
                            new Date("2014 01"),
                            1)
                        );

//d3.time.month.range(startDate, stopDate, step) creates the sequence of dates
//that are exact month values, starting with the month on or after the startDate 
//and continuing to the last start of month *before* the stop date
//(so it won't include January 2014.  The step value tell it how many months
//to skip at a time; we want every month, so step==1.

//There are similar methods for year, week, day, hour, minute and second, 
//and also versions for weeks starting on specific days of the week;
//Just replace "month" in "d3.time.month.range" with the appropriate interval.
//For plain numbers, use d3.range(start, stop, step).

I hope that all makes sense now.

这篇关于x 轴上的 d3.js nvd3 日期:仅显示一些日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆