D3 js - need an advice

Hi everyone,

Before to post my question, I have tried to get a hint for my question from the tutors, but for some reason I have not heard anything from them. Therefore I posting my question here only to get a hint or advice on what I am doing wrong that I barely see it. Hope someone assisst me with.
The issue that I cannot figure out is the data I loaded does not return any value and it is undefined which means that the code cannot return the required columns and it is not stored properly. Hence I need to change to code at all, but there is the problem that it should be so written without any changes only addind the codelines in ToDo.
Here is the code full code

 <html>
  <head>

    <style>
      body {
        font-family: Helvetica, Arial, sans-serif;
      }
      h1 {
        background-color: #2a5599;
        color: white;
        padding: 5px;
      }
      #AirlinesChart,
      #Map {
        border: 1px black solid;
        width: 40em;
        padding: 15px;
      }
      .mainView {
        display: flex;
      }
    </style>
    
    <script src="d3.js"></script>
    
  </head>

  <body>
    <h1>Airlines Routes</h1>
    <div class="mainView">
      <div>
        <h2>Airlines</h2>
        <svg id="AirlinesChart"></svg>
      </div>
      <div>
        <h2>Airports</h2>
        <svg id="Map"></svg>
      </div>
    </div>
 </body>
  <script>
    let store = {};

    function loadData() {
      let promise = d3.csv("routes.csv")   //TODO 1: Add the code to load the CSV file named "routes.csv" | 1 Line
      return promise.then((routes) => {
        store.routes = routes;             //TODO 2: Save the routes into our store variable;
        return store;
      })
    }

    function groupByAirline(data) {
      let result = data.reduce((result, d) => {
        let currentData = result[d.AirlineID] || {
          "AirlineID" : d.AirlineID,
          "AirlineName" : d.AirlineName,
          "Count" : 0
        };

        currentData.Count += 1;                   //TODO: Increment the count (number of routes) of ariline.
        result[d.AirlineID] = currentData;        //TODO: Save the updated information in the dictionary using the airline id as key.
        
        // Alternative 
        // currentData.Count += 1;                            //TODO: Increment the count (number of routes) of ariline.
        // result[d.AirlineID] = currentData["Count"];        //TODO: Save the updated information in the dictionary using the airline id as key.

        return result;
      }, {})
      result = Object.keys(result).map((key) => result[key]);
      result = result.sort( (plus, minus) => minus.Count - plus.Count);      //TODO: Sort the data in descending order of count.
    }

    function ShowData() {
    //Get the routes from our store variable
      let routes = store.routes;                                // this line could be skipped, but it is added in by tutors 
    // Compute the number of routes per airline.
      let airlines = groupByAirline(store.routes);
      console.log(airlines);
    }
    loadData().then(ShowData);
  </script>
</html>

Please, I only need a hint or your advice pointing to where the code is wrong.

Thanks in advance.

Kind regards,
Kanatbek

What does the csv file data look like?

Hi Randel,

Here is the link to the csv file. https://d3c33hcgiwev3.cloudfront.net/KOpRGHarEeiMwApe4i-fLg_2921db5076ab11e8bfdcf38107d6b501_routes.csv?Expires=1668556800&Signature=CiUY44FhS3GofK~JN5T0DUAxLj5Q5V3UnKHaJt0f7xCLifbp2iAitG199sal8jI9m-g10FRYboWeQSIAWBPbNrIDn4eEAg5I3Kfgzdsp1nJrizNGg0qKKDJsZcQFTwcleS1VOOB30wuYw3FifzGKDEDNT5Kr3nHykzpsAg8j0pQ_&Key-Pair-Id=APKAJLTNE6QMUY6HBC5A

When you attempt to return a promise, you will get undefined because the data has not finished loading. One way to deal with this is to make the loadData function async and then use await on the call to d3.csv().

async function loadData() {
   store.routes = await d3.csv(routes.csv);
}

FYI - since you made store a global variable, you do not need to return it in the function.

You could easily get rid of the global variable, by making loadData return store as an object you create inside of it and then add a store parameter to your showData function.

async function loadData() {
  const store = {};
  store.routes = await d3.csv("routes.csv");
  return store;
}

.
.
.

function ShowData(store) {
  //Get the routes from our store variable
  let routes = store.routes;
  // console.log(routes)// this line could be skipped, but it is added in by tutors
  // Compute the number of routes per airline.
  let airlines = groupByAirline(store.routes);
  console.log(airlines);
}

It means the code itself correct I only need to add async and await in loadData() function, have I grasped it correctly? :slight_smile:
On other side, if the store dictionary defined inside the loadData() function, not as global variable, I think I would not be able to call it outside of it, then it is storing all the values of the csv as function.
However, I have tried async and await to see if there is difference, but not the same issue - undefined. I am still wondering, what might be the cause for that.
I can read the csv file with loadData() function and aggregate it. But the rest code is failing giving an empty output. Even though I might have added everything correctly in commented ToDo tasks.

I would need to see the latest version of your code to help.

In this case the D3js V5, on Win10, browser Brave, the full version of the code is that I posted only to get the stored dictionary according to this code, as mentioned I am not allowed to change it except adding the code in ToDo task .

So the code started with the global variable store being assigned an empty object or did you add that?

It was assigned in the code. Not mine

You are saying the following function was already given to you and you did not write any of it?

    function loadData() {
      let promise = d3.csv("routes.csv")   //TODO 1: Add the code to load the CSV file named "routes.csv" | 1 Line
      return promise.then((routes) => {
        store.routes = routes;             //TODO 2: Save the routes into our store variable;
        return store;
      })
    }

Did you write the groupByAirline function? It does not return value, so when let airlines = groupByAirline(store.routes) executes, the value undefined will be assigned to airlines.

Two lines I added in d3.csv() and routes and in groupByAirlines() functions was also added currentData.Count += 1; and result[d.AirlineID] = currentData;

Well, unless you return the applicable value from groupByAirline, your console.log(airlines) will continue to display undefined.

Indeed, that’s what I cannot figure out in the code. I am wondering whether the last codes are currentData.Count += 1; and result[d.AirlineID] = currentData; correct or should it be differently?

That depends. What should the value of the variable result be created by the reduce method in the groupByAirline function?

The function will return a list of objects, where each object represents one airline and contains the following fields:

  • AirlineID: The id of the airline
  • AirlineName: The name of the airline
  • Count: The number of routes the given airline has.

Like I said before, your function currently returns the value undefined. Do you understand why?

Yes, the data I require by this function does not exist. Do you mean the problem lies on loadData() function?

The problem, is you are not explicitly returning a value in the groupByAirline function. If a function does not explicitly return a value, then the value undefined is returned by default.

Ok, I got the point. As I mentioned above in the post, the code is provided to add missing codelines in ToDo tasks that are commented out. I would like to understand which codeline is exactly an issue so that I rework it.

It is not an existing line of code that is the issue. It is that you are missing a line of code in the groupByAirline function. You need a return statement that returns result.

Honestly, the tutorial code is very poorly written in my opinion. I also think you need to learn some more Basic JavaScript with regards to how functions work.