Final Project: Check Jane’s Delivery Orders & Self-Reflection

Final Project Outline

I had thought of many ideas such as the stock prices visualization or construction of a physical staff by laser cutter before my final idea was confirmed, which was an extended project of my midterm.But the data illustrated for final project was completely from the one in the midterm project which demonstrated delivery platform, money, and discount. This project aimed to display the data from my personal delivery orders: location of restaurants, routes from the restaurants to NYU Shanghai, categories of orders, and time of orders. I am a kind of person who depends on delivery a great deal. Before final week, I had already made more than one hundred deliver orders ranging from bubble tea to Thai foods, where a lot of interesting properties appeared, for example, the type of food I favored most and ordered at the specific time and the time that I was likeliest to make an order. The visualization explored these properties of my orders made from both Eleme and Meituan during this semester(Sep.1 – Dec.1), which can be easily recognized through ignoring some minor information such as the name of a business and the date of order. In order to practice P5.JS and the use of API to have a better understanding of programming, I used P5.JS, Mapbox, and API to construct my final project.

Data Collection and Processing  

Initially, I intended to use Meituan and Eleme API to obtain my order information by using Node.js (Tutorial is here, However, the open Meituan Waimai Platform was only available to owners of business who update their business license, and Eleme Platform was not found. Thus, I manually extracted more than one hundred data from my order history to Excel sheet, including data, time, name of a restaurant and the link of restaurant page. Then, I put the address of each restaurant copied from the business page in Google Map to get the position in terms of latitude and longitude.

<Part of orders: Eleme & Meituan>


<Part of orders:Processed Excel sheet >


First, I only used the position as for the object’s property. Based on the location drawing model taught in class, I made the basic model that single point was drawn automatically one by one in the way that objects were listed in JSON file. Since the routes were overlapped if got from Mapbox API, I used the property of transparency to emphasize the frequency of orders I made.

To differentiate types of food, different colors are used to draw the routes from different locations. The way to realize in coding was to add the value of r, g, b to each object. But because of the diversity of the food, I generalized six categories of all food I ordered this semester: Bubble tea and desserts, BBQ and deeply fried food, Hot hot hot, Thai, Cantonese, and Korean food (because they are all meal with rice), Xiaolongbao & pizza (because they are kind of snacks which can be eaten while other things can be done), and noodles (because I ordered rice noodles a lot). Then I made some color by Adobe Kular, got the r, g, b value of each category and added the properties to JSON file. Modifying the JSON with more than one hundred objects directly was extremely troublesome, thus I added r, g, b value in CSV and converted CSV file to JSON by this website (






Visualization and Adjustment 

Tool: P5.JS, Mapbox, Mapbox API

Coding Basic:

  • Three functions: animateRoute(moving), drawRoute(done); drawCircle
  • Preload JSON, and get properties from an array, convert the
  • Animation: using percentage of drawing a route in terms of frame count
  • Build mapbox function to use the style and token and to set the center and zoom level
  • Use API to get the route based on two locations
  • Set a 24 hour timer based on milins(), and convert the string (time in JSON) to value by split function, and compare two values.


  • Add description of each color and title
  • Add timer and time I ordered
  • Modify the map by setting a dark style, deleting unrelated information such as streets, bridges and so on, inserting the NYU Shanghai logo to present the destination
  • Add effects of flicker and sound effect  to the drawing route

Need refinement:

  • The speed of loading JSON data does not match the speed of timer
  • The sound is noisy when routes are intensively drawing

begin end


Self – Reflection 

To be honest, I learned a lot from this class in programming skills, the concept of visualization in an effective and aesthetic way. However, the aesthetic attitude is not only limited in the class or materials, but life, instead, just as we explored fonts in our surroundings. The most important things I learnt are observation and extraction. I feel like every time I meet a great deal of information, I can somehow form a realization of extracting the one and presenting it in an effective way. The idea of deletion is very important from Envisioning Information If you can’t present data in a way that communicates your thoughts or the emergent information, there is no reason to present these data.

Also, P5.JS is a useful tool to present data, especially a lot of data with many  properties. GUI.js, and mapbox are very helpful when using P5.js to make some extended projects. In addition, loading JSON file, using node.js and rita.js, making brush to draw, downloading SVG file, visualizing sound, processing image and using API enrich my knowledge of coding with processing data.



The Final Project: One Two Three Four, Kevin Ni (Nb)

This is the documentation for the final project for the course Generating and Expressing Data taught by Professor XY.

Thoughts upon this project
I usually begin my documentation with the description of the technologies. However, I would like to take advance the thoughts part, and talk about the ideals first.

This project comes from the mid-term assignment where I basically collected all the code I had written before and ran some analysis upon the code to reveal the change of their relative abundance through time. I wasn’t really thinking of anything grave of serious that I should like to see conveyed through it. It was, to be honest, more of a remark of personal history and experience than an shout-out towards the larger audience.

Before I began working on the final project, I decided that I needed a clear outline of what this project was intended to say to people so that they would not get confused staring at it, having not the slightest hint barring the ever-scrolling lines of code on the screen. I thought for some time and came up to this point where I believed putting together the cold-blooeded, unfeeling yet unknown words and the readable, apprehendible and alive scription of what this code is for, could be giving them a mixed sense of technologies, in reflection of the mixed attitude of modern people towards the convenience technolgies have brought them and yet the repelling reluntance to accept technologies as an essential part of their life.

This being said, the initial thought of having multiple displays lying in a row, in pursuit of a visual impact remains unchanged.

The program part is written on the base of the mid-term one, but ported from Processing to p5.js for better cross-platform compatibility, considering that mobile phones were at first, included as a part of the show. New source code generated during the period of the second half of the semester is processes with the same principle and ran the same analysis. Wikipedia and other second-hand source of introduction of the language is collected by a bot and cleared of unnecessary format and noise. Comments restored from the source code that remains a somehow complete structure are also added in between the introduction, though in a rather small number.

There major technology difficulty is porting the program onto p5.js. Most part of the code worked well and required little modification, whilst the one subsystem in relation with HiDPI (aka. Retina on Apple computers) which offers a general solution for displays with various native resolution, especially those with very high ones, such as 4K. p5.js did not, as observed, support a scale factor that is not integral. In other words, scale factor such as 125% and 150% was (and still is) not supported. The solution is choose from the closest integer either one and then zoom the page in the browser to make the visible area meet the up/downscaled resolution in p5.js.

The Text-to-Speech part did not take up much attention for that there had already been a standard called Web Speech API serving such use. It could be found on the Mozilla Developers’ Network and offered a detailed documentation on its application. Google Chrome took the advantage of its own private translation service and provides with the Web Speech API a lot more choices other than the ones coming with the local system. That was the most important reason for choosing it.

The Show
So in case that the audience still didn’t get my point, I wrote a brief note and placed it at the left of the stall, in the hope that the words could offer them some assistance understanding the project.

Photos coming soon.

Final project: Bardentity

(Image to be updated)

For my final project, I started with one of my favorite things in the world, eating. After many iteration and communication with professor, it evolves to my final project “Bardentity”, which is more convincing and makes more sense.

I started with some scattered ideas such as “the sound of eating chips is great”, “ASMR should be cool”, “it need to be interactive”, “people would love me if they can take something with them from my project”, and “I want to use the laser cutter”. They are all about how I want to present my data, but I forgot to think about the data that I’m look into.

It became quite far-fetched to pull those ideas together. My first version of project was asking people to bite into a type of food and generate a soundwave, making a poster of the soundwaves, a paper sculpture of the soundwaves or etch the soundwave to the food itself. It is purely formalistic and blurred in what message to convey.

Thanks to the time constraints, I narrowed it down to biting chips and generate soundwave. Label printer was added but again, it is formalistic. Addition or removal of a label printer didn’t improve or deteriorate my concept at all. I worked on this project for quite a long time. And noticed that I’m working towards a wrong direction after a talk with Professor Feng.

He questioned my weakest link in the project, which is the huge gap between biting a chip and identity. I didn’t get my focus clear, since there are so many things better represent human identity than biting a chip, why I chose this to be my project. I was into eating but rather than adding everything I like into the project; it is more crucial to work towards a clear direction.

After being questioned and questioning myself, I came up with the final concept of Bardentity. Eating is a primary activity of everyone, and everyone has different chewing pattern or eating habit. To present this difference, I chose to record the sound of eating. To enlarge the sound, I chose chip as a media since its sound is crunchy and loud. It actually doesn’t matter what to eat. To make the difference of sound easy to be observed, I decided to visualize the soundwave. Since I want to make it a representative of each person, I made it into a barcode label, just like the one stick on product in the supermarket.

I started my interface on P5 and the printing code on processing. Tons of thanks to Professor Feng for the memobird printer’s code. The user flow is put one’s name in, click button to start recording and click button to stop. It generates a barcode and download to my processing data folder inside of my dropbox folder. Thanks to AJ’s idea of using IFTTT to connect Dropbox and Tumblr, the barcodes are automatically sync to Bardentity’s Tumblr page. Then the user put the name in the processing input box to prnt the label out.

Looking back to the evolution if my concept, I noticed that the deviation of my focus is somewhat due to my weakness in skill base. I’m thinking about different forms all the time because I tried them little before. Lack of practice makes me curious about every new form of presentation, which distract me from the core of my project. When I started a project, I was thinking about what new type of skill I can use, rather than what message I want to convey, or what data I want to look into. It’s a misunderstanding of after-class practice and final project. Fortunately, I was able to turn back onto the right track at the last minute on this project, though it still sounds a little far-fetched and looks like finding reasons for what I do. It’s one of the most important take-away I have from this course.

[ExDa] Final Project – Most Commented Songs Top 100 in NetEase Music

Professor: XY

For my final project I visualized 100 songs that have got the most comments in the music app NetEase Music in the form of an interactive bubble chart. Keeping the data I wanted to visualize in mind, my idea of how to visualize it changed a lot during the last few weeks.


NetEase Music doesn’t have their API for public use so I searched online for methods and tutorials of hacking the data. Unfortunately I didn’t quite understand the codes provided by great hackers and I didn’t have enough time to figure out how the codes work. As a result I referred to three sources listed below. These sources are not realtime data so I checked top 150 songs of each to make sure I didn’t miss any possible song, and made my own rank in an excel.

After finalizing the list of 100 songs I was going to visualize, I filled in all other data (name, language, type, top 5 comments and release date) manually in the excel. Getting information of 100 songs was really time consuming!!

100-1 100-2100-3100-4100-5


I tried to put these 100 songs in a 3D coordinate system (a cube skeleton) using the library three.js. I chose release date, language and type as x, y and z axes, so each song has a unique coordinate. Users can zoom in or drag it around to interact with them and thus get more information they want.3d
This is how 3d demo looks like. I encountered two difficulties when building this model. One was that for some reason the sprite text label was always slanted and I couldn’t fix it. The other was in a 3D space projected on a 2D screen it was hard for user to locate the actual coordinate of the songs and make accurate connections between the song cubes and the data labeled on axes. What’s more, after talking to Professor Roopa and XY and seeing the rap vocabulary example I realized that my project doesn’t necessarily need to be in 3D.

In a 2D graph, in order to give users as much information as in 3D, there should be more elements or attributes that can represent data apart from the coordinates. So I found another library canvas.js and modified its “bubble chart” example. Here’s a capture of the second demo:2d0
I tried my best to customize the chart, but still I had no idea how to replace the color circles with the album cover of the song and how to change some other details. The template brought me convenience as well as limits on style of visualization.

Therefore, finally, I decided to draw the chart all on my own in p5. First I came up with a demo of 20 songs similar to the bubble chart above:
Because there’s only three songs that were released before 2002, I drew broken lines instead of a straight line to indicate that time is folded here. The “DAYS” function in Excel helped me count how many days are there between the release date of the first song in 2002 and the release date of every song (the result is shown in Excel below the “time” column). I built a class for songs so that I can assign attributes to them and call functions using for loop.

Users can interact with the chart in two ways. When they hover the mouse over one of the songs a text div will pop up and show information including name, number of comments, language and release date of the song. When they click on it, they can listen to the song, and the 5 hottest comments (ones that get most likes) will appear on the right.

I used p5.dom.js to combine html elements and p5 canvas drawing. The pop-up song information block and the comment text are divs I add to the webpage using createDiv() function built in p5.dom.js. It’s much more easier to show and hide something if it is an html element. Styling becomes easier as well.

But this demo is still problematic. I divided them into only three categories, therefore y values of the songs of the same type are the same and some overlay on others. I discussed this issue with XY, he suggested I create multiple charts, each reflecting only one year or part of the whole timeline or choose number of the comments as y-axis. Both of these two approaches can solve the problem of songs overlapping, but at the same time they also have defects. Drawing multiple timelines and reducing the chart to one-dimension horizontal lines makes the data seem fragmented and users lose the general sense of the data. Using y-axis to represent the number of comments feels a little redundant because the size of circles already does that. After careful consideration I decided to label y-axis according to the number of comments. Although it may seem unnecessary, it can help users identify the rank of songs that haven’t got that much comments. For these songs, it’s difficult for users to tell the difference between their sizes because the difference (left pic) is not obvious compared to that between no.1 song and others (right pic). With its y-coordinate indicating the number of comments, the information is conveyed more clearly.
%e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2016-12-15-19-06-24 %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2016-12-15-19-06-19

Thus here is my final version:

I built four buttons for users to switch to the type of songs they want to see — funny, neutral, emotional and all types. Originally I wanted to use the show and hide methods of DOM element to realize the type switch. However, I failed to create the album cover image as elements using createImage() function. To achieve the same effect I had to draw the background chart lines and labels and images of corresponding type of songs again everytime users click on the button.

A stop button is added to enable users stop the song playing. Also, according to the suggestions made by professors and classmates after my presentation, necessary explanation is added to help users better understand the chart. I adjusted the line height of comment text so the text isn’t that crowded and becomes easier to read.

I didn’t change the font and background color. I agree with Jiamin’s idea that the chart should look like NetEase style. The font they use in most part of UI is just regular system sans serif font. In terms of the color scheme, I chose grey and white because I’d like the interface to be very simple. There are 100 album covers on the canvas already, which makes the chart very colorful and dazzling to some extent. In my opinion, if I add other bright color (such as red or big area of white color), it will distract people from data and make their eyes uncomfortable.

During the show I received some good advice as well. Above the hottest comment area I added a paragraph that displays the name of the song is being played now. I got this inspiration because when one of my friend was trying out my project, he randomly clicked around and he just forgot which song he clicked on.


Further development:

I think there is still much to work on though I’m very satisfied with my project. For example, the middle left part of the chart is very empty, which means I can rescale the axis. Another development is about the comments. I only picked five comments for each song, but in fact for one song there are at most 10 comments under “hottest comments” column. One possible way of doing it is to classify these comments and see the similarity or difference between the type of the song and that of comments.


Below is my code of p5 sketch. I omit the data that should be loaded in preload function otherwise the code would be too long.

var imgs = [];
var audios = [];
var songs = [];
var data;
var clickedIndex;
var bg;

function preload() {
  data = //data here, omitted


  for (var j = 0; j < 100; j++) {
    var audiopath = "mp3/" + j + ".mp3";
    audios[j] = loadSound(audiopath);
    console.log('loading song' + j);

  for (var i = 0; i < 100; i++) {
    var imgpath = "images/" + i + ".png";
    imgs[i] = loadImage(imgpath);
    //imgs[i] = createImg(imgpath).hide();
    console.log('loading img' + i);
    //songs[i].albumCover = imgs[i];

  for (var n = 0; n < 100; n++) {
    var songdata = data[n];
    songs[n] = new Song(songdata, imgs[n], audios[n]);
  var bg = loadImage('images/bg.jpg');

function setup() {
  var canvas = createCanvas(windowWidth, windowHeight);

function draw() {
  for (var n = 0; n < 100; n++) {
    if (dist(mouseX, mouseY, songs[n].x, songs[n].y) <= songs[n].d / 2 && songs[n].dis === true) {
      for (var m = 0; m < 100; m++) {
        if (m != n) {
    } else {

function mousePressed() {
  for (var n = 0; n < 100; n++) {
    if (dist(mouseX, mouseY, songs[n].x, songs[n].y) <= songs[n].d / 2) {
      for (var m = 0; m < 100; m++) {

function Song(songdata, img, audio) {
  this.hover = false; =;
  this.num = songdata.num;
  this.lan = songdata.lan; =;
  this.type = songdata.type;
  this.albumCover = img;
  this.comment = songdata.comment; = audio;
  this.time = songdata.time;
  this.dis = false;
  this.d = map(sqrt(this.num), sqrt(30000), sqrt(1102725), 20, 80);
  if (this.time >= 0 && this.time < 1405) {
    this.x = map(this.time, 0, 1405, 142.6, 418.6);
  } else if (this.time >= 2136 && this.time < 5391) {
    this.x = map(this.time, 2136, 5390, 473.8, 1150);
  } else if (this.time == -1) {
    this.x = 105;
  } else if (this.time == -2) {
    this.x = 60;
  } else {
    this.x = 130;

  if (this.num == 1102725) {
    this.y = 755;
  } else if (this.num == 560286) {
    this.y = 650;
  } else if (this.num == 460215) {
    this.y = 600;
  } else {
    this.y = map(this.num, 36000, 173474, 200, 500);

  this.ini = 'Playing Now: ' +;
  this.textDiv = createDiv(this.ini);
  ptitle = createP('Hottest comments top 5');
  ptitle.parent(this.textDiv);"font-size", "24px");"color", "#ffffff");"line-height", "102%");
  this.textDiv.position(1180, 140);"width", "250px");

  this.textDiv2 = createDiv('');
  var col = color(255, 255, 255, 220);
  this.textDiv2.position(this.x, this.y);"background-color", col);"margin-left", "5px");"margin-right", "5px");

  this.load = function() {
    var p = [];
    p[0] = createP("Name: " +;
    p[1] = createP("Comments: " + this.num);
    p[2] = createP("Language: " + this.lan);
    p[3] = createP("Release Date: " +;
    for (var i = 0; i < 4; i++) {
      p[i].style("font-size", "16px");
      p[i].style("color", "#101010");
    this.comments = this.comment.split(';');

    for (var j = 0; j < 5; j++) {
      var p1 = createP(this.comments[j]);
      p1.parent(this.textDiv);"font-size", "14px");"color", "#ffffff");

  this.drawPoint = function() {
    image(this.albumCover, this.x, this.y, this.d, this.d);
    ellipse(this.x, this.y, this.d, this.d)

  this.clicked = function() {;;

function drawEmotional() {
  for (var n = 0; n < 100; n++) {
    if (songs[n].type == 1) {
      songs[n].dis = true
    } else {
      songs[n].dis = false

function drawNeutral() {
  for (var n = 0; n < 100; n++) {
    if (songs[n].type == 3) {
      songs[n].dis = true
    } else {
      songs[n].dis = false

function drawFunny() {
  for (var n = 0; n < 100; n++) {
    if (songs[n].type == 5) {
      songs[n].dis = true
    } else {
      songs[n].dis = false

function stopall() {
  for (var i = 0; i < 100; i++) {

function drawAll() {

  for (var n = 0; n < 100; n++) {

    songs[n].dis = true;

function bg() {
  for (var j = 0; j < 60; j++) {
    stroke(255, 100);
    for (var i = 0; i < 3; i++) {
      line(142.6 + 138 * i, 197 + 10 * (j + 1), 142.6 + 138 * i, 200 + 10 * (j + 1));

    for (var k = 0; k < 5; k++) {
      line(473.8 + 138 * k, 197 + 10 * (j + 1), 473.8 + 138 * k, 200 + 10 * (j + 1));


  for (var j1 = 0; j1 < 110; j1++) {
    line(46 + 10 * j1, 700, 50 + 10 * j1, 700);
    line(46 + 10 * j1, 540, 50 + 10 * j1, 540);

  //line(100, 200, 100, 800);
  line(46, 800, 55.1, 800);
  line(55.1, 800, 65.1, 790);
  line(65.1, 790, 79.1, 815);
  line(79.1, 815, 95.1, 775);
  line(95.1, 775, 110.1, 820);
  line(110.1, 820, 130.1, 782);
  line(130.1, 782, 142.6, 800);

  line(142.6, 800, 418.6, 800);
  line(473.8, 800, 1150, 800);

  line(418.6, 800, 428.1, 790);
  line(428.1, 790, 443.1, 815);
  line(443.1, 815, 460.1, 775);
  line(460.1, 775, 473.8, 800);

  line(30, 300, 30, 700);


  for (var m = 0; m < 3; m++) {
    var label1 = m * 2 + 2002;
    text(label1, 130 + m * 138, 820);

  for (var m1 = 0; m1 < 5; m1++) {
    var label2 = m1 * 2 + 2008;
    text(label2, 460 + m1 * 138, 820);

  text('Most Commented Songs Top 100 in Netease Music', 50, 100);
  var funny = createButton('Funny');
  var neutral = createButton('Neutral');
  var emotional = createButton('Emotional');
  var all = createButton('All');
  var stop = createButton('STOP');

  function buttonStyling(btn) {'width', '70px');'background-color', '#646464');'border', '2px solid #dcdcdc');'border-radius', '6px');'color', '#fafafa');
  funny.position(100, 140);
  neutral.position(180, 140);
  emotional.position(260, 140);
  all.position(340, 140);
  stop.position(1100, 140);
  text("Size of the album cover represent how many comments the song has got", 450, 146);
  text("FEW", 15, 250);
  text("COMMENTS", 10, 270);
  text("MORE", 15, 740);
  text("COMMENTS", 10, 760);

Final Project – Flight Data

I started off this journey knowing that I wanted to work with flight data of some sort. The idea came to me during the Thanksgiving holiday when I heard stories from my friends about how their flights got delayed. I related to their experience — every time I flew out of Pudong International Airport, my flight would have an minimum of an hour’s delay.

I found some inspiration from other projects such as one that analyzed flight patterns of all airlines out of the O’Hare Airport over the course of 1 year. I realized for a project such as mine, that was too large of a scale, too many data points that I didn’t know how to scrape. What I instead decided to do was focus on departing flights from Pudong International Airport within China. I initially decided to narrow it down by focusing on all the flights from one airline, but the data was still too broad — broad in the sense that I wasn’t sure what I wanted to represent with that data. I juggled around with the idea that I could focus on outbound flights from Shanghai to Beijing (all airlines, both airports so that I could compare the average times between 2 airports), and then I could analyzed average delays by the hour.

It at first was difficult trying to find flight data that went beyond that past week’s data. I actually emailed out to flightstats to try to get this data somehow. I was finally able to make an account to then look up the data I needed.

My greatest struggle was to find a way to represent my data. There were so many ideas for the type of data that I could work with and represent, but what it always came back down to that I was stuck with was how to visualize my data. I’ve looked up numerous blogs, and I’ve read that how to begin the process of visualizing: to first know what kind of data I wanted to represent. I had that box checked off, but I just didn’t know what I wanted to show and how to go from there. I tried the idea of using a color scheme with a time table, it definitely would have represented the direct data, but I didn’t have much to show, it wasn’t something interesting, original. I then went back to the drawing table and collected more data. I expanded to flights out of Pudong, but rather than just to Beijing, it was to the top 5 busiest airports in China, which includes Shenzhen, Guangzhou, Chengdu and Hong Kong.

I tried many ideas. Such as programming something on Processing that would be more interactive. I wanted the users to be able to click to bring up a certain week’s data of average delays from Sunday to Saturday, and compare on a week to week basis, but I struggled greatly with just trying to lay the grid down and be able to summon the correct row with color coding using the key press feature. I tried but I was not successful.

screen-shot-2016-12-11-at-8-52-47-pm screen-shot-2016-12-11-at-10-46-43-pm screen-shot-2016-12-11-at-10-46-18-pm screen-shot-2016-12-11-at-5-15-28-pm

I also tried another mapping idea with twine to represent the number of flights out, and delayed flights to Beijing, but the visualization looked too messy. Another was to use push pins on a map, the more twine that was wrapped around the airport, the greater the number of delays, but the hardest point is with representing a great number of delays, I wasn’t able to represent the course of time, and represent it in a way that viewers would want to or need the information.

fullsizerender fullsizerender-1 img_8115 fullsizerender-2 img_8117

In the end, I went with a poster like idea that you’d find on a bulletin board. It was supposed to give the statistics for flights out of Pudong to other four airports, noting flights that were on time, delayed and cancelled. The feedback I received was that it wasn’t clear and clean enough. To represent that sort of data, precision and accuracy is key. I should have used a program to compute the pie charts — it also should not have been hand-drawn. There were still questions left open about the data I chose to represent.


I still have ways to go, and more to learn, but I’m not giving up just yet.

boolean one = false;
boolean two = false;
boolean three = false;
boolean four = false;
boolean five = false;
boolean six = false;
boolean seven = false;

void setup() {
  size ( 2400, 1200);

void draw() {

  if (keyPressed) {

    if (key == '1') {
      //fill (255,0,0);
      one = true;
    if (key == '2') {
      //fill (255,0,0);
      two = true;
    if (key == '3') {
      //fill (255,0,0);
      three = true;
     if (key == '4') {
      //fill (255,0,0);
      four = true;
     if (key == '5') {
      //fill (255,0,0);
      five = true;
     if (key == '6') {
      //fill (255,0,0);
      six = true;
     if (key == '7') {
      //fill (255,0,0);
      seven = true;
  if (one) {
    rect(0, 100, width, 100);

      rect(0,200, 1374, 100); 
    for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 100, x + 100, 200);
    if (two) {
 rect(0, 220, width, 100);
    for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 220, x + 100, 320);
    if (three) {
      rect(0, 340, width, 100);
    for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 340, x + 100, 440);
    if (four) {
      rect(0, 460, width, 100);
      for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 460, x + 100, 560);
    if (five) {
      rect(0, 580, width, 100);
      for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 580, x + 100, 680);
    if (six) {
      rect(0, 700, width, 100);
    for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 700, x + 100, 800);
    if (seven) {
      rect(0, 820, width, 100);
    for ( float x = 100; x < 2300; x = x + 91.6) {
      line (x + 100, 820, x + 100, 920);


//for (int i = 0; i < 420; i = i + 10);
//rect (0,0, 60, 60);
//rect (60,0, 20, 60);
//rect (80,0, 20, 60);
//rect (100,0, 20, 60);
//rect (120,0, 20, 60);
//rect (140,0, 20, 60);

//rect (0, 60, 60, 60);
//rect (60,60, 20, 60);

//rect (0, 120, 60, 60);

//rect (0, 180, 60, 60);

//rect (0, 240, 60, 60);

//rect (0, 300, 60, 60);

//rect (0, 360, 60, 60);

//rect (0, 420, 60, 60);

//rect (0, 480, 60, 60);

//rect (0, 540, 60, 60);

Data Final — Manga Anatomy: Panel Transition with Storyline, visualized

My final is a counterpart to my midterm under the umbrella of my Comic Anatomy project. In the midterm documentation I envisioned 3 aspects to work on: bigger dataset, quantitative counterpart; combine content/story of the manga; make a physical piece. I think I achieve them very well in final.

This visualization explores how panel transition —an essential comic narrative methodology raised in Scott McCloud’s Understanding Comics — relates with storylines in Attack on Titan, a manga (Japanese comics) series by Isayama Hajime.

Covering half of the manga series (4 story arcs, 34 episodes in total. More details in index page), bar graphs that show percentages of different panel transitions used in each episode are complemented with images from manga that indicate stories and characters. In the format of a flag book, data of comic narrative is intertwined with the flow of stories, creating a dynamic narrative on the inner work of comics.

Ideation and data collecting/processing

My data was all collected manually, with a week of intensive manga reading, marking, counting, typing and calculating. And I was able to only cover half the series: 8 volumes, 4 story arcs, 34 episodes). It is also the length of the anime adaption (season 1). I proceed slowly and carefully because I didn’t have time to go over again and wanted to avoid mistakes as much as I could.

2     1

This process was much harder than I thought. It was truly a test of my patience, as well as my love for comics. But I made it through!


Since my dataset is not grab-and-go, I didn’t really know what it would look like in the end and thus couldn’t be able to decide what kind of visualization is to suit both my goal and the data. The original idea is to create a graph built on the structure of comic panel. Each rectangular panel is a chapter and its area indicate how much pages it occupies. Inside the rectangle multiple irregular polygons in different colors show the percentage of each type of panel transition used in every chapter. Reading route will connect all the panels like in my midterm and will branch upward to indicate storylines, characters and such. Something like this:


However, when I finished collecting the data and drew a bar chart in excel, I found out that between each chapter there is no major difference, probably because each chapter contains many episodes whose transition difference offset with each other. And also each chapter can include various events, characters, which makes it difficult to be stuck in one rectangular and draw relation with the one single set of percentages.


So I needed to break chapter into smaller unit. I drew another chart of transition types in episodes. The general distributions are similar: subject-to-subject transition is dominant, which is understandable. This is the most efficient way to push forward a story in one scene that stages multiple characters. But you can observe major changes in the use of the other 5 types. For example, in episode 28 and 29 where most of the panels are portraying Titan and human fighting, action-to-action transition takes over, scarcely leaving room for aspect-to-aspect and scene-to-scene transitions. While in episodes 19-21, the storyline focuses on trial, conversation and strategy, and the percentage distribution is the opposite. This is really good, because I wish to explore how narrative methodology work with stories. Even if the relation is subjective, flexible and sometime even confusing, I want to put them together, show the change and let reader observe and contemplate by themselves, forming a narrative of their own.


I could merge some of the episode together but in the end I just went with doing episode by episode. 34 in total are not bad, plus that each episode can have something interesting. I also decided to keep the shape of bar chart. The regular shape enables the reader to see the trend more easily. I changed the width of column according to the number of panels in each episode. Because the number of spreads in each episode are quite stable, readers can have a sense of how dense the panels are in each episode by the width of bar graph.


Up to this point I had to reconsidered my choice of visualization. I no longer needed the panel structure and the reading route.

To program an interactive page seemed to be a good choice, with which I can present storyline and the trend of data easily(something like this:, not like in a graph where things can get messy. But I really want to make something physical because I am visualizing comic book! It would be great to have something sitting next to and complementing my manga collection by offering a new angle to look at comic narrative. So why not just make a book?

A flag book would very nice. The rigid paper strips form a fluid structure and can create a flowing motion that are perfect for both clear display of data and visualizing the storyline. With this format I was able to take images directly from manga and put them together with bar graph, showing major characters, the intensity or mood of the plots and the type of events. I think images can stimulate more response than word description or labels, even if the reader hasn’t read this manga before.


I went to Fuzhou Road to buy supplies. And I prototyped several times to decide on tools(print/hand-draw), materials (paper thickness, color), and design (color palette, shape and position of bar graph, arrangement of manga images in relation to the bar graph, shape and dimension of the paper strips and book).

6     7

I want the bar graph to stand out and can be viewed collectively to show change and trend, but also can be contextualized individually in the storyline. So I chose the color palette of my midterm for each transition type. The bright colors distinguish very well from the black-and-white manga image. And I put the bar graph in the outer edge of the paper strip, and manga image following it. When you open the book and view them collectively, all the bar graph “float” in a nice grid and form a bar chart, while the storyline flows in the background in the direction of paper strips, guiding readers’ eyes to zoom in and inspect each strip(episode) individually.

The image I chose are major characters in that episode whose facial expressions and gestures to some degree can indicate the mood and event of that episode. I cut the characters I wanted from the manga panel, glued them to the paper strip and created an interesting collage summary for each episode. This is not a very objective data, but I guess that is what story is about: everybody has its own interpretation.

When it came to really make the book. Things moved forward quite smoothly. I first cut the paper strips and engraved a book cover using laser cutter. I turned my midterm visualization into a pattern and engraved them on a black paper. Then I wrapped the black paper around a cardboard paper to create my cover.

8     11

10     12

9     13

For the bar graph, I traced the excel chart in Illustrator (I did this under the highest zoom-in level, so they are pretty accurate), changed the colors, printed out and stuck to paper strips in episode order.

5     14

Cutting images from manga and making collage was fun but challenging. It made me try to tell a story of 40+ pages in a small paper strip. Some of the collage was pretty interesting. I am curious how people who never read the manga would respond to them.

15     img_1906

img_1962     img_1954

Finished Book

I am pretty satisfied with the finished book. The colorful bar graphs and manga images together generate good visual hierarchy and data layers, combining panel transition and storyline effectively and coherently. It can be viewed in different ways and can create some interesting geometry structures.

img_1965     img_1969

img_1930     img_1952

img_1937     img_1936

I didn’t have any caption on the book at the time of final presentation because I hadn’t figured out how to add caption without destroying the aesthetic of the spread. Yesterday I made a caption page and an index page (providing information on Attack on Titan for people who are interested). I glued each in a folded black paper and attached the caption inside the front cover, and the index inside the back cover. They are all in black and in symmetrical position with each other. Look good!

caption-for-book_s-01     index_s-01

img_1989     img_2003img_2002     img_2001

I really enjoyed this project and learned a lot. I want to give my thanks to XY and my classmates for all the critiques, feedbacks and help. Last but not least, I need to thank XY for helping me print out the visualization and getting that trashcan as my stand. Worked super well!


Expressing Data Final – 99 Names of Allah

For my final project, I wanted to analyze the 99 names of Allah by using their frequency in the Quran and then visualize it using traditional Islamic art and calligraphy methods.

Some existing projects on data I looked at while ideating:

[ Word Frequency Comparison Between Bible + Quran ]  

[ The Periodic Table of Islam ]

[ 786: Math + Quran ]

[ Oneness ]

The 99 names of Allah is a concept in Islam that represents the 99 different qualities or facets of God. These names describe the One God (one of the names is also “The One”): He is the Protector, the King, the Friend, and the One that Knows all at the same time. I thought it would be worthwhile to explore these names using the analysis and visualization techniques we used in class to see what the relationships between them were and if these relationships can be mapped using mathematical and generative models.

Getting data from the text file and saving it to a JSON file.

Getting data from the text file and saving it to a JSON file.


I initially had a lot of trouble figuring out how to get the data without extracting it manually. This, along with understanding how to visualize the conceptual complexities behind the names, ended up taking up a lot of time. Even after finally understanding how to get the API to work, I had a lot of trouble in terms of quality control. There were many English translations for the Quran available, and there is no consistency on how specific words can be translated (it’s not a complete mess; just more a complication involving synonyms. Arabic is a complex language and each word has multiple meanings. I could have used the simple Arabic one to scrape the data but even though I can read Arabic, my understanding is not too good and I didn’t feel comfortable doing it. After struggling with it, following Roopa’s suggestion, I switched to simple text as my data did not change. Still, because of the translation issue, I had to manually search up the names in an online web-based Quran to make sure that my array of names matched up to how they were described in that particular translation.


It was also difficult visualizing the data because I wanted it to be symmetrical and reminiscent of Islamic geometry but some names were very obviously more mentioned than others (which was the point). Also, it was interesting to consider how the names could be compared to each other, other than frequency. I wish I had expanded more than just evaluating frequency. But I do want to continue working on this and polish it, so hopefully that can happen.

Drafts + Tests:

screen-shot-2016-12-15-at-1-27-28-am screen-shot-2016-12-15-at-4-59-36-pm screen-shot-2016-12-15-at-5-00-06-pm



Final iteration:

screen-shot-2016-12-15-at-4-59-26-pmscreen-shot-2016-12-12-at-4-28-50-am screen-shot-2016-12-12-at-4-28-56-am screen-shot-2016-12-12-at-4-29-07-am screen-shot-2016-12-12-at-4-30-46-am screen-shot-2016-12-12-at-4-30-56-am screen-shot-2016-12-12-at-4-30-57-am

Below is the code for the last final orbit one. I also have the code for getting and organizing the data and the more even iteration.

//orbit variables
var maxScroll=30000;
var radiusX=400;
var radiusY=200;
var orbitTop=260; // position of orbit
var orbitLeft=500;
var speed=1000; // bigger number = slower
// initial setup	
var howFar=0;
var planet;
var planetborder;

//data variables
var names99;
var lengtharray = new Array();
var namesArray = new Array("Allah","Beneficent","Merciful","King","Holy", "Giver of peace", 
              "Granter of security", "Guardian","Mighty","Supreme", "Creator", "Maker", "Fashioner", 
              "most Forgiving", "Subduer","Giver", "Provider", "Judge", "Knowing", "straitens", "multiply",
              "Abasing", "exalt","givest the kingdom", "takest away the kingdom","Hearing","Seeing", "will judge between you",
              "Knower of subtleties", "Aware", "Forbearing", "the Great", "Grateful","High", "Preserver", 
              "Keeper", "Reckoner", "Lord of glory", "Gracious", "watcher", "Answering", "Ample-giving", "Wise",
              "Loving", "Glorious", "raise up those who are in the graves", "Witness", "Protector", "Strong", "Helper", "Praised",
              "record", "Originator", "originates", "gives life", "causes death", "Everliving", "Self-subsisting",
              "We found", "Honorable", "One", "He on Whom all depend", "He has the power", "Powerful", "He respites them", 
              "grant you a delay", "First", "Last", "Ascendant", "Knower of hidden things", "protector",
              "Most High", "Benign", "Oft-returning", "inflict retribution", "Pardoning", "Kind",
              "Master of the Kingdom", "Lord of glory and honor", "maintaining His creation with justice",
              "Gatherer", "Self-sufficient", "enrich", "Allah touch you with affliction",
              "Allah makes ample provision", "His light", "Guide", "Wonderful Originator", "for ever the person of your Lord",
              "We are the heirs", "means to bring them good" , "Allah is with the patient");
var knowing = new Array("Knowing", "Hearing", "Seeing","Knower of subtleties", "Aware", "watcher", "Wise","Witness","record", "Knower of hidden things");
var original = new Array("Originator", "originates", "One","Wonderful Originator", "Creator", "Maker", "Fashioner");
var forgiving = new Array("Merciful","most Forgiving", "Pardoning");
var glory = new Array("Glorious", "Lord of glory", "Lord of glory and honor", "Praised");
var giver = new Array("Allah makes ample provision", "Helper","Ample-giving","Provider","Giver of peace", "Granter of security","gives life", "givest the kingdom", "grant you a delay", "Gracious", "means to bring them good");
var selfreliant = new Array("Self-sufficient","Self-subsisting","Everliving");
var judge = new Array("Judge","will judge between you","inflict retribution","maintaining His creation with justice");
var protector = new Array("Granter of security", "Guardian", "Protector", "Strong","protector");
var reliant = new Array("Answering","He on Whom all depend", "He respites them","Oft-returning")

var arrayColor = new Array (knowing, original, forgiving, glory, selfreliant, judge, protector, reliant);
var colorArrays = new Array([165, 105, 189, 120],[133, 193, 233,120], [118, 215, 196,120],[247, 220, 111, 120],
                [229, 232, 232,120], [236, 112, 99,120], [22, 160, 133,120],[41, 128, 185,120]);

//organizing variables
var counter = 0;
var circlecounter = 0;
var naming = new Array();
var prevname = 0;
var arabic;
var bkg; 
var centerpiece;
function preload() {
  names99 = loadJSON("names99v2.json", loaded, error);
  arabic = [];
  for(var i=1; i<99; i++) {
    var fileName = "img/" + i + ".png";
    arabic[i] = loadImage(fileName);
  bkg = loadImage("bkg.jpg");
  centerpiece = loadImage("allahname.png");

function setup() {
  for(var name in names99) {
    if(names99[name] == names99[1]) {
      var counts = names99[name].length + 114;
    } else if(names99[name] == names99[2]) {
      var counts = names99[name].length + 114;
      append(lengtharray, counts);
    } else {
  count = lengtharray.length;
  var sample = lengtharray;
  lengtharray = sort(lengtharray, count);
  naming = namesArray;


// scroll function 

function mouseWheel() {
  howFar +=;

function draw() {
  image(bkg, width/2, height/2);
  translate(width/2, height/2);

  biggestnames = 90; //i =1, 89,i = 2, 88
  mediumnames = 85;
  shortestnames = 0;
  shortcounter = 1;

  // i is biggest 3 names
  //j is next biggest 6 names
  for(var i = 0; i < 3; i ++) {
    for(var attribute in arrayColor) {
      var thename = arrayColor[attribute];
      for(var quality in thename) {
      if(naming[biggestnames].includes(thename[quality])>0) {
        var col = colorArrays[attribute];
      } else {
        // fill(200);
    rotate(TWO_PI * i/5);
    for(var j = 0; j < 8; j++) {
      for(var attribute in arrayColor) {
      var thename = arrayColor[attribute];
      for(var quality in thename) {
      if(naming[mediumnames].includes(thename[quality])) {
        var col = colorArrays[attribute];
      } else {
       // fill(200);
    // x=(Math.sin((howFar/speed)*(lengtharray[mediumnames]))*radiusX)+orbitLeft;
    // y=(Math.cos((howFar/speed)*(lengtharray[mediumnames]))*radiusY)+orbitTop;
      //ellipse(x,y,y-lengtharray[mediumnames], y - lengtharray[mediumnames]);
      if(mediumnames > shortestnames) {
      image(arabic[mediumnames],x,y, (y-(2*lengtharray[mediumnames]))/2,(y-(2*lengtharray[mediumnames]))/2);
      // console.log(lengtharray[mediumnames]);
      for(var m = 0; m < 3; m++) {
        for(var attribute in arrayColor) {
          var thename = arrayColor[attribute];
          for(var quality in thename) {
            if(naming[shortestnames].includes(thename[quality])) {
              var col = colorArrays[attribute];
            else {
             // fill(200);
    //     x=(Math.sin((howFar/speed)*(lengtharray[shortestnames]))*radiusX)+orbitLeft;
    // y=(Math.cos((howFar/speed)*(lengtharray[shortestnames]))*radiusY)+orbitTop;
        if(shortestnames < arabic.length) {

          image(arabic[shortcounter],x,y, (y-(20*lengtharray[shortestnames]))/2,(y-(20*lengtharray[shortestnames]))/2);
        if(lengtharray[shortestnames] == lengtharray[mediumnames]) {
          //console.log("REPEAT REPEAT REPEAT");
    // console.log(shortestnames)
  fill(255, 255, 0,200);

function loaded(d) {
  names99 = d;

function error(err) {

function sortLengths(currentstring, prevstring) {
  var currentstringnumber = namesArray.indexOf(currentstring);
  var prevstringnumber = namesArray.indexOf(prevstring);
  // console.log(currentstring + ": " + currentstringnumber);
  //check in names 99 whihc on is greater
  if(names99[currentstringnumber].length > names99[prevstringnumber].length) {
    return 1;
  } else if(names99[currentstringnumber] < names99[prevstringnumber].length) {
    return -1;
  } else {
    return 0;

function drawHexagon(x,y, radius) {
  for(var i = 0; i < 6; i++) {
    var angular = PI * i/3;
    vertex(cos(angular)*radius, sin(angular)*radius);


[DF] 3D panelling

We learned two ways of 3D paneling in class, both of them are very useful. I never tried 3D paneling too in Maya before. And I felt very convenient when I used this tool in Rhino.

Above it the link to my rhino file. I made all my work on IMA’s laptop and I can’t open this file on my laptop. So I put a link here.

  Week 14: Response to Final Project

I struggled a lot through my final project. My theme is about paper tapes. I would like to visualize the top 100 popular paper tapes in China. Since it’s a newly-developed market, not many people know about it. Therefore, I wanted to do an introduction of paper tape.

I agree with what xy said. It is very hard to visualize a visual product. Therefore, I met a lot of problems. Even at the deadline of my project, I’m still confused about my concept and layout I should use. I asked many people who are not familiar with paper tapes market at all about their opinion. Most of them told me that what interests them is the pattern of paper tape. However, pattern is not a data. So I have come up with an idea about using paper tape pattern to show my data. I’m not a big fan of subjective data such as level of satisfactory. Hence, I decided to visualize very objective data, such as the size/width of paper tape, market price, its name and the retailer that produced these tapes. First of all, I decided to use a donut shape to make a metaphor of side view of tape. However, this shape is very misleading. Many people told me that they thought it is a visualization of CD instead of paper tape. I changed donut shape to pie chart in the end. I made a poster that shows all the pie charts. In order to show the pattern, I printed out these charts and cut them out. I covered them with tapes and connect them with paper tape.

Below is my work. I’m not satisfied with my project at all. It didn’t meet my goal. I will continue thinking about it.

223 326

13041004 193059338 webwxgetmsgimg

var tapes; //tapes is an array of tape
// var innerCircle;
var stAng; //the starting line of donut
var endAng; //the ending line of donut
var placeName; //color of inner circle that indicates producing place
var textCircle;
var fanColor;
var font;
var order;

function preload() {
  tapes = loadStrings('data/final.txt');
  font = loadFont('data/HelveticaNeueLTPro-UltLt.otf');

function setup() {
  createCanvas(1425, 6000);
  // saveSVG('Final');
  for (var i in tapes) {
    var values = tapes[i].split(',');
    var price = float(values[0] * 7.2); //original price of tape 
    var tapeSize = int(values[1] * 40); //the width of the tape
    var place = values[2]; //0=CN, 1=TW, 2=JP
    order = i;
    if (place == 1) {
      // placeName = "T W";//TW = red
      fanColor = color(191,255,185);
    } else if (place == 2) {
      // placeName = "J P"; //JP = green
      fanColor = color(183,235,255);
    } else {
      // placeName = "C N"; //CN = blue
      fanColor = color(255,183,185);

    stAng = 0 - 90;
    endAng = price - 90;
    innerCircle = int(20);
    textCircle = int(tapeSize+30);

    // translate(int(i / 8) * 100, i % 8 * 120);
    translate(i%5*250, int(i/5)*260);
    drawTape(tapeSize, price, stAng, endAng, innerCircle);


// saveSVG();

function drawTape(size, price, stAng, endAng, innerCircle) {
  translate(200, 200);


  //outer circle
  ellipse(0, 0, size, size); //r changes with tapesize
  //fan shape
  arc(0, 0, size, size, stAng, endAng);
  //inner circle
  // fill(255);
  // ellipse(0, 0, innerCircle, innerCircle); //inner circile, unchangable r
  //text circle
  // stroke(100,100,100);
  // noFill();
  // ellipse(0,0,textCircle,textCircle);
  // strokeWeight(1);
  // textAlign(CENTER,CENTER);
  // textSize(20);
  // textFont(font);
  // text(order,0,0);
  // text(placeName,0,20)



99 Names of God — Final Project


CONCEPT:  99 names of Allah

For my final project, I would like to conceptualize the Quran by searching and extracting verses only by the 99 names or attributes of God mentioned in the Quran and creating an interactive art piece centered around them. I’d want it to be representative of Islamic art, which mainly consists of patterns and shapes, specifically formed via arabic calligraphy. Right now, my idea is that the resulting project would be an animated fractal (a mathematical shape consisting of shapes entirely like that) and you can zoom in to see the specific fractal which will be consisting of the verses that mention this name.

I’m also exploring the concept of fractals in my other class, the Code of Music.


Here is a link about coding fractals with examples so you can see what I’m going to try to go for:



Quran API



[ Word Frequency Comparison Between Bible + Quran ]

Pitch Interactive

Utilizing Processing (+Rita.js?)

[ The Periodic Table of Islam ]

[ 786: Math + Quran ]