13

d3.jsでは、使用するx軸をd3.time.scale()設定x.domain([start_date, end_date])してから設定すると、データに含まれていない欠落している日付を0の値で「埋める」ことができます。nvd3.jsでも同じことをしたいですmulitBarChart

このコード( http://nvd3.org/livecode/#codemirrorNavに直接貼り付けることができます)は、年ごとの合計の棒グラフを示しています。2002年と2003年の値が欠落しています。スケールをに設定してからd3.time.scale()、データセットの最初と最後の年にドメインを設定して、欠落している年に0の値が自動的に追加されるようにします。それ、どうやったら出来るの?

nv.addGraph(function() {
    var chart = nv.models.multiBarChart();

    chart.xAxis
        .tickFormat(function(d){ return d3.time.format('%y')(new Date(d)); });

    chart.yAxis
        .tickFormat(d3.format(',f'));

    chart.reduceXTicks(false);
    chart.showControls(false);

    var data = [{
      'key': 'GB by year',
      'values': [
        {x: new Date().setFullYear('2001'), y: 0.12},
        {x: new Date().setFullYear('2004'), y: 0.03},
        {x: new Date().setFullYear('2005'), y: 0.53},
        {x: new Date().setFullYear('2006'), y: 0.43},
        {x: new Date().setFullYear('2007'), y: 5.5},
        {x: new Date().setFullYear('2008'), y: 9.9},
        {x: new Date().setFullYear('2009'), y: 26.85},
        {x: new Date().setFullYear('2010'), y: 0.03},
        {x: new Date().setFullYear('2011'), y: 0.12}
      ]
    }];        

    d3.select('#chart svg')
        .datum(data)
      .transition().duration(500).call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
});
4

3 に答える 3

12

上記の回答に基づいて、特定の種類のグラフに対して、数値のx値(Dateオブジェクトではない)と、強制されたX範囲および指定されたtickValues....を使用してこれを行うことができます。

棒グラフには機能がないようですが、nvd3.lineChartsは必要なことを実行します。multiBarChartモデルでは、forceX関数を適用できません(今までですか?)。

問題の解決策は、0を入力するか、シーケンシャルチャートタイプ(lineChartなど)を使用することです。

nv.addGraph(function() {
  var chart = nv.models.lineChart()
      .forceX(2001,2011);

  var tickMarks = [2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011]

  chart.xAxis
      .tickValues(tickMarks)
      .tickFormat(function(d){ return d });

  chart.yAxis
      .tickFormat(d3.format(',f'));

  var data = [{
    'key': 'GB by year',
    'values': [
      {x: 2001, y: 0.12},
      {x: 2004, y: 0.03},
      {x: 2005, y: 0.53},
      {x: 2006, y: 0.43},
      {x: 2007, y: 5.5},
      {x: 2008, y: 9.9},
      {x: 2009, y: 26.85},
      {x: 2010, y: 0.03},
      {x: 2011, y: 0.12}
    ]
  }];        

  d3.select('#chart svg')
    .datum(data)
    .transition().duration(500).call(chart);

  nv.utils.windowResize(chart1.update);

  return chart;
});   
于 2013-04-02T22:07:22.907 に答える
5

You can do this in 2 ways:

A) You either rewrite the axis component of nvd3 to use d3.time.scale() / make another axis component for this use case...

Or the easiest way:

B) You use the custom values for the axis. First of all you use the + operator ( +(date) ) to have the values in ms. There is a tickValues function in d3 that allows you to pass custom values for the ticks.. To force the X scale you have the forceX() method from the scatter (I assume you already know about this) and you write a simple function that takes custom values for ticks.... So if you force your scale to have values between Jan 1 2002 and Dec 31 2012 and then decide to have 4 ticks you can use either ticks directly or tickValues...

So it goes like this (add something similar to the multiBarChart.js file):

  lines.forceX(minValue, maxValue) //where minValue and maxValue are the values
  //converted to ms already after you did +(date)

  //then you just rewrite the ticks - if you want a custom number of ticks you can do it like this

  //numberOfTicks is a method I added to the axis component (axis.js) to give the number of ticks the user would like to have

  //x.domain() now contains the forced values instead of the values you initially used..
  var maxTicks = xAxis.numberOfTicks()-1, xMin = x.domain()[0], xMax = x.domain()[1], 
      xDiff = (xMax - xMin)/maxTicks, tickInterval = [];

  tickInterval[0] = xMin;

  for(i=1; i<maxTicks; i++){
    var current = xMin + i*xDiff;
    tickInterval[i] = current;
  }

  tickInterval[maxTicks] = xMax;

  //tickInterval already contains the values you want to pass to the tickValues function
  xAxis.tickValues(tickInterval);

