javascriptd3.jslinechartarea-chart

Line - area chart not showing


I am working with line-area chart using d3. But somehow the chart is not showing and there's no error in the console. I'm unable to figure out the issue. It will be helpful if anyone can help me with that.

I've added the entire code in Codepen. This is the link

Here's the sample code for ref:

const svg = d3.select("#chart")
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', `translate(${margin.left}, ${margin.top})`);
    svg.append('defs');
    svg.call(createGradient);
    svg.call(createGlowFilter);

    const xScale = d3.scaleTime()
        .domain([
            d3.min(parsedData, d => d3.min(d.values, v => v.x)),
            d3.max(parsedData, d => d3.max(d.values, v => v.x))
        ])
        .range([0, width]);

    const yScale = d3.scaleLinear()
        .domain([
            d3.min(parsedData, d => d3.min(d.values, v => v.y)),
            d3.max(parsedData, d => d3.max(d.values, v => v.y))
        ])
        .range([height, 0]);

    const line = d3.line()
        .x(d => xScale(d.x))
        .y(d => yScale(d.y))
        .curve(d3.curveCatmullRom.alpha());

    svg.selectAll('.line')
        .data(parsedData)
        .enter()
        .append('path')
        .attr('d', (d) => {
            const lineValues = line(d.values).slice(1);
            const splitedValues = lineValues.split(',');
            return `M0,${height},${lineValues},l0,${height - splitedValues[splitedValues.length - 1]}`
        })
        .style('fill', 'url(#gradient)')

    svg.selectAll('.line')
        .data(parsedData)
        .enter()
        .append('path')
        .attr('d', d => line(d.values))
        .attr('stroke-width', '2')
        .style('fill', 'none')
        .style('filter', 'url(#glow)')
        .attr('stroke', '#e4647f');

Thanks in advance!


Solution

  • I've created a fork of your code that has the line and area showing.

    Here are the major changes.

    First, I parsed the strings into dates:

    const parseTime = d3.timeParse("%b %Y");
    const parsedData = bar_chart_data.map(val => ({
      close: val.y,
      date: parseTime(val.x)
    }));
    

    parsedData is now an array of objects, so we can update the scales accordingly:

    const xScale = d3.scaleTime()
        // extent returns an array containing the min and max
        .domain(d3.extent(parsedData, d => d.date))
        .range([0, width]);
    
    const yScale = d3.scaleLinear()
        .domain([0, d3.max(parsedData, d => d.close)])
        .range([height, 0]);
    

    Next, I switched d3.line() to d3.area(), since you want to draw an area underneath the line. This will save you from having to manually construct the "d" attribute for the area.

    const area = d3.area()
        .x(d => xScale(d.date))
        .y1(d => yScale(d.close)) // top line
        .y0(yScale(0)) // base line, always at 0
        .curve(d3.curveCatmullRom.alpha(0.5));
    

    For drawing the line and area, we do not need to do a data join, we can just use append() and pass the parsedData array to the area generator for the area and to area.lineY1() for the top line:

    svg.append("path")
        .attr("d", area(parsedData))
        .style("fill", "url(#gradient)");
    
    svg.append("path")
        .attr("d", area.lineY1()(parsedData))
        .attr("stroke-width", "2")
        .style("fill", "none")
        .style("filter", "url(#glow)")
        .attr("stroke", "#e4647f");