点と点を線で結んでグラフにする時、点同士の間を補完する必要があります。
単純に直線でつなぐだけの線形補間でもグラフにはできますが、全ての点を通る滑らかな曲線を描画するのであれば3次スプライン曲線を利用するのが一般的です。
<?php $points = array(); $width = 300; $height = 100; for($x=0; $x<=$width; $x+=50){ $y = rand(0,100); $points[] = array($x, $y); } $spline = new CubicSpline($points); $spline->draw($width, $height); class CubicSpline { private $xx = array(); private $yy = array(); private $q = array(); private $r = array(); private $s = array(); private $n; private $points; function __construct($points){ $this->points = $points; $this->n = $n = count($points) - 1; // 区間の数 $h = array(); $b = array(); // Step1 for($i=0;$i < $n;$i++){ $h[$i] = $points[$i + 1][0] - $points[$i][0]; } for($i=1;$i < $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]); } // Step2 $g[1] = $h[1] / $b[1]; for($i=2;$i<$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<$n;$i++){ $u[$i] = ($d[$i] - $h[$i - 1] * $u[$i - 1]) / ($b[$i] - $h[$i - 1] * $g[$i - 1]); } // Step3 $this->r[0] = $this->r[$n] = 0.0; $this->r[$n - 1] = $u[$n - 1]; for($i=$n - 2; $i >= 1; $i--){ $this->r[$i] = $u[$i] - $g[$i] * $this->r[$i + 1]; } //Step4 for($i=0;$i<$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]); } return; } function value($x){ $points = $this->points; $n = $this->n; $i = -1; // 区間の決定 for($i1=1;$i1 < $n && $i < 0;$i1++){ if($x < $points[$i1][0]){ $i = $i1 - 1; } } if($i < 0){ $i = $n - 1; } // 計算 $x2 = $x - $points[$i][0]; $y = $points[$i][1] + $x2 * ($this->q[$i] + $x2 * ($this->r[$i] + $this->s[$i] * $x2)); return $y; } public function draw($width, $height, $hMargin=10, $vMargin=30 ){ $end = end($this->points); $image = imagecreatetruecolor($width + $hMargin * 2, $height + $vMargin * 2); $bg = imagecolorallocate($image, 255, 255, 255); $axis = imagecolorallocate($image, 180, 180,180); $color1 = imagecolorallocate($image, 30, 30, 30); $color2 = imagecolorallocate($image, 50, 150, 255); imagefill($image, 0, 0, $bg); imageline($image, $hMargin, $height + $vMargin, $hMargin + $width, $height + $vMargin, $axis); imageline($image, $hMargin, $vMargin, $hMargin, $height + $vMargin, $axis); $x1 = $y1 = $x2 = $y2 = 0; for($x=0;$x<$end[0];$x++){ $x1 = $x2; $y1 = $y2; $x2 = $hMargin + $x; $y2 = ($height + $vMargin) - $this->value($x); if($x == 0) continue; imageline($image, $x1, $y1, $x2, $y2, $color1); } foreach($this->points as $point){ list($x, $y) = $point; $x = $hMargin + $x; $y = ($height + $vMargin) - $y; imagefilledrectangle($image, $x - 2, $y - 2, $x + 2, $y + 2, $color2); } header('Content-Type: image/jpeg'); imagejpeg($image, null, 90); imagedestroy($image); exit; } }
サンプルではランダムに点をプロットしてそれらの点を通るスプライン曲線を描画しています。
クラスをインスタンス化する際に座標 array(x, y) を配列にしたものを渡し、draw() で画像として描画します。
このプログラムは下記参考 URL のソースコードを元に PHP で書きなおしたものです。
参考:
http://www.sist.ac.jp/~suganuma/cpp/2-bu/7-sho/7-sho.htm#e-7-42