skip to Main Content

I’m creating a 3-line chart using D3v7 but only 1 is showed. I’m unable to figure out why.

This is my dataset:

enter image description here

Current output:
enter image description here

Check out my code below:
// Setup SVG

var svg = d3.select("body").append("svg")
    .attr("width", width + paddingLeft + paddingRight)
    .attr("height", height + paddingTop + paddingBottom)
    .append("g")
    .attr("transform",
          "translate(" + paddingLeft + "," + paddingTop + ")");

// Setup scales

var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var colourScale = d3.scaleOrdinal(d3.schemeCategory10);

//Line generator

var line = d3.line()
    .x(function(d) {return x(d.monthyear); 
    })
    .y(function(d) { return y(d.total); });

// Load data

d3.csv('adidas_west_sales.csv').then(buildLineChart);

var parseTime = d3.timeParse("%Y-%m");

function buildLineChart(data)
{
    data.forEach(function(d)
    {
        d.MonthYear = parseTime(d.MonthYear);
    })

    var salesMethods = data.columns.slice(1).map(function(method)
    {   
        return {    method: method,
                    values: data.map(function(d) {
                        return {    monthyear: d.MonthYear,
                                    total: parseFloat(d[method])
                                }
                            }
                )}       
    });
    console.log(salesMethods);

    // Setup scales with data
    x.domain(d3.extent(data, function(d) {
        return d.MonthYear;}));

    y.domain([
        d3.min(salesMethods, function(b) {
            return d3.min(b.values, function(d) {
                return d.total;
            });
        }),
        d3.max(salesMethods, function(b) {
            return d3.max(b.values, function(d) {
                return d.total;
            });
        })
    ]);
    
    colourScale.domain(salesMethods.map(function(c) { return c.method}))
// Add Axis
svg.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x)
    .ticks(24)
    .tickFormat(d3.timeFormat("%b-%Y")))
    .selectAll("text")  
    .style("text-anchor", "end")
    .attr("dx", "-.8em")
    .attr("dy", ".15em")
    .attr("transform", "rotate(-65)");;

svg.append("g")
    .attr("class", "axis axis--y")
    .call(d3.axisLeft(y))
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", "0.71em")
    .attr("fill", "#000")
    .text("Total Sale, $");

// Add lines


 const lineGraph =
    svg.selectAll("path")
          .data(salesMethods)
          .enter()
              .append("path")
              .attr('stroke', function(d, i) { return colourScale(i)})
              .attr('stroke-width', 1.25)
              .style("fill", "none")
              .attr("d", function(d) { return line(d.values); });
       

}

salesMethods returns 3 values: "Online", "Instore", "Outlet" but there is only 1 line showed.
Is there something missing? Any help would be greatly appreciated!

2

Answers


  1. This code snippet may resolve your problem.

    // Sample data
        const data = [
            { monthYear: "2020-01", Instore: 5280000, Online: 143033, Outlet: 5525602 },
            { monthYear: "2020-02", Instore: 6588750, Online: 250233, Outlet: 3131293 },
            { monthYear: "2020-03", Instore: 7013750, Online: 181349, Outlet: 121259 },
            { monthYear: "2020-04", Instore: 9786250, Online: 251204, Outlet: 4461817 },
            { monthYear: "2020-05", Instore: 9032500, Online: 226795, Outlet: 4461817 },
            { monthYear: "2020-06", Instore: 8606250, Online: 223569, Outlet: 4461817 },
            { monthYear: "2020-07", Instore: 12758750, Online: 326500, Outlet: 4461817 },
            { monthYear: "2020-08", Instore: 3923750, Online: 94926, Outlet: 4461817 },
            { monthYear: "2020-11", Instore: 5280000, Online: 102780, Outlet: 4027729 },
            { monthYear: "2020-12", Instore: 5280000, Online: 117064, Outlet: 4461817 },
            { monthYear: "2021-01", Instore: 2300000, Online: 3454747, Outlet: 18660281 },
            { monthYear: "2021-02", Instore: 2573750, Online: 2974546, Outlet: 10743427 },
            { monthYear: "2021-03", Instore: 2851500, Online: 3283899, Outlet: 6204093 },
            { monthYear: "2021-04", Instore: 2795000, Online: 3608105, Outlet: 10785614 },
            { monthYear: "2021-05", Instore: 3563250, Online: 4503178, Outlet: 15244834 },
            { monthYear: "2021-06", Instore: 5426250, Online: 5837664, Outlet: 4712980 },
            { monthYear: "2021-07", Instore: 6420000, Online: 6422120, Outlet: 4985756 },
            { monthYear: "2021-08", Instore: 5280000, Online: 6369496, Outlet: 4260082 },
            { monthYear: "2021-09", Instore: 3145000, Online: 5210276, Outlet: 2950776 },
            { monthYear: "2021-10", Instore: 3471250, Online: 3986226, Outlet: 2442733 },
            { monthYear: "2021-11", Instore: 4271750, Online: 5183515, Outlet: 3509722 },
            { monthYear: "2021-12", Instore: 5576250, Online: 6302376, Outlet: 3737583 }
        ];
    
        // Chart dimensions
        const width = 800;
        const height = 500;
        const margin = { top: 20, right: 20, bottom: 50, left: 100 };
    
        // Create SVG
        const svg = d3.select("#chart")
            .append("svg")
            .attr("width", width)
            .attr("height", height);
    
        // Scales
        const parseTime = d3.timeParse("%Y-%m");
        const xScale = d3.scaleTime()
            .domain(d3.extent(data, d => parseTime(d.monthYear)))
            .range([margin.left, width - margin.right]);
    
        const yScale = d3.scaleLinear()
            .domain([0, d3.max(data, d => d3.max([d.Instore, d.Online, d.Outlet]))])
            .range([height - margin.bottom, margin.top]);
    
        // Line generator
        const line = d3.line()
            .x(d => xScale(parseTime(d.monthYear)))
            .y(d => yScale(d.value));
    
        // Colors
        const colors = d3.scaleOrdinal()
            .domain(["Instore", "Online", "Outlet"])
            .range(["blue", "green", "red"]);
    
        // Draw lines
        ["Instore", "Online", "Outlet"].forEach(type => {
            svg.append("path")
                .datum(data)
                .attr("fill", "none")
                .attr("stroke", colors(type))
                .attr("stroke-width", 2)
                .attr("d", d3.line()
                    .x(d => xScale(parseTime(d.monthYear)))
                    .y(d => yScale(d[type]))
                );
        });
    
        // Axes
        svg.append("g")
            .attr("transform", `translate(${margin.left},0)`)
            .call(d3.axisLeft(yScale));
    
        svg.append("g")
            .attr("transform", `translate(0,${height - margin.bottom})`)
            .call(d3.axisBottom(xScale).tickFormat(d3.timeFormat("%Y-%m")));
     #chart {
                width: 800px;
                height: 500px;
            }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
    <div id="chart"></div>
    Login or Signup to reply.
  2. Your data is essentially an array of arrays. When you get to adding your lines you need to have an outer data-bind so that d3 iterates over the outer array:

    const lineGraph = svg
      .selectAll('.line')
      .data(salesMethods)
      .enter()
      .append('g') //<-- create a `g` for each outer-array
      .attr('class', 'line') 
      .append('path') //<-- then add the path
      .attr('stroke', function (d, i) {
        return colourScale(i);
      })
      .attr('stroke-width', 1.25)
      .style('fill', 'none')
      .attr('d', function (d, i) {
        return line(d.values);
      });
    

    Running code here.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search