The coding works fine, but it's killing slow (Processing Optimization Tricks!)


#1

Hi guys,

Here is my coding. It works slowly, and I think there should be a way to speed it up.
Can anyone tell me how to make it more efficient? Thanks a lot.
Here is the link of original file

String [] allFonts=PFont.list();
// load all fonts installed on this computer into an array

PFont oFont=createFont("Univers",9,true);
// create the font for the data (value=0)

DateFonts [] dFont;



int [] dataNumR; // array of data "feels right"
int [] dataNumW; // array of data "feels wrong"
String [] dates; // array of data dates
float y; // for easing function 

void setup(){
  background(255);
  size(1440, 900);
  //smooth();
  dates=dataLoad("truthiness.tsv", 0);
  dataNumR=int(dataLoad("truthiness.tsv", 1));;
  dataNumW=int(dataLoad("truthiness.tsv", 2));;
  dFont=new DateFonts [dataNumR.length];

  for(int i=0;i<dataNumR.length;i++){
    //println(dataNum[i]);
    dFont[i]=new DateFonts(dataNumR[i],dataNumW[i]);
  }
}

void draw(){
  background(255);
  float newMouseY=map(mouseY,0,height,-7900,7900);
  y+=easeMove(y,0.1,newMouseY);
  for(int i=1;i<dataNumR.length;i++){
    pushMatrix();
    translate(width/2,(height/2-7900)+i*30-y);
    pushMatrix();
    textAlign(LEFT);
    textFont(oFont);
    fill(157);
    text(dates[i],-250,0);
    popMatrix();
    dFont[i].display();
    popMatrix();
  }  
}

String [] dataLoad(String filename, int colnNum){
  String [] rows=loadStrings(filename); 
  String [] newValue= new String [rows.length];
  for(int i=0;i<rows.length;i++){
    String [] column=split(rows[i],'\t');
    newValue[i]=column[colnNum];
  }
  return newValue;
}

float easeMove(float position,float easing,float mouseXY){
  float pos=position;
  float target=mouseXY;
  pos=(target-pos)*easing;
  return pos;
}

// make an object to load each data of each date

class DateFonts {
  PFont [] aFont;
  int numR,numW;// value of "feels right" and "feels wrong"
  float normNumber;
  
  DateFonts(int _numR, int _numW){
    numR=_numR;
    numW=_numW;
    
    // this if conditioning is trying to prevent heavy loading of RAM
    // but not sure if it facilitates the processing speed
    
    if(numR>=numW){
      aFont=new PFont[numR];
      int k;
      for(int i=0;i<aFont.length;i++){
        k=int(random(0,allFonts.length));
        aFont[i]=createFont(allFonts[k],30);
      } 
    } else if(numR<numW){
      aFont=new PFont[numW]; 
      int k;
      for(int i=0;i<aFont.length;i++){
        k=int(random(0,allFonts.length));
        aFont[i]=createFont(allFonts[k],30);
      }
    }
  }
  
  
  void display(){
    
    if(numR>0){        
      for(int i=0; i<numR;i++){
        textAlign(LEFT);
        color normColorR= lerpColor(color(11,202,222),
                          color(65,209,150),norm(numR,0,100)); 
        textFont(aFont[i]);
        fill(normColorR,2*255/numR);
        textSize(numR);
        text("feels right",0,0);
      }
    }if(numW>0){
      for(int i=0; i<numW;i++){
        textAlign(RIGHT);
        color normColorW= lerpColor(color(183,11,46),
              color(255,0,0), norm(numW,0,16));
        textFont(aFont[i]);
        fill(normColorW,2*255/numW);
        textSize(numW);
        text("feels wrong",-5,0);
      }
    }if(numR==0){  
      textAlign(LEFT);
      textFont(oFont);
      fill(11,202,222,150);
      text("nobody cares",0,0);
    } 
    if(numW==0){  
      textAlign(RIGHT);
      textFont(oFont);
      fill(183,11,46,150);
      text("nobody cares",-5,0);
    } 
  }  
}      

#2

Some key points:

  1. You are allowing the system to load all fonts on the system. For some users (including me), that is a HUGE amount of fonts. Instead of cycling through ALL fonts provided by PFont.list() choose a more reasonable subset. Even better, consider creating all of the fonts you need as vlw files include those files with your program.
  2. the createFont() function is very slow. Currently you are creating all of the fonts two times for every line of your data. I didn’t do the calculations, but that is A LOT of calls to createFont() which is why it takes 1,000,000 years for your app to startup :). If you must use createFont, create a single shared array of the created size 30 PFont instances and simply reference the shared array in your DateFonts constructor rather than creating a new one each time. You wouldn’t even loadFonts here, just pass a reference to the shared PFont.
  3. During your draw loop and in DateFonts.display() method you are drawing all data each time, even when the data is not going to be on the screen. By keeping track of your current Y position, you could prevent certain elements from being drawn, which will speed things up. For instance, if you have an array of data and as you are iterating through it and discover that it is impossible for the next element to be on screen (because its Y value is too big or too small), then you can break out of the loop and do something else.
  4. One final option would be to pre-render all of your data to a PGraphics object and save it to an image file or display the PGraphics object. Since you are not displaying “new” data, but just taking a new view of the same data, there are lots of optimization possibilities here.

