d3fc-series View on GitHub

A collection of components for rendering data series to SVG and canvas, including line, bar, OHLC, candlestick and more.

API Reference

This packages contains a number of D3 components that render various standard series types. They all share a common API, with the typical configuration requiring x and y scales together with a number of value accessors. There are SVG and Canvas versions of each series type, sharing the same configuration properties.

General API

SVG rendering

In order to render a line series to SVG, the data should be supplied via a data-join or datum, as follows:

const data = [
    {x: 0, y: 0},
    {x: 10, y: 5},
    {x: 20, y: 0}
];

const line = fc.seriesSvgLine()
    .crossValue(d => d.x)
    .mainValue(d => d.y)
    .xScale(xScale)
    .yScale(yScale);

d3.select('g')
    .datum(data)
    .call(line);

The line component is configured with the required value accessors and scales. In this case, the supplied data has x and y properties. The value accessors are invoked on each datum within the array, and simply obtain the value for their respective property. The scales are used to convert the values in the domain coordinate system (as returned by the accessors), to the screen coordinate system.

The series is rendered into a group (g) element by first selecting it, using datum to associate the data with this DOM node, then using call to invoke the series component, causing it to be rendered.

Canvas rendering

The seriesCanvasLine component has an API that is almost identical to its SVG counterpart, seriesSvgLine, the only difference is the addition of a context property, which is set to the context of the canvas that this series renders to.

const data = [
    {x: 0, y: 0},
    {x: 10, y: 5},
    {x: 20, y: 0}
];

var ctx = canvas.getContext('2d');

const line = fc.seriesCanvasLine()
    .crossValue(d => d.x)
    .mainValue(d => d.y)
    .xScale(xScale)
    .yScale(yScale)
    .context(ctx);

line(data);

Because D3 data-joins and data-binding only work on HTML / SVG, the canvas components are invoked directly with the supplied data. This causes the component to render itself to the canvas.

Decorate Pattern

The series components implement the decorate pattern by exposing a decorate property which is passed the data join selection, or canvas context, used to render the component. This allows users of the component to perform additional rendering logic.

For further details, consult the Decorate Pattern documentation.

The following example demonstrates how the fill color of each bar can be varied via decoration. The decorate property is passed the data join selection used to construct the component's DOM. Here, the enter selection is used to set the fill color based on the index:

const color = d3.scaleOrdinal(d3.schemeCategory10);

const svgBar = fc.seriesSvgBar()
    .decorate((selection) => {
        selection.enter()
            .style('fill', (_, i) => color(i));
    });

Here is the same example for a canvas bar series; the way that the decorate pattern works is subtly different. For SVG components the decorate function is invoked once with the selection that renders all of the bars (or points, candlesticks, ...), with canvas, the decorate function is invoked for each of the data-points in the series.

The decorate function is passed the context, datum and index. The context is translated to the correct position and the fill color set before invoking the decorate function. After decoration the bar itself is rendered.

const canvasLine = fc.seriesCanvasBar()
    .decorate((context, datum, index) => {
        context.fillStyle = color(index);
    });

Decoration can also be used to add extra elements to the series. In this example a text element is added to each bar via the enter selection.

The origin of each data-point container, which is a g element, is always set to the data-point location. As a result, the text element is translated vertically by -10, in order to position them just above each bar.

const svgBar = fc.seriesSvgBar()
    .decorate((selection) => {
        selection.enter()
            .append('text')
            .style('text-anchor', 'middle')
            .attr('transform', 'translate(0, -10)')
            .attr('fill', 'black')
            .text((d) => d3.format('.2f')(d));
    });

With canvas, you can also perform additional rendering to the canvas in order to achieve the same effect. Once again, the canvas origin has been translated to the origin of each data-point before the decorate function is invoked.

This example uses a point series, for a bit of variety!

const canvasLine = fc.seriesCanvasPoint()
    .decorate((context, datum, index) => {
        context.textAlign = 'center';
        context.fillStyle = '#000';
        context.font = '15px Arial';
        context.fillText(d3.format('.2f')(datum), 0, -10);
        // reset the fill style for the bar rendering
        context.fillStyle = '#999';
    });

Orientation

Most of the series renderers support both horizontal and vertical render orientations as specified by the orient property. In order to make it easy to change the orientation of a series, and to avoid redundant and repeated property names, a change in orientation is achieved by transposing the x and y scales.

The following example shows a simple bar series rendered in its default vertical orientation:

const data = [4, 6, 8, 6, 0, 10];

const xScale = d3.scaleLinear()
    .domain([0, data.length])
    .range([0, width]);

const yScale = d3.scaleLinear()
    .domain([0, 10])
    .range([height, 0]);

const barSeries = fc.seriesSvgBar()
    .xScale(xScale)
    .yScale(yScale)
    .crossValue((_, i) => i)
    .mainValue((d) => d);

d3.select('g')
    .datum(data)
    .call(svgBar);

By setting its orient property to horizontal, the x and y scales are transposed. As a result, the domain for both the x and y scale have to be switched. The following shows the changes required:

const xScale = d3.scaleLinear()
    .domain([0, 10])           // domain changed
    .range([0, width]);

const yScale = d3.scaleLinear()
    .domain([0, data.length])  // domain changed
    .range([height, 0]);

const barSeries = fc.seriesSvgBar()
    .xScale(xScale)
    .yScale(yScale)
    .orient('horizontal')      // orient property updated
    .crossValue((_, i) => i)
    .mainValue((d) => d);

This is part of the motivation behind naming the accessors mainValue and crossValue, rather than an orientation specific xValue / yValue.

Multi series

One series type that is worthy of note is the multi series. This component provides a convenient way to render multiple series, that share scales, to the same SVG or canvas.

The multi series renderers expose a series property which accepts an array of series renderers, together with the standard xScale and yScale properties. The following example shows how a multi series can be used to render both a line and bar series:

// a couple of series - value accessor configuration omitted for clarity
const barSeries = fc.seriesSvgBar();
const lineSeries = fc.seriesSvgLine();

const multiSeries = fc.seriesSvgMulti()
    .xScale(xScale)
    .yScale(yScale)
    .series([barSeries, lineSeries]);

d3.select('g')
    .datum(data)
    .call(svgMulti);

Notice that you do not have to set the xScale and yScale properties on each series - the scale are propagated down from the multi series.

The canvas API is very similar:

// a couple of series - value accessor configuration omitted for clarity
const barSeries = fc.seriesCanvasBar();
const lineSeries = fc.seriesCanvasLine();

const multiSeries = fc.seriesCanvasMulti()
    .xScale(xScale)
    .yScale(yScale)
    .context(ctx)
    .series([barSeries, lineSeries]);

multiSeries(data)

In this case the context is also propagated from the multi series to the children.

The multi series allows you to combine a range of different series types. If instead you have multiple data series that you want to render using the same series type, e.g. a chart containing multiple lines, the repeat series is an easier way to achieve this.

Auto bandwidth

A number of the series (bar, OHLC, boxplot) have a notion of 'width'. They all expose a bandwidth property where you can supply the width as a value (in the screen coordinate system).

Rather than specify a bandwidth directly, you can adapt a series with the fc.autoBandwidth component, which will either obtain the bandwidth directly from the scale, or compute it based on the distribution of data.

When used with a bandScale, the scale is responsible for computing the width of each band. The fc.autoBandwidth component invokes the bandwidth function on the scale and uses the returned value to set the bandwidth on the series.

var xScale = d3.scaleBand()
    .domain(data.map(d => d.x))
    .rangeRound([0, width]);

var svgBar = fc.autoBandwidth(fc.seriesSvgBar())
    .align('left')
    .crossValue(function(d) { return d.x; })
    .mainValue(function(d) { return d.y; });

Notice in the above example that the align property of the bar is set to left, which reflects the band scale coordinate system.

NOTE: The d3 point scale is a special cased band scale that has a zero bandwidth. As a result, if you use the fc.autoBandwidth component in conjunction with a point scale, the series will also have a bandwidth of zero!

When used in conjunction with a linear scale, the fc.autoBandwidth component computes the bar width based on the smallest distance between consecutive datapoints:

var xScale = d3.scaleLinear()
    .domain([0, 10])
    .range([0, width]);

var svgBar = fc.autoBandwidth(fc.seriesSvgBar())
    .crossValue(function(d) { return d.x; })
    .mainValue(function(d) { return d.y; })
    .widthFraction(0.5);

The fc.autoBandwidth component, when adapting a series, adds a widthFraction property which determines the fraction of this distance that is used to set the bandwidth.

When using a multi, or repeat series, the fc.autoBandwidth component should be used to adapt the bar (or OHLC, boxplot, ...) series directly, rather than adapting the multi or repeat series.

