Week 4: Data Visualization of the Paris 2024 Olympic Medals

SHORT DESCRIPTION: 

Our assignment for the fourth week is data visualization along with typography.  The data I chosen for this assignment is taken from the popular database website Kaggle. To visualize the data, I used a collection of different sized circles that was determined by the number of medals each of the 91 countries had won.

INITAL APPOACH 

Initially, I had a lot of trouble finding the data that I wanted to use for my assignment because the dataset wasn’t organize, lacked information, or was too complex to be used. In addition, I also didn’t know what I wanted to do, so I felt super unconfident and uncreative in my work. I had an early approach to display the decomposition of RGB values of a randomly chosen color, but the end product left me extremely unexcited and disappointed. Below was my first attempt for the data visualization of color.

First Sketch of Data Visualization: Click the screen to change colors

Through the frustration of this project, I decided to give data searching another chance and decided to use Kaggle since I was a familiar with the site and could filter through different categorizes of datasets. Eventually I ended up finding the Paris Olympic medal dataset and was interested in the breakdown and ranking of the countries that participated.

CODING PROCESS

To not let my RGB project go to waste, I decided to incorporate my main goals and what I learned from the RGB project into the visualization for the distribution of Olympic medals: generating a random color, changing the canvas when the mouse is clicked and having text on screen.

function getRandomColorAndRatio(){
  colorRatio = [random(0,255), random(0,255), random(0,255)];
  updateCircleColor();
}

function updateCircleColor(){
  circleColor = color(colorRatio[0], colorRatio[1], colorRatio[2]); 
}

function mousePressed() {
  getRandomColorAndRatio();
}

Also to note, I decided to remove the draw() function in my code because the name was deceptive to me, and I didn’t need my screen to constant refresh, so it was easier to declare my own function and call them in setup().

THE HARDSHIPS

Honestly, the hardest part this week was overcoming the uncreative block and finding a dataset I was interested to work with. For my code, I didn’t have too much trouble importing the data or implementing my idea because I already had a basis of what I wanted my project to look like and the interactive feature to because of my initial approach. I did have trouble figuring out the math to corelated the sizes of the circles with the number of medals awarded because I dumbly decided to work on the whole dataset instead of the first ten. So my future advice for people, is to work within a small range of your data first before implementing the code across the entire dataset. Otherwise, you’ll find that rank 84 in the world has the biggest circle and rank 1 has the smallest circle because you didn’t check your math.

Math for Circle Sizes
// circles are has a scale factor of 10% based on the ratio of a countries medals awarded with the total medals awarded in relation to the width 
  let size = 10 * (countryTotal/ totalMedalsAwarded); 
  let circleArea = (width) * size

THE UPSIDES

For my final product, I ended up with two concepts of my dataset. The first version is sort of a generative art that will randomly place the circles of the countries’ medal with a random color somewhere on the screen. Though, it sounds chaotic, I feel the circular shapes and (if lucky) the pastel color gives a bubbly and warm feeling to the viewer. It was also here that I noticed my mistake where rank 84 was much larger than the top ten because I had labeled each circle and didn’t see any of the top 10 countries listed. Through in the end, in the code I commented out the countries’ names and rank because I felt it added too much noise and unnecessary complexity into the composition.

Data Visualization 1: Click to change composition

For my second concept, I decided to have a structed data visualization. To do so, I simply implemented a double for-loop to create a 10 by 10 matrix and map each of the circle centers to their respective coordinates. Once the circles were maps, I uncommented the text label for the countries’ rank and medals, and I feel like it tired the project together. However, sometimes the randomization of the colors may cause the label, and sometimes the circle, to blend into the background and making it invisible. I think for future plans, it would be nice to figure out a solution to keep randomization but not have it blend with the background.

For-loop Code and If-Else Statement to check if there are still data to be processed
// organize the datas in a set 10 x 10 coordinate fashion 
function xyPos(){
  for (let yPos = 120; yPos < height; yPos+= 120){
    for (let xPos = 120; xPos < width; xPos += 120){
      // there will be extra spaces in the end so it is necessary to always check that there are still rows/ data left in the file to be processed
      if (fileRow < strings.length){
        lineFile = split(strings[fileRow], ",")
        runFile(xPos, yPos, lineFile);
        fileRow += 1
      }
    }
  }
}

I had to increase the canvas size to 1200 x 1200 in order for the labels to not overlap with each other, so here is the link to project, for anyone wanting to see the code.

Data Visualization 2: Visualizations of the number of medals award to each 91 participating countries

FINAL REMARKS 

While time consuming, compared to my first project, I am extremely happy with my final result. I really liked processing the data and understanding which of the data was useful to me and would be the most impactful to the viewer. I had also learned that the Olympics ranks by gold medals, not total medals. I was really confused why Brazil was ranked 8th when it had more medals than those that ranked higher than them. Overall, I had a lot of fun using the data and then seeing the work tied together.

Also, in my code, I have a breakdown of each countries’ medals by gold, silver, and bronze. I didn’t include it in concept 2 photo because I wanted to keep it straightforward and simple.

Breakdown of Countries' Medals
console.log('Team ' + countryCode + ' won ' + countryTotal + ' medals with ' + countryGold +' gold medals, ' + countrySilver + ' silver medals, and ' + countryBronze + ' bronze medals!')

Week 3 — Reading Reflect Interactivity

I thought the way Crawford wrote this paper was really interesting because it was structure in relaxed and reflect-based mannerism to describe what interactivity means. To Crawford, his definition of interactivity was a spectrum of based on the principle of two parties listening, thinking, and speaking. Initially, I was a bit taken aback by his definition especially when he brought up the examples of books and dancing, but towards the end of his article I came to an understanding and agreement with his argument. I feel interactivity should invoke an experience for the individual and the program itself should react to what the user has input, whether it be through speak or physical action.

When reading his paper, it reminded of modern popup art instillation where individuals could walk through an exhibition and the art itself was what the user created through pressing button or generated through movements. I feel like interactivity has definitely come a long way and to me it seems like artists are starting to take notice and incorporate it into their design. Also, through his structure of writing, it almost felt intentional because he wanted the article to be interactivity by suggesting the reader to contact him by email and leaving a personal touch with the reader.

As such, I feel a strong interactive system has the ability to connect with the user and make them feel something emotion when they are experiencing the project. At the same time the use is also able to control the environment around them and change how they perceptive the project. In my project, I hope to improve the degree of user interactions by hopefully having a “wow” factor when the person first sees my project, and after that experience, they’re able to explore more and have the ability to interact with the system.

Week 3 — Water Lily Pond OOP

SHORT DESCRIPTION: 

In week 3 of intro to IM, we were introduced to the concept of functions, arrays, and object-oriented programming. For my project. I decided to generate a lily pad pond with unique set of flowers, then for each object they would bounce off the walls or bound off of each other. I create two object instance class, one for the lily pads and one for the flowers whose locations are dependent on the lily pads.

Design Concept 

Last week, I had created an abstract water lily pond, and you can call me uncreative, but I just REALLY, REALLY wanted to create an aesthetically looking water lily pond. With last week’s assignment, the art had changed rapidly giving a sense of discomfort and urgency, and I wanted this week’s project to have a slower and relax feeling. Especially for me studying away in Abu Dhabi, I feel like my life has been so chaotic with settling into a new environment, experiencing new cultures and lifestyle, and adjusting into the new academic routine has been overwhelming.

As such, I am glad I choose to do a water lily pond because it kept my grounded and allowed me to relax. While I am happy with the end result, I do wish I could have added more elements into my project (rain, ripples, fish, etc) and made it more interactive. However, due to the time constraints of my schedule, I did the best I could and added as much detail with shading and colors to the elements I currently have on canvas.

Coding Processes

I began my project by referencing Ball Class program we had gone over in class since the shape of my lily pads would also be circular and stay within the boundaries of the screen. Functions with collisions were initially the most confusing part for me, and taking the time to digest the logic ultimately allowed me to then implement a function that checked for object collision – which is shown below.  The function below would use the distance formula to calculate the distance between the center of one object to the center of another object. Then if the distance was less than the sum of the objects’ radius, that meant there was an overlap, and the objects must then change direction. To change the direction, I simply just exchange the x-y speeds between the two objects, so they would then move in the opposite direction.

