D3 course on FreeCodeCamp Bar chart issue

Hi all,

I am creating a bar chart following the course on FreeCodeCamp and for some reason my bar chart is not displaying on the Web. Although it was appearing with an x-axis issue. When I tried to fix it both are not displaying anymore. I need help to understand what’s wrong with my code? If you look at line chart I created , it works fine.
*Please, be aware that there is a solution provided to pass this project , but I do not want to copy, then it is not in my style. :slight_smile: *

Here is the code:

<body>
        <div class="canvas">
                <!-- Bar  -->
                <div>
                        <div>GDP by Year in Bar chart</div>
                        <svg id="bar_title" width="500" height="400" style="background-color: darkkhaki;">
                                <g id="title" style="transform:translate(50px, 50px)"></g>
                        <g id="x-axis"></g>
                        <g id="y-axis"></g>
                        </svg>
                </div>
                <div>
                        <div>GDP by Year in Line chart</div>
                        <!-- Linear -->
                        <svg id="line_title" width="500" height="400" style="background-color: darkkhaki;">
                                <g id="linear" style="transform:translate(50px, 50px)"></g>
                        </svg>
                </div>
        </div>

<!-- D3 -->
<script  type="javascript">

// Loading data from URL
d3.json("https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json").then(ShowData);

const bar_chart = d3.select("#title");
const bar_title = d3.select("#bar_title");
function BarDraw(data) {
        let w = 400;
        let h = 300;

        data = data.data.map(fn => fn);
        data = data.map(dn => ({
                Date: new Date(dn.DATE),
                GDP: +dn.VALUE
        }));

        let max = d3.max(data, fn => +fn.GDP);
        let iter = data.map(fn => fn.Date);

        let x = d3.scaleBand().domain(iter).range([0, w]).padding(1.3);

        // bar_chart.append("g").attr("id", "x-axis").attr("transform", `translate(0,${h})`).call(d3.axisBottom(x).ticks(10).tickFormat(d3.timeFormat("%Y"))).selectAll("text").attr("transform", "translate(-10,0)rotate(-45)").style("text-anchor", "end");

        let y = d3.scaleLinear().domain([0, max]).range([h, 0]);
        // bar_chart.append("g").attr("id", "y-axis").call(d3.axisLeft(y))

        bar_chart.selectAll("rect")
                .data(data).enter()
                .append("rect")
                .attr("class", "bar")
                .attr("fill", "navy")
                .attr('stroke', "green")
                .attr("x", fn => x(fn.Date))
                .attr("y", fn => y(+fn.GDP))
                .attr("width", x.bandwidth())
                .attr("height", fn => y(+fn.GDP))

        let xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat("%Y"))
        d3.select("#x-axis").attr("transform", `translate(0, ${h})`).call(xAxis)

        let yAxis = d3.axisLeft(y)
        d3.select("#y-axis").call(yAxis)
};


// Line chart the same trouble  
const line_chart = d3.select("#linear");
const title = d3.select("linear_title");
function LineDraw(data) {
        let width = 400;
        let height = 300;

        data = data.data.map(fn => fn);
        let maxVal = d3.max(data, fn => +fn[1]);
        // Alternative
        data = data.map(dn => ({
                Date: new Date(dn[0]),
                GDP: +dn[1]
        }))

        let x = d3.scaleTime().domain(d3.extent(data, fn => fn.Date)).range([0, width]);
        line_chart.append("g").attr("transform", `translate(0, ${height})`).call(d3.axisBottom(x).tickFormat(d3.timeFormat("%Y")));

        let y = d3.scaleLinear().domain([0, maxVal]).range([height, 0])
        line_chart.append("g").call(d3.axisLeft(y));

        line_chart.append("path")
                .datum(data)
                .attr("fill", "none")
                .attr("stroke", "green")
                .attr("d", d3.line()
                        .x(d => x(d.Date))
                        .y(d => y(+d.GDP)))
}

function ShowData(data) {
        LineDraw(data);
        BarDraw(data);
}
</script>
</body>

I appreciate your contribution.

Kind reagrds,
Kanatbek

Create a project for your bar chart on codepen and post the link and it will be much easier for people to debug.

Hi Jeremy,

Thanks for you reply. Indeed, I could come up with it myself before to ask, however, I thought sharing the code would be better. Here is the link to the codepen

Kind regards,

There are several things I would change.

