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;
});
値を補間する必要は実際にはありません。実際には、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;
});
_
上記の回答に基づいて、特定のタイプのグラフに対して、数値の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;
});
これは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に設定し、コードのその部分を削除し、好きなように実行します...)