Bar chart - Display data when hovering

Hi all,
I’m trying to represent a very basic 1-column table as a bar chart. The .csv file reads as follows:


Value
50
100
150
200
250
300
350
400
450
500


My problem is I can’t manage to display each value on top of the bar when hovering over it. All values display at once and can’t figure out the algorithm for mouseX,Y. Below the code:

Bar[] bars;
//the data from the table will fill the array
Table table;

void setup() {
  size(500,500,P2D);
  loadData();
}

void draw() {
  background(255);
  
  //display all bars
  for(int i = 0; i < bars.length; i++) {
    bars[i].display();
    bars[i].rollover();
  }
}

void loadData() {
  //load file into table; header indicates the file has a non-data 1st row
  table = loadTable("data.csv", "header");
  
  //the size of the array is determined by the number of rows in the table
  bars = new Bar[table.getRowCount()];
  
  for(int i = 0; i < table.getRowCount(); i++) {
    
    TableRow row = table.getRow(i); //iterate over all the table rows
    
    //access the fields via their table names
    float Val = row.getInt("Value");
    
    //make a rectangle out of the data from each row
    float x = 50*i;
    bars[i] = new Bar(x,Val);
  }
}

class Bar {
  float x;
  float Val;
  
  //by default the mouse is not over the bar
  boolean inside = false;
  
  //Create the bar
  Bar(float tempX, float tempVal) {
    x = tempX;
    Val = tempVal;
  }
  
  //Checking if mouse is within the bar
  void rollover() {
    for(int i = 0; i < table.getRowCount(); i++) {
    if(mouseX > x && mouseX < x+50 && mouseY > height - table.getInt(i,0)) {
        inside = true;
      } else {
        inside = false;
        }
    }
  }
  
  //Display the bar
  void display() {
    stroke(255);
    fill(0);
    for(int i = 0; i < table.getRowCount(); i++) {
      rect(50*i,height,50,-table.getInt(i,0));
    }
    if(inside) {
      fill(255,0,0);
      textSize(10);
      textAlign(CENTER);
      for(int i = 0; i < table.getRowCount(); i++) {
        text(int(table.getInt(i,0)),25+50*i,height/2);
      }
    }
  }
}

Deleted … as full solutions for category homework not welcome.

1 Like

Thanks @mnse! That was espectacular, and much simpler than my solution. :sunglasses::+1:

Now I’m trying to extrapolate the same code by loading a different table in which I’m only using the 3rd column (Data_value) as the bar heights (divided by 1000 to fit in 500x500px):

table

The problem I’m finding when rendering is that some column widths look weird. Suspect that might be because of floating numbers? but I’ve tried to convert column width to integer to no avail.

How many rows are in the new table ?

Can you please show your code

It looks like you are still using your constant 50px width and not, what i showed you regarding bar width…

Means, do you still use this ?

rect(..,50,...)

Also if more than 500 rows it might also messing up as width gets < 1 …

Cheers
— mnse

@Chrisir… the new table contains 44 rows.

@mnse
Here’s the new code:

Bar[] bars;

//the data from the table will fill the array
Table table;

void setup() {
  size(500,500,P2D);
  textSize(15);
  textAlign(CENTER);
  loadData();
}

void draw() {
  background(255);
  
  //display all rectangles
  for(int i = 0; i < bars.length; i++) {
    bars[i].display();
    bars[i].rollover();
  }
}

void loadData() {
  //load file into table; header indicates the file has a non-data 1st row
  table = loadTable("business-employment-data-mar-2022-quarter-AFF.csv", "header");
  
  //the size of the array is determined by the number of rows in the table
  bars = new Bar[table.getRowCount()];
  
  for(int i = 0; i < table.getRowCount(); i++) {
    
    //defining bar width
    float w = width/table.getRowCount();
    
    //make a rectangle out of the data from each row
    bars[i] = new Bar(w*i,w,table.getRow(i).getFloat("Data_value")/1000);
  }
}
class Bar {
  float x;
  float w;
  float Val;
  
  boolean inside; //determine if the mouse is within the bar
  
  //Create the bar
  Bar(float tempX, float tempW, float tempVal) {
    x = tempX;
    w = tempW;
    Val = tempVal;
    inside = false; //by default the mouse is not within the bar

  }
  
  //Checking if mouse if over the bar
  void rollover() {
    if(mouseX > x && mouseX < x+w && mouseY > height - Val) {
        inside = true;
      } else {
        inside = false;
        }
  }
  
  //Display the bar
  void display() {
    stroke(255);
    fill(0);
    rect(x,height-Val,x+w,Val);
    if(inside) {
      fill(255,0,0);
      text(int(Val*1000),x+w/2,height-Val-10);
    }
  }
}

Thanks

In display ()
x+w is wrong

Just w

2 Likes

Thanks a lot @Chrisir!!!

sorry!
before my previous posting I’d removed to much :slight_smile:
just put in setup…

Correction added to the here

rectMode(CORNERS);

so this from my code would be correct

    rect(x, height-Val, x+w, height);

Cheers
— mnse

PS: But @Chrisir would also work :wink:

Really…?

I don’t know

Should work …

rectMode(CORNERS) interprets the first two parameters of rect() as the location of one corner, and the third and fourth parameters as the location of the opposite corner.

1 Like

It works as well, yeah thanks both @Chrisir and @mnse!

1 Like