11_1:表データ p5.js JavaScript

データセットは行と列として保持される場合が多くあるので、p5.jsでもその扱いを容易にするp5.Tableオブジェクトが提供されています。行と列で構成されるスプレッドシート(Excelなどで言う表)を扱ったことがあれば、コードから同じように操作できます。p5.jsでは、ファイルから表を読み取ったり直接作成することができます。また行や列はどれでも読み取りと書き込みが可能で、表の個々のセル(マス)を修正することもできます。以降では特に表データの操作方法を見ていきます。

表はセルのグリッドです。行は水平方向に並ぶ要素で、列は垂直方向に並ぶ要素です。データは個々のセルや、行、列から読み取ることができます。

表データは通常、行をカンマやタブ文字で区切ったプレーンテキストです。カンマ区切りの値(comma-separated values)のファイルはCSVファイルと呼ばれ、拡張子.csvが用いられます。タブを使用した場合の.tsvも時々使われます。

CSYやTSVファイルを読み込むには、まずそのファイルをスケッチのフォルダ内に配置し、loadTable()関数を使ってデータを取得します。

次のサンプルは、ボストン レッドソックスで強打者としてならしたデビッド・オルティーズの年度別成績を扱ったものです。下図は、A列から順に年度、ホームラン数、打点数、平均打率の数字を並べたExcelファイルの画面です。

ExcelファイルをCSV形式に変換して保存するには次のようにします。

  1. [ファイル]→[名前を付けて保存]を選択
  2. [名前を付けて保存]画面の[ファイルの種類]ドロップダウンメニューで[CSV UTF-8(カンマ区切り)]を選択
  3. [保存]ボタンをクリック

保存したCSVファイルをテキストエディタで開くと、下図のように表示されます。データのひとかたまりはカンマで区切られ、データ同士は改行で区切られた形です。

表の読み取り

このデータをloadTable()関数でp5.jsに読み込むと、表のデータはp5.Tableオブジェクトとして返されます。loadTable()関数は、setup()で安全にアクセスできるように、preload()内で呼び出します。

setup()内では、forループを使って各行を走査します。forループの条件にはp5.TableオブジェクトのgetRowCount()メソッドが利用できます(データ内の行数を数えます)。データは1999年から2014年までのものなので、列数は16個です。

let stats;

function preload() {
    // CSVファイルを読み取り、p5.Tableオブジェクトを得る
    stats = loadTable('ortiz.csv');
}

function setup() {
    // データの行数を得る
    print(stats.getRowCount()); // 16個
    // データの行数分だけ繰り返す
    for (let i = 0; i < stats.getRowCount(); i++) {
        // i行の0、1、2、3列から値を得て変数に代入
        const year = stats.get(i, 0);
        const homeRuns = stats.get(i, 1);
        const rbi = stats.get(i, 2);
        const average = stats.get(i, 3);
        print(year, homeRuns, rbi, average);
    }
}

forループ内では、p5.Tableオブジェクトのget()メソッドを使ってデータを取得しています。get()メソッドはパラメータとして、読み取るデータの行と列を取ります。

loadTable()

説明

ファイルまたはURLの内容を読み取り、その値を持つp5.Tableオブジェクトを作成する。ファイルを指定する場合は、スケッチの “data”フォルダに置く必要がある。filenameパラメータにはまた、オンライン上のファイルへのURLも指定できる。デフォルトでは、ファイルはコンマ区切り(CSV形式)と見なされる。’header’オプションが含まれていると、ヘッダ行を探す(最初の行に項目名が含まれていて、これをデータに含みたくない場合に指定する)。

オプション:
csv – 表を、コンマ区切りの値として解析する
tsv – 表を、タブ区切りの値として解析する
header – この表はヘッダ(タイトル)行を持っている

オプションを複数渡すときには、カンマで区切って渡す。
loadTable(‘my_csv_file.csv’, ‘csv’, ‘header’);

ロードされ保存されるファイルにはすべて、UTF-8エンコーディングが用いられる。この関数は非同期で動作する。つまり、スケッチの実行中、次行が実行される前、完了していない可能性がある。preload()内でloadTable()を呼び出すことで、setup()とdraw()が呼び出される前、その操作が完了していることが保証される。preload()の外では、オブジェクトの処理にコールバック関数が使用できる。この関数はサイズが64MBまでのファイルの取得に適している。

シンタックス

loadTable(filename, options, [callback], [errorCallback])
loadTable(filename, [callback], [errorCallback])

p5.Table

説明

p5.Tableオブジェクトは複数の行と列を持つデータを保持する。従来のスプレッドシートとよく似ている。ゼロからダイナミックに生成することも、既存のファイルのデータを使って生成することもできる。

シンタックス

new p5.Table([rows])

パラメータ

rows p5.TableRow[]: p5.TableRowオブジェクトの配列

プロパティ

columns、rows

メソッド

getRowCount():表の行数の合計を返す
get():表の指定された行と列の値を取得する。行はそのIDで指定する。列はIDでもタイトルでも指定できる。

表の描画

次のサンプルでは、homeRunsという名前の配列を作成し、ファイルを読み取った後、setup()内でデータの保持に使用しています。このときは、get()メソッドではなく、グラフの数値として使用できるようにgetNum()メソッドを使用しています。

draw()内では、homeRuns.lengthプロパティの長さ分だけforループを繰り返す作業を2回行っています。1回めは配列の各データ項目分の垂直線を描画し、2回めは配列の各データ項目から折れ線グラフを描画しています。

beginShape()とendShape()、vertex()関数については、「2_7:p5.js シェイプを手作りする」で述べています。

let stats;
const homeRuns = [];

function preload() {
    stats = loadTable('ortiz.csv');
}

