【PHP実践|実務向け】PHPで実現する3次スプライン補間による滑らかなグラフ描画

1. 導入

Webアプリケーションで動的にグラフを作成する際、単純な直線(線形補間)ではカクカクとした不自然な見た目になりがちです。ユーザー体験を向上させ、データを視覚的に美しく表現するためには、点と点を滑らかな曲線でつなぐ「スプライン補間」が非常に有効です。本記事では、PHPのGDライブラリを活用し、3次スプライン曲線を用いて滑らかなグラフを描画する手法を解説します。

2. 基礎知識

スプライン補間(Spline Interpolation)とは、与えられた複数の点の間を、多項式を使って滑らかにつなぐ手法です。特に「3次スプライン曲線」は、隣接する点の間を3次関数で結び、各点において関数の傾きが連続するように計算されます。これにより、グラフ全体として非常に自然な曲線を生成できるため、データ分析ツールやダッシュボード開発において頻繁に利用される技術です。

3. 実装/解決策

実装には、各区間における3次関数の係数を求める必要があります。以下の手順で処理を行います。
1. 各区間の幅(h)を計算する。
2. 3次方程式の連立方程式を解くための係数(q, r, s)を算出する。
3. 求めた係数を用いて、任意のX座標に対するY座標を算出する関数(valueメソッド)を作成する。
4. GDライブラリを使用して、算出された座標を線でつなぎ描画する。

4. サンプルプログラム

以下は、3次スプライン補間をクラス化したサンプルコードです。そのままコピーしてPHP環境で動作確認が可能です。

  • 3次スプライン補間クラス
  • /
    class CubicSpline
    {
    private $q = array();
    private $r = array();
    private $s = array();
    private $n;
    private $points;

    public function __construct(array $points)
    {
    $this->points = $points;
    $this->n = count($points) – 1;
    $h = $b = $d = $g = $u = array();

    // 差分計算
    for ($i = 0; $i < $this->n; $i++) {
    $h[$i] = $points[$i + 1][0] – $points[$i][0];
    }

    // 係数の算出(連立方程式の解法)
    for ($i = 1; $i < $this->n; $i++) {
    $b[$i] = 2.0 ($h[$i] + $h[$i – 1]);
    $d[$i] = 3.0 (($points[$i + 1][1] – $points[$i][1]) / $h[$i] – ($points[$i][1] – $points[$i – 1][1]) / $h[$i – 1]);
    }

    // 順方向消去
    $g[1] = $h[1] / $b[1];
    for ($i = 2; $i < $this->n – 1; $i++) {
    $g[$i] = $h[$i] / ($b[$i] – $h[$i – 1] $g[$i – 1]);
    }
    $u[1] = $d[1] / $b[1];
    for ($i = 2; $i < $this->n; $i++) {
    $u[$i] = ($d[$i] – $h[$i – 1] $u[$i – 1]) / ($b[$i] – $h[$i – 1] $g[$i – 1]);
    }

    // 逆方向代入
    $this->r[0] = $this->r[$this->n] = 0.0;
    $this->r[$this->n – 1] = $u[$this->n – 1];
    for ($i = $this->n – 2; $i >= 1; $i–) {
    $this->r[$i] = $u[$i] – $g[$i] $this->r[$i + 1];
    }

    // 最終的な係数決定
    for ($i = 0; $i < $this->n; $i++) {
    $this->q[$i] = ($points[$i + 1][1] – $points[$i][1]) / $h[$i] – $h[$i] ($this->r[$i + 1] + 2.0 $this->r[$i]) / 3.0;
    $this->s[$i] = ($this->r[$i + 1] – $this->r[$i]) / (3.0 $h[$i]);
    }
    }

    // 指定したX座標に対するYを計算
    public function value($x)
    {
    $i = 0;
    foreach ($this->points as $idx => $p) {
    if ($x <= $p[0]) { $i = max(0, $idx - 1); break; } } $x2 = $x - $this->points[$i][0];
    return $this->points[$i][1] + $x2 ($this->q[$i] + $x2 ($this->r[$i] + $this->s[$i] $x2));
    }
    }

    // 利用例:ランダムな点でグラフを描画
    $points = [[0, 20], [50, 80], [100, 30], [150, 90], [200, 50]];
    $spline = new CubicSpline($points);
    // 以降、GDライブラリで $spline->value($x) をループさせて線を描画してください。
    ?>

    5. 応用・注意点

    注意点:

    • 座標の順序: 3次スプライン補間はX座標が昇順に並んでいることを前提としています。入力データがバラバラの場合は、事前にX座標でソートしてください。
    • パフォーマンス: 大量のデータポイントがある場合、計算コストが増大します。必要に応じて間引き処理を行うか、フロントエンド側(Chart.js等)での描画も検討しましょう。
    • 境界条件: 本コードは両端の曲率を0とする「自然スプライン」の実装です。必要に応じて境界条件を調整することで、曲線のカーブの強さを制御可能です。

    バックエンドで画像生成を行う際は、メモリ使用量にも注意してください。高解像度な画像を出力する場合は、PHPのmemory_limitを確認しておくことをお勧めします。

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