:) idk what to call this – week 5

 

 

IDEA:

 

I was thinking of a way to make a text look cool. The first thought in my mind was to let the user manipulate its position using the mouse. But that was not enough, so I thought I might make it look like it’s raining the characters of the sentence with other effects (different sizes and colors every time the program runs).

 

 

DIFFICULTIES:

 

I tried making colors be generated in for loop inside another for loop but for some odd reason it did not work. It either did not display anything or ran like crazy and did not look good. Then I realized I did not need a for loop for it.

 

CODE:

PFont f;
String s;
float g;


void setup(){
size (640, 480);


f = createFont("Georgia", 35);
s = "Shaikha is amazing";


}

void draw(){
 
  
  background(0);
  g = random(200, 255);
  textFont(f);
  textSize(35);
  fill(255);
  text(s, mouseX, mouseY);

  if (mousePressed == true){

      for (int i = 0; i< s.length(); i++){
                 
          fill (245, g, 66);
          textSize(random(9,100));
          text(s.charAt(i), random(width), random(height));
    
      }
      

  }


}

 

 

Week 5: Data Viz!

Perhaps it was the fact that we spent last class doing translate and rotate to place objects in a circle or perhaps because I love radar charts, I gravitated towards doing a visualization resembling lines in a circle.

Using data from Google Calendar and my memory, I first logged how I spent my last week in terms of the number of hours spent in class and meetings, working, socializing, and practicing self-care.

Next, I started with the layout of the piece, drawing some dummy rectangles to organize the sketch.

sketch of rectangles drawn with for loop across sketchFrom there, I began experimenting with drawing the strokes in a circle.Second step in process of sketch; blurry text

It was rather unclear how long the lines actually were which was important since the length was supposed to convey the number of hours I spent engaged in a particular activity. I also was not vibing with the font.

I ended up drawing smaller circles for each day to have gridlines to show the number. I also learned how to load a font into Processing and used one of my favorite typefaces: Avenir!

process 3 of sketch; changed font to Avenir and made less blurry

One thing I needed to pay particular attention to was the order of drawing all the elements. Originally, I had my circles in the inner for loop which meant they kept getting drawn on top of so they were thicker than intended, they got drawn on top of the chart lines, and the obvious harm to performance.

Here is my final sketch!

final sketch!

And the code!

//class, meetings, social, work, self-care
float[][] data ={{1.25, 6.5, 1.0, 3.0, 2.25}, {4.25, 2.0, 4.0, 5.0, 1.0}, {3.75, 0.0, 4.0, 3.0, 1.0}, {2.5, 1.25, 3.0, 2.0, 3.0}, 
{1.25, 2.5, 3.0, 6.0, 3.0}, {0.0, 0.5, 6.0, 6.0, 3.0}, {0.0, 1.0, 3.0, 8.0, 2.0}};

PFont av;

String[] days = {"Sunday Feb 7", "Monday Feb 8", "Tuesday Feb 9", 
"Wednesday Feb 10", "Thursday Feb 11", "Friday Feb 12", "Saturday Feb 13"};

