var sales = [ {'Year':2011,'Month':'Jan','Sales':320}, {'Year':2011,'Month':'Feb','Sales':230}, {'Year':2011,'Month':'Mar','Sales':365}, {'Year':2011,'Month':'Apr','Sales':385}, {'Year':2011,'Month':'May','Sales':100}, {'Year':2012,'Month':'Jan','Sales':380}, {'Year':2012,'Month':'Feb','Sales':180}, {'Year':2012,'Month':'Mar','Sales':275}, {'Year':2012,'Month':'Apr','Sales':450}, {'Year':2012,'Month':'May','Sales':410}, {'Year':2013,'Month':'Jan','Sales':320}, {'Year':2013,'Month':'Feb','Sales':170}, {'Year':2013,'Month':'Mar','Sales':375}, {'Year':2013,'Month':'Apr','Sales':510}, {'Year':2013,'Month':'May','Sales':390}, {'Year':2014,'Month':'Jan','Sales':420}, {'Year':2014,'Month':'Feb','Sales':125}, {'Year':2014,'Month':'Mar','Sales':310}, {'Year':2014,'Month':'Apr','Sales':450}, {'Year':2014,'Month':'May','Sales':410}, {'Year':2015,'Month':'Jan','Sales':460}, {'Year':2015,'Month':'Feb','Sales':195}, {'Year':2015,'Month':'Mar','Sales':360}, {'Year':2015,'Month':'Apr','Sales':410}, {'Year':2015,'Month':'May','Sales':385} ]; // group by month, giving our per-month small multiples var groupedByMonth = d3.nest() .key(function(d) { return d.Month }) .entries(sales); // the various series components - setting the same crossValue // and main-value for each is a bit repetitive. var area = fc.seriesSvgArea() .crossValue(function(d, i) { return d.Year; }) .mainValue(function(d, i) { return d.Sales; }); var line = fc.seriesSvgLine() .crossValue(function(d, i) { return d.Year; }) .mainValue(function(d, i) { return d.Sales; }); var point = fc.seriesSvgPoint() .crossValue(function(d, i) { return d.Year; }) .mainValue(function(d, i) { return d.Sales; }); // the average line var average = fc.annotationSvgLine() .value(function(d) { return d; }); // bring all these renderers together into one using the multi-series. The area/point/line // are mapped to the 'values' returned by d3.nest, and the line annotation maps to the average var multi = fc.seriesSvgMulti() .series([area, line, point, average]) .mapping((data, index, series) => { switch (series[index]) { case average: return [d3.mean(data.values.map(function(d) { return d.Sales; }))]; default: return data.values; } }); // compute the extent of the y-values, adding some padding var yExtent = fc.extentLinear() .include([0]) .pad([0, 0.2]) .accessors([function(d) { return d.Sales; }]); // the chart! var chart = fc.chartSvgCartesian( d3.scaleLinear(), d3.scaleLinear() ) .xDomain([2010.5, 2015.5]) .yDomain(yExtent(sales)) .yOrient('left') .xTicks(2) .chartLabel(d => d.key) .plotArea(multi); // data-join to render our small multiples d3.select('#chart') .selectAll('div') .data(groupedByMonth) .enter() .append('div') .call(chart);