コンテンツにスキップ

スタック

· スタッキングは、長さを連続した位置の区間に変換します。たとえば、毎月の売上を示す棒グラフは、カテゴリ別に複数系列の棒グラフに分割し、棒を垂直に積み重ねてカテゴリの色分けを適用することができます。積み上げグラフは、全体の値とカテゴリごとの値を同時に表示できます。ただし、スタックの最下層のみが揃っているため、カテゴリ間を比較することは通常困難です。そのため、スタック順序を慎重に選択し、ストリームグラフを検討してください。(グループ化されたグラフも参照してください。)

円グラフジェネレーターと同様に、スタックジェネレーターは直接形状を作成しません。代わりに、位置を計算し、それを面ジェネレーターに渡したり、直接使用して、たとえば棒の位置を決めたりすることができます。

stack()

ソース · デフォルト設定で新しいスタックジェネレーターを構築します。使用方法については、stackを参照してください。

stack(data, ...arguments)

ソース · 指定された *data* の配列のスタックを生成し、各系列を表す配列を返します。追加の *arguments* は任意です。これらは、`this` オブジェクトとともにアクセサーに渡されます。

たとえば、毎月の果物の売上を示すこの整然とした表を考えてみましょう。

日付果物売上
1/2015りんご3840
1/2015バナナ1920
1/2015さくらんぼ960
1/2015ドリアン400
2/2015りんご1600
2/2015バナナ1440
2/2015さくらんぼ960
2/2015ドリアン400
3/2015りんご640
3/2015バナナ960
3/2015さくらんぼ640
3/2015ドリアン400
4/2015りんご320
4/2015バナナ480
4/2015さくらんぼ640
4/2015ドリアン400

これは、JavaScriptではオブジェクトの配列として表すことができ、おそらくCSVから解析されます。

js
const data = [
  {date: new Date("2015-01-01"), fruit: "apples", sales: 3840},
  {date: new Date("2015-01-01"), fruit: "bananas", sales: 1920},
  {date: new Date("2015-01-01"), fruit: "cherries", sales: 960},
  {date: new Date("2015-01-01"), fruit: "durians", sales: 400},
  {date: new Date("2015-02-01"), fruit: "apples", sales: 1600},
  {date: new Date("2015-02-01"), fruit: "bananas", sales: 1440},
  {date: new Date("2015-02-01"), fruit: "cherries", sales: 960},
  {date: new Date("2015-02-01"), fruit: "durians", sales: 400},
  {date: new Date("2015-03-01"), fruit: "apples", sales: 640},
  {date: new Date("2015-03-01"), fruit: "bananas", sales: 960},
  {date: new Date("2015-03-01"), fruit: "cherries", sales: 640},
  {date: new Date("2015-03-01"), fruit: "durians", sales: 400},
  {date: new Date("2015-04-01"), fruit: "apples", sales: 320},
  {date: new Date("2015-04-01"), fruit: "bananas", sales: 480},
  {date: new Date("2015-04-01"), fruit: "cherries", sales: 640},
  {date: new Date("2015-04-01"), fruit: "durians", sales: 400}
];

積み上げ系列(各 *果物* に対する系列または層、および各 *日付* に対するスタックまたは列)を計算するには、データを *日付* と *果物* でインデックス付け、データセット全体で異なる *果物* 名を計算し、最後に各 *日付* と *果物* の *売上* 値を取得します。

js
const series = d3.stack()
    .keys(d3.union(data.map(d => d.fruit))) // apples, bananas, cherries, …
    .value(([, group], key) => group.get(key).sales)
  (d3.index(data, d => d.date, d => d.fruit));

ヒント

d3-arrayのunionindexを参照してください。

結果の配列には、*系列* ごとに1つの要素があります。各系列には月ごとに1つの点があり、各点にはベースラインとトップラインを定義する下限値と上限値があります。

js
[
  [[   0, 3840], [   0, 1600], [   0,  640], [   0,  320]], // apples
  [[3840, 5760], [1600, 3040], [ 640, 1600], [ 320,  800]], // bananas
  [[5760, 6720], [3040, 4000], [1600, 2240], [ 800, 1440]], // cherries
  [[6720, 7120], [4000, 4400], [2240, 2640], [1440, 1840]]  // durians
]

各系列は、通常、面グラフをレンダリングするために面ジェネレーターに渡されるか、棒グラフの矩形を構築するために使用されます。

js
svg.append("g")
  .selectAll("g")
  .data(series)
  .join("g")
    .attr("fill", d => color(d.key))
  .selectAll("rect")
  .data(D => D)
  .join("rect")
    .attr("x", d => x(d.data[0]))
    .attr("y", d => y(d[1]))
    .attr("height", d => y(d[0]) - y(d[1]))
    .attr("width", x.bandwidth());

系列はキーアクセサーによって決定されます。返される配列の各系列 *i* は、*i* 番目のキーに対応します。各系列は点の配列であり、各点 *j* は入力 *data* の *j* 番目の要素に対応します。最後に、各点は配列 [ *y0* 、 *y1* ] として表されます。ここで、 *y0* は下限値(ベースライン)、 *y1* は上限値(トップライン)です。 *y0* と *y1* の差はこの点の計算されたに対応します。各系列のキーは *series*.key として、インデックスは *series*.index として使用できます。各点の入力データ要素は *point*.data として使用できます。

*stack*.keys( *keys* )

ソース · *keys* が指定されている場合、キーアクセサーを指定された関数または配列に設定し、このスタックジェネレーターを返します。

js
const stack = d3.stack().keys(["apples", "bananas", "cherries", "durians"]);

*keys* が指定されていない場合、現在のキーアクセサーを返します。

