Animated Data: Excess

image-title-here

This animated GIF was originally meant to be a flip-book, although with Covid-19 returning to NZ, and resources to make a flip-book becoming difficult to access, we decided to just complete the animation and remove the flip-book element of it. I titled this animation “Excess” as it represented excess food being wasted and rotting away.

The original black square represents the total food produced each year, which is “eaten” and “consumed” by humanity. I decided on white circles, as their randomly generated placement creates a unique “organic” feel to the removing of the black. Additionally, white is associated with negative space, and so placing a white object on a black object creates the illusion of having eaten away at that black object.

Once we get to the point that 1/3 of the “food” is left, that rots and falls away, leaving “fumes” behind that dissipate, revealing the statistic the animation was based on.

I decided the font based on testing with various fonts and seeing which ones where easiest to read despite the “fumes” covering parts of it.

For more details on the process behind this animation, see this blog post.

/* "Excess" by Melody Elwood
* Made in Proccessing 3.5.4
* V5 published on 21/08/2020
*/

//Imports
import fisica.*;

//CONSTANTS ********************************
int END_FRAMES = 60;
int MAX_FRAMES = 300;
int FRAME_RATE = 10;
int END_FRAME_RATE = 60;

int COUNT_STEP = 15; //12 [15]

int SIZE = 5; //10 [5]
int SIZE_ERROR = 5; //3 [5]
float DOT_MULTIPLIER = 2.5; //1 [2.5]

float GRAVITY = 400;
float DENSITY = 10;
float VELOCITY_DOWN = 400;
int NUM_WASTE_BALLS = 1100;
int WASTE_SIZE_INCREASE = 7;
//CONSTANTS END ***************************

//Global variables
PFont font;

int count = 0;
int rot_size; //313

FWorld world;


void setup() {
  //setup basic frame
  size(700, 700);
  background(255);
  frameRate(FRAME_RATE);
  
  //setup rot size
  rot_size = height-((height-20)/3)-20;
  
  //setup font
  String[] fontList = PFont.list();
  printArray(fontList);
  font = createFont("SansSerif.bold", 24);
  
  //set random seed for reproducibility
  randomSeed(22);
  
  //initiate the Fisica world
  Fisica.init(this);
  world = new FWorld();
  world.setGravity(0, GRAVITY);
  
  //Draw the inital square
  fill(0);
  rect(20, 20, width-40, height-40);
}

void draw() {
  
  //Set stroke and fill to white
  stroke(255);
  fill(255);
  
  //For an ever increasing number of dots, randomly place them within the allowed area
  //I used random placement as it created a more "organic consumption" look, without me needing to specify where to place the thousands of dots
  for (int i = 0; i < count*DOT_MULTIPLIER; i++) {
    float size = SIZE+random(-SIZE_ERROR, SIZE_ERROR);
    float x = random(width);
    float y = random(20, (height-20)-((height-20)-count)-size);

    //Make sure none end up in the "rot" area
    if (y >= rot_size)
    {
      y = random(20,(((height-20)/3)+((height-20)/3))-size);
    } 
    //create the dot
    circle(x, y, size);
  }
  
  //Increase the number of dots and how far along they can be
  count+=COUNT_STEP;
  
  //Because we're no longer working with flipbooks, I can have much more control over timing
  if(frameCount+1 == END_FRAMES)
  {
    frameRate(1); //Give the last frame before dropping a bit of hang time
  }
  else if (frameCount == END_FRAMES) { //If it's entering into the ending
    frameRate(END_FRAME_RATE);
    
    //Create all the "rot" dots
    for (int i = 0; i < NUM_WASTE_BALLS; i++) {
      float size = SIZE+random(-SIZE_ERROR, SIZE_ERROR) + WASTE_SIZE_INCREASE;
      float x = random(20, width-20);
      float y = random((((height-20)/3)+((height-20)/3)),height-20);
      
      //Create them into the Fisica world
      FCircle waste = new FCircle(size);
      waste.setPosition(x,y);
      waste.setDensity(DENSITY);
      
      waste.setVelocity(0, VELOCITY_DOWN);
      waste.setDamping(0.0);
      waste.setNoStroke();
      waste.setFill(0);
      world.add(waste);
    }
    
    //Start the physics by runing it through one step
    world.step();
    world.draw();
    
    //Allow white dots to be placed anywhere
    rot_size = height;
  }
  else if (frameCount > END_FRAMES) {
    //Run the ball drop sim
    world.step();
    world.draw();
  }

  //always print the text over everything (Hidden by the black to start)
  textFont(font);
  textAlign(CENTER);
  fill(0);
  text("Each year 1/3 of all food produced ends up rotting", width/2, height-(height-20)/3+10); 
  text("in the bins of consumers and retailers, or spoiling", width/2, height-(height-20)/3+34);
  text("due to poor transportation and harvesting practices.", width/2, height-(height-20)/3+58);



  //Absolute end
  if (frameCount > MAX_FRAMES)
  {
    //Stop the program
    frameRate(0);
    println("END");
  }
   
  //Save each fram to make it into a GIF later
  saveFrame("frame-######.png");
}