checkLilyCollision(otherLily) {
   // compute the distance between the current lily with the other lily 
   let distance = dist(this.lilyX, this.lilyY, otherLily.lilyX, otherLily.lilyY);
   
   // if the distances between two lilys are less than the sum of the radius 
   if (distance < this.radius + otherLily.radius){
     let tempSpeedX = this.lilySpeedX;
     let tempSpeedY = this.lilySpeedY; 
     
     // exchange direction and speed of the colliding lilies 
     this.lilySpeedX = otherLily.lilySpeedX; 
     this.lilySpeedY = otherLily.lilySpeedY;
     otherLily.lilySpeedX = tempSpeedX;
     otherLily.lilySpeedY = tempSpeedY; 
   }
 }

Additionally, I had also started by played around with the arc() function, in order to achieve the tiny slit for the lily pad. Below was a code sketch of the degrees which I wanted my lily pads to look.  From there, I dove deep into randomization the attributes of the lily pad class. Most properties such as speed, rotation, location, initial angle, etc were randomized using the random() or Math.random() function because I wanted each execution of the program to create a different and unique portrait.

function waterLily() {
   fill('rgb(42,140,42)'); // color of the lilypad
   arc(100, 100, 80, 80, 0, 11 * PI/6); 
 } 

Admittivity, I had a problem with overlapping lily pads with each execution of the program and had to rely on Chatgpt to help me resolve the issue. They had suggested to test over 1000 attempts and test if a new instance lily pad object would overlap with an existing lily pad object. I did change and delete a few lines of code Chatgbt provided, but below is what I ended up in my code.

function generateLily(){
  for (let i = 1; i < numLily + 1; i+= 1){
    let validPosition = false;
    let attempts = 0;
    while (attempts < maxAttempts && !(validPosition)){
      ...

      if (isLilyPositionValid(newLilyObject)){
        gLilyArr.push(newLilyObject);
        validPosition = true;
      }
      
      attempts += 1;
    }
  }
}

function isLilyPositionValid(newLilyObject){
  let initalSpacing = random(3,9)  
  // for each existing lily within the lily array 
  for (let existingLily of gLilyArr) {
    let distance = dist(newLilyObject.lilyX, newLilyObject.lilyY, existingLily.lilyX, existingLily.lilyY);
    if (distance < newLilyObject.radius + existingLily.radius + initalSpacing) {
      return false; // Overlap detected
    }
  }
  return true; // No overlap detected
}

When I completed my lily pads, I moved onto the flowers, which were my favorite and proudest section of my program. I created another class for my flowers for it be at the center of the lily pads to have a random number of petals, rotation, and combination of color. I used push() and pop() functions that I learned from my first assignment to save and reset the state of the canvas, alongside translation() which set the center of the flower to the center of the lily pad I was currently working on. I did have a problem with the layers stacking on top of each other and the color and degree of the layers changing each frame, but in the end, I was able to get it fixed by creating a unique array for the flower’s color, rotation, and layers.

Final Design

Below is the final program for this assignment. Overall, I am happy with the movement of the lily pads and how each of the flowers turned out. I liked how it is unique for each execution of the program, but it isn’t too overwhelming to the user. There were a lot of technical problems throughout the project, but the concept of a calm and pretty end project kept me motivated to continue working.


 

 

 

 

Week 2 — Reading Reflection

I thought Casey’s talk on chance operation was really cool! I feel like when people talk about computers/ tech, they think about how the systems are built from am extremely rigid structure. When in reality, computer system (especially now with AI) have the capability to produce series of random results beyond what humans can think of and learn/ fix their own programming. Although there is structure in the way computer programs are given sets of parameters (position of the pivot points, color of the objects, movement of the shapes, etc.), the way which the program takes the information and returns a result may not always be what humans expect to happen.

Throughout Casey’s talk, I kept thinking if he could have imagined how far generative art has come. Since Casey’s talk 12 years ago, we have applications such as OpenAI and ChatGPT that have the capabilities to generate some artwork based off user prompts. User do not even need to have technical skills in order to tell the computer what to do; whereas compared to 12 years ago, users likely had to understand the computer manual and/or operating system in order to create some digital art.

With that said, my favorite part of his talk was his demonstration from 30:52 to 34:14 of the commodore 64. Whenever I see technology from the ’80s to early 2000 I am just absolutely fantastically with how far the digital and physical world of technology has come. The commodore 64 is a simple 8-bit home computer in the ’80s, and knowing something so simple was able to produce something complex humans consider as art, is the coolest thing to me. Now as programs and technology continue to advance, I wonder what the future would bring for not only the art community, but how else technology can influence our society.

