# バッファからグラフを描く

## バッファとは

一定の時間データを保持する機構。ここでは、1フレームごとに新しい脳波を取得して、300フレーム（約5秒）前のデータまで保持する。

<figure><img src="/files/13PpRPi05YAwu1o51elf" alt=""><figcaption><p>実行画面</p></figcaption></figure>

## サンプルコード：

* 実行手順
  * Vieを装着し、Vie StreamでVieに接続
  * 「計測開始(Activate Sensor)」ボタンを押す
  * 「OSC転送(OSC Streaming)」ボタンを押す
  * 「ポート番号」と「デバイス識別子」を確認。（通常はそれぞれ、65001、1）
  * コードの実行
  * キーボードの1\~5キーで脳波を切り替える

{% file src="/files/tgpyuP7EGyXih9xXvs8O" %}

## サンプルコードの解説

### クラスの用意

Delta, Theta, Alpha, Beta, Gammaの数値をまとめて保持するクラスを用意する

{% code overflow="wrap" %}

```processing
//脳波格納用のクラス
class BrainWave{
  
  public float delta;
  public float theta;
  public float alpha;
  public float beta;
  public float gamma;
  
  BrainWave(){
    this.delta =0.0;
    this.theta =0.0;
    this.alpha =0.0;
    this.beta =0.0;
    this.gamma =0.0;
  }
  
  void set(float d,float t,float a,float b,float g){
    this.delta =d;
    this.theta =t;
    this.alpha =a;
    this.beta =b;
    this.gamma =g;
  }
  
}
```

{% endcode %}

### バッファの準備

```processing
////左と右の脳波を一定時間格納するバッファ、左用と右用
ArrayList<BrainWave> bwBufferLeft  = new ArrayList<BrainWave>();
ArrayList<BrainWave> bwBufferRight = new ArrayList<BrainWave>();

//バッファサイズ（300フレーム分のバッファ）
int bwBufferSize = 300;

void setup() {
  //中略
  //バッファを初期化する
  for(int i=0; i<bwBufferSize; i++){
    bwBufferLeft.add( new BrainWave() );
    bwBufferRight.add( new BrainWave() );
  }
}
```

### 毎フレームごとにバッファにデータを追加しつつ先頭を削除

```processing
void draw() {

  //中略
  
  //左脳波をバッファに格納
  BrainWave bwLeft = new BrainWave();
  bwLeft.set(waveLeft[0],waveLeft[1], waveLeft[2], waveLeft[3], waveLeft[4]);
  bwBufferLeft.add(bwLeft);
  
  //右脳波をバッファに格納
  BrainWave bwRight = new BrainWave();
  bwRight.set(waveRight[0],waveRight[1], waveRight[2], waveRight[3], waveRight[4]);
  bwBufferRight.add(bwRight);
  
  //バッファサイズが上限に達したら先頭を削除
  if(bwBufferLeft.size() > bwBufferSize){
    bwBufferLeft.remove(0);
  }
  if(bwBufferRight.size() > bwBufferSize){
    bwBufferRight.remove(0);
  }
  //中略
}
```

## beginShape() , vertex(), endShape()について

次のように書くと、(x0,y0)、(x1,y1)、(x2,y2)の各頂点を結ぶ線が描ける。

```processing
noFill();
beginShape();
vertex(x0, y0);
vertex(x1, y1);
vertex(x2, y2);
endShape();
```

### バッファを折れ線グラフとして描画

```processing
void draw() {

  //中略
  
  //左のバッファの折れ線グラフ
  beginShape();
  
  //バッファの先頭から最後まで格納されているBrainWaveのインスタンスにアクセスして数値を取得
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      //bwBufferLeft.get(i)で先頭からi番目のBrainWaveインスタンスにアクセス
      //bwBufferLeft.get(i).deltaで、インスタンスに保持されているdeltaの数値を取得
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    //折れ線グラフ上の点(x,y)を計算
    float x = 30 + i;
    float y = -1 * wave;
    //頂点を登録
    vertex(x,y);
  }
  endShape();
  //中略
}
```

### バッファを円環グラフとして描画

```processing
void draw() {

  //中略
  
　　　　//バッファの描画2:円環グラフ
  float centerX = 180;
  float centerY = height*0.7; 
  
  //左のバッファ
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    //バッファ内のデータを全て描画するのに4周分とすると
    //2.0Pi * 4 / bwBufferSizeで1バッファあたりの角度が求まる。
    //取得した数値waveは中心からの距離に対応させ、頂点の座標(x,y）を求める
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    //古いバッファ値はアルファが低く（薄く）なるようにする
    float alpha = 255.0 * (float)i / (float)bwBufferLeft.size();
    
    //vertex関数の直前に色指定（stroke() or fill()）することでその頂点固有の色を指定できる。
    stroke(red(cl), green(cl), blue(cl),alpha);
    vertex(x,y);
  }
  endShape();
  //中略
}
```

## プログラム全体

{% code overflow="wrap" lineNumbers="true" %}

