Week 4 Visualizing Data

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.

Week 4 Reading Reflection

One everyday thing that drives me crazy is elevators with touch-sensitive buttons instead of physical ones. At first glance, they look sleek, but they are often unresponsive. You tap once, nothing happens, so you tap harder, and suddenly it registers twice which makes it cancel. Sometimes there is no clear feedback whether your press was accepted, especially when the light is dim or there is no sound. In moments of hurry, like trying to catch the elevator before the doors close, that lack of immediate response is frustrating. Norman reminds us that confusion is usually the fault of design, not the user. In this case, the interface lacks both clear mapping, what action triggers what response, and adequate feedback. A simple return to tactile buttons, or at least a haptic or sound cue with instant visual confirmation, would solve most of these issues.

Applying Norman’s principles to interactive media, it is important to always consider feedback and signifiers. In an interactive project, the user should never feel uncertain about whether their action had an effect. For example, if I build a media sketch where users drag an object, the object should move right away with a slight animation or glow to show it is active. If there is a clickable option, it should visibly change on hover or after being pressed. These cues help show users what they can do without needing instructions. In interactive media, even subtle details like sound effects, small motion, or color changes can provide clarity. I believe the best digital designs are the ones where users do not have to stop and think, wait, did that work, but instead feel guided naturally from one step to the next.

Week 3 – Functions, Arrays, and Object Oriented Programming

Sketch

My Concept

For this project, I wanted to create a generative artwork inspired by an Instagram post I saw of a supernova made entirely with math. I was amazed by how something so natural and powerful could be represented through math and wanted to make my own version with code. I used object-oriented programming with classes and arrays to build a layered system: a static star field in the background, a clustered supernova core in the middle, and orbiting particle systems that appear when the mouse is clicked. The ParticleSystem class contains Particles as a sub-class for abstraction. The goal was to make the scene feel cosmic and expansive, with a balance of stillness and motion. The pink and orange hues of the supernova give it warmth and contrast nicely with the dark sky and moving particles.

Post Link

Code Highlight

My favorite part of the code was inside the Particle class. The update method receives origin which are the coordinates of the particles superclass, ParticleSystem. It then increments the the particle’s angle, which was set in the constructor to a random angle, by an also randomized angular velocity between 0.005 and 0.008. After that, I used trigonometry to convert the current angle and radius to x and y coordinates. These 3 lines of code are so simple, yet do very well in creating a smooth orbiting effect with any radius and speed.

// Update the particle's position
 update(origin) {
   // Orbit motion
   this.angle += this.speed;
   // Translate motion on x and y
   this.pos.x = origin.x + cos(this.angle) * this.radius;
   this.pos.y = origin.y + sin(this.angle) * this.radius;
 }

Reflection

Seeing the Instagram supernova showed me how math and code can express phenomena far beyond what we normally imagine drawing. Recreating my own version made me realize the power of classes in producing natural-looking patterns with surprisingly little code. What looks like thousands of unique particles is really the same rules repeated again and again, with variation coming from randomness and simple math. I also found that changing small details (like the radius range of the orbits or the color palette) transforms the entire mood of the scene. For me, this project reinforced how generative art is about designing systems of rules that unfold naturally into complex and beautiful results.

Week 3 Reading Reflection

Reading Chris Crawford’s first chapter on interactivity reshaped how I think about what makes a system truly interactive. At first I believed that something as simple as reacting to an input was enough. For example, when you open a refrigerator and the light turns on, I thought of that as interactivity. Crawford’s model of listening, thinking, and speaking challenged this assumption. He showed that real interactivity is more like a conversation, where input is not only noticed but also processed and answered in a meaningful way. This made me see that many things I used to count as interactive are really just reactive, because they skip the step of thinking.

This idea also helped me reflect on my own coding work. In my self portrait sketch, the eyes follow the mouse and the mouth curves up or down depending on mouseY. At first I was satisfied with these features because they give the impression of interaction, but after reading Crawford I realized that they are closer to one-way responses than to genuine dialogue. The system is listening and speaking, but it is not really thinking about how to respond. That missing step makes the interaction feel mechanical rather than conversational. I started to recognize that stronger interactivity requires the program to interpret or evaluate the input, not just mirror it back in a predictable way.

Looking ahead, I want to design sketches that create a deeper back-and-forth with the user. One improvement would be making more features react to user input. But, instead of only reacting in fixed ways, the program could process input in a way that gives the impression it has some awareness or personality. For example, rather than the mouth always curving in the same manner based on mouse position, the system could shape its response in ways that feel more expressive or varied, like how a person reacts differently in different contexts. This would give the user a sense that their actions are acknowledged in a meaningful way and make the interaction more engaging.

Week 2 Reading Reflection

