assignment 4: loading text

Initially, I wanted to make a nice data visualization, but by my standards, it would only be cool if the data was live. There’s little glamour in loading a CSV file — even Excel can do that. However, I really struggled to find a free API that lets you make bulk requests, and I couldn’t get around the request limit without paying for it. I settled for a project on loading/displaying text, and came up with my alphabet soup idea.

I tried creating a bowl of p5 alphabet soup, which lets you add new letters by typing on your keyboard. The alphabets all float randomly on the canvas, but they can bunch together if you haven’t pressed space. When they hit space, the bunch is ‘complete’, and the next time the user types, a new bunch is created. Under the hood, each bunch is just an array of “Letter” objects, each of which have their own position and speed. At the end of every array, there’s an invisible space, which I’m moving across the screen, and all the letters simply follow the next letter in the array. A little Perlin noise and rotation is used to simulate some turbulence in the liquid.

Additionally, the user can also use the mouse to scramble the letters on the screen. If the pointer is too close to a certain Letter, the Letter is separated from the bunch and it will go on moving independently. Whether the Letter was in the active bunch or an already completed bunch, it will be extracted from its array and added to a different one called floatingLetters. In this array, all the Letter objects are always moving around randomly. Letters in this array can also be scrambled — the user just has to hover the pointer near a Letter.

The logic to make the letters bunch together was a little tricky to pin down, and a bunch in this context wasn’t really like a boid. They have to (loosely) maintain a left to right order, and that depends on which direction they’re moving in. I eventually took the gradient (speed differential) of the last letter in the array, and made the rest of the letters arrange themselves accordingly. For example, if the next Letter is moving down and right, the current Letter will be drawn slightly to the left and up. If the next Letter is moving up and right, the current Letter will be drawn slightly to the left and below, and so on. There are four such cases.

calculateNewPosition(nextX, nextY, nextSpeedX, nextSpeedY) {
    this.rotation += noise(this.x * 0.01, this.y * 0.01) * 0.01;
    if (nextSpeedX > 0 && nextSpeedY > 0) {
      this.updatePosition(
        nextX - 30 + noise(xOff) * 20,
        nextY + noise(yOff) * 20
      );
    }
    if (nextSpeedX > 0 && nextSpeedY < 0) {
      this.updatePosition(
        nextX - 30 + noise(xOff) * 5,
        nextY + 30 + noise(yOff) * 5
      );
    }
    if (nextSpeedX < 0 && nextSpeedY < 0) {
      this.updatePosition(
        nextX + 30 + noise(xOff) * 5,
        nextY + 30 + noise(yOff) * 5
      );
    }
    if (nextSpeedX < 0 && nextSpeedY > 0) {
      this.updatePosition(
        nextX + 30 + noise(xOff) * 5,
        nextY - 30 + noise(yOff) * 5
      );
    }
  }

This is the final sketch:

I used a font that resembles the letters in alphabet soup, and each letter also has a shadow. In real soup, letters are always going above and below the surface of the liquid, which makes sometimes makes look smaller, fainter. I think I could make this more realistic if I added varying opacity to each letter. If the Letter objects randomly had a lower opacity, it would look like they were drowning a little.

reading reflection: week 4

Dan Norman takes a strictly humanistic stance in the opening of his book, which can be summed up nicely in this one line from the chapter: “It is the duty of machines and those who design them to understand people. It is not our duty to understand the arbitrary, meaningless dictates of machines.” His ideas are well informed and drawn from experience in both engineering and cognitive science, and I do in fact agree with him on the subject of the gap between designers’ faith in users who are willing to trial and error, and the very limited size of such a user base. Most people do really just want to get on with whatever they’re doing. However, the same people also want things to look nice. For example, almost all of us care about the aesthetic qualities of appliances we put in our homes. There’s people like the English couple mentioned in the book with the fancy washing machine, who don’t bother to learn about the machine’s functions but still keep the high-tech appliance around probably because it just looks nicer.

