Data visualization with d3.js

I want to create my Data visualization projects on my computer before submitting it on code pen. pls what should i need to add at my HTML heading.

thanks in advance

1 Like

Hello!

Hmm, the easiest would be to include the entire d3 library, like this:

<html>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="myFile.js"></script>
</body>
</html>

Where myFile.js is the file where your data visualization code will be.

thanks @skaparate but is still not working i dont know whether the API call need library that will run it.
take visualizing data with bar chart and tell me how the code should be.

Could you share your code here? Otherwise I can’t know what’s wrong :slight_smile:.

<!DOCTYPE html>
<html>
    <head>
        
    </head>
    <body>
        <h1>InshaAllah it will work</h1>
        <script src="https://d3js.org/d3.v5.min.js"></script>
        <script>
        loadData = ()=> {
            req = new XMLHttpRequest();
            req.open("GET", "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json" , true);
            req.send();
            req.onload= ()=>{
                json = JSON.parse(req.responseText);
                //create measurements
                const margin = 200;
                const width = 1000;
                const height = 600 - margin;
                const maxYScale = d3.max(json.data, (d) => d[1]);
          
                //date formatter
                const formatDate = d3.timeParse("%Y-%m-%d"); //convert from string to date format
                const parseDate = d3.timeFormat("%Y"); //format date to cstring
                    
                //tooltip selection
                const tooltip = d3.select("body")
                  .append("div")
                  .attr("id", "tooltip");
              
                //create svg
                const svg = d3.select("svg");
                const chart = svg.append("g")
                  .attr("transform", `translate(${margin}, ${margin})`);
          
                //title
                chart.append("text")
                  .attr("x", (width / 2))             
                  .attr("y", 0 - (margin / 2))
                  .attr("text-anchor", "middle") 
                  .attr("id", "title")
                  .text(json.source_name);
                
                //y-axis: split charts into 2 equal parts using scaling function
                const yScaleBar = d3.scaleLinear()
                  .range([height, 0]) //length
                  .domain([0, maxYScale]); //content
          
                //create x-axis
                const yAxis = d3.axisLeft(yScaleBar);
          
                //append y-axis
                chart.append("g")
                  .attr("id", "y-axis")
                  .call(yAxis);
          
                 //create x-scale: for enumerating bars bars
                const xScaleBar = d3.scaleBand()
                  .range([0, width]) //length
                  .domain(json.data.map((d)=> d[0])) 
                  .paddingInner(0.2);
                
                //for creating the x-axis
                const xScaleAxis = d3.scaleBand()
                  .range([0, width]) //length
                  .domain(json.data.map((d)=> parseDate(formatDate(d[0])))) 
                  .paddingInner(0.2);
          
                //create x-axis
                //const xAxis = d3.axisBottom(xScaleBar);
                const xAxis = d3.axisBottom(xScaleAxis)
                  .tickValues(xScaleAxis.domain().filter(function(d) { return (d % 5 === 0)}));
              
                //append x-axis
                chart.append("g")
                  .attr(`transform`, `translate(0, ${height})`)
                  .attr("id", "x-axis")
                  .call(xAxis);
          
                //make bars
                chart.selectAll("rect")
                  .data(json.data)
                  .enter()
                  .append("rect")
                  .attr("x", (d) => xScaleBar(d[0]))
                  .attr("y", (d) => yScaleBar(d[1]))
                  .attr("height", (d) => height - yScaleBar(d[1]))
                  .attr("width", xScaleBar.bandwidth())
                  .attr("class", "bar")
                  .attr("data-date", (d) => (d[0]))
                  .attr("data-gdp", (d) => (d[1]))
                  .on("mouseenter", function (d, i) {          
                    tooltip.style("visibility", "visible")
                      .attr("data-date", d[0])
                      .html("Date: " + d[0] + "<br>" + "GDP: " + d[1])
                      .style('left', d3.event.pageX + 10 + 'px')
                      .style('top', d3.event.pageY + 10 + 'px')
                      
                  })
                  .on("mouseleave", function (d, i) {
                    tooltip.style("visibility", "hidden")
                  });
          
               //grid lines
               chart.append('g')
                  .attr('class', 'grid')
                  .call(d3.axisLeft()
                  .scale(yScaleBar)
                  .tickSize(-width, 0, 0)
                  .tickFormat(''))
                  .attr("class", "grid-lines");
              
                //label x axis
                svg.append('text')
                  .attr('x', width / 2 + margin)
                  .attr('y', (height +  margin + 100))
                  .attr('text-anchor', 'middle')
                  .text('Year');
              
               //label y axis
                svg.append('text')
                  .attr('x', -(height / 2) - margin)
                  .attr('y', margin / 5)
                  .attr('transform', 'rotate(-90)')
                  .attr('text-anchor', 'middle')
                  .text('Gross Domestic Product');
             } 
          }
          
          loadData();
          </script>
    </body>
</html>
1 Like

Skimmed the code and I hope this helps:

  1. tooltip is selecting the main body element; I’d suggest making a new element/Div for your main graph container and select it by ID
  2. svg is looking to select a svg element in the DOM (HTML) which I don’t see exists? There is only an H1? … again I’d suggest making a new element/Div for your main graph container and select it by ID
1 Like

Apart from what @pjonp said, the main problem is that you have to append a SVG element to the page, not just select it.

One way to do it would be:

// For brevity I didn't copy all the code

