Processing Intermediate Article 6

Data Visualisation

Load CSV and JSON data in Processing and build interactive bar charts, scatter plots, line charts, and an animated bubble chart with HSB colour mapping.

⏱ 18 min data csv json visualization charts

Processing was originally designed for teaching visual thinking through code — and it has first-class support for loading and visualising data. This tutorial covers every data format Processing understands and builds up to a fully interactive animated bubble chart driven by a JSON file.

Loading CSV Data

Place your CSV file in the sketch’s data/ folder (Sketch → Add File or just drag it in). Processing’s Table class parses it automatically:

Table data;

void setup() {
  data = loadTable("cities.csv", "header");  // "header" reads first row as column names
  println("Rows: " + data.getRowCount());
  println("Columns: " + data.getColumnCount());
}

A sample cities.csv might look like:

city,population,area,gdp
Tokyo,13960000,2194,1065
New York,8336817,783,1600
London,8982000,1572,731

Access rows and columns by name or index:

for (TableRow row : data.rows()) {
  String city = row.getString("city");
  int    pop  = row.getInt("population");
  float  gdp  = row.getFloat("gdp");
  println(city + " – pop: " + pop + ", gdp: " + gdp);
}

Use getRow(i) to access a specific row by index, or findRow(value, column) to search for a row.

Loading JSON

loadJSONObject() parses a single object; loadJSONArray() parses an array at the top level.

JSONArray records;

void setup() {
  records = loadJSONArray("countries.json");

  for (int i = 0; i < records.size(); i++) {
    JSONObject country = records.getJSONObject(i);
    String name = country.getString("name");
    float  gdp  = country.getFloat("gdp");
    int    pop  = country.getInt("population");
    println(name + " gdp=" + gdp + " pop=" + pop);
  }
}

A matching countries.json:

[
  {"name": "Norway",  "gdp": 482.4, "population": 5379000,  "continent": "Europe"},
  {"name": "Germany", "gdp": 4072,  "population": 83240000, "continent": "Europe"},
  {"name": "Brazil",  "gdp": 1608,  "population": 214300000,"continent": "S.America"}
]

For nested objects, chain the getJSONObject() calls as needed.

Bar Chart from CSV

Table data;
float margin = 60;
float barW;

void setup() {
  size(800, 500);
  data = loadTable("cities.csv", "header");
  barW = (width - margin * 2) / (float) data.getRowCount();
}

void draw() {
  background(245);
  drawBarChart();
}

void drawBarChart() {
  float maxPop = 0;
  for (TableRow row : data.rows())
    maxPop = max(maxPop, row.getFloat("population"));

  textAlign(CENTER);
  textSize(11);

  for (int i = 0; i < data.getRowCount(); i++) {
    TableRow row = data.getRow(i);
    float pop = row.getFloat("population");
    float bh  = map(pop, 0, maxPop, 0, height - margin * 2);
    float x   = margin + i * barW;
    float y   = height - margin - bh;

    // colour bar by index using HSB
    colorMode(HSB, 360, 100, 100);
    fill(map(i, 0, data.getRowCount(), 0, 280), 70, 90);
    colorMode(RGB, 255);

    noStroke();
    rect(x + 4, y, barW - 8, bh, 3, 3, 0, 0);

    fill(80);
    text(row.getString("city"), x + barW / 2, height - margin + 15);
    text(nf(pop / 1_000_000.0, 0, 1) + "M", x + barW / 2, y - 5);
  }

  // axes
  stroke(180);
  strokeWeight(1);
  line(margin, height - margin, width - margin, height - margin);
}

Scatter Plot with Mouseover Labels

void drawScatter() {
  float maxGDP = 0, maxPop = 0;
  for (int i = 0; i < records.size(); i++) {
    JSONObject r = records.getJSONObject(i);
    maxGDP = max(maxGDP, r.getFloat("gdp"));
    maxPop = max(maxPop, r.getFloat("population"));
  }

  String hovered = null;

  for (int i = 0; i < records.size(); i++) {
    JSONObject r = records.getJSONObject(i);
    float x = map(r.getFloat("gdp"),        0, maxGDP, margin, width  - margin);
    float y = map(r.getFloat("population"), 0, maxPop, height - margin, margin);

    float d = dist(mouseX, mouseY, x, y);
    boolean over = d < 10;

    fill(over ? color(255, 80, 80) : color(80, 130, 200), 180);
    noStroke();
    ellipse(x, y, 14, 14);

    if (over) hovered = r.getString("name") +
                        " GDP: $" + nf(r.getFloat("gdp"), 0, 0) + "B";
  }

  if (hovered != null) {
    fill(20);
    textAlign(LEFT);
    textSize(12);
    text(hovered, mouseX + 12, mouseY - 6);
  }
}

