トレイルトップに戻る    印刷する

時系列のデータを図形の大きさで表すーDatamateを使って書く

ラーニングトレイル2の(2)時系列変化で、データの時系列変化を、図形の大きさで表しました。 この時、図形を描く位置やデータを切り替えるタイミング(アニメーションさせるスピード)は スケッチ内で計算しました。つまり、位置やアニメーションの指定を自分で書いたのですが、 Datamateライブラリ が提供する機能を使うと、その処理を個別に書かずに、Datamateに任せることができます。

Datamateライブラリを使う、つまりDatamate.jsファイルを参照できるように指定するには、2つの方法があります。

年ごとに円の大きさを切り変える

リストT2-2-1は、年ごとに変化するデータを、図形の大きさで表した例です。 このプログラムをDatamate.jsの機能を使って書き換えてみます。


クリックで開始⇔停止

[1]視覚化の対象となる内部テーブルを作る

9年分の年、猫の数、犬の数のデータを次のようなテーブルと考えます。
2013年2014年2015年2016年 2017年2018年2019年2020年2021年
84098425829783338672 8849876486288946
87148200799480087682 7616757973417106

このテーブルの行と列には、それぞれヘッダ(行の名前、列の名前)があります。 ヘッダのあるなしは任意に指定できますが、この例のようにヘッダ行、ヘッダ列があるテーブルがデフォルトです。
ヘッダ行、ヘッダ列を除いたデータ部分のことをデータテーブルと呼んで区別します。

Datamatemのmake()関数を使って、1行ごとに、行の名前とデータを指定します。
  Datamate.make('行の名前', [データの配列]);
