My Concept
For this project, I wanted to create a data-driven timelapse showing airports across Europe. Each airport is represented as a circle, and its size corresponds to the number of passengers in a given week. The idea is to make busier airports stand out visually while showing the flow of air traffic over time. I got the idea as I was looking for datasets on Kaggle. The first dataset I found had the Daily flight information on hundreds of European airports from 2016-2022. The problem was that it didn’t contain the coordinates of the airports for me to plot them in p5 as I envisioned. Thankfully, I found a second dataset that contains the coordinates of airports from around the world. I decided to remove all the non-European airports from the second dataset, then cross filter the two datasets by airport code to make a third csv file with all the information I need before using p5.
Code Highlight
Since I wanted to create a third dataset. I needed to clean out any irrelevant, redundant, or incomplete columns, then merge the two csv files. To remove the non European airports from the coordinates file, I used the below C++ program which reduced the number of rows from the original 83,000 to a couple hundred.
while (getline(inputFile, line)) { stringstream ss(line); string ident, lat, lon, continent; getline(ss, ident, ','); getline(ss, lat, ','); getline(ss, lon, ','); getline(ss, continent, ','); continent = trim(continent); cout << continent << endl; if (continent == "EU") { cout << "Found an EU row" << endl; outputFile << line << "\n"; } }
I then wrote this code to only take the airports that appear in both flights.csv and airports.csv, and write then to a third file, which I uploaded to p5
while (std::getline(flightsFile, line)) { std::stringstream ss(line); std::vector<std::string> cols; std::string cell; while (std::getline(ss, cell, ',')) { cols.push_back(trim(cell)); } if (cols.size() < 6) continue; // skip malformed rows std::string icao = cols[3]; // Skip row if airport not found in airportMap auto it = airportMap.find(icao); if (it == airportMap.end()) continue; // Write row with coordinates outFile << cols[0] << "," << cols[1] << "," << cols[2] << "," << cols[3] << "," << cols[4] << "," << cols[5] << "," << it->second.lat << "," << it->second.lon << "\n"; } airportsFile.close(); flightsFile.close(); outFile.close(); std::cout << "Merged CSV with coordinates created successfully.\n"; return 0;
Finally, in p5, I looped through all the airport data and positioned them based on their coordinates mapped to the canvas size. Then I made the sizes of the airports correspond to their traffic using Power of Log Scaling to make the less busy airports extra small and the busy airports extra big so the contrast is clearer.
// Map coordinates and size for (let i = 0; i < airports.length; i++) { airports[i].x = map(airports[i].lng, minLng, maxLng, 50, width - 50); airports[i].y = map(airports[i].lat, minLat, maxLat, height - 50, 50); // Inverted Y because p5 coordinates are top to bottom // Power of log scaling for exaggerated size airports[i].size = map( pow(log(airports[i].passengers + 1), 2), 0, pow(log(maxPassengers + 1), 2), 2, 60 ); }
Sketch
Reflection
I was impressed by how even large datasets can be visualized effectively with only a few lines of code once the mapping is set up. Using loops and data structures allows complexity to emerge naturally. This project reinforced how math and data can drive visual design, and how small adjustments, like using a logarithmic scale instead of linear mapping, can completely change how readable a visualization is.
For future improvements, I would like to make the timelapse smoother, add color coding by country or region, and include tooltips or labels when hovering over airports so users can see exact values. I could also allow filtering by week or year to explore trends more interactively. These enhancements would make the visualization more engaging and informative.