Line Chart with Animated Drawing

Animate the line being drawn by limiting how many data points are rendered based on frameCount:

float[] values = {12, 19, 8, 27, 22, 34, 30, 41};
int visiblePoints = 0;

void draw() {
  background(250);
  if (visiblePoints < values.length) visiblePoints++;

  stroke(60, 120, 200);
  strokeWeight(2);
  noFill();
  beginShape();
  for (int i = 0; i < visiblePoints; i++) {
    float x = map(i, 0, values.length - 1, margin, width  - margin);
    float y = map(values[i], 0, 50,         height - margin, margin);
    curveVertex(x, y);
  }
  endShape();
}

curveVertex draws a Catmull-Rom spline through the points so the chart feels smooth rather than jagged.

Colour Mapping with HSB

Switch colorMode to HSB to map a data value to a hue range:

colorMode(HSB, 360, 100, 100, 100);
float hue = map(value, dataMin, dataMax, 240, 0);  // blue → red
fill(hue, 80, 90, 80);

Reset to RGB afterwards if other parts of your sketch depend on it:

colorMode(RGB, 255);

Full Example: Animated Bubble Chart

Create data/countries.json as shown above, then run this sketch:

JSONArray records;
float margin = 70;
float t = 0;

void setup() {
  size(900, 600);
  records = loadJSONArray("countries.json");
  textFont(createFont("SansSerif", 12));
}

void draw() {
  background(252, 252, 248);
  t += 0.012;
  drawAxes();
  drawBubbles();
  drawTitle();
}

void drawAxes() {
  stroke(200);
  strokeWeight(1);
  line(margin, height - margin, width - margin, height - margin);
  line(margin, margin, margin, height - margin);

  fill(120);
  textAlign(CENTER);
  textSize(11);
  text("GDP (billion USD)", width / 2, height - 10);
  pushMatrix();
  translate(16, height / 2);
  rotate(-HALF_PI);
  text("Population", 0, 0);
  popMatrix();
}

void drawBubbles() {
  float maxGDP = 5000, maxPop = 250_000_000;
  String hovered = null;
  float hx = 0, hy = 0;

  colorMode(HSB, 360, 100, 100, 100);

  for (int i = 0; i < records.size(); i++) {
    JSONObject r = records.getJSONObject(i);
    String name = r.getString("name");
    float  gdp  = r.getFloat("gdp");
    float  pop  = r.getFloat("population");

    // animated wobble
    float wobble = sin(t + i * 1.3) * 4;

    float x = map(gdp, 0, maxGDP, margin, width  - margin) + wobble;
    float y = map(pop, 0, maxPop, height - margin, margin)  + wobble;

    // radius proportional to GDP, hue by index
    float r_ = map(gdp, 0, maxGDP, 6, 45);
    float hue = map(i, 0, records.size(), 0, 300);

    boolean over = dist(mouseX, mouseY, x, y) < r_;
    fill(hue, over ? 90 : 70, over ? 100 : 85, 85);
    noStroke();
    ellipse(x, y, r_ * 2, r_ * 2);

    // label inside if bubble is big enough
    if (r_ > 22) {
      fill(0, 0, 100, 90);
      textAlign(CENTER, CENTER);
      textSize(10);
      text(name, x, y);
    }

    if (over) { hovered = name + "  GDP $" + nf(gdp, 0, 0) + "B  Pop " +
                           nf(pop / 1_000_000.0, 0, 1) + "M";
                hx = x; hy = y; }
  }

  colorMode(RGB, 255);

  if (hovered != null) {
    fill(30, 200);
    rect(mouseX + 12, mouseY - 20, textWidth(hovered) + 16, 22, 4);
    fill(255);
    textAlign(LEFT);
    textSize(11);
    text(hovered, mouseX + 20, mouseY - 6);
  }
}

void drawTitle() {
  fill(50);
  textAlign(LEFT);
  textSize(16);
  text("Country GDP vs Population", margin, margin - 10);
}

Key Takeaways

  • loadTable("file.csv", "header") gives you a Table object with named columns accessible via row.getString(), row.getFloat(), etc.
  • loadJSONArray() and loadJSONObject() parse JSON with no external libraries.
  • Map data values to pixel coordinates with map(value, dataMin, dataMax, pixelMin, pixelMax).
  • colorMode(HSB, 360, 100, 100) is the most intuitive way to assign perceptually distinct colours across a dataset.
  • Animated entry and hover interactions transform static charts into explorable, engaging pieces.