Going into my work, I hope to have the ability to randomize my work on a deeper level and not only with simple generators with colors and shapes. I hope to explore more on how computers are able to compute and generate different numbers and the probability which they have different numbers. I feel the more I learn about computer architecture and how computers think for themselves through numbers the more I become fascinated with the mechanism behind it. As I learn and do more with projects, I hope to create generative/ AI models for whatever it is I want.

Week 2 — Generative Art with Loops

SHORT DESCRIPTION: 

In week 2 of intro to IM we were introduced to the concept of for and while loops in class and was asked to create a small project using these concepts. For my project, I decided to create a simple generative art program that selects a random shape and fits them onto the screen based off a given coordinate point. In order to achieve randomness in my project, I had used the Math.random() * n + 1 to generate number between 0 to n inclusively.

Design Concept 

Initially, I had wanted my design to be static, pure black and white piece with square grids that are filled with semi-circles rotated to different degrees, but I felt li

ke this concept has been used or seen before, so I decided to try something new. When I started the project, I knew I wanted to keep it simple, yet complex at the same time. My goal was to create a portrait that resembles modern contemporary art with color, where someone can make their own subjective opinions about the piece.

In the end, I created a dynamic and colored piece that changes what the individual sees on the screen every 2-seconds, and when the users press their mouse, the piece turns black and white. While I diverted from my original concept, I am still extremely happy with my final result and was still able to incorporate the black and white feature into my project.

Coding Processes

To achieve a structured, yet random pattern, I started by designing a grid pattern, where each square is 50 x 50 pixels. Then, in each square, there would be a randomly selected shape in the center of that grid. For the program to select a random shape, I created a function (getRandomShape) that would return a type:string from a shapes array (type: string).

The function that I wrote to select a random shape is as follows:

