Week 4: Passing Moments (Data Visualization)

(higher amplitude = longer sleep; larger frequency = longer lifespan)

Conception

In this project I wanted to demonstrate the idea of passing moments and how your total lifespan affects how fast you may perceive each moment. Since I love animals, the project started with me just wanting to play around with some data regarding animals; however, I was struggling to find something interesting.

At first I had some data with brain mass and wanted to compare each animal’s brain mass to body mass ratio using circles but it ended up looking very bland so I completely scrapped that sketch.

Then I looked around online for some more databases until I found one that had both lifespan and sleep durations. I thought I could perhaps make something to visualize the impermanence of life and demonstrate the idea of “passing moments.” You could say it’s a bit of a memento mori in a way for both you and the animal mentioned on screen.

Development

I was thinking of how I could represent lifespan and I thought about the heart rate monitors beside hospital beds. I thought perhaps I could use sin waves to represent life span and have the amplitude and frequency be scaled with different things, so that’s what I went with.

I matched the frequency with their life span 

let frequency = map(chosenMammal.lifeSpan, 2, 80, 0.02, 0.08);
...
sin(x*frequency - frameCount * 0.1)

Then I matched the amplitude with hours of sleep per day

let sleepHours = chosenMammal.totalSleep;
let ampMult = 8;
...
let y = height/2 + sin(x*frequency - frameCount * 0.1) * sleepHours * ampMult;

Together, I was able to use the beginShape() and endShape() functions to create a continuous animated sine wave for the mammal. However, that felt like it lacked a frame of reference so I added another wave behind it in gray to represent humans. This way, it could really put into perspective just how fast each moment for us vs the chosen mammal was. I was quite proud of how this part turned out.

function drawSleepSpiral(chosenMammal, color){
  let sleepHours = chosenMammal.totalSleep;
  let ampMult = 8;
  let frequency = map(chosenMammal.lifeSpan, 2, 80, 0.02, 0.08);
  
  push();
  noFill();
  
  if (chosenMammal == allMammals[21]){ //21 is human
    stroke(200);
  } else{
    stroke(color);
  }
  
  strokeWeight(6);
  beginShape();
    for (let x = 0; x < width; x+=1){
      let y = height/2 + sin(x*frequency - frameCount * 0.1) * sleepHours * ampMult;
      vertex(x,y);
    }
  endShape();
  pop();
}

I wasn’t happy with how the default font looked so I loaded in a very beloved font, Helvetica, into the project with what we learned last week.

textFont("Helvetica");
textAlign(CENTER, CENTER);

I was also thinking of adding a text input for the user to put in how many hours they sleep and compare that to the mammal onscreen but I felt like that took away from the idea of lifespan and sounded more like I wanted the user to acknowledge how healthy their sleep schedule was, which I thought would greatly detract from the memento mori effect I was aiming for.

Lastly I added a mousePressed function to cycle through the database without having to hit the start button each time.

function mousePressed(){
  chosenMammal = random(allMammals); // switch to a new mammal on click
  randomColor = random(colorArray); //changes to a random color with the same click
}
Conclusion / Difficulties Endured

I didn’t even realize I could upload my own files and create folders in the sketch files until this past week so this production piece provided me with a lot more insight into what p5js is capable of.

I initially had some trouble figuring out how to get the data out from the CSV file in a natural and efficient way but then I remembered I could extract each column data as a separate characteristic of my object like this:

for (let i = 0; i < table.getRowCount(); i++) {
  let mammalObject = {
    species: table.getString(i, "Species of animal"),
    bodyMass: table.getNum(i, "Body Weight (kg)"),
    brainMass: table.getNum(i, "Brain Weight (g)"),
    totalSleep: table.getNum(i, "Total sleep (hrs/day)"),
    lifeSpan: table.getNum(i, "Maximum life span (years)")
  };
  allMammals.push(mammalObject) //now i can obtain mammalObject.bodyMass for instance
}//closes for() after appending all mammals

This made the process of finding specific attributes of the chosen mammal so much more convenient and efficient.

I also made sure credit the source of my database at the very end of my code: https://gist.github.com/yppmark/d907dc265a84cac76ba7

Author: Hubert Chang

NYUAD Class of 2027

Leave a Reply