What is the best way to create small multiples in d3.js v6?

I am trying to create small multiple bar charts that have different y-axis scales using d3 v6. There are a few examples out there (https://flowingdata.com/2014/10/15/linked-small-multiples/) of small multiples for previous versions of d3, but not v6, which seems to have a good number of changes implemented.

I don’t have much experience with d3, so I am probably missing something obvious, but I can’t get the bars to properly generate, the axes are generating (though I think I am generating them too many times on top of each other).

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Small multiple bar charts</title>    
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
    <div id='vis'></div>
    <script type="text/javascript">
    
    // Set the sizing metrics
    var width = 150;
    var height = 120;
    var margin = {top: 15, right: 10, bottom: 40, left: 35};

    // Create the axes
    var xScale = d3.scaleBand()
                    .range([0, width])
                    .padding(0.1);
                
    var yScale = d3.scaleLinear()
                    .range([height, 0]);

    var xAxis = d3.axisBottom()
                    .scale(xScale);

    // Load the data
    d3.csv('data.csv').then(function(data) {
        data.forEach(function(d) {
            d.segment = d.segment;
            d.parameter = d.parameter;
            d.the_value = +d.the_value;
        });
        
        // set the x domain
        xScale.domain(data.map(function(d) { return d.segment; }));

        // group the data
        metrics = Array.from(
            d3.group(data, d => d.parameter), ([key, value]) => ({key, value})
        );

        // create a separate SVG object for each group
        var svg = d3.select('#vis').selectAll('svg')
                    .data(metrics)
                    .enter()
                    .append('svg');

        // loop over the data and create the bars
        metrics.forEach(function(d, i) {
            console.log(d);
            console.log(metrics);
            yScale.domain([0, d3.max(metrics, function(c) { return c.the_value; })]);

            svg.selectAll('.bar')
                .data(d)
                .enter().append('rect')
                .attr('class', 'bar')
                .attr('x', function(c) { return xScale(c.segment); })
                .attr('width', xScale.bandwidth())
                .attr('y', function(c) { return yScale(c.the_value); })
                .attr('height', function(c) { return height - yScale(c.the_value); })
                .attr('fill', 'teal');

            svg.append('g')
                .attr('transform', 'translate(0,' + height + ')')
                .call(xAxis)
        });
    });
    </script>
</body>
</html>

Here is the data file:

segment,parameter,the_value
A,one,33
A,two,537723
A,three,14
A,four,5
A,five,0.093430759
B,one,76
B,two,137110
B,three,16
B,four,20
B,five,0.893868331
C,one,74
C,two,62020
C,three,25
C,four,14
C,five,0.862952872

Eventually I would also like to get the charts linked so that when series A is hovered on the first graph the value will display for each series on all of the graphs, but the first step is to get the visuals properly working.

9 thoughts on “What is the best way to create small multiples in d3.js v6?”

Leave a Comment