【PHP】散布図作成ツール PHP-Scatterplot

PHP

PHP-Scatterplot について

散布図作成ツールをPHPで作ってみました。

Githubで公開しています。 Composer でインストールできます。

GitHub - macocci7/PHP-Scatterplot: PHP-Scatterplot is a simple PHP library to create scatter plot easily.
PHP-Scatterplot is a simple PHP library to create scatter plot easily. - macocci7/PHP-Scatterplot

こんな感じの基本的な散布図に1次回帰線を入れてみたり、

こんな感じに複数のデータをレイヤーとして重ねたり、参照線や仕様限界線を入れてみたり、

凡例表示してみたり、色や線の太さを変えてみたり、色々カスタマイズできます。

こんな感じで1つのCSVの複数の項目について組み合わせを変えて比較したりできます。

環境要件

  • PHP CLI 8.1以降
  • Imagick PHP Extention
  • Composer

インストール

作業用ディレクトリを作り、そこでコマンドを実行します。

composer require macocci7/php-scatterplot

基本的な使い方

パッケージに同梱されている examples をコピーしていじってみましょう。

cp -ra vendor/macocci7/php-scatterplot/examples ./

BasicUsage.php を見てみましょう。

<?php

require('../vendor/autoload.php');

use Macocci7\PhpScatterplot\Scatterplot;

$sp = new Scatterplot();

$layers = [
    [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [1,2,3,4,5,8,4,7,11,9,1],
    ],
];

$sp->layers($layers)
   ->create('img/BasicUsage.png');

これだけで散布図を作成することができます。

実行してみましょう。

php -f BasicUsage.php > BasicUsage.md

examples/img/BasicUsage.png という画像ファイルができています。

こんな感じの基本的な散布図が保存されています。

複数のレイヤーを使う

複数の種類のデータをレイヤーとして重ねた散布図を作ることができます。

examples/UsingLayers.php を見てみましょう。

<?php
require('../vendor/autoload.php');

use Macocci7\PhpScatterplot\Scatterplot;

$sp = new Scatterplot();

$layers = [
    'John' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [1,2,3,4,5,8,4,7,11,9,1],
    ],
    'Jake' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [11,8,10,7,9,6,5,3,4,2,1],
    ],
    'Hugo' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [4,8,10,1,9,6,5,3,7,1,11],
    ],
    'Alex' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [3,5,11,4,8,2,9,10,1,11,7],
    ],
];

$legends = array_keys($layers);

$sp->layers($layers)
   ->create('img/UsingLayers.png');

複数の種類のデータを $layers にハッシュとして格納してから

$sp->layers($layers) としてデータセットし、 create() で1つの散布図を生成しています。

実行してみましょう。

php -f UsingLayers.php > UsingLayers.md

example/img/UsingLayers.png という画像が生成されています。

プロパティの変更

上記2つの散布図は味気ないので、色々と属性を変更してみます。

examples/AdjustDisplayByMethods.php を開いてみましょう。

<?php
require('../vendor/autoload.php');

use Macocci7\PhpScatterplot\Scatterplot;

$sp = new Scatterplot();

$layers = [
    'John' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [1,2,3,4,5,8,4,7,11,9,1],
    ],
    'Jake' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [11,8,10,7,9,6,5,3,4,2,1],
    ],
    'Hugo' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [4,8,10,1,9,6,5,3,7,1,11],
    ],
    'Alex' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [3,5,11,4,8,2,9,10,1,11,7],
    ],
];

$legends = array_keys($layers);