Another interesting case study would be SMEG, a home appliance company with a focus on design. They consistently get a bad rap for the poor quality of their products, which are simply not good investments. Yet, SMEG remains immensely popular, and consumer behavior shows that people are willing to pay much more for an appliance, be it of poorer quality, for something that just looks nice. Thus, I have this lingering question for Dan Norman: “so what?” Humans were born into an unbending, mystifying nature. But people still made it work, weaved clothes from flowers of cotton and learned to bake bread from grains. Now, is a washing machine with one too many functions really going to the nemesis to human development? Are we expected to be so lazy that reading a device manual becomes too much to ask? I’m really not talking about bad design — if I have to struggle to read text on a website in an avant-garde font, maybe that’s a design choice worth reevaluating. But some pretty doors that blend into a building’s facade, which can be swung open by pushing on either one of just two ends, shouldn’t really be that much of a headache to most people, considering once you’ve taken a minute to figure out which end to push, you can forever go on enjoying the nice design of a normally functioning door.

Week 4- Reading reflection The design of everyday things

When I find a door that doesn’t work or a machine acting strangely, I often joke with my mom that maybe the person who made it learned everything online. I really liked how this text talks about the hidden problems with everyday things, how we use machines, and why it’s important to make technology that works well with people, not the other way around.

In fact, this text got me thinking about making things we use every day easier for everyone. For example, let’s talk about SIRI. I get annoyed that I have to change my way of speaking just to make it understand me. I think it should understand English no matter how I speak it. And if I struggle with this, I can imagine how tough it must be for someone with a speech problem. SIRI is supposed to help us, but it doesn’t always do a good job.

When we make machines and stuff, it’s not just about how they look or how fancy they are. We learned this from what happened at Three Mile Island. At first, they blamed the people working there for the problems, saying it was their fault. But then, Don Norman and other experts looked into it more and found that it was also because the machines were hard to understand and use.

Personally, I find it interesting how Don Norman changed from being an engineer who cared mostly about technical stuff to someone who saw how important it is to understand how people think and act when designing things. His journey is really fascinating.

Reading reflection – Week #4

Norman’s book, “The Design of Everyday Things,” is a seminal work in the field of design. It provides core ideas that are applied in all design fields, UI and UX design being no exception as it relates more to our class. As I was reading I was reflecting on how Norman’s ideas could be applied to digital design, especially his thoughts about feedback, mapping, and emotional design.

Norman emphasizes the importance of providing clear and immediate feedback to users. In case of digital design, I believe that feedback is especially crucial. Unlike various everyday physical objects, computers appear like black boxes to many of the users and thus communication between the user and the interface is important. Thus, In UI/UX design, feedback is essential to inform users about the outcomes of their actions. Visual cues, animations, and messages should help users comprehend the cause-and-effect relationship of their interactions with the system.

Like anywhere, mapping in digital design is about creating a clear and intuitive connection between user interface elements (controls) and their corresponding actions or functions. This idea made me think how mapping is performed in the virtual space. Here consistency plays a huge role, for instance consistent iconography or color schemes for buttons that perform similar functions such as save, delete, submit. The physical or spatial arrangement of such controls also conforms to user’s expectations and mental models of applications or websites, and working together with feedback results in smooth operations.

Another key thought in the reading that I think is important in digital design is emotional design. Emotional design in UI/UX goes beyond aesthetics and usability; it is about creating interfaces that emotionally connect with users. One brand that comes to mind as a great example is Apple, who’s success can be attributed to its mastery of emotional design in UI/UX. Their products and interfaces go beyond mere functionality; they create products with sense of elegance and sophistication, evoking positive emotions such as admiration and desire. They consistently strive for user experience that focuses on simplicity and intuitiveness, making their users feel empowered and in control. The minimalist aesthetic, friendly interfaces and consistency along their different product define the brand’s identity. This quality generates a strong emotional connection with people, who frequently identify with Apple’s ideals and lifestyle.

Week 3 – OOP

For the week 3 assignment I decided to inspire myself with the magical concept of “sigils”, a type of symbol used to represent the signature of deities or manifestations. Each time the sketch is executed, a new one is generated with random circles and lines. The code was also based on one of the examples we saw in class.

Week 4 – Audio Visualizer!

