Tuesday, January 20, 2015

How to create a Heat map using Processing.

In this post I explain how to create a heat map using Processing language. Processing is mostly used to generate creative visual designs through programming. Underlying language of Processing is Java. But in Processing it uses simplified syntax for graphical programming unlike Java. For more information you can refer home page of Processing

To design our heat map I am going to use Bi-linear Interpolation algorithm. Bi-linear interpolation is an extension of linear interpolation for interpolating functions of two variables (e.g., x and y) on a regular 2D grid (Wikipedia).

Algorithm 
Source - Wikipedia
Goal - Find the unknown value f(p) at a point p =(x,y)using the,
Points with Known values -
  •  Q11 = (x1,y1)
  •  Q12 = (x1,y2)
  •  Q21 = (x2,y1)
  •  Q22 = (x2,y2)
Linear interpolation in x direction,
Source - Wikipedia
 Linear interpolation in y direction,
Source - Wikipedia
 Combining both results, f(p) = f(x,y)
Source - Wikipedia

Here is the Processing sketch of the above algorithm for an 2X2 array. The interpolated values are represented by colors, which will eventually generate the desired heat map.

int r = 2;  // number of rows in input array
int c = 2;  // number of columns in input array
int t = 300;  // parameter (array resize factor)
int rows = (r-1)*t;  // height of the heat map
int cols = (c-1)*t;  // width of the heat map

float[][] array = {{3,1},{2,5}};  // input array
float[][] interp_array = new float[rows][cols]; // interpolated array

void setup() {
  size(cols, rows);
  noStroke();
}

void draw() {
  bilinearInterpolation();
  applyColor();
}

void bilinearInterpolation() {  // Bi-linear Interpolation algorithm

  for (int i=0; i<r; i++) {
    for (int j=0; j<c; j++) {
      int x = j*t - 1;
      int y = i*t - 1;
      if (x<0)
        x=0;
      if (y<0)
        y=0;
      interp_array[y][x] = array[i][j];
    }
  }

  for (int y=0; y<rows; y++) {
    int dy1 = floor(y/(t*1.0));
    int dy2 = ceil(y/(t*1.0));
    int y1 = dy1*t - 1;
    int y2 = dy2*t - 1;
    if (y1<0)
      y1 = 0;
    if (y2<0)
      y2 = 0;
    for (int x=0; x<cols; x++) {
      int dx1 = floor(x/(t*1.0));
      int dx2 = ceil(x/(t*1.0));
      int x1 = dx1*t - 1;
      int x2 = dx2*t - 1;
      if (x1<0)
        x1 = 0;
      if (x2<0)
        x2 = 0;
      float q11 = array[dy1][dx1];
      float q12 = array[dy2][dx1];
      float q21 = array[dy1][dx2];
      float q22 = array[dy2][dx2];

      int count = 0;
      if (q11>0)
        count++;
      if (q12>0)
        count++;
      if (q21>0)
        count++;
      if (q22>0)
        count++;

      if (count>2) {
        if (!(y1==y2 && x1==x2)) {

          float t1 = (x-x1);
          float t2 = (x2-x);
          float t3 = (y-y1);
          float t4 = (y2-y);
          float t5 = (x2-x1);
          float t6 = (y2-y1);

          if (y1==y2) {
            interp_array[y][x] = q11*t2/t5 + q21*t1/t5;
          } else if (x1==x2) {
            interp_array[y][x] = q11*t4/t6 + q12*t3/t6;
          } else {
            float diff = t5*t6;
            interp_array[y][x] = (q11*t2*t4 + q21*t1*t4 + q12*t2*t3 + q22*t1*t3)/diff;
          }
        } else {
          interp_array[y][x] = q11;
        }
      } else {
        interp_array[y][x] = 0;
      }
    }
  }
}

void applyColor() {  // Generate the heat map
 
  color c1 = color(0, 0, 255);  // Blue color
  color c2 = color(0, 255, 0);  // Green color
  color c3 = color(255, 0, 0);  // Red color
  color c4 = color(255,255,0);  // Yellow color
 
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      float value = interp_array[i][j];
      color c;
      float fraction;
     
      if (value>=1 && value<2) {
        fraction = (value-1)/1.0;
        c = lerpColor(c1, c2, fraction);
      } else if (value>=2 && value<3) {
        fraction = (value-2)/1.0;
        c = lerpColor(c2, c3, fraction);
      } else if (value>=3 && value<5) {
        fraction = (value-3)/2.0;
        c = lerpColor(c3, c4, fraction);
      } else
        c = c4;
      stroke(c);
      point(j, i);
    }
  }
}


If you are not familiar with Processing syntax, you can refer the Processing reference page.  
Here is the generated heat map.

generated heat map

6 comments:

  1. Hello - Thank you for this awesome work on heat maps display. I have been looking for some time for canned software such as this for a project I am working on. I am not a professional programmer and struggle a bit with all but the simplest code. I would would like to incorporate your code in my prototype. Can you assist me in some modifications? I have inputs from an 8x8 array and would like to display using a heat map for the values. This is in real time as much as 10 Hz.

    Looking forward to your reply.

    Regards,

    Ken

    ReplyDelete
    Replies
    1. Hi,

      Thanks for incorporating my post into your project.
      Please do the following changes in code to use it with 8X8 input array.

      int r = 8; // number of rows in input array
      int c = 8; // number of columns in input array

      float[][] array = new float[r][c];

      In a seperate function pass the array inputs as an argument to the function and assign those values to the variable array.

      You can refer Processing home page how to handle functions & array assignments.

      Thanks

      Delete
  2. Hello, I keep getting "this size of sketch could not be determined from your code. Use only numbers (not variables) for the size() command. Thoughts?

    ReplyDelete
    Replies
    1. void settings() {
      size(cols, rows);
      }

      ^^^^^^^^^^^ remove "size()" from void setup and add the above!

      Delete
  3. Not sure if I'll even get a response but here it goes...

    What do you have as the maximum and minimum values in the variable array? I'm trying to normalize my data down to the range that you use. Thanks!

    ReplyDelete
    Replies
    1. For anyone wondering this in the future. I did some testing and the values range from 1.0-5.0 (inclusive)

      Delete

Note: Only a member of this blog may post a comment.