//tooltip selection
          const tooltip = d3
            .select('body')
            .append('div')
            .attr('id', 'tooltip');

          //create svg
          const svg = d3
            .select('body')
            .append('svg')
            .attr('width', width)
            .attr('height', height);
          const chart = svg
            .append('g')
            .attr('transform', `translate(${margin}, ${margin})`);
// Here goes the rest of your code.
1 Like

I made all the changes you said i should make, but still not working. i am thinking may be there is library i need to add at the heading of my HTML. pls if possible you can copy the code and run it on your computer.

thanks

I used your code and changed the lines from my last comment, and it worked (at some degree :stuck_out_tongue:). Here is the working code:

 
<!DOCTYPE html>
<html>
    <head>
        
    </head>
    <body>
        <h1>InshaAllah it will work</h1>
        <script src="https://d3js.org/d3.v5.min.js"></script>
        <script>
        loadData = ()=> {
            req = new XMLHttpRequest();
            req.open("GET", "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json" , true);
            req.send();
            req.onload= ()=>{
                json = JSON.parse(req.responseText);
                //create measurements
                const margin = 200;
                const width = 1000;
                const height = 600 - margin;
                const maxYScale = d3.max(json.data, (d) => d[1]);
          
                //date formatter
                const formatDate = d3.timeParse("%Y-%m-%d"); //convert from string to date format
                const parseDate = d3.timeFormat("%Y"); //format date to cstring
                    
               //tooltip selection
          const tooltip = d3
            .select('body')
            .append('div')
            .attr('id', 'tooltip');

          //create svg
          const svg = d3
            .select('body')
            .append('svg')
            .attr('width', width)
            .attr('height', height);
          const chart = svg
            .append('g')
            .attr('transform', `translate(${margin}, ${margin})`);
          
                //title
                chart.append("text")
                  .attr("x", (width / 2))             
                  .attr("y", 0 - (margin / 2))
                  .attr("text-anchor", "middle") 
                  .attr("id", "title")
                  .text(json.source_name);
                
                //y-axis: split charts into 2 equal parts using scaling function
                const yScaleBar = d3.scaleLinear()
                  .range([height, 0]) //length
                  .domain([0, maxYScale]); //content
          
                //create x-axis
                const yAxis = d3.axisLeft(yScaleBar);
          
                //append y-axis
                chart.append("g")
                  .attr("id", "y-axis")
                  .call(yAxis);
          
                 //create x-scale: for enumerating bars bars
                const xScaleBar = d3.scaleBand()
                  .range([0, width]) //length
                  .domain(json.data.map((d)=> d[0])) 
                  .paddingInner(0.2);
                
                //for creating the x-axis
                const xScaleAxis = d3.scaleBand()
                  .range([0, width]) //length
                  .domain(json.data.map((d)=> parseDate(formatDate(d[0])))) 
                  .paddingInner(0.2);
          
                //create x-axis
                //const xAxis = d3.axisBottom(xScaleBar);
                const xAxis = d3.axisBottom(xScaleAxis)
                  .tickValues(xScaleAxis.domain().filter(function(d) { return (d % 5 === 0)}));
              
                //append x-axis
                chart.append("g")
                  .attr(`transform`, `translate(0, ${height})`)
                  .attr("id", "x-axis")
                  .call(xAxis);
          
                //make bars
                chart.selectAll("rect")
                  .data(json.data)
                  .enter()
                  .append("rect")
                  .attr("x", (d) => xScaleBar(d[0]))
                  .attr("y", (d) => yScaleBar(d[1]))
                  .attr("height", (d) => height - yScaleBar(d[1]))
                  .attr("width", xScaleBar.bandwidth())
                  .attr("class", "bar")
                  .attr("data-date", (d) => (d[0]))
                  .attr("data-gdp", (d) => (d[1]))
                  .on("mouseenter", function (d, i) {          
                    tooltip.style("visibility", "visible")
                      .attr("data-date", d[0])
                      .html("Date: " + d[0] + "<br>" + "GDP: " + d[1])
                      .style('left', d3.event.pageX + 10 + 'px')
                      .style('top', d3.event.pageY + 10 + 'px')
                      
                  })
                  .on("mouseleave", function (d, i) {
                    tooltip.style("visibility", "hidden")
                  });
          
               //grid lines
               chart.append('g')
                  .attr('class', 'grid')
                  .call(d3.axisLeft()
                  .scale(yScaleBar)
                  .tickSize(-width, 0, 0)
                  .tickFormat(''))
                  .attr("class", "grid-lines");
              
                //label x axis
                svg.append('text')
                  .attr('x', width / 2 + margin)
                  .attr('y', (height +  margin + 100))
                  .attr('text-anchor', 'middle')
                  .text('Year');
              
               //label y axis
                svg.append('text')
                  .attr('x', -(height / 2) - margin)
                  .attr('y', margin / 5)
                  .attr('transform', 'rotate(-90)')
                  .attr('text-anchor', 'middle')
                  .text('Gross Domestic Product');
             } 
          }
          
          loadData();
          </script>
    </body>
</html>

And here is a picture of the project working (not entirely, of course, since that’s what you have to learn):

1 Like

thank you so much @skaparate the code is now working. I will be very happy if i will have you as a mentor cux i am learning alone and that is sometimes making me to lost confidence in programming as a young boy from Africa, Nigeria.

I’ve never been a mentor, but I can try :stuck_out_tongue:. That said, I must recognize that D3 is not something I have experience with (other than the FCC curriculum).

thanks alot. my future ambition is to be a full stack web developer.

so pls help me with your contact apart from that of freecodecamp