Is it possible to create an indexed list (array) of RGB values for "fill()"?

edited September 2015 in Library Questions

I'm creating a (10 bar) bar graph inside a 'for' loop, and want to 'fill' each bar in a different colour from an indexed list (or array) of RGB colours. I'm sure it must be possible, but everything I've tried has failed. :(

Does anyone know how this could be done?

To help it make sense, this is the size statement: size(600,200);

Here's the 'for' loop:-

for(Index=0;Index<10;Index++) { InBuffer[Index]=MyPort.read(); fill(<*indexed RGB value*>); rect(Index*60,200,60,-InBuffer[Index]); }

(This is my first 'real' sketch.)

Thanks in advance, guys.

Answers

  • _vk_vk
    edited September 2015

    Untested

    edit: Tested and compiled, no error. Processing 2.2.1

    color[] colorList = new color[14];
    colorList[0] = color(255, 0, 255);
    //...
    
    fill(colorList[0]);
    

    :)

  • edited September 2015

    That was the first thing I tried, vk, but I get the error:- Syntax error on(s), misplaced construct(s)

    (This is in V3.0b5, I should say, too.)

  • edited September 2015

    I just tried it in V1.5.1, and get "Unexpected token"

    In both versions, the error is on the second line.

  • edited September 2015

    Expanding on vk's sample: :ar!

    // forum.processing.org/two/discussion/12490/
    // is-it-possible-to-create-an-indexed-list-array-of-rgb-values-for-fill
    
    // 2015-Sep-12
    
    final int COLORS = 10, DIM = 40;
    final color[] colors = new color[COLORS];
    
    size(400, 50, JAVA2D);
    smooth(4); // just smooth(); for P1.5.1
    noLoop();
    
    strokeWeight(1.5);
    stroke(0);
    rectMode(CORNER);
    
    for (int i = 0; i != COLORS; colors[i++] = (color) random(#000000));
    
    for (int i = 0; i != COLORS; ++i) {
      fill(colors[i]);
      rect(i*DIM, 0, DIM, DIM);
    }
    
  • That worked, but I don't understand most of it to modify to suit my needs. (First sketch) I'm not sure where to start.... Can the colours be initialised in advance? They can't be random, the graph will be refreshed at least once per second, from data arriving at the COM port. Are the Java2D, smooth(4); noLoop();strokeWeight(1.5); stroke(0); rectMode(CORNER); bits necessary to fix my problem?

    Is it possible to use the first two lines of your example, initialise the 10 colours there, then use the rest of my code as it was originally?

  • edited September 2015

    Obviously not - this fails with an error:-

    final int COLORS = 10, DIM = 40;

    final color[] colors = new color[COLORS];

    colors[0]=(23,34,45);

  • edited September 2015

    This is now a "Library Question"! And maybe it got nothing to do w/ arrays! 8-X
    If the color value comes outta some read(), you just need to pass that as fill()'s parameter. :-B

  • Well, it was worth a try, but I think I'll go back to shades of grey. This has got me 10 times as confused. Thanks anyway guys, I appreciate the attempt to help.

  • edited September 2015

    No, the colour value doesn't come out of the read - the height of each bar does. And I want to easily differentiate between the bars with colours that stay the same each time the bars are refreshed. I'll scale the values that I receive serially, to get the right heights to fit nicely in the graph, then iterate through the for loop creating the bars, and colour (shade) each as i go with pre-initialised colours(shades) using the index from the loop to retrieve each corresponding colour(shade). But as I say, I'll go back to grey shades, then I only need a single value for each shade rather than 3 to create an RGB colour. I know what I'm doing in C, but am lost with Processing.

  • edited September 2015 Answer ✓

    In my example I've relied on filling the array w/ random() colors for convenience.
    If you've already got some fixed palette, it's even easier to create the color[] array:

    final color[] PALETTE = {
      #FF0000, #008000, #0000FF
    };
    

    Just place as many color values there as you'd need to represent those bars. O:-)
    Read more about datatype color here: https://Processing.org/reference/color_datatype.html

  • edited September 2015

    Excellent, you did it. :) That compiles fine. I've wrestled with this for so long that grey was looking better and better by the minute. I wrote Arduino code for one part of this project, so I could use an existing Arduino library - no problems, wrote PIC code for another part - no problems, then after 12 hours straight the Processing part just wasn't coming together. I eventually got the Processing serial stuff working, then couldn't master the easy bit. Thank you very much for this. I knew it was easy, but couldn't for the life of me figure it out. Once again, I owe you one. Now I'll see if I can work out how to label the bars......

  • edited September 2015

    Actually, it looked good until I tried this:-

    fill(PALETTE[0]); - No go. (Error on VariableDeclaratorId)

    It looked good until then, too. Not to worry, I can learn to live with grey. I'll just make the shades light,dark,light,dark, and they'll stand out fine.

  • edited September 2015

    What you're describing isn't normally possible. Function fill() accepts float type.
    And color is automatically coerced as float btW.
    Much probably you've forgotten some ; or bracket.
    But w/o seeing your code there's no way to help ya there! (:|

  • edited September 2015

    Here's the full sketch, in shades of grey:-

    (For now, I'm sending values from the micro that don't need scaling to fit in the graph.) Also, the shades of grey are just randomly chosen - not for good contrast between neighbouring bars.

    `import processing.serial.*;

    Serial MyPort; // Create object from Serial class int[] InBuffer=new int[10]; int Index; int[]Shades={24,55,48,23,78,40,200,63,230,140};

    void setup() { size(600,200); MyPort=new Serial(this,"COM6",19200); }

    void draw() { if ( MyPort.available()>0) { for(Index=0;Index<10;Index++) { InBuffer[Index]=MyPort.read(); fill(Shades[Index]); rect(Index*60,200,60,-InBuffer[Index]); } MyPort.clear(); } }`

    For some reason, pasting into the "code" tags didn't work properly. ??? It's all there though.

  • edited September 2015

    I tried again - it just won't go in as 'code'??? Anyway, it works just fine in grey. I can live with that.

  • import processing.serial.*;
    
    Serial MyPort;  // Create object from Serial class
    int[] InBuffer=new int[10];
    int Index;
    int[]Shades={24, 55, 48, 23, 78, 40, 200, 63, 230, 140};
    
    void setup() 
    {
        size(600, 200);
        MyPort=new Serial(this, "COM6", 19200);
    }
    
    void draw()
    {
        if ( MyPort.available()>0)
        {
            for (Index=0; Index<10; Index++)
            {
                InBuffer[Index]=MyPort.read();
                fill(Shades[Index]);
                rect(Index*60, 200, 60, -InBuffer[Index]);
            }
            MyPort.clear();
        }
    }
    
  • edited September 2015

    For your interest, the data originateswill originate from a Mattel Mindflex headset. I'm using the Arduino Brain Library from 'kitschpatrol' to parse it, then sending it serially via an RF link to the PC, for Processing to display the graph. Updates from the EEG headset come once per second. It's also sent to a PIC that will control a DC motor's speed with PWM. (This is simulated data right now, generated by the Arduino, then sent via the RF link, until I shake out the bugs.)

  • edited September 2015 Answer ✓

    Here's my attempt: :D

    // forum.processing.org/two/discussion/12490/
    // is-it-possible-to-create-an-indexed-list-array-of-rgb-values-for-fill
    
    // GoToLoop (2015-Sep-13)
    
    import processing.serial.Serial;
    
    static final int QTY = 10, DIM = 60, FPS = 10;
    final color[] colors = new color[QTY];
    final int[] heights  = new int[QTY];
    int idx;
    
    void setup() {
      size(600, 200, JAVA2D);
      smooth(4);
      noLoop();
      frameRate(FPS);
    
      strokeWeight(1.5);
      stroke(0);
      rectMode(CORNER);
    
      keyPressed(); // Comment it out once you've got your PALETTE[].
      //new Serial(this, "COM6", 19200); // Uncomment to activate it!
    }
    
    void draw() {
      background(0300);
      for (int i = 0; i != QTY; ++i) {
        fill(colors[i]);
        rect(i*DIM, height, DIM, -heights[i]);
      }
    }
    
    void serialEvent(Serial s) {
      heights[idx] = s.read();
      if ((idx = (idx + 1) % QTY) == 0)  redraw = true;
    }
    
    void keyPressed() {
      for (int i = 0; i != QTY; ++i) {
        colors[i]  = (color) random(#000000);
        heights[i] = (int) random(height);
      }
      redraw = true;
    }
    
    void mousePressed() {
      keyPressed();
    }
    
    • Again I'm using random() colors for convenience.
    • Replace colors[] w/ your own fixed PALETTE[] later.
    • And since I don't have any Serial here, I'm simulating it inside keyPressed().
    • Uncomment new Serial(this, "COM6", 19200); in order to ignite your Arduino readings. :P
  • edited September 2015 Answer ✓

    As a bonus, here's the very same example above running online: \m/
    http://studio.ProcessingTogether.com/sp/pad/export/ro.9qxrHCEYG6Z9o

    Of course, Serial class won't work online! >-)

  • Eureka. :)

    That's fine the way it is. It doesn't matter if the colours are random each time I run it, as long as they stay the same the whole time it 'is' running, and they do. I won't even try initialising 10 colours at all. It works very well with serial input.

    It's only for diagnostics while I get the hardware all sorted out, and then maybe to help me train my brain to concentrate. For motor control, I'll only actually use 1, or maybe 2 of the 10 channels, "Attention", and "Meditation", the others are the alpha, beta, delta, theta and gamma waves, some in high ,lo format, (low alpha, high alpha). I'll scale everything for 0-255 output, then make the graph 255 tall.

    A very big thank you, mate. I didn't expect you to go to all of this trouble.

    Next up I'll see if I can get labels on each bar, but that's not really important. If necessary, I'll just keep a legend on paper below the monitor.

    Once again, thank you very much. Might have a nap now, I'm exhausted.

  • edited September 2015

    After a couple of hours sleep, I realised how I could have been doing it right from the start. Simple. I was just too tired. I didn't need a multi-dimensional array at all. The labels were easy, too, once I had time to look up "text()" in the reference. I wanted to use 'byte', but it appears to be 'signed' and generates errors with the larger values, so used 'char'. Compiles and runs fine.

    char[] Red={220, 12, 86};
    char[] Green={12, 103, 220};
    char[] Blue={105, 215, 8};
    int TextVPos=268;
    
    size(600, 270);
    
    fill(Red[0], Green[0], Blue[0]);
    rect(0, 255, 60, -127);
    fill(Red[1], Green[1], Blue[1]);
    rect(60, 255, 60, -55);
    fill(Red[2], Green[2], Blue[2]);
    rect(120, 255, 60, -200);
    
    textSize(11);
    fill(0);
    text("   Signal", 2, TextVPos);
    text(" Attention", 62, TextVPos);
    text("Meditation", 122, TextVPos);
    
  • edited September 2015

    That's not very efficient since a color is made outta aRGB together.
    Rather than having those 3 attributes spread among 3 arrays, just have 1 PALETTE[] array;
    like vk showed at his 1st post:

    final color[] PALETTE = {
      color(220, 12, 105), 
      color(12, 103, 215), 
      color(86, 220, 8)
    };
    
    final String[] TITLES = {
      "Signal", 
      "Attention", 
      "Meditation"
    };
    
    size(600, 270, JAVA2D);
    smooth(4);
    noLoop();
    
    strokeWeight(1.5);
    stroke(0);
    rectMode(CORNER);
    
    background(0350);
    
    fill(PALETTE[0]);
    rect(0, 255, 60, -127);
    fill(PALETTE[1]);
    rect(60, 255, 60, -55);
    fill(PALETTE[2]);
    rect(120, 255, 60, -200);
    
    textSize(11);
    fill(0);
    
    text(TITLES[0], 2, 268);
    text(TITLES[1], 62, 268);
    text(TITLES[2], 122, 268);
    
  • Oh no, you're right - far from efficient, but it would have worked.

    As I said, that's how I could have been doing it, not should. :)

  • And yep, I'm sticking with your method. Having thought of the 3 x array method, I had to try it though.

  • edited September 2015 Answer ✓
    • When coding in Java & JavaScript, uppercase camel style is reserved for class & interface names.
    • Variables & functions use instead lowercase camel style.
    • That is, instead of TextVPos, the 1st letter should be lower case: textVPos.
    • And finally, constants are all in uppercase w/ underlines separating words in them.
  • Thanks, I'll keep those points in mind. The upper-case camel style is what I use in C, just a habit. In C, I usually do use upper case for constants. I wasn't sure in Processing.

    And as an aside, I've already showed off a screenshot of your re-write of the sketch while running, on the Electronics Point forums, in a thread I'm involved in there on a Mind-Controlled Robot Car. (Gave you full credit, of course.) Thank you again. I'm pleased with the way it's all coming together now.

  • edited September 2015 Answer ✓

    Just a last reminder, you can also place those graph bar text() in 1 String[] array too: $-)

    final String[] TITLES = {
      "Signal", 
      "Attention", 
      "Meditation"
    };
    
    text(TITLES[0], 2, 268);
    text(TITLES[1], 62, 268);
    text(TITLES[2], 122, 268);
    
  • edited September 2015

    Ha. I should have, shouldn't I? I wasn't thinking that far ahead yet. Still stoked that the colour version of the bars is working so well. I'll put it all together properly tomorrow, now that I know how, and after a good night's sleep. It's 10:30pm here in Oz, and I've only had that one short nap in the last 36 hours. I'm exhausted. I'll be able to think more clearly tomorrow. Oh, and I looked up 'final' , too, so I can get it's usage correct.

Sign In or Register to comment.