At first I thought randomness only mattered in games, from simulating rolling a dice to how Minecraft generates new worlds with caves, mountains, and villages that always look different. I assumed randomness was just for variety in play and had little place in art or design. Watching Casey Reas’ talk completely changed that assumption. I was amazed by the art you can generate using randomness. What struck me most was how a set of simple rules, combined with small unpredictable changes, could create results that felt alive and unique. His examples showed me that randomness is not just a tool for unpredictability but also for discovery, allowing new patterns and visuals to emerge that no one could have planned in advance.

 

Before, I believed coding should always be exact, like solving a math problem where the answer must be correct. Reas showed me that art can be structured yet open-ended, where randomness works as a collaborator rather than an obstacle. Seeing grids of dots or lines shift in slightly unexpected ways made me realize that unpredictability is what gives the piece depth and character. I now think the best balance is to set clear boundaries for the work, such as the palette, the number of elements, or the layout, but then leave space for randomness to control movement, position, or interaction. That way the work keeps its structure but also grows in ways no one could have fully imagined. For me, the optimum balance is when structure provides a stable foundation for the art to not look completely random like scribbles, while randomness adds the spark that makes each result surprising and engaging.

Week 2 – Loops

Sketch

My Concept

This week, I wanted to make a simple work of art using for() loops. The piece I made explores how repetition and rhythm can form mesmerizing visual patterns. I started with a simple grid of circles, using nested loops to control the rows and columns as we learned in class. I wanted to make a field of circles that felt alive, so I thought about how I was going to vary their sizes and colors. The sin() function in mathematics is frequently used to model oscillations and waves in nature, so I figured why not map the circles’ diameters to it in some way to shift their sizes in a wavy pattern as they moved across the canvas. As for varying the colors, I made two of the fill() function’s arguments dependent on the coordinates of the circle with each iteration of the loop, while keeping the other arguments constant so the colors don’t contrast too much.

Code Highlight

It was a bit tricky to figure out how exactly I was going to map the sin values to the size of each circle. I ended up defining the variable d as the distance of each circle from the center, and using it as input for sin. Since the range of sin, which is [-1,1], is too small to use as a radius, I used the map() function to to increase its range to [5,15]. Finally, I stored whatever was calculated in the size variable and used that in drawing each ellipse.

let d = dist(x, y, width / 2, height / 2); // distance from center
let size = map(sin(d * 0.05), -1, 1, 5, 15); // wavy circle sizes
ellipse(x, y, size); // draw the circle

This small section controls the shifting “wave” effect, transforming what would otherwise be a flat grid of circles into a dynamic field with depth and rhythm.

Reflection

I was amazed by how powerful loops can be in creating a piece that looks intricate but only requires a few lines of code. My entire draw function fit in 7 lines of code! At first glance, the result seems like something that would take countless steps to draw manually, but by letting the computer repeat instructions, complexity emerges naturally. It taught me to see code not only as instructions for individual shapes but as a way to design systems that generate patterns on their own. Another thing I that was cool is how small changes to the rules, like adjusting the sine function, completely transform the mood of the work.

Using 10 as the coefficient of d

 

Using 0.03 as the coefficient of d

Self Portrait

For this assignment, I wanted to make an interactive self portrait that actually looked like me without overcomplicating it. I began by making the head, hair, neck, ears, and shirt using basic shapes. I wasn’t satisfied with how round the face was, especially at the chin, so I used the beginShape function to create a custom face that was sharper. I used blue and white ellipses for the eyes and a triangle for a simplistic nose. The pupils follow the mouse’s coordinates, but are clamped with the map function so they are forced to stay inside the eye.

Code Highlight

I wanted to make the portrait smile/frown depending on the mouse’s Y coordinate, so I made the mouth’s curve a custom shape that stretches from a predefined vertex to another using the quadraticVertex function. The first and second arguments of the function are the coordinates of the point that will “pull” the curve towards itself, and its Y coordinate depends on the Y coordinate of the mouse.

// Mouth
  stroke(150, 0, 0);
  strokeWeight(5);
  noFill();

  // Fixed corners of the mouth
  let x1 = 170,
    y1 = 285;
  let x2 = 230,
    y2 = 285;

  // Higher mouse = happy 
  // Lower mouse = sad 
  let controlY = map(mouseY, 0, height, 310, 260);

  // Mouth Curve
  beginShape();
  vertex(x1, y1);
  quadraticVertex(200, controlY, x2, y2);
  endShape();

Sketch

Reflection and Ideas

Overall, I’m happy with how the portrait turned out, since it balances simplicity with interactivity. The use of basic shapes combined with custom shapes gave me flexibility while still keeping the code manageable. I especially liked how the mouth animation added a sense of personality and expression to the face. For improvement, I would make the hair more natural by experimenting with arcs, curves, or irregular shapes rather than just rectangles and ellipses. Another possible improvement would be adding subtle shading or color gradients to give the portrait more depth and realism.