Hope this helps... I know it's hack but it worked in my case :) And of course if you already formatted the date to be displayed as year you will get the values for the years when displaying the ticks :)

This is how I did it for lines. For multiBarChart you will need to add an extra step: you need to deal with the reduceTicks functionality (set it to false, delete that part of the code, do whatever you like with it...)

于 2013-01-24T11:54:39.673 に答える
5

値を補間する必要は実際にはありません。multiBarChartsを含むほとんどのnvd3チャートのスケールを実際に変更できますが、それを機能させるために実行する必要のある追加の作業がいくつかあります。

あなたがする必要がある基本的なことはこれです:

var xScale = d3.time.scale();
chart.multibar.xScale(xScale);

その後、それはうまくいくはずです!multiBarChartはxScaleがであると想定しているため、そうでない場合を除きd3.scale.ordinal()ます。xScale.rangeBandsしたがって、設定してそのタイプであることを偽造する必要がありますxScale.rangeBand

xScale.rangeBands = xScale.range;
xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * SOME_VALUE };

問題は、SOME_VALUEを取得することです。これは、個々のバーの幅と等しくする必要があります。これは、チャート全体の幅と、データに欠落しているゼロ値を含むティック数の2つに依存します。

nvd3が内部で使用可能な幅を取得する方法は次のとおりです。

var container = d3.select('#chart svg'),
    availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;

ただし、ウィンドウのサイズが変更された場合は、次の値を更新する必要があります。

nv.utils.windowResize(function() {
    availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
});

ティック数の取得に関しては、これはデータのみに依存します。あなたの場合、2001年から2011年の間に毎年11ティックがあります。したがって、スケール定義全体は次のようになります。

var container = d3.select('#chart svg'),
    availableWidth,
    numTicks = 11,
    xScale = d3.time.scale();

function updateAvailableWidth() {
    availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
}
updateAvailableWidth();
nv.utils.windowResize(updateAvailableWidth);

xScale.rangeBands = xScale.range;
xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * availableWidth / numTicks; };

chart.multibar.xScale(xScale);

最後に、xDomainを手動で設定する必要があります。以前の順序スケールでこれを実行すると失敗しますが、線形時間スケールではうまく機能します。

chart.xDomain([new Date().setFullYear('2001'), new Date().setFullYear('2011')]);

すべてをまとめると、次のサンプルコードがあります(http://nvd3.org/livecode/#codemirrorNavに貼り付け可能):

nv.addGraph(function() {
    var chart = nv.models.multiBarChart(),
        container = d3.select('#chart svg'),
        availableWidth,
        numTicks = 11,
        xScale = d3.time.scale();

    function updateAvailableWidth() {
        availableWidth = (chart.width() || parseInt(container.style('width')) || 960) - chart.margin().left - chart.margin().right;
    }
    updateAvailableWidth();
    nv.utils.windowResize(updateAvailableWidth);

    xScale.rangeBands = xScale.range;
    xScale.rangeBand = function() { return (1 - chart.groupSpacing()) * availableWidth / numTicks; };

    chart.multibar.xScale(xScale);
    chart.xDomain([new Date().setFullYear('2001'), new Date().setFullYear('2011')]);

    chart.xAxis
        .tickFormat(function(d){ return d3.time.format('%y')(new Date(d)); });

    chart.yAxis
        .tickFormat(d3.format(',f'));

    chart.reduceXTicks(false);
    chart.showControls(false);

    var data = [{
      'key': 'GB by year',
      'values': [
        {x: new Date().setFullYear('2001'), y: 0.12},
        {x: new Date().setFullYear('2004'), y: 0.03},
        {x: new Date().setFullYear('2005'), y: 0.53},
        {x: new Date().setFullYear('2006'), y: 0.43},
        {x: new Date().setFullYear('2007'), y: 5.5},
        {x: new Date().setFullYear('2008'), y: 9.9},
        {x: new Date().setFullYear('2009'), y: 26.85},
        {x: new Date().setFullYear('2010'), y: 0.03},
        {x: new Date().setFullYear('2011'), y: 0.12}
      ]
    }];        

    container.datum(data).transition().duration(500).call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
});
于 2015-12-07T20:17:56.197 に答える