$sp->layers($layers)
   ->limitX(0, 12) // Xの下限上限
   ->limitY(0, 12) // Yの下限上限
   ->gridXPitch(2) // Xのグリッド刻み幅
   ->gridYPitch(2) // Yのグリッド刻み幅
   ->bgcolor('#ccccff') // キャンバス背景色
   ->colors(['#ffffff']) // プロットの色
   ->plotSize(4) // プロット円の直径
   ->fontColor('#333333') // フォントの色
   ->grid(1, '#999999') // グリッドの線幅と色
   ->gridXOn() // X軸グリッド表示ON
   ->gridYOn() // Y軸グリッド表示ON
   ->regressionLine(3, ['#666666', '#cc2222', '#2222cc', '#22cc22']) // 1次回帰線:幅と色
   ->referenceLineX(1.5, 1, '#00ccff') // 参照線X:参照値、線幅、色
   ->referenceLineY(1.5, 1, '#00ccff') // 参照線Y:参照値、線幅、色
   ->specificationLimitX(0.5, 11.5, 1, '#ff00ff') // 仕様限界線:下限、上限、線幅、色
   ->specificationLimitY(0.5, 11.5, 1, '#ff00ff') // 仕様限界線:下限、上限、線幅、色
   ->labelX('DATA X') // X軸ラベル
   ->labelY('DATA Y') // Y軸ラベル
   ->caption('SCATTER PLOT') // キャプション
   ->legends($legends) // 凡例
   ->create('img/AdjustDisplayByMethods.png');

メソッドは他にもいくつかあります。

resize(), frame(), axis(), fontPath(), fontSize(),

gridXOn(), gridXOff(), gridYOn(), gridYOff(),

referenceLineXOff(), referenceLineYOff(), referenceLinesOff(),

specificationLimitXOff(), specificationLimitYOff(), specificationLimitsOff(),

regressionLineOn(), regressionLineOff(), legendOff() などです。

では、実行してみましょう。

php -f AdjustDisplayByMethods.php > AdjustDisplayByMethods.md

examples/img/AdjustDisplayByMethods.png が生成されています。

このような感じになります。

解析データの取得

画像生成をすることなく、解析データだけを取得できるようにクラスを切り出しています。

Macocci7\PhpScatterplot\Analyzer を使うと、

平均、最大値、最小値、分散、標準偏差、共分散、相関係数、1次回帰線式などの

解析結果のデータを取得することができます。

Macocci7\PhpScatterplot\Scatterplot クラス自体もこのクラスを継承しているので、

Scatterplot のインスタンスでも同様に取得可能です。

examples/ParsedData.php を開いてみましょう。

<?php
require('../vendor/autoload.php');

use Macocci7\PhpScatterplot\Analyzer;

$a = new Analyzer();

$layers = [
    'John' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [1,2,3,4,5,8,4,7,11,9,1],
    ],
    'Jake' => [
        'x' => [1,2,3,4,5,6,7,8,9,10,11],
        'y' => [11,8,10,7,9,6,5,3,4,2,1],
    ],
];

var_dump($a->parse($layers));

Macocci7\PhpScatterplot\Analyzer のインスタンスを生成して、

parse() メソッドの引数に $layers を渡すと、解析結果をハッシュで返します。

実行してみましょう。

php -f ParsedData.php > ParsedData.txt

実行結果の出力が ParsedData.txt に保存されています。

ちょっと長いので、データの構造を示します。

[
  'John' => [ // $layers のキー
    'count' => 11, // データ(x,y)の件数
    'x' => [
      'Mean' => 6, // Xの平均値
      'Max' => 11, // Xの最大値
      'Min' => 1,  // Xの最小値
      'Variance' => 10, // Xの分散
      'StandardDeviation' => 3.1622776601683795, // Xの標準偏差
    ],
    'y' => [ (構造はXと同じなので省略) ],
    'Covariance' => 5.181818181818182, // XとYの共分散
    'CorrelationCoefficient' => 0.5135343537364686, // 相関係数
    'RegressionLineFormula' => [ // 1次回帰線の式: Y = aX + b
      'a' => 0.5181818181818182, // 傾き
      'b' => 1.8909090909090907, // Y切片
    ],
  ],
  'Jake' => [ (構造は'John'と同じなので省略) ],
]

散布図マトリックス

例えば、1つのCSVの複数の項目について、それぞれのペアで散布図を作る

