Random rows/columns in a csv file and print text with typewriter effect

Hi all,

I am starting on a project that involves using data from a large csv. For now I am just playing with the processing Table/row documentation and have created a mammals.csv file containing

amount, species, name 
0, Capra circus, Goat
1, Panthera Pardus, Leopard
2, Equus Zebra, zebra

What I am trying to achieve is

  1. Randomly select one row
  2. First print the amount of that row
  3. Clear screen
  4. Then print name of that same row
  5. Clear screen
  6. Start process again

With the the below code both amount and name are appearing at the same time

Table table;

void setup() {
  
  table = loadTable("mammals.csv", "header");
  size(500,500);
  background(0);

}
void draw() {

background(0);

  TableRow row = table.getRow((int)random(0,3)); //print a random row 
   String name = row.getString("name"); // prints name for row 
   textSize(32); //text size 
   fill(255,0,0);
   text(name, 100,100); // what to print and where 
   delay(1000); //delay for 5 seconds 
   
   
   //background(0); //background used to clear 
   String amount = row.getString("amount"); //a string with amount 
   textSize(32); //text size 
   text(amount, 100,100); 
   delay(1000); 

}

I have tried to insert a background() between the String name and String amount but that is just returning amount.

Any suggestions much appreciated!

2 Likes

draw doesn’t update the screen throughout

draw just updates the screen once at the end of draw

Hence, your approach won’t work.

Instead

instead, have a boolean situationShowAmount before setup()

in draw():

if(situationShowAmount) show amount, else show the name

instead of using delay try a timer

before setup():
int timer=0;

In draw():

if(millis()-timer > 1200) {
    // toggle
    situationShowAmount = ! situationShowAmount ; // toggle 
    timer=millis(); 
}

Chrisir

2 Likes

Hi Chrisir,

Thanks for the reply.

I think I understand what you mean. if over 1200 millis seconds have passed and amount does not equal amount, show amount??

However, I am confused as to why I should do this before setup() as I am unsure how to call it in draw in relation to amount and name.

Any further clarification would be great!

1 Like

Hola Chrisir, I learned this also through your input on my code, thank you very much for your help :slight_smile: the way you use booleans right before an if statement, is that what is called a ‘Flag’? and/or a ‘switch’?

3 Likes

I’d say I use a boolean variable in or with an if-clause.

It’s called a flag. (a marker if something is true or not)

(switch() is a command in processing similar to if...else if...else if... else..... Some might call a flag a switch (myself) but I think flag is better: Bit field - Wikipedia)

(if your boolean situationShowAmount needs more states than two, just go for an int which can have a lot of states (0,1,2,3…). Used often for the states of a program (e.g. for Intro Screen, Game, Game Over Screen, High Score Screen, Help Screen…))

Remark

What I was trying to say was:

  • make a timer to toggle situationShowAmount (if-clause 1) and
  • evaluate situationShowAmount in another if-clause (if-clause 2), acting accordingly (showing amount or name)

Chrisir

Table table;
TableRow row;
boolean situationShowAmount=true; 
int timer;

String amount="", name=""; 

void setup() {
  size(500, 500);
  background(0);
  table = loadTable("mammals.csv", "header");
  readData(); 
  timer=millis();
}

void draw() {

  background(0);

  if (situationShowAmount) {
    //show amount
    textSize(32); //text size 
    text(amount, 100, 100);
  } else {
    textSize(32); //text size 
    fill(255, 0, 0);
    text(name, 100, 100); // what to print and where
  }

  // ---------------------------------------------------

  if (millis()-timer > 3200) {
    // toggle
    situationShowAmount = 
      ! situationShowAmount;  
    readData(); 
    timer=millis();
  }//if
}

void readData() {
  if (situationShowAmount) {
    //read amount 
    row = table.getRow((int)random(0, 3)); //print a random row 
    amount = row.getString("amount"); //a string with amount
  } else {
    //read name 
    // row = table.getRow((int)random(0, 3)); //print a random row 
    name = row.getString("name"); // prints name for row
  }
}
//
2 Likes

@OptOut

I corrected my mistake and made a full sketch

2 Likes

I corrected my code again

besides from the headline

amount, species, name 

I had to remove the space signs (and the last invisible one behind the name)

