Week 4 – Data Visualization

Concept

Having taken MVC last semester, as with many others, spherical coordinates are still stuck in my head. Since my last week’s assignment was space themed, I wished to stick with it for a bit longer. With the inspiration from this p5js sketch and the help of this video, I was able to understand how to plot points using the three axes in p5js. As there are few things to be plotted on the globe compared to the standard map, I decided to concern this project with meteorite landings.

I downloaded my CSV file from the NASA website and cleaned it up in Microsoft Excel such that it contained only the relevant rows, mass, latitude, and longitude. Furthermore, I removed the rows with blank cells so that they do not take up more space than needed.

function preload() {
  meteors = loadTable("M_New.csv", "csv");
}

After plotting the points I was left with the following sketch:

https://editor.p5js.org/ajlasacic/full/yxr9xvKC4

Note: The program is very demanding so I posted only the link in order not to crash the website. By changing the step variable, more landings can be seen.

Challenges

The most challenging part was understanding where the latitude and longitude are supposed to be pasted. Since they were given in degrees in the CSV file, I put the angleMode() to DEGREES. Unfortunately, this plotted the points only on one side of the globe, which took some time to understand why. After reverting back to normal parameters, the points were plotted just right.

let mass = meteors.getColumn(0);
  let lat = meteors.getColumn(1);
  let lng = meteors.getColumn(2);

  for (let i = 2; i < n; i += step) {
    let lat_ = lat[i];
    let lng_ = lng[i];

    strokeWeight(map(mass[i], 0, upper_mass_size, 0.7, 5));
    if (flag == true) {
      stroke(map(mass[i], 0, upper_mass_color, 120, 30), 100, 90);
    } else {
      stroke(255);
    }

    let z = r * cos(lat_);
    let y = r * sin(lat_) * sin(lng_);
    let x = r * sin(lat_) * cos(lng_);
    point(x, y, z);
  }

Another challenge was understanding how to map the size of the magnitude of the meteors on the map. By using the MIN and MAX functions in Excel, I extracted the smallest and biggest values within the dataset and set them as the values of their respective variables. By using the map() function (considerably the best function in p5js), I was able to set different sizes to the points within the sketch. By trial and error method, I was able to conclude 0.7 and 5 were perfect

strokeWeight(map(mass[i], 0, upper_mass_size, 0.7, 5));

Although the meteors in the dataset are quite similar in mass, slight differences can be seen on the graph. Lastly, I wished to create the sphere more interactive by changing colors. The colors were also added using the map() function, but I was stuck on how to change them when the mouse was pressed. By adding a global boolean flag variable, I was able to overcome this issue and change the color by setting its value to true or false.

Reflection

Although I am not quite satisfied with this project, I am grateful that I could achieve its main purpose which was plotting in 3d. I tried adding texture to the sphere to show the countries, but the picture did properly wrap no matter how much I edited it. In the future, I wish to make the plot more readable by adding either country outlines or an earth texture. Overall, I am pleased that I know how to plot in 3d using p5js.

 

Generative Text_Aaron

Concept

The idea for this code was to generate a random text/ character on the canvas using noise feature. the canvas color becomes darker and darker with each word generated and printed on the screen. I was inspired by the idea of dots disappearing from my computer screen as I worked on a data visualization project I had given up on.

Implementation

The concept was implemented using p5.js. Key technical implementations includes preload and noise feature.

Challenges

Some of the challenges I faced was randomizing the position of both the word and character on the screen; I couldn’t solve it.

Generative Text – Aigerim

Inspiration/Concept

For this project, I created a fortune cookie application that gives a random fortune. I love getting fortune cookies and seeing my luck (even though I do not believe in them, it is still a fun activity), and I wanted to transfer that fun little moment into a web application. To create the effect of anticipation one gets when opening the cookie’s package I made a fortune come up as in a typewriter, letter by letter without revealing everything all at once.

The Product

I am really happy with the way it turned out, especially given that I was not really sure what I was going for when I just started the project. The product is really simple and minimalistic, and I love it this way because I want the focus to be on the fortune itself, which I think was achieved pretty nicely.

Challenges