If you take care of these issues your app will go extremely fast even on the web in processing js.

Keep us posted!

@garhodes


#3

Thx Chris. I’ll try those methods to test if I can figure it out.


#4

Hi guys. I’ve tried those methods. To declare a charset for createFont improves the performance a lot. I tried using PGraphics, but It did’t work well as I expect. Maybe I did’t use it correctly.

Here is my final coding.

String [] allFonts=PFont.list();
// load all fonts installed on this computer into an array

PFont oFont;
// create the font for the data (value=0)

PFont [] aFont;


char[] charset={'f','e','l','s','r','i','g','h','t','w','o','n'};
// it saves lots of memories 

DateFonts [] dFont;

int [] dataNumR; // array of data "feels right"
int [] dataNumW; // array of data "feels wrong"
String [] dates; // array of data dates
float y; // for easing function 

void setup(){
  background(255);
  size(1200, 800);
  oFont=createFont("Univers",9,true);
  aFont=new PFont[100]; // load 100 fonts from PFont.list()
                        // it improves performance too
    int k;
    for(int i=0;i<aFont.length;i++){
        k=int(random(0,allFonts.length));
        aFont[i]=createFont(allFonts[k],30,true,charset);
      } 
  dates=dataLoad("truthiness.tsv", 0);
  dataNumR=int(dataLoad("truthiness.tsv", 1));;
  dataNumW=int(dataLoad("truthiness.tsv", 2));;
  dFont=new DateFonts [dataNumR.length];

  for(int i=0;i<dataNumR.length;i++){
    dFont[i]=new DateFonts(dataNumR[i],dataNumW[i]);
  }
}

void draw(){
  background(255);
  float newMouseY=map(mouseY,0,height,0,16000);
  y+=easeMove(y,0.2,newMouseY);
  
  int showNum=27; // try to split the dataset for display()
  if (y>=0 && y<800){
    for(int i=0;i<showNum*2;i++){
      pushMatrix();
      translate(width/2,(height/2+110)+i*30-y);
        pushMatrix();
        textAlign(LEFT);
        textFont(oFont);
        fill(157);
        text(dates[i],-250,0);
        popMatrix();
      dFont[i].display();
      popMatrix();
    }
  }
  if (y>=14400){
    for(int i=showNum*17;i<dataNumR.length;i++){
      pushMatrix();
      translate(width/2,(height/2+110)+i*30-y);
        pushMatrix();
        textAlign(LEFT);
        textFont(oFont);
        fill(157);
        text(dates[i],-250,0);
        popMatrix();
      dFont[i].display();
      popMatrix();
    }
  }
  for(int j=1;j<18;j++){
    if(y>=height*j && y<height*(j+1)){
      for(int i=showNum*(j-1);i<showNum*(j+2);i++){
        pushMatrix();
        translate(width/2,(height/2+110)+i*30-y);
          pushMatrix();
          textAlign(LEFT);
          textFont(oFont);
          fill(157);
          text(dates[i],-250,0);
          popMatrix();
        dFont[i].display();
        popMatrix();
      }
    }
  }
}

String [] dataLoad(String filename, int colnNum){
  String [] rows=loadStrings(filename); 
  String [] newValue= new String [rows.length];
  for(int i=0;i<rows.length;i++){
    String [] column=split(rows[i],'\t');
    newValue[i]=column[colnNum];
  }
  return newValue;
}

float easeMove(float position,float easing,float mouseXY){
  float pos=position;
  float target=mouseXY;
  pos=(target-pos)*easing;
  return pos;
}

// make an object to load each data of each date

class DateFonts {
  
  int numR,numW;// value of "feels right" and "feels wrong"
  float normNumber;
  int [] j;
  
  DateFonts(int _numR, int _numW){
    numR=_numR;
    numW=_numW;
    j = new int [100]; // generate a random sheet
    for(int i=0; i<j.length;i++){
      j[i]=int(random(0,aFont.length));
    }
  }
  
  
  void display(){
      for(int i=0; i<numR;i++){
        textAlign(LEFT);
        color normColorR= lerpColor(color(11,202,222),
                          color(65,209,150),norm(numR,0,100)); 
        textFont(aFont[j[i]]);
        fill(normColorR,2*255/numR);
        textSize(numR);
        text("feels right",0,0);
      }
      for(int i=0; i<numW;i++){
        textAlign(RIGHT);
        color normColorW= lerpColor(color(183,11,46),
              color(255,0,0), norm(numW,0,16));
        textFont(aFont[j[i]]);
        fill(normColorW,2*255/numW);
        textSize(numW);
        text("feels wrong",-5,0);
      }
    if(numR==0){  
      textAlign(LEFT);
      textFont(oFont);
      fill(11,202,222,150);
      text("nobody cares",5,0);
    } 
    if(numW==0){  
      textAlign(RIGHT);
      textFont(oFont);
      fill(183,11,46,150);
      text("nobody cares",-5,0);
    } 
  }  
}