For this week’s assignment, I decided to create an audio visualizer using p5.js, exploring both data visualization and generative text. I chose one of my all-time favorite songs for this assignment because it’s filled with diverse sound effects and beats, making it perfect for visualization. This visualizer represents the audio’s amplitude as dynamic circles. Louder beats create larger and more distant circles, and the lyrics sync with the audio, causing more circles when the lyrics begin. I learnt a lot of new functions and concepts in the process of making the following.

Concept
It uses Fast Fourier Transform (FFT) analysis to break down the audio signal into its frequency components. These components are then represented as circles on the canvas. The amplitude of each frequency band determines the size and color of the corresponding circle. The analyze() returns a spectrum array of amplitude values at each.  point.

Sketch

Click anywhere to begin!

 (The interlude that comes after the chorus is particularly interesting to observe, as the amplitude and beats vary significantly.)

Favorite parts of code

While the way this visualizer turned out makes me happy, my favorite part of this, (and my main struggle) was working with the text. I used a csv file I found online with timestamps for each line in the lyrics and then tried to display the lyrics accordingly by first converting the string to time, calculating the next Timestamp and adding color gradients to make it visually match. 

function displayLyric() {
  // check if there are lyrics data and if the current lyrics index is within the length of file
  if (lyricsData.length > 0 && currentLyricIndex < lyricsData.length) {
    // check if the song is playing and the current audio time exceeds the nextLyricTime
    if (song.isPlaying() && song.currentTime() >= nextLyricTime) {
      // display the lyric text for the current index with animation
      let lyricText = lyricsData[currentLyricIndex].split("]")[1];
      
      // calculating the lerp amount based on lyricTextOpacity for text animation
      let lerpAmount = lyricTextOpacity/255;

      let lerpedColor = lerpColor(color(255, 100, 100), color(100, 100, 255), lerpAmount);

    
      fill(lerpedColor);
      text(lyricText, width / 2, height / 2);
      lyricTextOpacity = 255;
      
      // move to the next lyric
      currentLyricIndex++;

      // updating nextLyricTime with the timestamp of the next lyric 
      if (currentLyricIndex < lyricsData.length) {
        let nextTimestamp = lyricsData[currentLyricIndex].split("]")[0].substring(1);
        nextLyricTime = convertTimestampToSeconds(nextTimestamp);
      }
    } else {
      // if the song is not at the next lyric yet, continue displaying the text
      if (lyricTextOpacity > 0) {
        let lyricText = lyricsData[currentLyricIndex - 1].split("]")[1];
        
        // decrease text opacity
        lyricTextOpacity -= 2;
        
        let lerpAmount = lyricTextOpacity / 255;
        let lerpedColor = lerpColor(color(255, 100, 100), color(100, 100, 255), lerpAmount);
        fill(lerpedColor);
        text(lyricText, width / 2, height / 2);
      }
    }
  }
}

It looked different earlier when I had the angle mode set to degrees but when I accidentally commented it out and tried to run it, it looked prettier and more effective. This is how it looked with the angled mode set to degrees.

Reflections and future Improvements

I learnt many new functions and found this assignment quite fun as I listened to the same song a million times. For future improvements, maybe I can make this interactive by adding multiple audios and having a click option where the users can choose the audio they want to be visualized. I can also try adding more animation to the text like creating a falling or a popout effect.

References

Tutorials: https://www.youtube.com/watch?v=uk96O7N1Yo0, https://www.youtube.com/watch?v=2O3nm0Nvbi4

Lyrics timestamps: https://www.megalobiz.com/lrc/maker/Something+just+like+this.54445587

Audio:https://www.youtube.com/watch?v=FM7MFYoylVs

Coding Assignment – Week #4

For this week’s assignment I wanted to create a sketch that would be responsive to audio. From the beginning, I knew that I wanted to use a piece of classical music and utilize amplitude to visualize the music. I wanted to recreate a low-fidelity feeling of something like this:

Here is my sketch (open in a separate tab for the sound):

 The p5.js library is used in this project to build an audio-driven visual representation. The Particle class is in charge of creating particles with certain properties such as position, angle, speed, and radius. The amplitude of the Orchestral Suite by Johann Sebastian Bach is utilized to modify the speed and angle of the particle. When the audio amplitude exceeds a predetermined threshold, the particles vary their angle and radius, resulting in visually unique behavior. Furthermore, boundary checks are used to verify that particles do not bounce off the canvas’s edges. The primary program generates a grid of tiny particles and dynamically draws lines between them, resulting in a complicated, developing visual pattern.