文字列は引用符で囲みます(二重"でも一重'でもいい)。このデータの場合、次のようにmake()関数を3回実行します。 ひとつ目のmake()関数は、ヘッダ行を作るもので、列のヘッダを配列内に指定しています。
Datamate.make('年', ['2013年', '2014年', '2015年', '2016年', '2017年',
                     '2018年','2019年', '2020年', '2021年']);
Datamate.make('猫', [8409, 8425, 8297, 8333, 8672, 8849, 8764, 8628, 8946]);
Datamate.make('犬', [8714, 8200, 7994, 8008, 7682, 7616, 7579, 7341, 7106]);

[2]データを表示する領域(レイアウトスペース)を作る

表示のための領域をレイアウトスペースと呼び、この領域を複数のエリアに分割して、エリアの中に、この例だとデータの大きさを表す赤い円を描きます。
Datamate.makeArea()関数を使って、レイアウトスペース作り、エリアに分割します。
Datamate.makeAreas(x座標, y座標, 横幅, 高さ, 横方向のエリア数, 縦方向のエリア数);
キャンバス内でのレイアウトスペースの(x,y)座標と、幅と高さ、そしてその領域を何列に分けるか、何行に分けるかを指定します。 キャンバス全体を横方向に2つのエリアに分割するには次のように書きます。
Datamate.makeArea(0, 0, width, height, 2, 1);

[3]分割したエリアに番号を振る

Datamate.bindAreas()関数を使って、エリアに番号を振ります。
Datamate.bindAreas([番号, 番号,..]);
猫と犬の2つデータをどのエリアに表示するかを指定するときに、この番号を使います。
Datamate.bindAreas([0, 1]);
番号は必ずしも、0から始める必要はなく、連続の数字である必要もありません。デフォルトでは、0から順番に番号が振られるので、そのままでいい場合、bindAreas()関数の実行は省略できます。

[4]テーブルから値を取り出す

データを反映したグラフィックスをエリアに描画するために、テーブルから値を取り出すにはvalue()関数を使います。
Datamate.value(行の指定, 列の指定);
  行の指定:行の名前あるいはデータテーブルのインデックス(0から振られる。ヘッダ行の次が0)
  列の指定:列の名前あるいはデータテーブルのインデックス(0から振られる。ヘッダ列の次が0)
例えば、猫の2013年のデータを取り出すには、次のように書きます。
Datamate.value('猫', 0);
または
Datamate.value(Datamate.rowName(0), 0);
rowName()関数は行のヘッダ(名前)を返す関数です。列のヘッダはcolumnName()関数で得られます。

[5]エリアの描画をする関数を定義する

データを円の大きさとして描画するこの例の描画処理を分解すると、次のようになります。 この処理をエリアごとに繰り返すので、エリアの番号を引数として渡し、 これらの描画処理を関数としてまとめて定義しておきます。 関数として描画処理をまとめておくと、それをdraw()関数から呼び出すだけでよく、エリアごとの描画処理をdraw()関数内で記述する必要がなくなります。

関数内での描画処理には、2つの情報が必要です。 これらの情報を関数の引数として渡すことにします。関数名は任意です。
function drawData(syurui, number) {
	.....
}
例えば、猫のデータを左側のエリアに表示するには、次のように引数を指定します。
drawData('猫', 0);    // 表示エリア0に'猫'データを表示
または
drawData(Datamate.rowName(0), 0);

[6]エリアの中央の位置、大きさなどの情報を得る

描画処理を行う関数(上の[5]で定義したdrawData()関数)内で、 描画をする際には、エリアの情報(中央位置や幅、高さ)が必要になります。 Datamate.area()関数は、描画エリアの情報(位置や大きさの情報を保持するareaオブジェクト)を返します。
Datamate.area(エリアに振った番号);
この例ではdrawData()関数内で、引数で渡されたエリア番号を使って、次のように領域情報を得ます。
const area = Datamate.area(block);
Datamate.area()関数が返す値(areaオブジェクト)には、次のような変数に領域の情報が保存されています。 エリアの中央に円を描くなら、変数centerXとcenterYを使って、次のように書きます。
ellipse(area.centerX, area.centerY, w, w);  //wは直径
 

[7]データを順に表示する(再生する)

テーブルのデータを順に表示することで、データの変化をアニメーションとして描画できます。 この例だと、横方向(行)に注目するデータを変えることで、時系列(年ごと)変化を表示できます。

Datamateには、今注目している(focusを当てている)データのインデックスを返す関数foucsX()とfoucsY()があります。引数に0を指定すると今フォーカスしている値のインデックスを返します。引数に1を指定するとフォーカスしている値の次の値のインデックスを返します(つまり、引数はフォーカスしている値からの距離を意味する)。
const indexX = Datamate.foucsX(0); //フォーカス中のデータの横方向(列)のインデックスを返す
const indexY = Datamate.foucsY(0); //フォーカス中のデータの縦方向(行)のインデックスを返す
そして、play()関数を使って、フォーカスするデータを順に動かします(これを再生と呼びます)。再生することで、関数foucsX()とfoucsY()が返すインデックスが順に変化します。 play()の引数には、1秒間に何回データを動かす(次のデータを取り出す)のかを指定します。
Datamate.play(1秒間に横方向に動かす回数, 1秒間に縦方向に動かす回数);
例えば、引数に2を指定すると0.5秒ごとに、引数に0.4を指定すると2.5秒ごとに、foucsX()関数、foucsY()関数で取り出されるデータのインデックスが順番に進みます。 play()関数の引数に0を指定するとデータは動きません。
再生しない(Datamate.play()関数を実行しない)場合、foucsX()、foucsY()関数で取り出されるデータのインデックスは先頭のままです。

再生をループしたい時は、loop()関数を使います。
Datamate.loop(横方向の再生をループするか, 縦方向の再生をループするか);
引数をtrueとすると再生がテーブルの最後の値までいくと先頭に戻ります。デフォルト(指定しない場合)はfalseで、最後のインデックスで止まります。

リストT2-2-1では、スケッチが起動されてからの経過時間を計算して、3秒たったらデータを切り替えるといった処理を書いていましたが、 データ切り替えの処理はDatamate.play()関数がするので、その記述は不要になります。

【リストT2-5-1】
const title = "猫と犬の飼育推計数";
const titleX = 120;  //この↑表題を表示するx座標
function setup() {
  createCanvas(450, 250);
  Datamate.make('年', ['2013年', '2014年', '2015年', '2016年', '2017年', '2018年',
                                                '2019年', '2020年', '2021年']);
  Datamate.make('猫', [8409, 8425, 8297, 8333, 8672, 8849, 8764, 8628, 8946]);
  Datamate.make('犬', [8714, 8200, 7994, 8008, 7682, 7616, 7579, 7341, 7106]);
  Datamate.makeAreas(0, 0, width, height, 2, 1);
  Datamate.bindAreas([0, 1]);
  Datamate.play(0.3, 0);  //横方向に動かす
  Datamate.loop(true);    //ループする。Datamate.loop(true, false); と同じ。第2引数は省略可
  noStroke();
  textAlign(CENTER, CENTER);
}
function draw() {
  background(210);
  drawData('猫', 0);    // 表示域0に'猫'データを表示  drawData(Datamate.name(0), 0);
  drawData('犬', 1);    // 表示域1に'犬'データを表示  drawData(Datamate.name(1), 1);
}
function drawData(syurui, block) {
  const area = Datamate.area(block);         //表示エリアをとりだす
  const index = Datamate.focusX(0);          //今フォーカスしているデータのインデックス
  const year = Datamate.columnName(index);   //列のヘッダ
  const value = Datamate.value(syurui, index);
  const w = map(value, 7000, 9000, 30, 200);  //データを円の直径に換算
  fill(200, 0, 0);
  ellipse(area.centerX, area.centerY, w, w);
  fill(0);
  text(title+"("+year+")", titleX, 30);  //表題と年の表示
  fill(255);
  text(syurui + "\n" + value + "千頭", area.centerX, area.centerY); //データの種類と頭数の表示
}

演習問題

【問題T2-5-1】
リストT2-5-1を変更し、円の大きさがスムーズに変化するようにしてみよう。
今フォーカスしている値のインデックスを返すfocusX()、focusY()関数は、今のインデックスと次のインデックスとの間を補間(内挿)する機能を備えています。補間機能を有効にするには、第2引数にtrueを指定します。
【リストT2-5-1】の場合、次のように書くと、play()関数で指定したフレームレートで、focusX()が返すインデックスが徐々に動きます(整数インデックスの間の値が返る)。それをvalue()関数に指定すると、連続的に変化する値が得られ、この値を使って、円の大きさを計算すると、スムーズに変化させることができます。
const indexForHokan = Datamate.focusX(0, true); //focusX(0)とfocusX(1)の間を補間したインデックス
const value = Datamate.value(syurui, indexForHokan);
ただ、このvalueをそのまま数値の表示に使うと、数が大きく変化して見にくいので、数値表示用のデータは補間しない値を使う方がいいでしょう。

リストT2-2-2では、犬と猫の円の直径用に別々の変数を用意して、変化する円の直径を(自分で)計算していました。Datamate.jsを使って順次データを取り出していく場合は、この変化の計算をDatamate.focusX()の補間機能に任せるのが簡単です。

【問題T2-5-2】
問題T2-2-1を、Datamate.jsを使って書き直してみよう。 画像ファイルは、画像ページからコピーできます。
copyright © info