web-dev-qa-db-ja.com

nvd3.jsmultiBarChartの軸でドメインとスケールを設定する方法

D3.jsでは、d3.time.scale()を使用するようにx軸を設定してから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;
});
13
cerberos

値を補間する必要は実際にはありません。実際には、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を取得することです。これは、個々のバーの幅と等しくする必要があります。これは、チャート全体の幅とティック数includeの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;
});
_
5
meustrus

上記の回答に基づいて、特定のタイプのグラフに対して、数値の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;
});   
12
tmarthal

これは2つの方法で実行できます。

A)d3.time.scale()を使用するようにnvd3の軸コンポーネントを書き直すか、このユースケース用に別の軸コンポーネントを作成します。

または最も簡単な方法:

B)軸にカスタム値を使用します。まず、+演算子(+(date))を使用して、ミリ秒単位の値を取得します。 d3にはtickValues関数があり、ティックのカスタム値を渡すことができます。Xスケールを強制するには、スキャッターからforceX()メソッドを使用し(これについては既に知っていると思います)、次のような単純な関数を記述します。ティックのカスタム値を取ります。したがって、スケールに2002年1月1日から2012年12月31日までの値を強制し、4ティックにすることにした場合は、ティックを直接使用するか、tickValuesを使用できます。

したがって、次のようになります(multiBarChart.jsファイルに似たものを追加します)。

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

これがお役に立てば幸いです...私はそれがハックであることを知っていますが、私の場合はうまくいきました:)そしてもちろん、日付を年として表示するようにすでにフォーマットしている場合は、ティックを表示するときに年の値を取得します:)

これは私がラインのためにそれをした方法です。 multiBarChartの場合、追加の手順を追加する必要があります。reduceTicks機能を処理する必要があります(falseに設定し、コードのその部分を削除し、好きなように実行します...)

5
paxRoman