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

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

问题描述

我有一个奇怪的问题,在xAxis上显示日期。
我生成如下数据:

  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};
}



在我的lineChart中,我想创建x轴: p>

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

现在,如果我看看图表,只有几个日期可见。这就是为什么我创建了数组testarr的脱脂问题。 testarr的内容是
8日期而不是12(我生成12)



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



我无语,希望有人能帮助我。 >

谢谢你们!



完成下面的代码:



for lineChart: lineChart结果

 < 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图表);

// TODO:找出一个好的方法来自动执行这个操作
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>

如果我不注释掉

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


$ b b

部分,轴显示Jan70到处。



对于下面的MultiBarChart代码: MultiBar Result

 < script& 
var chart;
nv.addGraph(function(){
chart = nv.models.multiBarChart()
.margin({bottom:30,top:25})
.transitionDuration )
.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);
});
$ b b 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>


解决方案

折线图轴,标记显示关键点在线,但不是每个可想象的价值。在许多情况下,如果图表显示每个数据,那么刻度将非常接近,标签将重叠并变得不可读。人们期望能够基于到相邻刻度标记的距离来估计线上的位置。



相反,假定条形图的x值为不同类别,其可能不具有自然顺序。它们可以是苹果,桔子和香蕉。没有办法根据相邻标签(苹果和香蕉)的值估计中间值(橘子),因此默认情况下显示所有标签,即使它们最终重叠和不可读。 p>

但是,对于折线图,你只有12个日期值,所以你有空间适应所有的标签没有重叠?常规d3方法告诉轴应该包含多少个滴答作为 axis.ticks() 。我看到你试图做类似的事情,但 axis.tickSize()方法控制每个勾线的长度,而不是有多少。但是, axis.ticks()不适用于NVD3 - 内部方法会覆盖您在轴上设置的任何值。



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



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



选项1: strong>直接从数据中获取x值。

  chart.xAxis.tickValues(ideas.values.map ){return dx;})); 

//Array.map (function)创建一个新数组,其中每个值都是
的结果//调用原始数组的相应元素上的函数。
//因为你的数据在ideas.values中作为{x:date,y:number}对象的数组,
//此方法创建一个包含数据中所有日期的数组。选项2:
使用d3 /github.com/mbostock/d3/wiki/Time-Intervals#wiki-intervalrel =nofollow noreferrer>时间间隔方法计算日期序列。

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

//d3.time.month.range(startDate,stopDate,step)创建日期序列
//是精确的月份值,从startDate开始或之后的月份开始
//并继续到月份的最后开始* before *停止日期
//(所以它不会包括2014年1月。步长值告诉它多少月
//我们希望每个月,所以step == 1。

//有年,周,日,小时,分钟和秒的类似方法
//以及从一周的特定日期开始的周期的版本;
//只需用适当的间隔替换d3.time.month.range中的month
//对于纯数字,使用d3.range(start,stop,step)

p>

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.

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

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