```processing
import oscP5.*;
import netP5.*;

//OSCP5クラスのインスタンス
OscP5 oscP5;

float [] waveLeft  = new float[5];
float [] waveRight = new float[5];

//左と右の脳波を一定時間格納するバッファ、左用と右用
ArrayList<BrainWave> bwBufferLeft  = new ArrayList<BrainWave>();
ArrayList<BrainWave> bwBufferRight = new ArrayList<BrainWave>();

//バッファサイズ（300フレーム分のバッファ）
int bwBufferSize = 300;

int selectedWaveByKey = 0;

String [] colorHex = {"FF034AA6", "FF72B6F2", "FF73BFB1", "FFF2A30F", "FFF26F63"};
String [] bandName = {"Delta", "Theta", "Alpha", "Beta", "Gamma"};

void setup() {
  size(800,600,P2D);
  frameRate(60);
  //ポートを65001に設定して新規にOSCP5のインスタンスを生成
  oscP5 = new OscP5(this,65001);
  
  //バッファを初期化する
  for(int i=0; i<bwBufferSize; i++){
    bwBufferLeft.add( new BrainWave() );
    bwBufferRight.add( new BrainWave() );
  }
  textSize(15);
}

void draw() {
  background(0);
  noStroke();
  
  //左脳波をバッファに格納
  BrainWave bwLeft = new BrainWave();
  bwLeft.set(waveLeft[0],waveLeft[1], waveLeft[2], waveLeft[3], waveLeft[4]);
  bwBufferLeft.add(bwLeft);
  
  //右脳波をバッファに格納
  BrainWave bwRight = new BrainWave();
  bwRight.set(waveRight[0],waveRight[1], waveRight[2], waveRight[3], waveRight[4]);
  bwBufferRight.add(bwRight);
  
  //バッファサイズが上限に達したら先頭を削除
  if(bwBufferLeft.size() > bwBufferSize){
    bwBufferLeft.remove(0);
  }
  if(bwBufferRight.size() > bwBufferSize){
    bwBufferRight.remove(0);
  }
  
  //ラベル
  fill(255);
  text("Left", 30, 30);
  text("Right", 430, 30);
  
  //waveLeftの描画
  for(int i=0;i<5;i++){
    fill(unhex(colorHex[i]));
    rect(130, 50+30*i, waveLeft[i], 20);
    fill(255);
    text(bandName[i], 30, 65+30*i);
    text(floor(waveLeft[i])+"%", waveLeft[i]+140, 65+30*i );
  }
  
  //waveRightの描画
  for(int i=0;i<5;i++){
    fill(unhex(colorHex[i]));
    rect(530, 50+30*i, waveRight[i], 20);
    fill(255);
    text(bandName[i], 430, 65+30*i);
    text(floor(waveRight[i])+"%", waveRight[i]+540, 65+30*i );
  }
  

  
  //バッファの描画1:折れ線グラフ
  pushMatrix();
  translate(0,height/2);
  
  //左のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  rect(30, -100, bwBufferSize, 100);
  stroke(unhex(colorHex[selectedWaveByKey]));
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    float x = 30 + i;
    float y = -1 * wave;
    vertex(x,y);
  }
  endShape();
  
  //右のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  rect(430, -100, bwBufferSize, 100);
  stroke(unhex(colorHex[selectedWaveByKey]));
  beginShape();
  for(int i=0; i<bwBufferRight.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferRight.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferRight.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferRight.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferRight.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferRight.get(i).gamma;
    }
    float x = 430 + i;
    float y = -1 * wave;
    vertex(x,y);
  }
  endShape();
  popMatrix();
  
  //バッファの描画2:円環グラフ
  float centerX = 180;
  float centerY = height*0.7; 
  
  //左のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  ellipse(centerX,centerY,200,200);
  ellipse(centerX,centerY,100,100);
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    float alpha = 255.0 * (float)i / (float)bwBufferLeft.size();
    stroke(red(cl), green(cl), blue(cl),alpha);
    
    vertex(x,y);
  }
  endShape();

  //右のバッファ
  centerX = 590;
  
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  ellipse(centerX,centerY,200,200);
  ellipse(centerX,centerY,100,100);
  beginShape();
  for(int i=0; i<bwBufferRight.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferRight.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferRight.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferRight.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferRight.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferRight.get(i).gamma;
    }
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    float alpha = 255.0 * (float)i / (float)bwBufferRight.size();
    stroke(red(cl), green(cl), blue(cl),alpha);
    
    vertex(x,y);
  }
  endShape();
  
  
  
  //インタラクションガイド
  fill(255);
  text("Press key \"1,2,3,4,5\" to select a wave.",30,height-10);

}

//OSCメッセージを受信した際に実行するイベント
void oscEvent(OscMessage msg) {
  
  if(msg.checkAddrPattern("/wave/L/1")==true) {   
    for(int i=0;i<5;i++){
      waveLeft[i] = msg.get(i).floatValue();
    }    
  }
  if(msg.checkAddrPattern("/wave/R/1")==true) {   
    for(int i=0;i<5;i++){
      waveRight[i] = msg.get(i).floatValue();
    }    
  }

}

//脳波格納用のクラス
class BrainWave{
  
  public float delta;
  public float theta;
  public float alpha;
  public float beta;
  public float gamma;
  
  BrainWave(){
    this.delta =0.0;
    this.theta =0.0;
    this.alpha =0.0;
    this.beta =0.0;
    this.gamma =0.0;
  }
  
  void set(float d,float t,float a,float b,float g){
    this.delta =d;
    this.theta =t;
    this.alpha =a;
    this.beta =b;
    this.gamma =g;
  }
  
}

void keyPressed(){
 
  if(key == '1'){
    selectedWaveByKey = 0;
  }
  
  if(key == '2'){
    selectedWaveByKey = 1;
  }
  
  if(key == '3'){
    selectedWaveByKey = 2;
  }
  
  if(key == '4'){
    selectedWaveByKey = 3;
  }
  
  if(key == '5'){
    selectedWaveByKey = 4;
  }
  
  
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://masaki-yamabe.gitbook.io/dda2023-vie-visualization/baffakaragurafuwoku.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