This project was a good opportunity to learn about the sound library. Here some crucial lines:

this.amp = new p5.Amplitude();
// and
let vol = this.amp.getLevel();

The p5.Amplitude class is part of the p5.js sound package and allows to measure the amplitude or loudness of audio in real-time. By creating this instance, the sketch has the capacity to evaluate and respond to the dynamics of the audio. The getLevel() function of the p5.Amplitude object (this.amp) gets the current audio amplitude level.  This value changes while the audio plays, offering a dynamic indicator of the intensity of the song.

Another part of the code that I was proud of was the drawing of the lines between particles:

  // looping through all the particles
  for (let i = 0; i < particles.length; i++) {
    let particleA = particles[i];
    particleA.update();
    particleA.display();

    // initializing an inner loop to compare the current particle to other particles and calculating distances
    for (let j = i + 1; j < particles.length; j++) {
      let particleB = particles[j];
      let distance = dist(
        particleA.position.x,
        particleA.position.y,
        particleB.position.x,
        particleB.position.y
      );

      // drawing a line between particles that are closer than 100 pixels
      if (distance < 100) {
        line(
          particleA.position.x,
          particleA.position.y,
          particleB.position.x,
          particleB.position.y
        );
      }
    }
  }
}

This is a very simple principle, where basically every particle in the outer loop is compared to all the other particles by looping through them in the inner loop. It was quite a basic structure but it allowed for of the main effects in the sketch.

Ideas for future improvements would be performance optimization, especially when dealing with a large number of particles. The audio tended to become messy once I would initialize more particles (sometimes it can be heard even in the current sketch). I would also like to introduce different types of particles with varying behaviors, for example, some particles could respond to bass frequencies, while others react to treble.

Data Visualization Assignment

Overview:

I have an unhealthy obsessions with Postcards, specially those that carry a very Edgy-vintage design that looks like they were made using Paint 🙂 and since the 1st of October coincides with the World Postcard day I have decided to create a non commissioned postcards to my favorited museum ever the MoMA (Museum of Modern Arts). 

I went on Kaggle and found a dataset of with LITERALLY ( 67695 ) of MoMa artist so thought first of distinguishing the non American artist with the color grey to emphasize on the global domain of the MoMa and the scattered the name of the artist all over the screen, and then I printed at the Middle of the screen postcards from MoMA.

So the Data Visualization part is that this code distinguishes the American from the Non American Artist visually by color. which If I would have thought of creating this postcards by hand would have been a nightmare for me as a designer wen I have a dataset of 67695 artists 🙂

Embedded sketch:

Mockup Rendering:

 

 

 

 

 

 

 

Highlight of the code I am proud of:

This was my first time I work with Dataset and it wasn’t easy at all. So I guess I am proud of my logic of distinguishing the artists Nationality.

// Define the box parameters
 let boxX = 50;
 let boxY = 50;
 let boxWidth = width - 2 * boxX;
 let boxHeight = height - 2 * boxY;

 // Extract artist data from the CSV
 for (let i = 0; i < table.getRowCount(); i++) {
   let row = table.getRow(i);
   let artistName = row.get('Name');
   let nationality = row.get('Nationality');
   let status = row.get('Status');

   if (artistName && nationality) {
     artistData.push({ name: artistName, nationality, status, x: 0, y: 0 });
   }
 }

The above code defines the parameters for a rectangular “box” on a canvas, specifying its position and dimensions. It then iterates through rows of a CSV file, extracting artist data such as name, nationality, and status. If both the name and nationality exist, this data is stored in an object and added to the artistData array. This process prepares the artist data for subsequent display within the specified box on the canvas.

Reflection:

This was my hardest Assignment yet as that finding a dataset and thinking of an idea to model the dataset was not easy at all however, I am very happy with the end result as that If I found that on the shelf of the MoMA I would love to have that postcards that keeps all the names of the artist I was impressed by their work closer to me, so that I would take the opportunity to google the artist that my eye falls into. And I am writing an email to MoMA perhaps they are interested to take this into their postcards collection :0.

Future improvements: 

