Ideation / Research
I first started off with wanting to pursue an idea that was artistic but also made sense in terms of its value as data visualization. I personally believe that data visualization is a great way to tell a story and send a message, whether it be sociopolitical or otherwise. First, I had to find a dataset (.csv file) that I wanted to work with. For this, I went to a website called Kaggle which had a bunch of fun and interesting data files for users to download for free. After browsing around for a while, I came across one that had the nutritional information of 80 different cereals, presumably in the US. In another class, I had a discussion with a fellow student who told me that in the US, many food products, despite appearing diverse, are owned by only a handful of companies, essentially being a market full of monopolies. Given that the US prides itself on how democracy fosters free markets, I was surprised to learn that monopolies exist within this system, as they seem to contradict the principles of a free market. To explore this contradiction, I decided to use the cereal.csv dataset to create a visualization that highlights the monopoly in the cereal industry. Each animation and effect is designed with a particular purpose, conveying meaningful insights about this issue.
Process / Code Review
For the cereal nodes, I wanted their colors to reflect their sugar content, making it easy to visually interpret how much sugar each cereal contains. To do this, I used the ‘map()’ function to scale the red intensity based on the sugar level, where low-sugar cereals are black and higher sugar cereals appear redder than black. This creates an intuitive color gradient that emphasizes the nutritional differences between cereals.
for (let cereal of cereals) {
let sugarLevel = cereal.sugar; // scale from 0-15
let redColor = map(sugarLevel, 0, 15, 0, 255); // more sugar = more red
fill(redColor, 50, 50); // red tones based on sugar content
ellipse(cereal.x, cereal.y, 10, 10);
for (let cereal of cereals) {
let sugarLevel = cereal.sugar; // scale from 0-15
let redColor = map(sugarLevel, 0, 15, 0, 255); // more sugar = more red
fill(redColor, 50, 50); // red tones based on sugar content
ellipse(cereal.x, cereal.y, 10, 10);
}
}
for (let cereal of cereals) {
let sugarLevel = cereal.sugar; // scale from 0-15
let redColor = map(sugarLevel, 0, 15, 0, 255); // more sugar = more red
fill(redColor, 50, 50); // red tones based on sugar content
ellipse(cereal.x, cereal.y, 10, 10);
}
}
To connect each cereal to its parent company, I created animated lines that gradually extend from the manufacturer to each cereal. Instead of appearing all at once, the lines animate over time, emphasizing the idea of hidden connections between brands that aren’t immediately obvious.
animationProgress = min(animationProgress + 0.02, 1);
// drawing animated connections
for (let link of links) {
let midX = lerp(link.start.x, link.end.x, animationProgress);
let midY = lerp(link.start.y, link.end.y, animationProgress);
line(link.start.x, link.start.y, midX, midY);
animationProgress = min(animationProgress + 0.02, 1);
// drawing animated connections
stroke(0, 0, 0, 100);
for (let link of links) {
let midX = lerp(link.start.x, link.end.x, animationProgress);
let midY = lerp(link.start.y, link.end.y, animationProgress);
line(link.start.x, link.start.y, midX, midY);
}
animationProgress = min(animationProgress + 0.02, 1);
// drawing animated connections
stroke(0, 0, 0, 100);
for (let link of links) {
let midX = lerp(link.start.x, link.end.x, animationProgress);
let midY = lerp(link.start.y, link.end.y, animationProgress);
line(link.start.x, link.start.y, midX, midY);
}
Finally, I added subtle movement to the cereal nodes. Each one has a slight floating effect, created by modifying its x and y positions with sine and cosine functions. This gives the visualization a dynamic, organic feel rather than a static diagram. The manufacturers remain fixed, symbolizing their stronghold over the market, while the cereals drift slightly, reinforcing the idea that individual brands may seem independent but ultimately remain tied to their parent companies.
// floating effect for cereals
for (let cereal of cereals) {
cereal.x += sin(frameCount * 0.01 + cereal.offset) * 0.5;
cereal.y += cos(frameCount * 0.01 + cereal.offset) * 0.5;
// floating effect for cereals
for (let cereal of cereals) {
cereal.x += sin(frameCount * 0.01 + cereal.offset) * 0.5;
cereal.y += cos(frameCount * 0.01 + cereal.offset) * 0.5;
}
// floating effect for cereals
for (let cereal of cereals) {
cereal.x += sin(frameCount * 0.01 + cereal.offset) * 0.5;
cereal.y += cos(frameCount * 0.01 + cereal.offset) * 0.5;
}
+ Additionally, when hovering over a manufacturer, its abbreviated initials expand to reveal the full company name. This design choice symbolizes how large corporations often remain anonymous at first glance, its domineering presence only becoming recognizable when we, as consumers, dig deeper.
Reflection
Surprisingly, the hardest part of this assignment was actually loading and properly parsing the csv file. As you can also see in the code, there’s a good amount of debugging that for the csv file. Initially I had use ‘loadString()’, however, I quickly realized that ‘loadString()’ treats the CSV as a single string rather than structured data, making it difficult to extract individual values. To fix this, I switched to ‘loadTable()’ with the “csv” and “header” options enabled, which allowed me to access data in a more organized way using column names. Even after switching to “loadTable()”, I ran into issues where some rows had missing or improperly formatted values. To handle this, I added debugging statements, such as console.log(table.columns); to check the structure and console.warn() messages to flag any problematic rows. I also included a check for undefined or null manufacturer values to prevent errors from breaking the program. Overall, I think I really enjoyed doing this project because I felt like I was able to incorporate a lot of meaning into it. Through the process, I realized that I particularly find interest in embedding social commentary in my works. I think adding a bit more interactivity could be the next step.
Final Work