などといったことをすると、データの比較が楽にできます。

使用例としては、東京の1ヵ月間の気象データを基にマトリックスを作ってみました。

平均気温、最高気温、最低気温、降水量、日照時間、平均気圧などの項目が

気象庁のWEBサイトから一つのCSVでダウンロード可能です。

気象庁|過去の気象データ・ダウンロード
気象庁が提供するページです

フォーマットにかなりクセがあり使いにくいデータですが、

必要なデータを簡単に取り出せるように CSV操作用のクラスを用意しています。

examples/Matrix.php を開いてみましょう。

<?php
require('../vendor/autoload.php');
require('./class/CsvUtil.php');
require('./class/Combination.php');

use Macocci7\CsvUtil;
use Macocci7\Combination;
use Macocci7\PhpScatterplot\Scatterplot;

$cu = new CsvUtil();
$cb = new Combination();

$cu->load('csv/weather_tokyo.csv')
   ->encode('SJIS', 'UTF-8')
   ->offset(7);
$heads = $cu->heads(4);
$days = $cu->raw()->column(0);

$dictionary = [
    '平均気温(℃)' => 'Mean Temperature(℃)',
    '最高気温(℃)' => 'Maximum Temperature(℃)',
    '最低気温(℃)' => 'Minimum Temperature(℃)',
    '日照時間(時間)' => 'Sunshine Hours(h)',
    '降水量の合計(mm)' => 'Precipitation Amount(mm)',
    '平均現地気圧(hPa)' => 'Mean Local Air Pressure(hPa)',
];
$columns = [1, 4, 7, 10, 14, 21];
$parsed = [];
$pairs = $cb->pairs($columns);
foreach ($pairs as $index => $pair) {
    $x = $pair[0];
    $y = $pair[1];
    $layers = [
        'Tokyo, Japan' => [
            'x' => $cu->float()->column($x),
            'y' => $cu->float()->column($y),
        ],
    ];
    
    $sp = new Scatterplot();
    $sp->layers($layers)
       ->regressionLineOn()
       ->labelX($dictionary[$heads[$x]])
       ->labelY($dictionary[$heads[$y]])
       ->caption('Weather in Tokyo : ' . $days[0] . '~' . $days[count($days) - 1])
       ->create(sprintf("img/Matrix%02d.png", $index));
    $parsed[] = $sp->parse($layers);
}

examples/csv/weather_tokyo.csv を読み込んで配列に格納してから、

SJIS → UTF-8 の変換をしています。データが8行目からなので、

offset() で配列インデックス7を指定しています。項目名は5行目にあるので、

heads(4) で項目名一覧を取得しています。

1列目(8行目以降)が日付なので、column(0) で取得しています。

raw() は型変換無しの指定です。英語表記に変換するために $dictionary を使っていますが、

日本語のままで使う場合は、$dictionary を全て削ればOKです。

$dictionary[$heads[$x]] の箇所は $heads[$x] にすれば日本語になります。

$columns は、使用する項目の列の配列インデックスです。

pairs() で $columns の各要素について全ペアを取得し $pairs に格納しています。

$pairs についてループを回して散布図を生成しています。

では、実行してみましょう。

php -f Matrix.php > Matrix.md

examples/img/ 内に、 Matrix00.png ~ Matrix14.png が生成されています。

Matrix.md はMarkdown形式のファイルなので、VSCodeなどのプレビュー機能で確認できます。

Github上で表示させた場合の画面は次のような感じになります。

それぞれの散布図の下の「Properties」をクリックすると、parse() の結果が表示されます。

相関係数などを確認しながら、相関がありそうなのか確認できます。

各散布図をクリックすると散布図を見ることができます。

次の図は、平均気温と最高気温の散布図です。正の相関があることがわかります。

このような感じの散布図が生成されています。

以上です。

(2024/03/10追記)Version 1.1.1 にアップデートしました。

詳細については、こちらの記事をご覧ください。

コメント

タイトルとURLをコピーしました