If I would have attempted this assignment once again I would:

  • Enhanced User Interaction: The inclusion of interactive elements, such as mouse-based actions or keyboard input, can empower users to explore the artist data interactively. This might involve enabling users to filter artists based on specific criteria or offering additional information upon clicking an artist’s name.
  • Responsive Design: Implementing a responsive design approach ensures that the project can adapt seamlessly to various screen dimensions and orientations, guaranteeing an optimal user experience across different devices.
  • Informational Overlays: Providing informative overlays or tooltips that furnish users with supplementary details about each artist when they hover over or click on an artist’s name can enhance the user’s understanding of the data.
  • Dynamic Animations: The addition of fluid animations for transitions, color alterations, and text movements injects dynamism into the visualization, thereby engaging users more effectively.
  • Search Functionality: Incorporating a search feature empowers users to search for particular artists or filter data based on various attributes, thereby enhancing usability.
  • Sorting Mechanisms: Offering sorting options for the artist list, permitting users to sort by attributes such as name, nationality, or status, enhances the user’s ability to explore and comprehend the data.
  • Data Updates: By enabling real-time data updates through either connecting to a live dataset or facilitating the upload of new CSV files, the project can remain current and relevant.

code:

//Batool Al Tameemi, Intro To Im 
//Assignment 5: Datasets and visualization 
let table; // Declare a variable to hold the CSV data
let artistData = []; // Initialize an array to store artist data

function preload() {
  // Load your CSV file
  table = loadTable('artists.csv', 'csv', 'header');
}

function setup() {
  createCanvas(800, 600);
  noLoop();

  // Define the box parameters
  let boxX = 50;
  let boxY = 50;
  let boxWidth = width - 2 * boxX;
  let boxHeight = height - 2 * boxY;

  // Extract artist data from the CSV
  for (let i = 0; i < table.getRowCount(); i++) {
    let row = table.getRow(i);
    let artistName = row.get('Name');
    let nationality = row.get('Nationality');
    let status = row.get('Status');

    if (artistName && nationality) {
      artistData.push({ name: artistName, nationality, status, x: 0, y: 0 });
    }
  }

  // Draw a box
  noFill();
  stroke(0);
  rect(boxX, boxY, boxWidth, boxHeight);

  // Display artist names with the specified conditions
  textSize(12);
  textAlign(LEFT, TOP);

  for (let artist of artistData) {
    let x = random(boxX, boxX + boxWidth - textWidth(artist.name));
    let y = random(boxY, boxY + boxHeight - textAscent());

    // Check for overlap with existing text
    let overlapping = false;
    for (let existing of artistData) {
      if (artist !== existing) {
        let d = dist(x, y, existing.x, existing.y);
        if (d < 20) {
          overlapping = true;
          break;
        }
      }
    }

    // Set text color based on conditions
    if (artist.nationality !== 'American') {
      fill(192, 192, 192); // Silver
    } else if (artist.status === 'Dead') {
      fill(255, 215, 0); // Gold
    } else {
      fill(0); // Default text color
    }

    // If not overlapping, display the text
    if (!overlapping) {
      text(artist.name, x, y);
      artist.x = x;
      artist.y = y;
    }
  }

}



function draw() {
 textSize(30);
  textAlign(CENTER, CENTER);
  fill(random(0,255)); // Set text color to black

  // Set the built-in font
  textFont("Georgia"); 
  stroke(color(255));
  // Calculate the center of the canvas
 let centerX = width / 2;
  let centerY = height / 2;

  // Use frameCount to create a continuously changing color
  let hue = (frameCount * 2) % 360; // Adjust the factor for color speed
  let textColor = color(0);
  fill(textColor);

  // Display the text at the center of the screen
  text("Postcards from ", centerX, centerY - 90);
  textSize(160);
  text("MoMA", centerX, centerY);


}

 

Week 4- Data Visualization

The World’s Best Countries For Women, 2021