First, you are setting sizes in the svg tags that are larger than the dimensions in the d3 functions to draw graphs and it’s confusing to not have all that together. Secondly, you’re defining some axes in the SVG in the HTML separately from the d3 and they seem to be interfering. Unless there’s good reason (like mixing React and D3), it’s usually simpler to let D3 handle the SVG in its entirety.

As for the problems with the axes, you have working axes and data processing in the line chart. You should start there adapting those for the bar chart. The y-axes will be the same and the x-axes will be very similar. I would consult the documentation for d3.scaleBand() at the D3 github repo to find any differences from the d3.scaleTime() already in use.

Hi Jeremy,

Thanks. It looks like the Bar chart has only 2 columns on the x-axis when you look at the x-axis output. Althout this was the main issue when I drew expected bar chart, but it has disapeared at all while I tried to fix x-axis.
Having browsed documentation or other webpages did not give my any hint or solution to fix issue.
Can you please point me to the trouble I have in the code, except xScale?

Kind regards,

You’re going to have to log the values you are actually using as you draw the visualization.

First, you are processing the data twice (two maps):

  data = data.data.map((fn) => fn);
  let max = d3.max(data, (fn) => +fn[1]);

  data = data.map((dn) => ({
    Date: new Date(dn.DATE),
    GDP: +dn.VALUE
  }));

Second, you have to give a band scale the entire domain (see the examples there), not the ends

  let x = d3
    .scaleBand()
    .domain(
      d3.extent(data, (fn) => {
        return fn.Date;
      })
    )
    .range([0, w]);

like you do here with d3.extent() (this causes the two bar problem).

Finally, as you construct the rectangles for the bars

  bar_chart
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("class", "bar")
    .attr("fill", "navy")
    .attr("stroke", "green")
    .attr("x", (fn) => x(fn.Date))
    .attr("y", (fn) => y(+fn.GDP))
    .attr("width", x.bandwidth())
    .attr("height", y(+fn.GDP));

you should log the values you are using, as in change your x attribute callback to something like

    .attr('x', (d) => {
      console.log(`bar x attr: ${x(d.Date)}`);
      return x(d.date);
    })

and so on with the rest of the attributes (y, width, height) until you can create the visualization. Similarly, you may need to log the values as you process the data and as you set the band scale domain.

Hi Jeremy,

I figured out that second data iteration by defining Date and GDP in bar chart does return undefined. Even though it was charmly returning values like in Line chart - strange.

Can you please look at the code of y-axis? I know there are a lot output that’s why it’s
in disorder and min & max gives me only two column.
The chart is now displaying, but I have to re-work it to add bar columns width.

If the codepen does not display the bar chart, please check this one - replit

Kind regards,

HI,

I finally solved x-axis, but the bar chart is now not working. Can you please look at it?

Kind regards,
Kanatbek

Right now it looks like you have your x and y axes swapped. I looked at your code and you’re not logging the positions you are returning from your functions setting the bar x, y, width, and height, which would be helpful for debugging the position issue.

Indeed, the .attr("y", fn => x(fn[0])) is not returning and it’s undefined although the .data(data) contains fn[0] values.

Now I have the bar colons dispaying in bar chart after editing the code showed below.

.attr("height", x.bandwidth() + 5)
                .attr("y", (fn, i) => {
                        // console.log(h - y(fn[1]))
                        return (h - y(fn[1]))
                })

but the bar colons do not wantto match each year position. Can you help me with it, please?

Kind reagrds,
Kanatbek

Hi,

There are some issues on my bar charts that I could not solve with this dataset. Can you please look at them and tell me what the holy cow is going on there. If you fix the x-axis the bar colons are messing up else x-axis. link

Otherwise I just want to copy the neccassry data from json file and paste it in JS script and done, but it is to easy for me while I want to visualize datasets using APIs or links. I think you get the point.

Kind regards

There’s nothing wrong with the dataset. Right now, your axes are still reversed (x and y are in the wrong places). If you’re having trouble drawing the bars, you should review the lessons on drawing rectangles in the curriculum and then draw a rect at a given position and try to position it where you want it. Then, adapt that for the bars by setting the x, y, height, and width attributes from your data and scales.

Hi,

I haven 't said the data is wrong, but I will fix this bar chart soon. Though line chart works charm with one go.

Thanks for you replies and hints.

Kind regards,
Kanatbek

By the way, I just now saw the sample bar chart provided in the course, and it looks like line chart and barely looks like a bar. In this case I have already createed such bar chart in Horizontal and Vertical and the rest will be added next year :slight_smile:

Thanks for your replies above and have a great christmas and happy new-year.

Kind regards,
Kanatbek

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.