[Assignment 4] Population By Cities

Concept

For this assignment, I did data visualization of population by cities based on this dataset: Population by Cities (downloaded from https:// www.kaggle.com/data sets/i2i2i2/cities-of-the-world?select=cities15 000.csv). The inspiration came from pointillism, an art technique in which small dots are used to form an image. I was curious if I would be able to draw a world map by putting points on where the cities are located. I marked cities with large populations in red and blue colors to indicate these cities are large. In the end, I was able to generate a world map only using small points on the canvas as shown above.

Code

This assignment was rather straightforward to code because it did not require any mathematical logics, unlike my previous works. This code starts by loading dataset into an array. Then, the program will find minimum and maximum values of latitude, longitude, and population of the cities. Different from the class example, I used an array to store minimum and maximum values, because I would have to declare 6 different variables without arrays. Function findMinMax() is used to find these values from the dataset. The function will break down each row of dataset for every “,” it has. Then, the program goes through the entire entity in a given index to find min and max. In the end, the function returns an array that contains min and max values.

let dataArr = []; //Stores city population and location data

//0: min value, 1: max value
let latRangeArr = []; //latitude range
let longRangeArr = []; //longitude range
let popRangeArr = []; //population range

//In preload()
dataArr = loadStrings("data.csv"); //load data

//In setup()
latRangeArr = findMinMax(dataArr, 1);, 
longRangeArr = findMinMax(dataArr, 2);
popRangeArr = findMinMax(dataArr, 3);

function findMinMax(myArr, index) {
  let returnArr = [];

  let minN = Number.MAX_VALUE;
  let maxN = Number.MIN_VALUE;

  for (let i = 1; i < myArr.length; i++) {
    row = split(myArr[i], ",");

    let temp = float(row[index]);

    if (temp < minN) minN = temp; if (temp > maxN) maxN = temp;
  }

  returnArr[0] = minN;
  returnArr[1] = maxN;

  return returnArr;
}

Calculated min and max will be used to scale up or down the data based on the canvas size.

Very next step I took is to put points on the canvas using latitudes and longitudes. Each point was created using classes because each point must contain information about latitude, longitude, and population. Class method drawCity() will actually draw points on a canvas when called.

class City {
  constructor(long, lat, pop) {
    this.long = long;  //longitude
    this.lat = lat;  //latitude
    this.pop = pop;  //population
  }

  drawCity() {
    //I removed some part for the purpose of demonstration
    circle(this.long, this.lat, r);  //draw circles
  }
}

Using for() loop, the program creates City objects and stores them into an array. map() was used to scale longitude and latitude data relative to the width and height of p5js canvas. The population data was scaled from 0 to 100, so I can known population of cities in percentile for later.

for (let i = 1; i < dataArr.length; i++) {
    row = split(dataArr[i], ",");
    //create City object and store in array. map() is used to fit values into a given range
    cityArr[i] = new City(
      map(float(row[2]), longRangeArr[0], longRangeArr[1], 0, width),
      map(float(row[1]), latRangeArr[0], latRangeArr[1], height, 0),
      map(float(row[3]), 0, popRangeArr[1], 0, 100)
    );

    cityArr[i].drawCity();  //draw City objects
  }

At this point, I was able to generate a world map using only points. Then, I changed drawCity() as shown below to mark large population cities in reds and blues. Top 30% cities is drawn red and top 30%~60% cities were drawn blue. For cities that are not within the range was drawn in grey circles. Not to mention, because there were so many cities, I had to increase the size of red/blue circles in order to make them visible.

drawCity() {
    let r = 0.5;
    noFill();
    strokeWeight(1.25);
    stroke(100, 100, 100);
    if (this.pop > 70) {  //display top 30% (population) cities as red circles 
      strokeWeight(2.5);
      stroke(220, 0, 0);
      r = 4;
    } else if (this.pop > 40) {  //display top 30%~60% (population) cities as blue circles
      strokeWeight(2.5);
      stroke(0, 0, 220);
      r = 3;
    }
    circle(this.long, this.lat, r);  //draw circles
  }

Reflection / Future Improvements

This project was very satisfying to just look at it. I really like the fact that small points placed in different coordinates can actually produce a map of our world. Though some countries, such as Greenland, is not visible due to the missing information, anyone who sees this project will be able to recognize the world map. It was also surprising to see capital of my home country—Seoul, South Korea—is within top 30%~60% cities in terms of the population size.

In the I would like find a more complete dataset, which will allow me to make a better map that includes countries that are not displayed in this project. Not to mention, I do not like the colors used here. Although I wanted highly populated cities to be visible on the map, red and blue are not in harmony with grey color. Next time, I would like to find a better color combination.

One thought on “[Assignment 4] Population By Cities”

Leave a Reply