color[] palette = {#28464B, #855A5C, #8A8E91, #B8D4E3, #FED766};

String[] legend = {"class", "meetings", "social", "work", "self-care"};

int scale = 20;

void setup(){
  av = loadFont("Avenir-Book-48.vlw");
  hint(ENABLE_STROKE_PURE);
  size(1300, 500);
  background(255);
   fill(#6D7174);
  textAlign(CENTER);
  textFont(av, 36);
  text("How I Spend My Week (and too much time in meetings)", width/2, 50);
  drawKey();
  drawLines();
  textAlign(CENTER);
  textFont(av, 10);
  fill(#6D7174);
  textAlign(LEFT);
  text("Notes: The length of line corresponds to the number of hours spent that day engaging in that activity. The color corresponds to the activity.", 15, height-15);
}

//draws lines at top showing the colors and activities
void drawKey(){
  int x = 800/data[0].length;
  for (int a = 0; a < data[0].length; a++){
    stroke(palette[a]);
    strokeWeight(3);
    line(width/6 * a + x, 100, width/6 *a +x + 50, 100);
    textFont(av, 12);
    textAlign(LEFT);
    text(legend[a], width/6 *a +x + 65, 102);
  }
}

void drawLines() {
  textAlign(CENTER);
  int x = width / days.length;
  float angle = 360/data[0].length;
  for (int i = 0; i < data.length; i++) {
    //draws guiding circle gridlines
    textFont(av, 12);
 noFill();
      strokeWeight(0.5);
      stroke(#D4D8D8);
      circle(x * i + 100, height/2, 2*scale);
      fill(#D4D8D8);
      text("2", x * i + 100 + scale, height/2);
      noFill();
      circle(x * i + 100, height/2, 4*scale);
      fill(#D4D8D8);
      text("4", x * i + 100 + 2* scale, height/2);
      noFill();
      circle(x * i + 100, height/2, 6*scale);
      fill(#D4D8D8);
      text("6", x * i + 100 + 3* scale, height/2);
    fill(#6D7174);
    //draw day labels
    text(days[i], x * i + 100,height- 100);
    for (int j = 0; j < data[i].length; j++){
      //draws the chart lines
      translate(x * i + 100, height/2);
      rotate(angle * j);
      strokeWeight(3);
      stroke(palette[j]);
      line(0,0,0,data[i][j] * scale);
      fill(255);
      strokeWeight(1);
      ellipse(0, data[i][j] * scale, 7, 7);
      rotate(-angle * j);
      translate(-(x * i + 100), -height/2);
    }
  }
}

 

Week 4: Shivering Letters

//a string of text
String s = "Shivering in Abu Dhabi";
// Create an array the same size as the length of the String
Letter[] letters = new Letter[s.length()];
//Check the font list
//println(PFont.list());
PFont f;

void setup() {
  size(600, 600);
  f = createFont("Courier New", 30);
  textFont(f);

  // The initial position
  int x = 100;
  for (int i = 0; i < s.length (); i++) {
    letters[i] = new Letter(x, height/2, s.charAt(i)); 
    x += textWidth(s.charAt(i));
  }
}

void draw() { 
  background(255,255,0);

  // loop through the letters array and display letters
  for (int i = 0; i < letters.length; i++) {
    letters[i].display();

    // If the mouse is pressed the letters shiver; otherwise, they return to their original location or station
    if (mousePressed) {
      letters[i].shiver();
    } else {
      letters[i].station();
    }
  }
}

class Letter {
  float x,y;
  float X,Y;
  float fluctuation;
  char letter;

  Letter (float _x, float _y, char _c) {
    X = x = _x;
    Y = y = _y;
    x = random(width);
    y = random(height);
    fluctuation = random(TWO_PI);
    letter = _c; 
  }


  void display() {
    //Choose random color for each letter
    fill(random(255));
    //strokeWeight(2);
    textAlign(CENTER);
    textSize(30);
    pushMatrix();
    translate(x,y);
    rotate(fluctuation);
    text(letter,0,0);
    popMatrix();
  }

  // Fluctuate the letters
  void shiver() {
    x += random(-5,5);
    y += random(-5,5);
    fluctuation += random(-1,1);
  }

  // Return the letter to the initial positions using lerp function
  void station() {
    x = lerp(x,X,0.05);
    y = lerp(y,Y,0.05);
    fluctuation = lerp(fluctuation,0,0.05);
  }
}

Motivation

I want to display letters in a shaky form representing how tremendously the temperature fluctuates between daytime and night time in Abu Dhabi. I can wear sweaters at night or early morning and shorts at noon.

Process

I want to make the letter blink in different shades of one color (I should have chosen red!) to represent the temperature change. When the mouse is pressed, individual letters moved freely around the initial position and they come back to the station and stand still when the mouse is released. Also, I based the code for my class Letter on  our class file circleLetterSketch and took reference from The Coding Train Youtube channel. In the coding and googling process, I discovered the println(PFont.list()) funtion to know all the fonts available in Processing after some failed trials with different random fonts I searched the names on the internet. Also, the lerp function is also used to fluctuate letters within a limited range to create a shaking effect as if the letters were shivering because of the cold night or foggy morning here these days.

 

Week 4: data visualization

Inspiration:

I think that it is useful to know how to visualize data and generate text in Processing. That’s why this week I explored them both, not focusing only on one of them. To be honest, before this version I had many other attempts to make something creative (lyric video, for example). However, I gave up for now and decided to represent and compare the interest overtime for a few of my favorite TV-shows, Game of Thrones, Sherlock, and Grey’s Anatomy.

Process:

I took the data from Google Trends Explore and had 3 CSV files, which graphs you can see below. I also added text at the top of my work using the geomerative library. I played with sizes, figures, colors, and actually understood what the functions of this library mean using this resource.

I displayed 3 graphs under each other and added titles to them. I also had the timeline that shows which years are displayed. All titles are typewritten (kinda), so they appear letter by letter.

Problems:

This assignment was not as easy as I thought, so I spend hours understanding how things work here. The order of functions is extremely important because few times elements didn’t display only because I messed up the order.

Result:

Code:

import geomerative.*;
RFont font;
RPoint[] pnts;
String phrase = "TV-shows";
String word1 = "Game of Thrones";
String word2 = "Grey's Anatomy ";
String word3 = "Sherlock       ";
float xOffset = 0;
Table table1, table2, table3;
float spacing;
PFont f; 
int counter;
  
float[] intervals = new float[11];

void setup() {
  size(600, 720);
  loadData();
  stroke(255, 0, 0, 75);
  smooth();
  frameRate(5);
  
  f = createFont("Courier New", 10);
  textFont(f);
  
  RG.init(this);
  font = new RFont("Franklin Goth Ext Condensed.ttf", 85, RFont.LEFT);
  
  RCommand.setSegmentLength(2);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp;
  grp = font.toGroup(phrase);
  grp = grp.toPolygonGroup();
  pnts = grp.getPoints();
  xOffset = width - grp.getBottomRight().x - grp.getBottomLeft().x;
  xOffset = xOffset/2;
  
  for (int i=0; i<10; i++) {
    intervals[i]=width/10*i;
  }

  noFill();
  stroke(255, 255, 255, 85);
}

void loadData() {
  
  // Load CSV file into a Table object
  // "header" option indicates the file has a header row
  table1 = loadTable("GameOfThrones.csv", "csv");
  spacing = float(width)/(table1.getRowCount()-3);
  println(table1.getRowCount()+" "+spacing);
  
  table2 = loadTable("GreysAnatomy.csv", "csv");
  spacing = float(width)/(table2.getRowCount()-3);
  println(table2.getRowCount()+" "+spacing);
  
  table3 = loadTable("Sherlock.csv", "csv");
  spacing = float(width)/(table3.getRowCount()-3);
  println(table3.getRowCount()+" "+spacing);
}

void draw() {
  background(10, 10, 20, 80);

  line(0, height/4, width, height/4);

  
  for (int i=0; i<10; i++) {
    line(intervals[i], height/4+10, intervals[i], height/4-10);
    fill(0, 102, 153, 204);
    textAlign(CENTER);
    textFont(f);
    fill(255);
    text("201"+i, intervals[i], height/4+20);
  }
  
  textAlign(LEFT);
  textSize(20);
  fill(255);
  typewriteText(word1,  width/10, height/4+50);
  
  typewriteText(word2, width/10, height/2+50);
  
  typewriteText(word3, width/10, height/4*3+50);
  
  text("some of my favorite", width/10, 30);
  text("through the years", width-width/2, height/4-55);
  
  noFill();
   
  beginShape();
  for (int i = 3; i < table1.getRowCount(); i++) {
    TableRow row0 = table1.getRow(i);
    float interest = row0.getFloat(1);
    float x = (i-3)*spacing ;
    float y = map(interest, 0, 100, height/2, height/4+50);
    curveVertex(x, y);
  }
  endShape();
  
   beginShape();
  for (int i = 3; i < table2.getRowCount(); i++) {
    TableRow row0 = table2.getRow(i);
    float interest = row0.getFloat(1);
    float x = (i-3)*spacing ;
    float y = map(interest, 0, 100, height*3/4, height/2+50);
    curveVertex(x, y);
  }
  endShape();
  
   beginShape();
  for (int i = 3; i < table3.getRowCount(); i++) {
    TableRow row0 = table3.getRow(i);
    float interest = row0.getFloat(1);
    float x = (i-3)*spacing ;
    float y = map(interest, 0, 100, height, height*3/4+50);
    curveVertex(x, y);
  }
  endShape();
  
  for (int i=0; i< pnts.length; i++) {
    float x = pnts[i].x + xOffset;
    float y = pnts[i].y + height/4-80;

    float diam = 7;
    ellipse(x, y, diam, diam);
  }
}

void typewriteText(String word, float start, float finish){
  
  if (counter < word.length())
    counter++;
  text(word.substring(0, counter), start, finish, width, height);
}

Text || Emotional Circle

Emotional Circle

This week from the perspective of the class was dedicated to text modification and data visualization, however from my  personal perspective it was about mental health. This week i’ve learned a bit about feelings, emotions and mental health. I bumped into different articles and interesting posts. My personal experience + new information gave birth to the visualization of Emotional Circle

First my code looked like this. The color and atmosphere are dark and gloomy, so I decided to be positive and added some motivation  to the code

Code:

To make the circle text move I used geomerative library and some piece of code which found in references.  To output all the text statements easier I put them in the array.

import geomerative.*;
PFont sourceLight;
RShape   grp;
RShape   circle;
String [] names = {"fear", "sadness", "anxiety", "confusion", "calmness", "exitment", "pain", "horror", "interest", "nostalgia", "disgust", "hatred", "acceptance"} ;
int i = 0;
boolean ignoringStyles = false;
PFont  HelveticaNeue;

void setup(){
   
  size(900, 700);
  smooth();
  textSize(30);
  HelveticaNeue = createFont("HelveticaNeue-Light",10);
  textAlign(CENTER);
  
  RG.init(this);
  
  grp = RG.getText("Choose not to blame yourself", "FreeSans.ttf", 72, RG.CENTER);

  RG.setPolygonizer(RG.ADAPTATIVE);
  RG.setPolygonizerAngle(0.065);
  grp = RG.polygonize(grp);
    
  circle = RG.getEllipse(0, 0, 20);
  circle = RG.centerIn(circle, g, 220);  
}

void draw(){
  translate(width/2, height/2);
  background (0);
  fill(0);
  stroke(254, 184, 198);
  float t = map(mouseX, 0, width, 0.01, 0.99);
  RShape circleSeg = RG.split(circle, t)[0];
  
  RG.setAdaptor(RG.BYELEMENTPOSITION);
  RShape adaptedGrp = RG.adapt(grp, circleSeg);
  
  RG.shape( adaptedGrp );
  
  noFill();
  stroke(255, 200);
    
  RG.shape( circleSeg );
  frameRate(2);
}

void keyPressed(){

 if (key == 's')
  fill(253);
  textFont(HelveticaNeue);
  textSize(random(30, 60));
  textAlign(CENTER);
  text(names[i], 0, 0);
  i++;
}

void mousePressed(){
  ignoringStyles = !ignoringStyles;
  RG.ignoreStyles(ignoringStyles);
}

 

This video shows the last result of my coding, but not the last way of thinking

 

Femicide

*Trigger warning: as you can see by the title, I walk about deaths of women in my home country and describe the femicide that inspired me to work on this project under the Inspiration section*

Description:

This is a project that showcases the number of femicides committed in the country of Honduras since January 2021. It displays the number of cases by department (Honduran word for state) and the user can place the mouse on top of the bubbles containing the numbers to look at the name of the department. Meanwhile, the map of Honduras can be seen forming in the background, with the bubbles placed on their respective location in the map.

Inspiration:

To be honest, my original idea was to make something using generative text, however, I felt like I understood generative text better than I did data visualization, so I decided to make the project based on data visualization to practice more. The idea of displaying the number of femicides committed in Honduras, my country since the start of 2020 came from I post I saw last week about a girl who was detained by the police at night and was discovered dead in her cell (most likely because she resisted an attempt to sexual assault by the policemen who imprisoned her). The police took her to the hospital already dead, but filed in the report that she was taken alive and died while the doctors treated her and they refused to perform an autopsy, dismissing the case as a suicide attempt. The hospital, however, released their report in which they explained that she was strangled (most likely by men). Because of how boldly the police died, many people in the town where this happened started to make a campaign that grew into a social media under the hashtag JusticeForKeyla (the name of the girl). Nevertheless, though the police has acknowledged that Keyla didn’t commit suicide, they refused to investigate. The policemen who incarcerated Keyla have been re-assign and their whereabouts are not known.

I was outraged by this case, not only because it was the police, the people charged with the safety of citizens, the ones who killed her but also by the fact that they lied to openly about it. Femicide, unfortunately, is not something uncommon in my country and cases like Keyla’s are some of the few that are actually been investigated, if not by the police, by the Honduran people. It is very dangerous to be a women in Honduras and in honor of the 90% of the victims that will not receive justice for their murder, I decided to make this visualization.

Process:

I had no idea how to start the project. I knew what I wanted it to look like and I had the data of the femicides this year from one of the NGO’s back home that advocates for women’s rights., but I didn’t know how to come up with the logic to actually write the code. I decided to make a sketch of how I wanted the visualization to look like to get my ideas in order.

This is what I came up with:


After doing the sketch, I decided to first get the locations of the coordinates in which to place the circles. I did this mainly using trial and error and the mouseX, mouseY . I also tried experimenting with other shapes. The rectangle was a good contender, but I preferred the overall look of the circles.

This is what they looked like:

Once I had the locations, I added them to the data set containing the # of deaths.

Afterwards, I decided to stop hardcoding and get to work with the Table object. This took quite some time as I didn’t really understand how to read the rows of the table that well. Thus, I went to Baba Daniel Shiffman for help and watch a lot of his videos on Tabular Data in Processing.It was a great resource and after following along his examples, I manage to grasp a fair amount of the knowledge needed to proceed. (He also gave me the idea of using a hover so the user could see the number of deaths and the department, which I tried with the original ‘hardcoded’ version).

The difficult part came when doing the objects. I found it very difficult to make the bubbles look like I wanted them to, since there were departments that had 74 to 50 deaths in January, contrasting  with other departments that had only 1 or 2 deaths (which are mainly the inhabited territories ), thus I couldn’t use the same scale for make all the circles since one would look too big while the others too small. I opted for having different scaling values for the radius of the bubbles depending on the magnitude of the number of deaths .

Afterwards, I remember look at my visualization thinking that it looked pretty good regardless of the fact that every 30 minutes I edited something I completely crashed the program. But alas, the main product was finalized. I still wanted to do something more with the background because I wanted more circles in the sketch. I read through some of my class notes and remembered that I have never used ArrayList<>; . I then Googled ideas to practice using ArrayList<>; and someone in a forum mentioned making a background out of digital circles using. I then binged watch for two days how to use ArrayList<>; and did some pretty lame attempts at it, but once I manage to understand what I was doing, I decided to make a background since the map I was using was a transparent png . It look fine, but a little overwhelming because of all the color.

When that was done, I decided to experiment a little with the things we learned last lecture about pixels  and took the color values of the pixels in the image I had for the map of Honduras to determine the color of the circles that would comprise the more dynamic map. That created some very interesting results (and also a lot of bugs).

This is what one of my final sketched looked like. 
Then, I recalled that I had forgotten to add the hover function for this ‘final’ version of the sketch, but since I had resized the bubbles, some of the smaller ones where not hovering correctly. Figuring out why my logic was wrong took a lot of time, but at the end it was a silly mistake of not including the scale variable in the radius to calculate the distance between the mouse and the center of the bubble.

Finally, I began to toy around with the colors of the background because I was creating circles for all of the canvas, so the circles outside the map would be white and thus wouldn’t show on the screen. I wanted to see if I could use this circles to make the sketch nicer and a black background provided a very nice contrast. I also decided to add more space between the circles because I thought that the visualization looked better with the spaces. The most interesting thing is that since the circles are created randomly, when I run the program it looks different (even if it is very slightly) every time.

This is the final result

Difficulties:

I already mentioned some in the project description, but my main difficulties were:

  1. Making sure that the Table set loaded correctly and under its respective variable.
  2. Finding the x and y locations where the bubbles needed to be. It wasn’t necessarily hard, but it was very time consuming and such a pain.
  3. Figuring out the logic to create objects using the Table (this took a lot of Google and many tutorials).
  4. Trying not to get confused about what I was editing in the main function since it is quite long. (I gave up and decided to make functions for each step and then call those functions in the setup() and the draw() ).
  5. Making the bubbles look good.
  6. Learning how to use ArrayList. I don’t know why but this was very hard for me to grasp, specially how to compare values of different elements within the array list (the whole for(class object: objectList) thing).
  7. The circles for the map where very hard. It took a lot of my time just to figure out how to detect if they touched another circle or not.
  8. I named a variable expand() and it wasn’t working correctly because Processing has an inbuilt function called expand() that I wasn’t aware of.
  9. I had to add a variable called attempts to control the main loop that loads the map because I read in a forum that if you don’t do it, then you will have an infinite loop and that is bad.
  10. Figuring out what was wrong with the hover because it wasn’t working after resizing the bubbles.
  11. SO. MUCH. DEBUGGING (I’m gonna become an exterminator)

Conclusion:

A good chunk of my time for this project was watching and reading tutorials about how to do things. I think it was beneficial in the sense that, I didn’t feel completely lost about what alternatives to try, but it also frustrated me a lot when I thought I was doing everything right but then I made a very small and silly mistake that kept me up at night.

Overall, I liked this project. It was very personal and I think that helped me keep on working regardless of how often stuff didn’t work.

This is the link to my GitHub because the coded is somewhat long and I already took a lot of space with my explanation.

distorted typography [week 4]

THE INSPIRATION:

I’m terrified of Instagram’s algorithm to show me exactly what I’ve been looking for. That’s how I found this guy whose artworks are all in one fashion, blue, white, and kinetic words on top of distorted pictures. This technique has been implemented a lot for ads, campaigns thus it’s certainly a stylish way to represent any message to an audience.


THE IDEA:

Bostandyq means freedom in the Kazakh language. For my assignment, I was very much inspired by Tim and decided to use this chance to convey a message about how political prisoners rarely get their fair share of justice, although justice was what they fought for. In the artwork, it’s metaphorical how this word gets distorted whenever you try to cursor on it, it gets separated, spread out, and almost invisible at some parts, which also represent how freedom became a property of those above in government and now plays a catch-me-if-you-can game with accused of political opinions.

THE EXECUTION:

I’ve used the copy function to translate a region of pixels from one to another area of the window and it copies a region of pixels from a source image into the destination.  While the copy image does translate part of the image to the other, iterating it with sin function makes it move, well at least imitate the movement of a horizontal wave.

DIFFICULTIES:

Since the graphics were of the same dimension and had the same function, three texts were overlapping on top of each other. Before that, I only had a code where it says “copy(pg, sx, sy, sw, sh, dx, dy, dw, dh); copy(pg1, sx, sy, sw, sh, dx, dy, dw, dh);copy(pg2, sx, sy, sw, sh, dx, dy, dw, dh);”  one after the other and as a result, the last one would only show since processing reads it from top to bottom and the last one was closing the view of two previous graphics. I resolved this issue by putting it all under for loop, where each graphics gets its time to shine under if condition with the implementation of random for the condition.

THE CODE:

PGraphics pg;
PGraphics pg1;
PGraphics pg2;
PFont font;

void setup() {
  font = createFont("Courier", 600);
  size(1600, 800, P2D); //renderer should be defined
  pg = createGraphics(1600, 800, P2D);
  pg1 = createGraphics(1600, 800, P2D);
  pg2 = createGraphics(1600, 800, P2D);
}

void draw() {
  background(0);
  
  pg.beginDraw();
  pg.background(#2103a8);
  pg.fill(255);
  pg2.fill(#F9F9F9);
  pg.textSize(300);
  pg.pushMatrix();
  pg.translate(width/2, height/2-300);
  pg.textAlign(CENTER, CENTER);
  pg.text("bos", 0, 0);
  // text 1
  
  pg.popMatrix();
  pg.endDraw();
  
  pg1.beginDraw();
  pg.background(#2103a8);
  pg2.fill(#F9F9F9);
  pg.textFont(font);
  pg1.textSize(300);
  pg1.pushMatrix();
  pg1.translate(width/2, height/2-100);
  pg1.textAlign(CENTER, CENTER);
  pg1.text("tan", 0, 0);
  //text 2
  
  pg1.popMatrix();
  pg1.endDraw();
  
  pg2.beginDraw();
  pg.background(#2103a8);
  pg2.fill(#F9F9F9);
  pg.textFont(font);
  pg2.textSize(300);
  pg2.pushMatrix();
  pg2.translate(width/2, height/2+150);
  pg2.textAlign(CENTER, CENTER);
  pg2.text("dyq", 0, 0);
  pg2.popMatrix();
  pg2.endDraw();
  //text3


  int tilesX = 12;
  int tilesY = 12;

  int tileW = int(width/tilesX);
  int tileH = int(height/tilesY);

  for (int y = 0; y < tilesY; y++) {
    for (int x = 0; x < tilesX; x++) {
      //creating a table

      // WAVE
      int wave = int(sin((frameCount + ( x*y )) * 0.05) * 200);

      // SOURCE
      int sx = x*tileW + wave;
      int sy = y*tileH;
      int sw = mouseX;
      int sh = mouseY;


      // DESTINATION
      int dx = x*tileW;
      int dy = y*tileH;
      int dw = tileW;
      int dh = tileH;
      
      
      for (int i=0; i<random(0,4); i++){
        if (i==0){
          copy(pg, sx, sy, sw, sh, dx, dy, dw, dh);
        }
        if (i==1){
          copy(pg1, sx, sy, sw, sh, dx, dy, dw, dh);
        }
        if (i==2){
          copy(pg2, sx, sy, sw, sh, dx, dy, dw, dh);
        }
        //to show three different text one after the other using random
      }
    }
  }
}

 

Google Trends – Data Visualization

Inspiration and Initial Implementation

This week’s project was data Visualization. My work today was built upon the class example of plotting a line graph and inspired by Google Trends data representation of a line graph to make it more advanced and also interactive!

In the class example, we downloaded a .csv file of the number of cupcakes sold worldwide from January 2004 to February 2021. This is what we worked on when just learning how to read files and manipulate data on the screen :

There was a plotting problem in this code because we used the line() function to draw the line between 2 data points (see below). We had to keep track of the previous point in this case which gave an error in the beginning for the initial point and did not plot the last point. I managed to fix this by shifting the indices but the method was not very efficient. Using the vertex() function inside beginShape() and endShape() function proved to be more logical.

After I got the plotting correct, I positioned my line graph properly in the center of the page (a little off-centered from the top to leave space for the heading) and drew the axes and border.

This was crucial for what I was going to do next – The most challenging part of this Data Visualization.

THE TASK!

Inspired by how Google represents its line graphs, I wanted to make my line graph interactive – display the value of y-axis whenever the user hovers over a data point.

Now, there were several things to keep in mind here:

  • Since the line graph only plots the data points and joins them together, it is crucial that we display only the data available to us represented by the points and not the intermediate values. For this, I had to first locate find peaks and locate which peaks are closest to the mouse pointer (because I should not display a random intermediate value if a mouse pointer is in between two consecutive data points). I did integer division for this and then compared if the previous or the latter peak was greater.
  • Once the closest peak was determined, I need a vertical line through it and I have to display the corresponding x and y values for this data point. To get the data values for a certain peak, I actually had to reverse the code for how I got peak values to create the vertical line. This took quite a bit of time to figure out and understand how to implement.
  • Where to display the text? I decided to display the year and month on the top right corner as it looked neat and compact. But faced more dilemma as to where to display the number of cupcakes. It should be close to the peak value but not close to other points (to avoid confusion). Displaying this text with respect to MouseX and MouseY proved to be a great idea! The vertical line passing through the point clearly indicates which point corresponded to the data and also gives the user flexibility as to where they want it to be displayed – giving them a sense of control (and it’s honestly fun too to see it move that way!).

Now one major problem I faced here was a mismatch of the line graph, the vertical line, and the text that was being displayed. None of them were matching. After a lot of trial and errors and printing ample println() statements, I was able to make all 3 coincide.

Yet, another problem awaited me. Since I was retrieving the data from the .csv file based on where the mouse pointer was, I often ran outside the bounds of the rows in the table which kept on giving the error.

Even when I restricted the value to be shown only when the mouse was in the range, there was a sight range in which I still got an error. In an attempt to fix this, I discovered something new about the curveVertex() function (which I used before vertex() to draw my line graph). curveVertex does not draw the first and last point. So, when my mouse pointer was with the first 2 and last 2 points, I was still getting an error. I managed to fix this by switching to vertex() function which draws all points.

Once I finally managed to get the line graph as desired, I labeled the axes, made grid lines, etc. to make it look more professional. I also added color to break the monotony. The process looks like below:

What more can my data say?

Once I was satisfied with my line graph, I wanted to add some additional information about the data by using another representation method. I decided to show the number of cupcakes sold as a percentage of the maximum number of cupcakes sold in the entire data collected. This would tell me how the cupcakes in a particular month performed as compared to the others. A pie chart seemed just the right fit for this! I used the arc() function in which I made the arc as complete as the percentage of cupcakes sold.

Lastly, I added the heading, gave a background color and I was done! This is what my final outcome looks like:

CODE

Table table;
float spacing;
float marginT, marginB, marginL, marginR; // of the rectandle
float h, w; // height and width of the display
float innerBorderX, innerBorderY; // for the line graph
int peakX; // to display value of cupcakes
int maxVal = 100; //found the max num of cupcakes sold in any month by using max() function in excel
int arcW; 
float arcX, arcY; // for pie chart
String s1 = "Number of Cupcakes Sold Worldwide", s2 = "From January 2004 to February 2021"; //for my heading

//defining colors
color blue1 = color(42, 157, 244);
color blue2 = color(10, 57, 200);
color greyblue = color(208, 239, 255);
color grey1 = color(146, 167, 179);
color grey2 = color(231, 230, 225);

void setup() {
  fullScreen();
  //size(1280, 720);
  loadData();
  marginT = 0.2*height;
  marginB = height - 0.05*height;
  marginL = 0.1*width;
  marginR = width - 0.1*width;
  h = marginB - marginT;
  w = marginR - marginL;
  innerBorderX = 0.05*w;
  innerBorderY = 0.05*h;
  arcW = 120;
  arcX = marginR-arcW/2;
  arcY = marginT/2;
  println(w);
  loadData();
}

void loadData() {
  // Load CSV file into a Table object
  table = loadTable("multiTimeline.csv", "csv");
  // spacing is rowcount - 4 since the first three rows and the last row are superfluous
  spacing = (w-2*innerBorderX)/(table.getRowCount()-3);
}

void draw() {
  background(grey2);

  //draw display rectangle
  pushStyle();
  stroke(grey1);
  rect(marginL, marginT, w, h);
  popStyle();

  //to display x and y axis
  pushStyle();
  strokeWeight(2);
  line(marginL+innerBorderX, marginT+innerBorderY, marginL+innerBorderX, marginB-innerBorderY);
  line(marginL+innerBorderX, marginB-innerBorderY, marginR-innerBorderX, marginB-innerBorderY);
  //label the axes
  textSize(16);
  textAlign(CENTER);
  fill(grey1);
  text("Cupcakes", marginL+innerBorderX, marginT + innerBorderY - 7);
  text("Month", marginR-innerBorderX, marginB - innerBorderY + 17);
  popStyle();

  //grid lines
  pushStyle();
  stroke(grey2);
  fill(grey1);
  textSize(16);
  textAlign(RIGHT);
  //line1
  float yline = map(25, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY);
  line(marginL+innerBorderX, yline, marginR-innerBorderX, yline);
  text("25", marginL+innerBorderX-5, yline);
  //line 2
  yline = map(50, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY);
  line(marginL+innerBorderX, yline, marginR-innerBorderX, yline);
  text("50", marginL+innerBorderX-5, yline);
  //line 3
  yline = map(75, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY);
  line(marginL+innerBorderX, yline, marginR-innerBorderX, yline);
  text("75", marginL+innerBorderX-5, yline);
  //line 4
  yline = map(100, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY);
  line(marginL+innerBorderX, yline, marginR-innerBorderX, yline);
  text("100", marginL+innerBorderX-5, yline);
  popStyle();

  //draw the line graph first
  pushStyle();
  strokeWeight(3);
  stroke(blue1);
  noFill();
  beginShape();
  // start at row 3 since the first few rows are filler
  for (int i = 3; i < table.getRowCount(); i++) {
    TableRow row0 = table.getRow(i);
    float interest = row0.getFloat(1);
    float x = (i-3)*spacing ;
    float y = map(interest, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY); //map the data values to my display area
    vertex(marginL+innerBorderX+x, y);
  }
  endShape();
  popStyle();

  //Draw line and circle on line with mouseX
  //Choose closest peak

  //if mouse is inside the inner box
  if (mouseX<marginR-innerBorderX && mouseX>marginL+innerBorderX && mouseY<marginB-innerBorderY && mouseY>marginT+innerBorderY)
  {
    //See if it is closer to prior peak
    if ((mouseX % spacing) < spacing/2 ) {
      peakX = int(mouseX / spacing);
      //println("condition1");
      //println(mouseX);
      //println("spacing = " + spacing);
      //println("mouseX % spacing = " + mouseX % spacing);
      //println("peakX = " + peakX);
    } else {
      //otherwise closer to next peak
      peakX = int(mouseX / spacing) + 1;
    }

    //Print text at mouse of the peak value
    pushStyle();
    fill(0);
    textSize(20);
    if (int(peakX-int((marginL+innerBorderX)/spacing))+3 < 209) //to avoid out of bounds error
    {
      //draw the vertical line
      line(peakX * spacing, marginT, peakX * spacing, marginB);

      //write value of peak
      String val = nf(table.getRow(int(peakX-int((marginL+innerBorderX)/spacing))+3).getFloat(1), 0, 0);
      text(val, mouseX, mouseY);

      //display month
      pushStyle();
      textAlign(RIGHT);
      String mon = table.getRow(int(peakX-int((marginL+innerBorderX)/spacing))+3).getString(0);
      textSize(16);
      text("Year-Month: " + mon, marginR - 25, marginT + innerBorderY);
      popStyle();

      //draw circle at peakX at height using map function
      TableRow r0 = table.getRow(int(peakX-int((marginL+innerBorderX)/spacing)+3));
      float value = r0.getFloat(1);
      float cirY = map(value, 0, 100, marginB-innerBorderY, marginT+2*innerBorderY);
      pushStyle();
      fill(blue2);
      stroke(blue2);
      circle(peakX*spacing, cirY, 7);
      popStyle();

      //draw piechart for number of cupcakes sold as a percentage of max value
      pushStyle();
      fill(greyblue);
      stroke(grey1);
      arc(arcX-20, 0+arcY, arcW, arcW, 3*PI/2, 3*PI/2+value/maxVal*TWO_PI, PIE);
      textAlign(CENTER, CENTER);
      textSize(16);
      fill(0);
      text(nf(value/maxVal*100, 0, 1) + "%", arcX-20, arcY);
      popStyle();
    }
    popStyle();
  }

  //heading
  pushStyle();
  fill(blue2);
  textSize(40);
  textAlign(LEFT, TOP);
  text(s1, marginL+20, 0+40);
  textSize(20);
  fill(blue1);
  text(s2, marginL+20, 0+90);
  popStyle();
}

 

Week 4 – What is the meaning of life?

Inspiration

“What is the meaning of life?” I always wonder about the answer to this question, whenever I get a bad mark/eat sweets that ruin my face/pet cats that I am allergic to, and more. It’s a very difficult question, so why not generate text that will showcase the chaos of answers we might get, even with my limited abilities.

Understanding Arrays

So, the main thing that I got from the video was that the array was that of a list that starts from 0 and goes upwards. So, it can pull out any number from that list that would be identified with, in our case, a word, and thus, we can get that word out on the screen. Like, I tried to do that with keyPressed function, and there, each time that I pressed the “space”, words will change. Like, I had a question “what is the meaning of life” and another text with variants using the array (live, laugh, love). So, each time I pressed space the meaning of life would change! :D, how cool is that?

So, for the final product, I just repeated the scary thingy we did in class since it took a lot of time for me to understand how everything interacts together. Then, I added the twist with the live, laugh, and love. The meaning does indeed change very fast since life is fleeting with each second that you might be reading this is to capture this temporal event.

Project Version number 1

String [] meaningofLife = {"Live", "Love", "Laugh"} ;
String meaningHolder = ""; //store whatever name we randomly pull out of the array
String question = "What is the meaning of life?";
PFont myFont;
int xPos;


void setup() {
  size (2500, 1500);
  myFont = createFont("Courier New", 72);
  textFont(myFont);
  textAlign(CENTER);
  textSize(100);
  xPos = width;
  //println(meaningofLife.length); discover how many characters there are
  
}

void draw() {
  background (255);
  fill(0);
  textSize(90);
  //text (question, width/2, 300);
  xPos -=4;
  
  if  (xPos<= - textWidth(question)) {
   xPos = width; 
  }
 
  for (int i=0; i<question.length(); i++) {
   char c =  question.charAt(i);
   float x = width/4 + i*textWidth(c);
   float y = height/4 + random(-5, 5);
   text(c, x, y);
  }
}

void mouseMoved() {
  textSize(random(40, 72));
  meaningHolder = meaningofLife[int(random(meaningofLife.length))];
  text(meaningHolder, mouseX, mouseY);
}

However, after a meeting with the Professor, a question of the design was brought up, so I tried to make the design more intentional. Here, I added a more chaotic atmosphere, eased my job with for() function. I especially like how at some point the random function just goes out of hand and all meaning disappears leaving jiggling “what is the meaning of life?” text. As if showing the scariness of the question, feeling of being lost as to what is exactly the meaning of life.

String [] meaningofLife = {"Live", "Love", "Laugh", "Nothing", "Family", "Knowledge"} ;
String meaningHolder = ""; //store whatever name we randomly pull out of the array
String question = "What is the meaning of life?";
PFont myFont;
PFont myFont2;
int xPos;


void setup() {
  size (2500, 1500);
  myFont = createFont("Courier New Bold", 72);
  myFont2 = createFont("Courier New Italic", 72);
  textAlign(CENTER);
  textSize(100);

  //println(meaningofLife.length); discover how many characters there are
}

void draw() {
  textFont(myFont);
  background (50);
  fill(0);
  xPos -=4;

  if  (xPos<= - textWidth(question)) {
    xPos = width;
  }

  for (int i=0; i<question.length(); i++) {
    char c =  question.charAt(i);
    float x = width/4 + i*textWidth(c);
    float y = height/4 + random(-5, 5);
    text(c, x, y);
  }
}
void mouseMoved() {
   textFont(myFont2);
   fill(255);
  for (int i=0; i<5; i++) {
    textSize(random(66, 72));
    float w;
    float h;
    meaningHolder = meaningofLife[int(random(meaningofLife.length))];
    w = random(i*100, i*900);
    h = random (i, i*500);
    text(meaningHolder, w, h);
  }
}

 

Credit

This guy is awesome, love this guy for the way he explains stuff, and he shall be my savior for this assignment!

Generative Text – not so easy

I learnt from my mistake in the Week 3 assignment and started working on the Week 4 assignment earlier than usual. Initially, the plan was to work on data visualization, but then I felt there was more for me to learn from generative text output (I think it is cooler). Attached below is the screenshot of what I ended up making.

Yes, as simple as it seems, this assignment really did take me 2 days. I was not very comfortable with generative text because I felt we went over it pretty quickly in class last Wednesday, so the first goal was to fully understand the example we covered in class.

I then decided to expand on the class example using a similar model but by adding a couple of more features. One way this could be done was to show the text being drawn on the screen, and this is what I ended up doing. To do this, I had to make sure that the block of code which drew the text was included in the draw() function. If I included that in the setup(), like in the class example, it would all be displayed at once, because setup() is called only once when the code is run.

Next, I found it hard to figure out how to move text to the next line while using a single string, because it was going out of the screen. I tried using “\n” inside the string but this didn’t work. I then made 4 different strings, and used if conditions to ensure that each string was drawn in the appropriate place after the previous string was completed.

Lastly, I played with the colors and used a couple of variables, some of which were used inside the stroke() function, until I ended up having something which satisfied my aesthetics.

The video is attached below. The only reason I have this song in the background is because it helped me get through Saturday night, when I spent Valentine’s day trying to make this thing work 🙂

Attached below is the code for the assignment

import geomerative.*;
import processing.sound.*;
SoundFile file;

String audioName = "song.mp3";
String path;

RFont font; 
RPoint[] pnts, pnts2, pnts3, pnts4;
float xValue = 0;
float yValue = 0;
int i = 0;
int j = 0;
int k = 0;
int l = 0;
int r = 150;
boolean change = true;
float xOffset = 0;
float xOffset2 = 0;
float xOffset3 = 0;
float xOffset4 = 0;
float diam = 20;
 
void setup(){
  frameRate(120);
  background(255);
  size (800, 800);
  path = sketchPath(audioName);
  file = new SoundFile(this, path);
  file.loop();
  RG.init(this);
  font = new RFont("Franklin Goth Ext Condensed.ttf", 150, RFont.LEFT);
  
  // getting the points along the multiple strings
  RCommand.setSegmentLength(1);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp, grp2, grp3, grp4;
  grp = font.toGroup("This took me");
  grp = grp.toPolygonGroup();
  pnts = grp.getPoints();
  
  xOffset = width - grp.getBottomRight().x - grp.getBottomLeft().x;
  xOffset = xOffset/2;
  
  grp2 = font.toGroup("2 hours");
  grp2 = grp2.toPolygonGroup();
  pnts2 = grp2.getPoints();
  
  xOffset2 = width - grp2.getBottomRight().x - grp2.getBottomLeft().x;
  xOffset2 = xOffset2/2;
  
  grp3 = font.toGroup("--------");
  grp3 = grp3.toPolygonGroup();
  pnts3 = grp3.getPoints();
  
  xOffset3 = width - grp3.getBottomRight().x - grp3.getBottomLeft().x;
  xOffset3 = xOffset3/2;
  
  grp4 = font.toGroup("days");
  grp4 = grp4.toPolygonGroup();
  pnts4 = grp4.getPoints();
  
  xOffset4 = width - grp4.getBottomRight().x - grp4.getBottomLeft().x;
  xOffset4 = xOffset4/2;
    
  noFill();
}

void update(){
  stroke(r, r, 0, 75);
  // setting a different color for the third string
  if (i >= pnts.length && j >= pnts2.length && k < pnts3.length){
    stroke(50);
  }
  ellipse(xValue, yValue, diam, diam);
}
 
void draw(){
      // printing the first string on the canvas
      if (i < pnts.length){
        update();
        if (r >= 0 && change == true){
          r -= 1; 
        }
        else if(r == 225 && change == false){
          r -= 1; 
          change = true; 
        }
        else{
          r +=1;
          change = false; 
        }
        xValue =  pnts[i].x + xOffset;
        yValue = pnts[i].y + height/2 - 150;
        i++;
      }
      
      // printing the second string after the first one has been printed
      if (i >= pnts.length){
        if (j < pnts2.length){
        update();
        if (r >= 0 && change == true){
          r -= 1;  
        }
        else if (r == 225 && change == false){
          r -= 1; 
          change = true; 
        }
        else{
          r +=1;
          change = false; 
        }
        xValue =  pnts2[j].x + xOffset2;
        yValue = pnts2[j].y + height/2;
        j++;
        }
        
      // printing the 3rd string on the canvas after the first two have been printed
      if (i >= pnts.length && j >= pnts2.length){
        if (k < pnts3.length){
          update();
        if (r >= 0 && change == true){
          r -= 1;  
        }
        else if (r == 225 && change == false){
          r -= 1; 
          change = true; 
        }
        else {
          r +=1;
          change = false; 
        }
        xValue =  pnts3[k].x + xOffset3 + 60;
        yValue = pnts3[k].y + height/2;
        k++;
        }
        
      // printing the 4th string after the first 3 have been printed
      if (i >= pnts.length && j >= pnts2.length && k >= pnts3.length){
        if (l < pnts4.length){
          update();
        if (r >= 0 && change == true){
          r -= 1;  
        }
        else if (r == 225 && change == false){
          r -= 1; 
          change = true; 
        }
        else{
          r +=1;
          change = false; 
        }
        xValue =  pnts4[l].x + xOffset4;
        yValue = pnts4[l].y + height/2 + 150;
        l++;
        }
      }
      }
      }
        
}