function getRandomShape() {
  const shapes = ['circle', 'triangle', 'square', 'ellipse', 'rect'];
  let randShape = shapes[Math.floor(Math.random() * shapes.length)]
  // console.log(randShape)
  return randShape

In the code, I had taken advantage of the Math library function .floor() and .random() in order to generate an integer that is within the length of the shapes array. Later I could also use the same functions to randomly assign the size of the shape. After which, running the code created a simple static design.

Some examples of the shapes bound within each 50 x 50 grid :

While I could have stopped there, I decided to play around more with the Math library and decided to shift the shape’s center, so it wasn’t restricted within each 50 x 50 square grid. As a result, it led to complex and unpredictable placements of the shape size and centers.

Some example of the randomized shape center

The Hardships

On top of the unpredictable pieces, I wanted to go further and implement an interactive “water ripple” effect that would emerge from where the user clicked on the screen. Unfortunately, I didn’t realize how complicated that process was because I had used the noLoop() in the draw() function to only produce one image at a time. Therefore, I couldn’t have the shapes stay static which the background continues to refresh (or at least I couldn’t figure how…). I spent a couple frustrating hours trying to get my idea to work before realizing the noLoop() was the issue. To future me and anyone else, understand the affect noLoop() will have your project and background, especially when working with for and while loops.

Eventually, I did get rid of the noLoop() in my draw() function and reduce the framerate to 2 fps because I didn’t want to give up on making my project interactive. [Another pro tip: the default framerate (60 fps) will make a project like this incomprehensible because the canvas is changing constantly.]

Achievements 

After dropping the ripple effect idea, I went back to my original idea of a black and white canvas. Using the mouseClicked() function, I set a variable “colorChange” to true if the mouse is pressed and make the canvas black and white, otherwise it would return to its default state of false and make the canvas colored. I really enjoyed this process because it exposed me more to p5’s library and allowed me to incorporate another idea I originally wanted to do.  I also felt like it added more depth and cool composition to my project.

let colorChange = false
... 

function mouseClicked(){
  return mouseIsPressed
  }
...

function drawShape(x, y){

  colorChange = mouseClicked()
    
    if (colorChange){
     circleColor = '#FFFFFF'
     rectColor = '#FFFFFF'
     circleColor = '#FFFFFF'
     squareColor = '#FFFFFF'
     triangleColor = '#FFFFFF'
     rectColor = '#FFFFFF'
     ellipseColor = '#FFFFFF'    
    }
}
Final Design

Below is my final design. I am happy with how it turned out and made me appreciate the process behind generative art and randomness. In the future, I hope to figure out how to implement a ripple effect and ability to create more generative projects.

[Press anywhere to make it black & white!]

 

Week 1 – Self Portrait

Short Description

For the first assignment of my intro to IM class, we had to design a self-portrait of yourself. I have been wanting to take an IM/ IMA class for the past two years at NYU, so I was really excited to get started and work on this project. I wanted my portrait to portray some of my favorite characteristics of who I am as a person. As such, portrait is a small reflection of the character that I am.

Character Design Concept

For my character, I took inspiration from the appearance of Duolingo character. Now before you judge, I often feel the need to add contrast and extensive detail to a design, so I have trouble simplifying my ideal design into primary shapes and colors. Therefore, specifically referencing Violet (my favorite) from Duolingo, I was able to simplify how the human anatomy is suppose to look and add details accordingly to my needs.

The Outfit

My next I asked myself, “what did I want my character to wear?” And so, I decided to dress her up in one of my to-go outfits in a black tank top, green cargo pants, and pair of off-white sneakers.  In addition, I have a cartilage piercing and two lobe piercing on one of my ears, so I added silver jewelry that I typically wear on my character’s ear. I could have added my other ear, but I thought my character looked good as it was. I also can’t forget my pair of silver/blue glasses, so my character can look even more like me.

The Background

After I had completed my character design, I moved onto the background and added some little detail of things I liked. At first, I wanted a cool animated background, but then I realized I wasn’t that comfort/ knowledge on p5 and decided on a plain background of my favorite color – burgundy red. Then, in the corner of the screen is my pet cat (Mio), who I love very much. Lastly, I added “Hello!” to the background to greet anyone that may come across my character.

The Coding Process

Given this was my first time working in p5, I am really happy with the outcome of my design. I had some issue with simplicity and wanting to do more than I was currently able to do. However, after experimenting and testing the p5 reference functions, I was able to work a lot more comfortably.

The Hardships 

THE HAIR. I believe the thing I work on the longest out of everything on my character was the hair. I could not find a shape that fit exactly what I wanted, and the math functions for the shapes were initially all so confusing to me. Eventually I searched up ‘character designs in p5’ on Google to see if hair was just supposed to look bad with the simple shapes, but I came across a post by Erika Noma who used the bezier() function and life was good again. I wouldn’t say my hair is how I imagined it to look, but it works. Although understanding the parameters was a little confusing to me, I do recommend anyone wanting to do a simple curvy/ waving shape to use this function because you’re able to insert 4 different points.

// hair front (on face)

fill('#927242');
bezier(200, 85, 245, 80, 280, 143, 257, 160) // left hair
bezier(200, 85, 135, 80, 120, 140, 135, 160) // right hair

The Brightside/ Greatest Achievement

After working through several shapes and functions to find the perfect hair shape, I felt like I became an expert on the math components of p5. For some functions such as arc() and rotate(), I didn’t realize at first the angles were measured radians, not degrees. You can imagine my confusion when errors were blowing up on the console and the shapes started flying across my screen. Through this project, the unit circle became my best friend and biggest support :’).

As such, through this experience, I was able to encode a simple waving action to my character. With the help of ChatGBT to understand the push(), pop(), and translate() functions that were outside of the p5 reference page, I was able to tweak my project to move based on the x-position of the mouse. The code below is the function for the waving action of my character. I am super proud I was able to make my character come to life and turn my difficulties into something positive.

/* right arm
  -- translate the center to where the arm would pivot 
  -- push() & pop() so it doesn't affect the rest of the drawing 
  -- let angle which the arm will wave based on the x-position of the mouse 
*/

fill("rgb(242,222,203)") // filled at the top for the arms 
push()
translate(245, 230)
let angle = map(mouseX, 0, width, PI/ 10 , PI / 4) 
rotate(angle)
ellipse(0, -40, 15, 100)   // right arm 
fill('rgb(233,200,170)')
circle(0, -113, 20) // right tiny circle hand :3 
pop()

My Final Self-Portrait Reflection

Overall, I am pretty satisfied with the outcome of my final design. I was able to incorporate different aspects of myself onto my character and show who I am as a person. Given I was hesitant and unsure if I could implement something that moves in my project, I feel I have learned a lot through my experience with p5 and overcoming technical difficulties. Going forward, I hope to learn more about the potentials of p5 (frames, rendering, input/output, etc) and continue to design fun projects.  I advise anyone starting out with p5 to not give up and continue to learn through trial and error!