# Stacks

Examples · Stacking converts lengths into contiguous position intervals. For example, a bar chart of monthly sales might be broken down into a multi-series bar chart by category, stacking bars vertically and applying a categorical color encoding. Stacked charts can show overall value and per-category value simultaneously; however, it is typically harder to compare across categories as only the bottom layer of the stack is aligned. So, chose the stack order carefully, and consider a streamgraph. (See also grouped charts.)

Like the pie generator, the stack generator does not produce a shape directly. Instead it computes positions which you can then pass to an area generator or use directly, say to position bars.

## stack()

Source · Constructs a new stack generator with the default settings. See *stack* for usage.

*stack*(*data*, ...*arguments*)

Source · Generates a stack for the given array of *data* and returns an array representing each series. Any additional *arguments* are arbitrary; they are propagated to accessors along with the `this`

object.

For example, consider this tidy table of monthly fruit sales:

date | fruit | sales |
---|---|---|

1/2015 | apples | 3840 |

1/2015 | bananas | 1920 |

1/2015 | cherries | 960 |

1/2015 | durians | 400 |

2/2015 | apples | 1600 |

2/2015 | bananas | 1440 |

2/2015 | cherries | 960 |

2/2015 | durians | 400 |

3/2015 | apples | 640 |

3/2015 | bananas | 960 |

3/2015 | cherries | 640 |

3/2015 | durians | 400 |

4/2015 | apples | 320 |

4/2015 | bananas | 480 |

4/2015 | cherries | 640 |

4/2015 | durians | 400 |

This could be represented in JavaScript as an array of objects, perhaps parsed from CSV:

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

To compute the stacked series (a series, or layer, for each *fruit*; and a stack, or column, for each *date*), we can index the data by *date* and then *fruit*, compute the distinct *fruit* names across the data set, and lastly get the *sales* value for each *date* and *fruit*.

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

The resulting array has one element per *series*. Each series has one point per month, and each point has a lower and upper value defining the baseline and topline:

```
[
[[ 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
]
```

Each series in then typically passed to an area generator to render an area chart, or used to construct rectangles for a bar chart.

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

The series are determined by the keys accessor; each series *i* in the returned array corresponds to the *i*th key. Each series is an array of points, where each point *j* corresponds to the *j*th element in the input *data*. Lastly, each point is represented as an array [*y0*, *y1*] where *y0* is the lower value (baseline) and *y1* is the upper value (topline); the difference between *y0* and *y1* corresponds to the computed value for this point. The key for each series is available as *series*.key, and the index as *series*.index. The input data element for each point is available as *point*.data.

*stack*.keys(*keys*)

Source · If *keys* is specified, sets the keys accessor to the specified function or array and returns this stack generator.

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

If *keys* is not specified, returns the current keys accessor.

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

The keys accessor defaults to the empty array. A series (layer) is generated for each key. Keys are typically strings, but they may be arbitrary values; see InternMap. The series’ key is passed to the value accessor, along with each data point, to compute the point’s value.

*stack*.value(*value*)

Source · If *value* is specified, sets the value accessor to the specified function or number and returns this stack generator.

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

If *value* is not specified, returns the current value accessor.

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

The value accessor defaults to:

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

CAUTION

The default value accessor assumes that the input data is an array of objects exposing named properties with numeric values. This is a “wide” rather than “tidy” representation of data and is no longer recommended. See *stack* for an example using tidy data.

*stack*.order(*order*)

Source · If *order* is specified, sets the order accessor to the specified function or array and returns this stack generator.

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

If *order* is a function, it is passed the generated series array and must return an array of numeric indexes representing the stack order. For example, to use reverse key order:

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

The stack order is computed prior to the offset; thus, the lower value for all points is zero at the time the order is computed. The index attribute for each series is also not set until after the order is computed.

If *order* is not specified, returns the current order accessor.

`stack.order() // d3.stackOrderNone`

The order accessor defaults to stackOrderNone; this uses the order given by the key accessor. See stack orders for the built-in orders.

*stack*.offset(*offset*)

Source · If *offset* is specified, sets the offset accessor to the specified function and returns this stack generator.

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

The offset function is passed the generated series array and the order index array; it is then responsible for updating the lower and upper values in the series array. See the built-in offsets for a reference implementation.

If *offset* is not specified, returns the current offset acccesor.

`stack.offset() // d3.stackOffsetExpand`

The offset accessor defaults to stackOffsetNone; this uses a zero baseline. See stack offsets for the built-in offsets.

## Stack orders

Stack orders are typically not used directly, but are instead passed to *stack*.order.

### stackOrderAppearance(*series*)

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

Source · Returns a series order such that the earliest series (according to the maximum value) is at the bottom.

### stackOrderAscending(*series*)

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

Source · Returns a series order such that the smallest series (according to the sum of values) is at the bottom.

### stackOrderDescending(*series*)

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

Source · Returns a series order such that the largest series (according to the sum of values) is at the bottom.

### stackOrderInsideOut(*series*)

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

Source · Returns a series order such that the earliest series (according to the maximum value) are on the inside and the later series are on the outside. This order is recommended for streamgraphs in conjunction with the wiggle offset. See Stacked Graphs — Geometry & Aesthetics by Byron & Wattenberg for more information.

### stackOrderNone(*series*)

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

Source · Returns the given series order [0, 1, … *n* - 1] where *n* is the number of elements in *series*. Thus, the stack order is given by the key accessor.

### stackOrderReverse(*series*)

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

Source · Returns the reverse of the given series order [*n* - 1, *n* - 2, … 0] where *n* is the number of elements in *series*. Thus, the stack order is given by the reverse of the key accessor.

## Stack offsets

Stack offsets are typically not used directly, but are instead passed to *stack*.offset.

### stackOffsetExpand(*series*, *order*)

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

Source · Applies a zero baseline and normalizes the values for each point such that the topline is always one.

### stackOffsetDiverging(*series*, *order*)

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

Source · Positive values are stacked above zero, negative values are stacked below zero, and zero values are stacked at zero.

### stackOffsetNone(*series*, *order*)

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

Source · Applies a zero baseline.

### stackOffsetSilhouette(*series*, *order*)

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

Source · Shifts the baseline down such that the center of the streamgraph is always at zero.

### stackOffsetWiggle(*series*, *order*)

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

Source · Shifts the baseline so as to minimize the weighted wiggle of layers. This offset is recommended for streamgraphs in conjunction with the inside-out order. See Stacked Graphs — Geometry & Aesthetics by Bryon & Wattenberg for more information.