2 Likes

Doh! Silly me…that makes sense, thanks for the help Chrisir!

2 Likes

Sorry to bother you again @Chrisir, I just realised an error as a result of lack of clarity on my OP.

The amount that appears should be the corresponding amount to the name that appears so

Goat 1
Leopard 2
Zebra 3

From what I can see, the amount is selecting a random number that is not related to the name.

1 Like

that was an error I corrected on my code above.

Please try again.

1 Like

Apologies…that’s returning a nullpointererror on line 49:
name = row.getString("name"); // prints name for row

1 Like

in read data we repeated this after the else:

   row = table.getRow((int)random(0, 3)); //print a random row    

Bad.

1 Like

my Bad.

before setup():

boolean situationShowAmount=true;

must be true so we start with reading the amount before using it

2 Likes

Thanks for your patience…think that’s it :grinning:

1 Like

you can also use

getRowCount()

see here

row = table.getRow((int)random(0, table.getRowCount())); //get a random row

2 Likes

Hi everybody,

I decided to post this question here rather than start a new thread as it is related to previous posts…hope that is ok, and if not I’ll be happy to create a new thread.

So I have now changed the output of the content. Instead of having name followed by amount I would like them to display at the same time, however, I would like to display this content using a typewriter effect, so one character at a time.

One name + corresponding amount to appear to on screen at the same time, but appearing character by character and then randomly selecting a new row…

The csv file has been changed slightly (multiple digits)

amount, species, name 
0.45.753.2311, Capra circus, Goat
1.11232.34564.56, Panthera Pardus, Leopard
2.435.654.684, Equus Zebra, zebra

The following code has been cobbled together from various sources, it’s almost there (but at the same time, probably not!)

Table table; //creates table 
TableRow row; // creates row 
String amount="", name="", nameAmount=""; //string 
int counter = 0 ; //set counter to zero 

void setup() {
  size(500, 500);
  background(0);
  //frameRate(1); //frameRate for speed of text?
  table = loadTable("mammals.csv", "header"); //table to load 

}

void draw() {
  
  background(0); //set background colour 
  fill(255, 0, 0); //set text colour 
  textSize(32); //text size 
  readData(); // calls readData Fucntion 
}

void readData() {

    row = table.getRow((int)random(0, 3)); //selects a random row from 
    amount = row.getString("amount"); //a string with amount
    name = row.getString("name"); // prints name for row
    String nameAmount = amount +  " " + name; // Lets me put name + amount together 
  
   println (nameAmount); //prints to console, just for me
  
  if (counter < nameAmount.length())  // if counter is less than the amount of char of NameAmount
    counter++; //increase counter by 1 
  text(nameAmount.substring(0, counter), 100, 100, width, height); 
  delay (1000);

  }

The problems with the above code:

  • The numbers and letter that appear seemed to be jumbled from other rows - although the end number and name does appear. correctly but only for this first iteration

  • I also get a string index out of range error which I think is occurring in the subString()

Any suggestions would be great!

1 Like

Don’t use delay

Never

(Except with external devices)

use my timer instead

Don’t allow a new word to be chosen as long as the old one isn’t finished

2 Likes

Thanks @Chrisir will give it a try :slight_smile:

1 Like

sorry to bother you again @Chrisir could I ask you to elaborate on
‘Don’t allow a new word to be chosen as long as the old one isn’t finished’

I’m taking that to mean that I should create another boolean so I can make a conditional
Ahead is my pseudocode

if(newString != finishedString){
then keep iterating through newString
}

but not sure if my logic is correct.

1 Like

Yes!

I meant you have one variable that is named showHowManyLettersOfThatData (in your wording counter)

You increase this

When it’s >= the length of the String, set it to 0 and choose a new word

pseudo-code:

if(timer............) {
      showHowManyLettersOfThatData++; 
}

if( showHowManyLettersOfThatData >= nameAmount.length() )  {
     showHowManyLettersOfThatData =0; 

    row = table.getRow((int)random(0, 3)); //selects a random row from 
    amount = row.getString("amount"); //a string with amount
    name = row.getString("name"); // prints name for row
    String nameAmount = amount +  " " + name; // Lets me put name + amount together 
  
   println (nameAmount); //prints to console, just for me

}
2 Likes