My concept: While scrolling through Kaggle, I found an article with an interesting title “The World’s Best Countries For Women”. I wanted to know the ranking of the countries and on which categories they were assessed such as women’s employability, women’s rights, women’s literacy rate, etc. Although the article doesn’t exhaustively describe these aspects, the visualization of this data was particularly interesting for me. I have been inspired by the image attached below in Fig. 1, meaning that the circles representing the countries needed to align on a circular path. Additionally, the circles should demonstrate a visible differentiation of the score of the overall assessment of each country’s performance, which could be achieved by the different radius of circles corresponding to the specific countries: the higher the score, the bigger the radius. During the coding, I decided to give a more interesting shape for the data visualization, so the circles would be in a more spiral path. Last but not least, the array of the shades of the purple colors was created because it is believed that purple is a color of feminism. I wanted to raise awareness of women’s conditions and opportunities in different countries through this data visualization. 

Fig 1. The data visualization I was inspired by.

A highlight of the code I am proud of is the for loop because it incorporates many functions and steps such as naming each variable in the data set, giving the size of circles to corresponding countries based on score, and the path of the spiral path according to the ranking. More specifically, I am proud of the function of the x and y coordinates of each circle because the formula used for that creates a perfectly drawn 2D spiral path I was looking for. 

 for(let r=0; r<table.getRowCount();r++) {
    const name = table.getString(r, "Country");
    const rank= table.getNum(r, "Rank");
    const score = table.getNum(r, "Score");
//calculating the positions x, y of the ellipses based on the rank of each country.
    const x = 2*(180-rank)*cos(rank*5)+width/2;
    const y = 2*(180-rank)*sin(rank*5)+height/2;
//scaling the score range of (0,100) to fit the range of (0, 30) to control the size of the ellipses, so they could fit the canva.
    const scoremap = map(score, 0, 100, 0, 30);
    ellipse(x, y, scoremap);
    fill(0);

//calculating the positions of x, y of the names of the countries  based on the rank of each country.
    let xtext=2.5*(180-rank)*cos(rank*5)+width/2-19;
    let ytext=2.5*(180-rank)*sin(rank*5)+height/2;
//changing the x position of the names of the countries to specific countries in order to avoid overlapping of the names with the ellipses.
    if (rank>=97 && rank<=116){
      xtext = 2.5*(180-rank)*cos(rank*5)+width/2-35; 
    }
    if (rank>=136) {
      xtext = 2.5*(180-rank)*cos(rank*5)+width/2+5;
    }
//checking the distance between the mouse and the ellipse. 
    let d = dist(mouseX, mouseY, x, y);
//if the mouse is on the ellipse, the name of the country and the ellipse corresponding to that country is filled is orange color. 
  if (d < scoremap/2) {
    fill(255, 95, 31);
    text(name, xtext, ytext);
    ellipse(x, y, scoremap);
  } else {
    fill(0);
    text(name, xtext, ytext);
    fill(random(colors));
    ellipse(x, y, scoremap);
    }
  }

Embedded sketch

MOVE YOUR MOUSE OVER ANY CIRCLE TO SEE WHICH COUNTRY IS REPRESENTED

Reflection and ideas for future work or improvements: Because of the small distance between the countries, some of the names overlap. Hence, it is better to resize the canvas or make the changes in a space for each of the country names so that one is closer to the circle, while the other is a bit in a distance. Additionally, for aesthetic purposes, it would be great to add more details to the sketch such as Perlin noise which appears when the mouse is clicked, or the line of the small circles going from the country circles to the center.

Week 4 | Data Visualization Assignment

The Concept:
For this assignment, I want to do a data visualization sketch. After looking for various data sets and APIs, I decided to choose some data that relates to a personal interest. I decided to create a data visualization of 2016 world’s top 100 football players voting that chooses the best player of the world. It was really interesting to read some of this data as I never know these variations in voting and what makes it more interesting is that Ronaldo, my favorite player, was the best player in that year.

Code Highlight:
I am proud of this part of the code, mapping the voting values to the width o the bar corresponding to the value and increasing the width of the bar at the begging of the sketch display. The concept of mapping is very useful in many ways I have tried while figuring out how to draw the bars.

Sketch:
Reflection and ideas for future work or improvements:
I liked that he sketch effectively introduces a dynamic bar expansion effect, engaging viewers from the start. However, further improvements could involve adding smooth animations for a more visual transition. Additionally, considering user interactivity, such as mouse interactions for control, could enhance user engagement and exploration of the data.