The biggest challenge for me was restarting the typewriter when a user clicks on the mouse and the typewriter is done writing. Since my function is not blocking, I had multiple fortunes written on top of one another at some point. To solve this, I added a boolean printing that is set to True whenever I am about to enter the typeWriter function within start and set it back to False when I am about to leave it. Then, whenever a mouse is clicked, I first check whether the variable is true or not and print a new fortune when the previous one is done printing (or displaying) and the user clicks.

function start() {
  if (printing == false) {
    printing = true;
    typeWriter(random(fortunes), 0, 50, height / 2, 80);
  }
}

function mouseClicked() {
  start();
}

 

HW4: Generative Text Video

Inspiration

The inspiration for this generative text art was to use text to render a live video. The goal was to use the brightness of each pixel in a video capture to determine the color of a letter displayed in the center of the pixel and to keep rendering this video live. The code was inspired from a coding challenge by coding train.

Concept

The concept was to create a generative piece of art that was unique to the video input. The text displayed would change based on the brightness of each pixel, resulting in a dynamic and ever-changing piece of art. The text used was limited to the string “ME” and the letters were displayed in the center of each pixel. The string can also be changed to say something else.

Implementation

The implementation involved using the p5.js library to capture video input and display text on a canvas. The code loops through each pixel in the video capture, calculates the brightness of the pixel in grayscale, and uses that value to set the color of the displayed text. The text is displayed in the center of each pixel and changes based on the brightness of the pixel.

Challenges

One of the main challenges that I faced was to decide on an appropriate dimensions of the rendered video in order for p5.js to not break while looping through the video.

Reflections

Overall, this project was a successful exercise in creating generative art using code. The dynamic and ever-changing nature of the art is an interesting concept that can be expanded upon in future projects. The ability to use video input as the source for the art adds an extra level of interactivity and uniqueness to the piece.

Sketch Link: https://editor.p5js.org/swostikpati/full/U-0U4yVHN

References

A game of Madlibs – Hana

I decided to use the word randomizer task as a way to make a fun game of madlibs.

I loaded all words from a .csv file, and categorized them appropriately. Then I printed the text onto the canvas, leaving spaces for the words which will be chosen by the program and distinguishing them with a red font.

Here is an example of how the specific words are chosen randomly:

//function which randomly chooses and returns a verb through the use of random integers
function chooseVerb() {
  let num = int(random(verbs.length));
  return verbs[num];
}

This same function is repeated for nouns and adjectives as well. This function itself returns the word and I use the returned value to print onto the canvas:

//putting the paragraph together and printing it on the canvas
function printMadLibs() {
  text("Summer is all about the beach! During the daytime, you can ", 10, 20);
  fill("red");
  text(chooseVerb(), 335, 20);
  fill("black");
  text("in the lake or sea and collect seashells and ", 10, 40);
  fill("red");
  text(chooseNoun(), 245, 40);
.
.
.

This was a very fun program to work on since it is based on the popular game of Madlibs. Each time you refresh it will have a new set of words chosen randomly, and sometimes they are very funny, other times they make no sense.

This was the first time I have done any sort of file manipulation in JavaScript, so I am happy to have learned how to do it. I mainly used the class notes and P5 reference page to figure things out.

Assignment 4: Music Visualization

This code uses a circular pattern to represent sound. It plays a song using the p5 library and then plots the song’s amplitude in a circular pattern. The draw method in the code first sets up the canvas and the Amplitude object before preloading the sound file and drawing the visualization.

The circular pattern is produced by the code using the p5.js methods translate, beginShape, vertex, and endShape. The map and random functions are also used by the code to produce the visualization’s design. The amplitude data is likewise stored in an array. The circular pattern is then produced using the amplitude data.

It took some time to get the code to function correctly. I had to confirm that both the sound playback and the amplitude data storage were accurate. I wanted to confirm that the visualization was being rendered properly as well. The toughest issue was appropriately storing the amplitude data in the array.

I was able to add certain design components, such as the random fill color, and the way the sounds circle around the mouse after the code was functioning well. This gives the visualization a beautiful visual component.

I want to enhance the visualization in the future by including more design components. Also, I’d want to provide a mechanism for regulating the visualization’s pace. The user would be able to decide how quickly or slowly the visualization changes thanks to this. The visualization’s size and form may now be adjusted, I’d like to mention. The user would then be able to tailor the display to their preferences.

Homework 04 – Data visualization – “Notable people”

Sketch

Concept

I wanted to do a data visualisation that would show the world in an interesting way. Since I’ve been working on a project which created a dataset of two million notable people in history, I decided to use that dataset. Since this dataset is huge (the whole .csv file is 1 GB), I decided to filter it so that I only look at people in Europe with a notability index as defined in the paper of 23.5 or more. This led to a dataset with 52000 observations and a file size of 4.3 MB.

Each observation (row) in the dataset, after filtering and selecting only the columns I wanted to use, has the birth year, birth location and death location (latitude and longitude) of a notable person in history, as defined by the paper. Therefore I decided to make my visualisation a timeline, from 3500 BC to 2020 AD, where for every year I draw the birth and death locations of all people born at that year. Moreover, the more notable the person as defined by their notability index, the bigger their circle would be. I draw the people as translucent circles, so that if many people were born near the same location, the colors will add up. I picked the color green to represent a birth location, and red to represent a death location.

Code highlight

I’m particularly proud of the part of my code that converts a person’s latitude and longitude into (x, y) coordinates which I use to draw the person later. Latitude and longitude are coordinates on a sphere, while x and y are coordinates on a two-dimensional plane. I essentially needed to figure out a map projection. There are many of these, such as the Mercator projection, Robinson projection, etc. However, I managed to find a projection for which the code is incredibly simple: the Equirectangular projection. This formula is very simple: we map latitude to x and longitude to y. However, this produces a map rotated 90 degrees clockwise, so we also rotate it by using a bit of linear algebra.

function getCoordsFromLatLon(lat, lon) {
  // Equi-rectangular projection.
  // Formula from:
  // https://www.marksmath.org/classes/common/MapProjection.pdf
  // (lat, lon) -> (x, y)
  // But we also rotate 90 degrees:
  // (x, y) -> (y, -x)
  return {x: lat, y: -lon};
}

Note that changing this mapping function will result in different interesting visualizations.

Reflection

The final visualization looks good, especially after tuning a few of the parameters, such as the colors, radii, and transparency of the circles. The dataset I used is huge and has many parameters besides the ones I used. For example, instead of coloring circles based on the person’s birth and death, we can instead use data such as a person’s occupation (discovery/science, culture, leadership, sports/games, other), which might show interesting effects over different locations. Finally, we can can even create a 3D visualization where we place the points on an actual sphere that we might move around. However, the slow performance of p5.js might make this difficult with more than a few thousand data points.

Assignment 3 – Generative Art

Concept

Last semester, I was doing my study away in New York and when the semester ended, I decided to travel to the other end of the country to San Francisco, because why not. While I was there, one of the many places on my checklist was the Golden Gate Park. Inside it was a Japanese Tea Garden. It was one of the most aesthetically pleasing and peaceful places I have ever been. One of the many things I really liked about that tea garden were the unique Japanese trees that it had, and so, as a small tribute of remembrance, I tried to make a Japanese tree of my own for this project.

Implementation

I started off by making the basic shapes for the background. I placed the rectangles for the window, pot, sky, wall and circles for the moon. The main part however, were the leaves. To keep it simple, I made a very basic Class for a circular leaf and then went on to add the functions for its movement and appearance. the idea I had was to fill up different clusters of leaves for the tree. I made three clusters or regions of leaves, each having their own set of leaves. The leaves would fall from the clusters in a random fashion and subsequently be deleted from the array when they exit the canvas from the bottom. I also decided it was a good idea to make use of noise for the first time to make the fall seem more natural. So I went on and added noise in the x-direction while making the leave travel downwards simultaneously.

However straightforward this may seem, I encountered quite a few bugs along the way and thankfully managed to resolve them. I will share the significant ones here.

Positioning the Leaves

I started off by creating the x0 and y0 coordinates for the center of the cluster where the leaf object would be. I also specified the clusterWidth and clusterHeight in the leaf’s constructor. The initial position of the leaf was placed randomly in the cluster by selecting a random position in the rectangular area bounded by it:

class Leaf {
  // x0 and y0 specify the center of the cluster of leaves (one of the 3 clusters)
  constructor(x0, y0, clusterWidth, clusterHeight) {
...

Following this, I found out that I had to use a separate variable to store this initial x-position since I was making use of noise in the move() function of the leaf’s class. I couldn’t add the xPos variable to itself to update its value since that would enlarge it too abruptly inside the draw function thanks to the noise() function. It took me quite some while to figure this out as this wasn’t a very straightforward bug, but I eventually got there:

// using a separate variable for the initial position of x since xPos will
    // always be changing in draw() and this will cause abrupt behavior in the
    // leaf's x-movement if used along with noise inside move()

    // positioning initialX, xPos, and yPos within the cluster
    this.initialX = random(x0 - clusterWidth, x0 + clusterWidth);
    this.xPos = random(x0 - clusterWidth, x0 + clusterWidth);
    this.yPos = random(y0 - clusterHeight, y0 + clusterHeight);

...

// for the leaf's falling movement
  move() {
    // only make the leaf fall if the fall attribute of the object is true
    if (this.fall) {
      // giving some noise in the x direction to give a natural feel while falling
      this.xPos = this.initialX + noise(this.xoff) * 100;
      this.xoff += this.xincrement;
      // incrementing y to make the leaf fall vertically
      this.yPos += this.ySpeed;
    }
Removing the Leaves

Since I was keeping a check both on whether a leaf is alive or not and whether it is falling or not, I had to implement both of these concurrently. For instance, if a leaf reached the end of the canvas and it got deleted from the array, the code that randomly chooses a leaf to fall would not know whether the leaf is alive or not and could encounter an empty object. So I added a check for whether the leaf is alive before making it fall and it fixed the bug that I was facing. Moreover, if the leaves[] array becomes empty, the random(0, leaves.length) would return zero and that would cause an error again since the element at index zero doesn’t exist. So I added a check for that as well:

// choosing a random leaf to fall every 20 frames

  // if the leaves[] array becomes empty, it causes an error because the length is 0 but
  // the 0th element doesn't exist anymore so we provide a check for that as well

  if (frameCount % 20 == 0 && leaves.length != 0) {
    // choosing a random leaf index to make it fall from the tree
    index = int(random(0, leaves.length));

    // check if the leaf at the random index is alive and present inside the array
    if (leaves[index].alive) {
      // if yes then make the leaf fall
      leaves[index].fall = true;
    }
  }
Randomizing Leaf Color

At first I tried to do this within the Leaf class itself but then I realized that if I choose the color inside the draw() function of the Leaf class, it would cause the leaf to change color continuously because the draw() function loops continuously. I couldn’t place the array inside the standard draw() function either for the same reason. So I came up with the idea of creating a global array that would store the two leaf colors (shades of purple) and then choose the color inside the attributes of the leaf class as a this.color attribute:

// array which stores the two shades of purple for the leaves
let leafColors = ["#963990", "#4B2454"];

class Leaf {
  // x0 and y0 specify the center of the cluster of leaves (one of the 3 clusters)
  constructor(x0, y0, clusterWidth, clusterHeight) {

...

    // choosing a random shade of purple from the two specified in the global array
    this.color = leafColors[int(random(0, 2))];
  }

...

// drawing the leaf
  draw() {
    noStroke();
    fill(this.color);
    ellipse(this.xPos, this.yPos, this.width, this.height);
  }

Reflection

I feel like I managed to get the kind of aesthetic feel I was going for in this assignment. The color combinations worked really well and the tree stood out within a minimalistic background without being too overwhelming. I went for a kind of peaceful and calm feel and the falling leaves did well to prortray that feeling as well. It was unfortunate that I had to start from scratch after losing progress mid-assignment but gladly I was able to recall the functions I made and how I implemented them. It was disheartening at first but after putting in some extra hours I was able to remake the project exactly how I wanted to in the first place. As for the future, I would definitely like to save my progress often and make the habit of hitting the save shortcut from time-to-time, although it sounds trivial but its something i would definitely like to work on. Excited to see what I can do with transformations for our next assignment!

 

Generative Artwork Bifrost

Concept and Inspiration

In this assignment we had to create a generative artwork using Object-Oriented Programming elements such as arrays and objects. In this project I tried to recreate the mythological rainbow bridge Bifrost.  In Norse mythology, the Bifröst (also known as the Bifrost Bridge or the Rainbow Bridge) is a bridge that connects the realm of the gods Asgard to the mortal world Midgard. The Bifröst is depicted as a rainbow bridge that shimmers and changes colors. The concept of the Bifröst has been influential in works of fiction, inspiring elements of magic and fantasy in various forms of media. I tried to create an immersive experience of traveling using this Bifröst bridge, and tried to depict how it would look like from inside.

Draft 1

First I created a white stars on black background with an immersive movement. After testing out various angles and parameters for speed and size I integrated rainbow background change and increased the speed.

Final Version

In this assignment I paid extra attention to the structure, clarity, and organization of my program. I made use of functions as needed to organize structure of my program and tried to assign meaningful names for variables.

Code of Project

var star = []; // array to store all the stars
var numOfStars = 200; // number of stars to be displayed
var speed = 8; // speed at which stars move
var backgroundHue = 0; // hue value for the background color

// the setup function is called once when the program starts
function setup() {
  createCanvas(600, 400); 
  for (var i = 0; i < numOfStars; i++) {
    star[i] = new Star(); // creates new instances of the Star object and adds them to the star array
  }
}

// the draw function is called repeatedly until the program is stopped
function draw() {
  backgroundHue = (backgroundHue + 1) % 360; // updates the hue value for the background color
  colorMode(HSB); 
  background(backgroundHue, 100, 100); 
  for (var i = 0; i < numOfStars; i++) {
    star[i].update(); // updates the position of each star
    star[i].show(); // displays each star
  }
}

// the Star object constructor
function Star() {
  this.x = random(0, width); 
  this.y = random(0, height); 
  this.z = random(0, width); // z-coordinate for the star (used for the 3D effect)
  this.h = random(0, 360); // hue value for the star color

  // updates the position of the star
  this.update = function () {
    this.z = this.z - speed; // reduces the z-coordinate to move the star towards the viewer
    if (this.z < 1) {
      this.z = width; // if the star goes off the screen, it reappears at the back
      this.x = random(0, width); // new x-coordinate
      this.y = random(0, height); // new y-coordinate
      this.h = random(0, 360); // new hue value
    }
  };

  // displays the star
  this.show = function () {
    noStroke(); // removes the stroke around the star
    colorMode(HSB); 
    fill(this.h, 100, 100); 

    // calculates the x-coordinate and y-coordinate of the star on the screen
    var sx = map(this.x / this.z, 0, 1, 0, width);
    var sy = map(this.y / this.z, 0, 1, 0, height);

    // calculates the size of the star based on its z-coordinate
    var r = map(this.z, 0, width, 32, 0);
    ellipse(sx, sy, r, r); // draws the star as an ellipse
  };
}

Challenges and Improvements

Creating a believable rainbow effect for the stars and the background can be challenging. It requires careful use of color gradients and blending modes to produce the desired visual effect. Another improvement can be made to star movement. Implementing realistic star movement can be difficult, especially when it comes to creating a 3D illusion on a 2D canvas. It’s important to carefully consider the equations used to move the stars, as well as the way they are drawn on the canvas

HW Week 3 – OOP Art in p5js

Inspiration

I had quite an intensive day and one of the fun parts of it was actually solving puzzles and playing games in a pair for one of the student capstone experiments I participated in. One of the games resembled tic-tac-toe for me and I used to love playing it. With the homework assignment based on the use of classes and arrays, I tried to recreate the game in a basic setting using p5js.

The product

I am overall satisfied with the technical aspect of the code but I as look closer at the visual implementation I think it needs a strong improvement here to be somewhat ‘artsy’ at least to a minimal extent. I want to develop it a bit further playing with design and making it more interactive.

Since I thought that just X and O were completely boring, I decided to switch them simply to IM and CS to draw a winner in this friendly ‘competition’ between majors.

Challenges

For me, it was getting used to the implementation of how to apply a function for each cell in p5js. It was a bit confusing since I am more used to retrieving code functions into separate blocks, yet this implementation looks tidier.

this.cells.forEach(function (cell) {
  if (cell.r == r && cell.c == c && 0 == cell.v) {
    cell.t = t;
    if (turn == "IM") {
      cell.v = 1;
    } else {
      cell.v = -1;
    }
  }
});

Summary

I have used 2 classes for the Tic-Tac-Toe game: Board and Player, and I believe this assignment was useful to me in regards to practising OOP code writing. It was also quite a while since my last game implementation, even a basic one like this. The aspect that I think I really need to work on more is the visual representation of the game and making it more creative in the sense of design. Yet, this was a fun and useful experience of implementing.