A problem as hard as a rock face

I am facing the realization of the American GDP graph (this project).

I attach the product code so far.

<!DOCTYPE html>
<html>
  <head>
    <title>American GDP</title>
    <meta charset="UTF-8">
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style>
      #main {
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        align-items: center;
        width: 100vw;
        height: 100vh
      }
      #title {
        font-family: sans-serif;
        font-size: 2em;
        font-weight: bold;
        text-align: center;
        padding-top: .5em;
        padding-bottom: .5em;
        margin-top: .5em;
        margin-bottom: .5em;
        width: 100%;
        background-color: greenyellow;
      }
      #canvas {
        background-color: gold;
      }
      .tick {}
      .bar{}
    </style>
  </head>
  <body>
    <div id="main">
      <div id="title">USA Gross Domestic Product</div>
      <div id="canvas">
      </div>
    </div>

    <script>
      const url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json";

      const req = new XMLHttpRequest();
      req.open("GET", url, true);
      req.send();
      req.onload = function() {
        let jsonData = JSON.parse(req.responseText);
        drawChart(jsonData);
      };
      
      function drawChart(data) {
        let arr = data["data"]; // solo il campo 'data', il resto no

        const parseDate = d3.timeParse("%Y-%m-%d");

        const dataset = arr.map(item => {
          return [
            parseDate(item[0]),
            item[1]
          ]
        })

        const w = 900;
        const h = 550;
        const padding = 50;

        const maxDate = d3.max(dataset, d => d[0]);
        const minDate = d3.min(dataset, d => d[0]);

        const xScale = d3.scaleTime()
          .domain([minDate, maxDate])
          .range([padding, w - padding])
        
        const maxGdp = d3.max(dataset, d => d[1]);
        const minGdp = d3.min(dataset, d => d[1]);

        /*>_>*/console.log('1 ### ', 'maxGdp: ', maxGdp);
        /*>_>*/console.log('2 ### ', 'minGdp: ', minGdp);

        const yScale = d3.scaleLinear()
          .domain([0, maxGdp])
          .range([h - padding, padding])

        /*>_>*/console.log('3 ### ',
          'yScale(50): ', yScale(50),
          '\nyScale(500): ', yScale(500),
          '\nyScale(5000): ', yScale(5000),
          '\nyScale(50000): ', yScale(50000));

        const xAxis = d3.axisBottom(xScale)
        const yAxis = d3.axisLeft(yScale)
  
        const chart = d3.select('#canvas')
          .append('svg')
          .attr('width', w)
          .attr('height', h)

        // const barWidth = ((h - (padding * 2)) / dataset.length) - .30;
        
        chart
          .selectAll('circle')
          .data(dataset)
          .enter()
          .append('circle')
          .attr('class', 'bar')
          .attr('cx', (d) => xScale(d[0]))
          .attr('cy', (d) => (h - padding - yScale(d[1])))
          .attr('r', 2)
          .attr('fill', 'black')
        
        /*
        chart
          .selectAll('rect')
          .data(dataset)
          .enter()
          .append('rect')
          .attr('class', 'bar')
          .attr('x', (d) => xScale(d[0]))
          .attr('y', (d) => (h - padding - yScale(d[1])))
          .attr('height', (d) => yScale(d[1]))
          .attr('width', barWidth)
          .attr('fill', 'black')
        */

        chart.append('g')
          .attr('id', 'x-axis')
          .attr('transform', 'translate(0, ' + (h - padding) + ')')
          .call(xAxis)
        chart.append('g')
          .attr('id', 'y-axis')
          .attr('transform', 'translate(' + padding + ', 0)')
          .call(yAxis)
      }
    </script>
  </body>
</html>

If you run this program on a WEB page you can see that the graph IS FLIPPED. The problem is that the yScale method returns wrong values (I entered a console.log() to see the problem: the higher the input values, the lower the output value, and it should be opposite).
I have tried to modify the code in a thousand ways, but if I can represent the data correctly, then the y-axis is wrong, and vice versa.
I have compared the code with a thousand sources, but it seems to me that my code strictly follows the D3 specification.

Don’t pay attention to the fact that the design is still ‘ugly’ and that the chart uses circles instead of bars, that’s not the problem. The work must be done, but I’m stuck on this problem, and if I don’t fix it, I can’t move on.

Hello there,

This is where I see a problem, because you already should be accounting for the offset (h-padding) in the definition of yScale:

I hope this helps

@Sky020 !!! Many thanks. I cannot understand how I couldn’t see that.

1 Like

Just the way of programming - sometimes it requires a new/second set of eyes :slightly_smiling_face: