D3 Please help me to understand & solve the problem

Hi, I do not get exactly how x or yScale apply. I’m making first project and so far have this code:

d3.json('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json', function (data){
  
  var gdp = data.data.map((i) => i[1]);
  console.log(gdp);
  let year = data.data.map(function (i) {
    let quarter;
    let years = i[0].substring(0,4);
    let temp = i[0].substring(5,7);
   
    if(temp ==='01'){
      quarter = 'Q1'
    }
    else if (temp ==='04'){
      quarter ='Q2'
    }
    else if (temp ==='07'){
      quarter ='Q3'
    }
    else if (temp ==='10'){
      quarter ='Q4'
    }
 
    
  return years + ' ' + quarter;
  });
  
  
  let yearsDate = data.data.map(item => item[0])
  
  let min = d3.min(gdp);
  let max = d3.max(gdp);
  console.log('minimum is: ' + min +' and maximum: ' + max);
  
 
  
  
  let xScale = d3.scaleLinear().domain([0, max]).range([10,1500]);
  let yScale = d3.scaleLinear().domain([min,max]).range([900,0]);
  console.log('scale of Y is: '+ yScale);
  
  let svg = d3.select('main').append('svg').attr('width',1500).attr('height',1000);
  
  svg.selectAll('rect').data(gdp).enter().append('rect').style('height', d=>d+'px').style('width','4px').attr('x',(d,i)=>i*5).attr('y',(d,i)=>1000 - d/20);
  
  
}) 

Looks likes this:


which is more or less accurate. But question is when I change lat line to this:

 svg.selectAll('rect').data(gdp).enter().append('rect').style('height', d=>yScale(d)).style('width','4px').attr('x',(d,i)=>i*5).attr('y',(d)=>1000 - yScale);

Everything got wrong:

Can somebody explain please how yScale works and etc. I’m trying to log, read FCC or official documentation but so far it didn’t click to me.

I appreciate your time and help!

CODEPEN: https://codepen.io/volodymyr-rudov-tsymbalist/pen/ZEYdNNm

Since you set y attribute as .attr('y',(d)=>1000 - yScale) but you need to pass d as yScale() argument i.e. .attr('y',(d)=>1000 - yScale(d)).

It just revert the diagram but the graph is incorrect.

in your yScale variable you set range [900,0] change it to [0,900] i.e :

let yScale = d3.scaleLinear().domain([min,max]).range([0,900]);
1 Like

Thank you, it works! Do you mind explain me please? Because in FCC exercise it was that first argument is top point of the SVG file and second argument is zero.

Is it because of the fact that x,y are 0,0 at the top left corner?

1 Like

the range() function creates a range for given domain .
let you seted the domain to [0,1] and seted the range to [0,10].
so your scale function will be:

var myScale= d3.scaleLinear().domain([0, 1]).range([0,10]);

D3 creates a function myScale which accepts input between 0 and 1 (the domain) and maps it to output between 0 and 10 (the range).

it means it scales [0 ,1] to [0,10].

when you give 0.1 to myScale i.e myScale(0.1) it will returns 1 and for 0.2 it will returns 2 and for 0.3 it will returns 3 and so on.

hope you understand.

1 Like

Currently I’m understanding better as I post one problem and solved it. But have a question.

Right now I use 2 different scales of Y because yAxes need domain(0,max).range(topPoit, 0)

let yAxisScale =d3.scaleLinear().domain([0,max]).range([paddingY, 0])

and bar height and Y needs domain(0,max).range([0,topPoint])

 let yScale = d3.scaleLinear().domain([0,max]).range([0, paddingY]);

which is confusing me. Is it like it should be or I did something wrong?

 let yAxisGroup = svg.append('g').call(yAxis).attr('id','y-axis').attr('transform','translate(60,0)');
 
  
  svg.selectAll('rect').data(gdp).enter().append('rect').style('height', d=>yScale(d)).style('width','2px').attr('x',(d,i)=>(20+i)*3).attr('y',d=>paddingY-yScale(d)).attr('class', 'bar').attr('data-gdp', (d,i)=>{
    return data.data[i][1]
  }).attr('data-date',(d,i)=>{return data.data[i][0]})
  
  

you need change your code if you want to use one scale for both y-axis and bar-height.

  1. since your bar is not showing correctly because of flex and other properties you set to dataholder class. so remove all css you used for dataholder class.
  2. change the range of yScale as follows:
let yScale = d3.scaleLinear().domain([0,max]).range([ paddingY,padding]);
  1. for yAxis use yscale instead of yAxisScale i.e.
  let yAxis = d3.axisLeft(yScale);
  1. for rect change y attribute as follows:
  .attr('y',d=>yScale(d))
  1. for rect change height as follows:
  .style('height', d=>paddingY- yScale(d))
1 Like

Thank you very much! Very good explanation! So basically flex and justify content did all the mess in the svg content?

Didn’t expect that CSS can contribute so drastically to the JS code.