var canvasBar = fc.seriesCanvasBar()

var canvasLine = fc.seriesCanvasLine();

var canvasMulti = fc.seriesCanvasMulti()
    .xScale(xScale)
    .yScale(yScale)
    .series([fc.autoBandwidth(canvasBar), canvasLine]);

Line

# fc.seriesSvgLine()
# fc.seriesCanvasLine()

Constructs a new line renderer for either canvas or SVG.

Common properties

# seriesLine.crossValue(accessorFunc)
# seriesLine.mainValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesLine.xScale(scale)
# seriesLine.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesLine.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical.

# seriesLine.curve(scale)

If curve is specified, sets the curve factory and returns this series. If curve is not specified, returns the current curve factory.

This property is rebound from line.curve.

Canvas specific properties

# seriesCanvasLine.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Point

# fc.seriesSvgPoint()
# fc.seriesCanvasPoint()

Constructs a new point series renderer for either canvas or SVG.

Common properties

# seriesPoint.crossValue(accessorFunc)
# seriesPoint.mainValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesPoint.xScale(scale)
# seriesPoint.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesPoint.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical.

# seriesPoint.type(type)

If type is specified, sets the symbol type to the specified function or symbol type and returns this point series renderer. If type is not specified, returns the current symbol type accessor.

This property is rebound from symbol.type.

# seriesPoint.size(size)

If size is specified, sets the area to the specified function or number and returns this point series renderer. If size is not specified, returns the current size accessor.

This property is rebound from symbol.size.

Canvas specific properties

# seriesCanvasPoint.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Area

# fc.seriesSvgArea()
# fc.seriesCanvasArea()

Constructs a new area series renderer for either canvas or SVG.

Common properties

# seriesArea.crossValue(accessorFunc)
# seriesArea.mainValue(accessorFunc) # seriesArea.baseValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesArea.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical.

# seriesArea.xScale(scale)
# seriesArea.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesArea.curve(scale)

If curve is specified, sets the curve factory and returns this series. If curve is not specified, returns the current curve factory.

Canvas specific properties

# seriesCanvasArea.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Bar

# fc.seriesSvgBar()
# fc.seriesCanvasBar()

Constructs a new bar series renderer for either canvas or SVG.

Common properties

# seriesBar.crossValue(accessorFunc)
# seriesBar.mainValue(accessorFunc)
# seriesBar.baseValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesBar.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical.

# seriesBar.xScale(scale)
# seriesBar.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesBar.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

Canvas specific properties

# seriesCanvasArea.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Candlestick

# fc.seriesSvgCandlestick()
# fc.seriesCanvasCandlestick()

Constructs a new candlestick renderer for either canvas or SVG.

# seriesCandlestick.crossValue(accessorFunc)
# seriesCandlestick.highValue(accessorFunc)
# seriesCandlestick.lowValue(accessorFunc)
# seriesCandlestick.openValue(accessorFunc)
# seriesCandlestick.closeValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesCandlestick.xScale(scale)
# seriesCandlestick.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesCandlestick.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# seriesCandlestick.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

OHLC

# fc.seriesSvgOhlc()
# fc.seriesCanvasOhlc()

Constructs a new OHLC renderer for either canvas or SVG.

Common properties

# seriesOhlc.crossValue(accessorFunc)
# seriesOhlc.highValue(accessorFunc)
# seriesOhlc.lowValue(accessorFunc)
# seriesOhlc.openValue(accessorFunc)
# seriesOhlc.closeValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesOhlc.xScale(scale)
# seriesOhlc.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesCandlestick.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# seriesOhlc.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

Canvas specific properties

# seriesCanvasOhlc.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Boxplot

# fc.seriesSvgBoxPlot()
# fc.seriesCanvasBoxPlot()

Constructs a new boxplot renderer for either canvas or SVG.

Common properties

# seriesBoxPlot.crossValue(accessorFunc)
# seriesBoxPlot.medianValue(accessorFunc)
# seriesBoxPlot.upperQuartileValue(accessorFunc)
# seriesBoxPlot.lowerQuartileValue(accessorFunc)
# seriesBoxPlot.highValue(accessorFunc)
# seriesBoxPlot.lowValue(accessorFunc)
# seriesBoxPlot.width(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesBoxPlot.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical

# seriesBoxPlot.xScale(scale)
# seriesBoxPlot.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesBoxPlot.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# seriesBoxPlot.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

Canvas specific properties

# seriesCanvasBoxplot.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Errorbar

# fc.seriesSvgErrorBar()
# fc.seriesCanvasErrorBar()

Constructs a new error bar renderer for either canvas or SVG.

Common properties

# seriesErrorBar.crossValue(accessorFunc)
# seriesErrorBar.highValue(accessorFunc)
# seriesErrorBar.lowValue(accessorFunc)
# seriesErrorBar.width(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesErrorBar.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either horizontal (default) or vertical

# seriesErrorBar.xScale(scale)
# seriesErrorBar.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesErrorBar.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# seriesErrorBar.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

Canvas specific properties

# seriesCanvasErrorBar.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Heatmap

# fc.seriesSvgHeatmap()
# fc.seriesCanvasHeatmap()

Constructs a new heatmap series renderer for either canvas or SVG.

Common properties

# seriesHeatmap.crossValue(accessorFunc)
# seriesHeatmap.highValue(accessorFunc)
# seriesHeatmap.colorValue(accessorFunc)

If accessorFunc is specified, sets the accessor to the specified function and returns this series. If accessorFunc is not specified, returns the current accessor. The accessorFunc(datum, index) function is called on each item of the data, returning the relevant value for the given accessor. The respective scale is applied to the value returned by the accessor before rendering.

# seriesHeatmap.xScale(scale)
# seriesHeatmap.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesHeatmap.colorInterpolate(interpolate)

If colorInterpolate is specified, sets the interpolator used to map color values to colors and returns this series. If colorInterpolate is not specified, returns the current interpolator.

# seriesHeatmap.xBandwidth(bandwidthFunc) # seriesHeatmap.yBandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# seriesHeatmap.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

Canvas specific properties

# seriesCanvasErrorBar.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Multi

# fc.seriesSvgMulti()
# fc.seriesCanvasMulti()

Constructs a new multi series renderer for either canvas or SVG.

Common properties

# seriesMulti.series(seriesArray)

If seriesArray is specified, sets the array of series that this multi series should render and returns this series. If seriesArray is not specified, returns the current array of series.

# seriesMulti.xScale(scale)
# seriesMulti.yScale(scale)

If scale is specified, sets the scale and returns this series. If scale is not specified, returns the current scale.

# seriesMulti.mapping(mappingFunc)

If mappingFunc is specified, sets the mapping function to the specified function, and returns this series. If mappingFunc is not specified, returns the current mapping function.

When rendering the multi-series, the mapping function is invoked once for each of the series supplied via the series property. The purpose of the mapping function is to return the data supplied to each of these series. The default mapping is the identity function, (d) => d, which results in each series being supplied with the same data as the multi-series component.

The mapping function is invoked with the data bound to the multi-series, (data), the index of the current series (index) and the array of series (series). A common pattern for the mapping function is to switch on the series type. For example, a multi-series could be used to render a line series together with an upper bound, indicated by a line annotation. In this case, the following would be a suitable mapping function:

const multi = fc.seriesSvgMulti()
    .series([line, annotation)
    .mapping((data, index, series) => {
      switch(series[index]) {
        case line:
          return data.line;
        case annotation:
          return data.upperBound;
      }
    });

# seriesMulti.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified function, and returns this series. If decorateFunc is not specified, returns the current decorator function.

With the SVG multi series, the decorate function is invoked once, with the data join selection that creates the outer container. With the canvas multi series the decorate function is invoked for each of the associated series.

Canvas specific properties

# seriesMulti.context(ctx)

If ctx is specified, sets the canvas context and returns this series. If ctx is not specified, returns the current context.

Repeat

# fc.seriesSvgRepeat()
# fc.seriesCanvasRepeat()

Constructs a new repeat series renderer for either canvas or SVG.

The repeat series is very similar in function to the multi series, both are designed to render multiple series from the same bound data. The repeat series uses the same series type for each data series, e.g. multiple lines series, or multiple area series.

The repeat series expects the data to be presented as an array of arrays. The following example demonstrates how it can be used to render multiple line series:

const data = [
  [1, 3, 4],
  [4, 5, 6]
];

const line = fc.seriesSvgLine();

const repeatSeries = fc.seriesSvgRepeat()
    .xScale(xScale)
    .yScale(yScale)
    .series(line);

d3.select('g')
    .datum(data)
    .call(repeatSeries);

The repeat series also exposes an orient property which determines the 'orientation' of the series within the bound data. In the above example, setting orient to horizontal would result in the data being rendered as two series of three points (rather than three series of two points).

Common properties

# seriesRepeat.series(series)

If series is specified, sets the series that this repeat series should render and returns this series. If series is not specified, returns the current series.

# seriesRepeat.orient(orientation)

If orientation is specified, sets the orientation and returns this series. If orientation is not specified, returns the current orientation. The orientation value should be either vertical (default) or horizontal.

# seriesRepeat.xScale(scale)
# seriesRepeat.yScale(scale)
# seriesRepeat.decorate(decorateFunc)
# seriesRepeat.context(ctx)

Please refer to the multi series for the documentation of these properties.

Grouped

# fc.seriesSvgGrouped(adaptedSeries)
# fc.seriesCanvasGrouped(adaptedSeries)

Constructs a new grouped series by adapting the given series. This allows the rendering of grouped bars, boxplots and point series etc ...

The grouped series is responsible for applying a suitable offset, along the cross-axis, to create clustered groups of bars (or points etc ...). The grouped series rebinds all of the properties of the adapted series.

The following example shows the construction of a grouped bar series, where the scales and value accessors are configured:

var groupedBar = fc.seriesSvgGrouped(fc.seriesSvgBar())
    .xScale(x)
    .yScale(y)
    .crossValue(d => d[0])
    .mainValue(d => d[1]);

Rendering a grouped series requires a nested array of data, the default format expected by the grouped series expects each object in the array to have a values property with the nested data, however, this can be configured by the values accessor.

[
  {
    "key": "Under 5 Years",
    "values": [
      { "x": "AL", "y": 310 },
      { "x": "AK", "y": 52 },
      { "x": "AZ", "y": 515 }
    ]
  },
  {
    "key": "5 to 13 Years",
    "values": [
      { "x": "AL", "y": 552 },
      { "x": "AK", "y": 85 },
      { "x": "AZ", "y": 828 }
    ]
  }
]

The fc.group component from the d3fc-group package gives an easy way to construct this data from CSV / TSV.

With the data in the correct format, the series is rendered just like the other series types:

container.append('g')
    .datum(series)
    .call(groupedBar);

And the grouped canvas series is rendered as follows:

groupedCanvasBar(series);

Common properties

# grouped.bandwidth(bandwidthFunc)

If bandwidthFunc is specified, sets the bandwidth function and returns this series. If bandwidthFunc is not specified, returns the current bandwidth function.

# grouped.subPadding(padding)

If padding is specified, sets the sub-padding to the specified value which must be in the range [0, 1]. If padding is not specified, returns the current sub-padding. The sub-padding value determines the padding between the bars within each group.

Stacked

There is not an explicit series type for rendering stacked charts, it is a straightforward task to render stacked series with the existing components. This section illustrates this with a few examples.

The following code demonstrates how to render a stacked bar series to an SVG. Note that the axis configuration is omitted for clarity:

var stack = d3.stack()
    .keys(Object.keys(data[0]).filter(k => k !== 'State'));

var series = stack(data);

var color = d3.scaleOrdinal(d3.schemeCategory10);

var barSeries = fc.seriesSvgBar()
    .xScale(x)
    .yScale(y)
    .crossValue(d => d.data.State)
    .mainValue(d => d[1])
    .baseValue(d => d[0])
    .decorate((group, data, index) => {
        group.selectAll('path')
            .attr('fill', color(index));
    })

var join = fc.dataJoin('g', 'series');

join(container, series)
    .call(barSeries);

The d3 stack component is used to stack the data obtained from the d3 CSV parser. The SVG bar series value accessors are configured based on the output of the stack component. Finally a d3fc datajoin is used to render each row of data using the bar series.

With canvas, the code is very similar, with a for each loop used in place of the data join:

var canvasBarSeries = fc.seriesCanvasBar()
    .xScale(x)
    .yScale(y)
    .crossValue(d => d.data.State)
    .mainValue(d => d[1])
    .baseValue(d => d[0])
    .context(ctx);

series.forEach(function(s, i) {
    canvasBarSeries
        .decorate(function(ctx) {
            ctx.fillStyle = color(i);
        })(s);
});

In both cases, the decorate pattern is used to set the color for each bar series.

Found a problem in this page? Submit a fix!