js
stack.keys() // () => ["apples", "bananas", "cherries", "durians"]

キーアクセサーのデフォルトは空の配列です。キーごとに系列(層)が生成されます。キーは通常文字列ですが、任意の値にすることもできます。InternMapを参照してください。系列のキーは、各データポイントとともに値アクセサーに渡され、ポイントの値が計算されます。

*stack*.value( *value* )

ソース · *value* が指定されている場合、値アクセサーを指定された関数または数値に設定し、このスタックジェネレーターを返します。

js
const stack = d3.stack().value((d, key) => d[key]);

*value* が指定されていない場合、現在の値アクセサーを返します。

js
stack.value() // (d, key) => d[key]

値アクセサーのデフォルトは次のとおりです。

js
function value(d, key) {
  return d[key];
}

注意

デフォルトの値アクセサーは、入力データが数値を持つ名前付きプロパティを公開するオブジェクトの配列であると想定しています。これはデータの「ワイド」表現であり、「タイディ」表現ではなく、推奨されなくなりました。タイディデータを使用する例については、 *stack* を参照してください。

*stack*.order( *order* )

ソース · *order* が指定されている場合、順序アクセサーを指定された関数または配列に設定し、このスタックジェネレーターを返します。

js
const stack = d3.stack().order(d3.stackOrderNone);

*order* が関数の場合は、生成された系列配列が渡され、スタック順序を表す数値インデックスの配列を返す必要があります。たとえば、逆キー順序を使用するには、次のようにします。

js
const stack = d3.stack().order(series => d3.range(series.length).reverse());

スタック順序はオフセットの前に計算されます。したがって、すべての点の下限値は、順序が計算されるときにゼロです。各系列のindex属性も、順序が計算されるまでは設定されません。

*order* が指定されていない場合、現在の順序アクセサーを返します。

js
stack.order() // d3.stackOrderNone

順序アクセサーのデフォルトはstackOrderNoneです。これはキーアクセサーによって指定された順序を使用します。組み込み順序については、スタック順序を参照してください。

*stack*.offset( *offset* )

ソース · *offset* が指定されている場合、オフセットアクセサーを指定された関数に設定し、このスタックジェネレーターを返します。

js
const stack = d3.stack().offset(d3.stackOffsetExpand);

オフセット関数は、生成された系列配列と順序インデックス配列に渡されます。その後、系列配列の下限値と上限値を更新する役割を担います。参照実装については、組み込みオフセットを参照してください。

*offset* が指定されていない場合、現在のオフセットアクセサーを返します。

js
stack.offset() // d3.stackOffsetExpand

オフセットアクセサーのデフォルトはstackOffsetNoneです。これはゼロベースラインを使用します。組み込みオフセットについては、スタックオフセットを参照してください。

スタック順序

スタック順序は通常直接使用されるのではなく、 *stack*.order に渡されます。

stackOrderAppearance( *series* )

js
const stack = d3.stack().order(d3.stackOrderAppearance);

ソース · 最も早い系列(最大値による)が最下位になるような系列順序を返します。

stackOrderAscending( *series* )

js
const stack = d3.stack().order(d3.stackOrderAscending);

ソース · 最も小さい系列(値の合計による)が最下位になるような系列順序を返します。

stackOrderDescending( *series* )

js
const stack = d3.stack().order(d3.stackOrderDescending);

ソース · 最も大きい系列(値の合計による)が最下位になるような系列順序を返します。

stackOrderInsideOut( *series* )

js
const stack = d3.stack().order(d3.stackOrderInsideOut);

ソース · 最大値に基づいて、最も早い系列を内側に、後の系列を外側に配置するような系列順序を返します。この順序は、wiggle オフセットと組み合わせてストリームグラフに使用することを推奨します。詳細については、Byron & Wattenberg による Stacked Graphs — Geometry & Aesthetics を参照してください。

stackOrderNone(series)

js
const stack = d3.stack().order(d3.stackOrderNone);

ソース · 指定された系列順序 [0, 1, … n - 1] を返します。ここで、nseries の要素数です。したがって、スタック順序は キーアクセサ によって指定されます。

stackOrderReverse(series)

js
const stack = d3.stack().order(d3.stackOrderReverse);

ソース · 指定された系列順序の逆順 [n - 1, n - 2, … 0] を返します。ここで、nseries の要素数です。したがって、スタック順序は キーアクセサ の逆順で指定されます。

スタックオフセット

スタックオフセットは通常、直接使用されるのではなく、stack.offset に渡されます。

stackOffsetExpand(series, order)

js
const stack = d3.stack().offset(d3.stackOffsetExpand);

ソース · ゼロベースラインを適用し、各点の値を正規化して、トップラインが常に1になるようにします。

stackOffsetDiverging(series, order)

js
const stack = d3.stack().offset(d3.stackOffsetDiverging);

ソース · 正の値はゼロの上に積み重ねられ、負の値は ゼロの下に積み重ねられ、ゼロの値はゼロに積み重ねられます。

stackOffsetNone(series, order)

js
const stack = d3.stack().offset(d3.stackOffsetNone);

ソース · ゼロベースラインを適用します。

stackOffsetSilhouette(series, order)

js
const stack = d3.stack().offset(d3.stackOffsetSilhouette);

ソース · ストリームグラフの中心が常にゼロになるように、ベースラインを下にシフトします。

stackOffsetWiggle(series, order)

js
const stack = d3.stack().offset(d3.stackOffsetWiggle);

ソース · レイヤーの加重振動を最小限に抑えるようにベースラインをシフトします。このオフセットは、inside-out 順序と組み合わせてストリームグラフに使用することを推奨します。詳細については、Bryon & Wattenberg による Stacked Graphs — Geometry & Aesthetics を参照してください。