function setup() {
    createCanvas(480, 120);

    const rowCount = stats.getRowCount();
    // 表の行数分だけ繰り返す
    for (let i = 0; i < rowCount; i++) {
        // print(stats.getNum(i, 1));
        // 各行のホームラン数を数値として得て、homeRuns配列に入れる
        homeRuns[i] = stats.getNum(i, 1);
    }
    // print(homeRuns);
}

function draw() {
    background(204);
    stroke(153);
    line(20, 100, 20, 20);
    line(20, 100, 460, 100);
    // 年度数分だけ、垂直線を描く
    for (let i = 0; i < homeRuns.length; i++) {
        const wx = map(i, 0, homeRuns.length - 1, 20, 460);
        line(wx, 20, wx, 100);
    }

    noFill();
    stroke(0);
    beginShape();
    // 折れ線グラフを描く
    for (let j = 0; j < homeRuns.length; j++) {
        const x = map(j, 0, homeRuns.length - 1, 20, 460);
        const y = map(homeRuns[j], 0, 60, 100, 20);
        vertex(x, y);
    }
    endShape();
}

このプログラムを実行すると、下図左の結果が描画されます。下図右は、Excelの機能を使って作成した折れ線グラフです。

p5.Table.getNum()

説明

表の指定された行と列から浮動小数を取得する。

p5.TableのgetObject()メソッドを使用すると、表データがオブジェクトとして取得できるので、ホームラン数以外のデータも楽に得られます。

let stats;
let ortizObject;
let rowNum = 0;

function preload() {
    stats = loadTable('ortiz2.csv', 'csv', 'header');
}

function setup() {
    createCanvas(480, 120);
    // 表データをオブジェクトとして取得
    ortizObject = stats.getObject();
    print(ortizObject);
    // データの行数
    rowNum = Object.keys(ortizObject).length;
    noLoop();
}


function draw() {
    background(204);
    stroke(153);
    textSize(10)
    line(20, 100, 20, 20);
    line(20, 100, 460, 100);
    // 年度数分だけ縦線を描き、年度を描画する
    for (let i = 0; i < rowNum; i++) {
        const wx = map(i, 0, rowNum - 1, 20, 460);
        const year = ortizObject[i].year;
        line(wx, 20, wx, 100);
        text(year, wx - 10, 110);
    }

    noFill();
    stroke(0);
    beginShape();

    // 折れ線グラフを描き、ホームラン数を描画する
    for (let j = 0; j < rowNum; j++) {
        const x = map(j, 0, rowNum - 1, 20, 460);
        const homerun = ortizObject[j].homerun;
        const y = map(homerun, 0, 60, 100, 20);
        vertex(x, y);
        text(homerun, x - 5, y)
    }
    endShape();
}

getObject()

説明

すべての表データを取得し、オブジェクトとして返す。列名が渡された場合には、そのタイトルを属性名に持つ行オブジェクトが保持される。

シンタックス

getObject([headerColumn])

29,470都市のデータ

次のサンプルでは、アメリカの各都市の緯度経度情報などをまとめた下図のようなCSVファイルを扱います。具体的なデータは2行めから29471行めまであるので、29470都市のデータがあることになります。

このCSVファイルの1行めにあるのはヘッダです。ヘッダは各列の内容を明確にするラベルを定義するもので、今の場合で言うと、zip(郵便番号)、state(州名)、city(都市名)、lat(緯度)、lng(経度)がヘッダとして定義されています。

ヘッダがあると、表を置き換えたp5.Tableオブジェクトで扱いやすくなります。たとえばgetNum()やgetString()メソッドでヘッダ名を指定して値が取得できます。そのためには、loadTable()関数に’header’を与えます。

let cities;

function preload() {
    cities = loadTable('cities.csv', 'header');
}

function setup() {
    // 最初の行の、city列とlat列の値を得る
    const city = cities.getString(0, 'city');
    print(city);
    const latitude = cities.getNum(0, 'lat');
    print(latitude);
}

次のサンプルを実行してマウスをキャンバス上に移動させると、アメリカの都市の位置を円で描いた地図が描画され、マウスをさらに動かすと円で描いた地図も移動します。

let cities;

function preload() {
    cities = loadTable('cities.csv', 'header');
}

function setup() {
    createCanvas(480, 240);
    fill(255, 150);
    noStroke();

    // 最初の行の、city列とlat列の値を得る
    const city = cities.getString(0, 'city');
    print(city);
    const latitude = cities.getNum(0, 'lat');
    print(latitude);
}

const setXY = (lat, lng) => {
    const x = map(lng, -180, 180, 0, width);
    const y = map(lat, 90, -90, 0, height);
    ellipse(x, y, 0.25, 0.25);
}

function draw() {
    background(0);
    const xoffset = map(mouseX, 0, width, -width * 3, -width);
    translate(xoffset, -600);
    scale(10);
    for (let i = 0; i < cities.getRowCount(); i++) {
        const latitude = cities.getNum(i, 'lat');
        const longitude = cities.getNum(i, 'lng');
        setXY(latitude, longitude);
    }
}

getString()

説明

表(p5.Table)の指定された行と列から文字列値を取得する。行はそのIDで指定する。列はIDでもタイトルでも指定できる。

シンタックス

getString(row, column)

パラメータ

row – 整数:行のID(数値)
column – 文字列|整数:列名(ヘッダ、文字列)かID(数値)

戻り値

文字列

getNum()

説明

表(p5.Table)の指定された行と列から浮動小数値を取得する。行はそのIDで指定する。列はIDでもタイトルでも指定できる。

シンタックス

getNum(row, column)

パラメータ

row – 整数:行のID(数値)
column – 文字列|整数:列名(ヘッダ、文字列)かID(数値)

戻り値

数値

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA