11/5の“pChartを導入してみよう。”で、値が連続していないと(つまり途中に値の欠落があると)プロット間をラインで結んでくれず、ただのプロットグラフになってしまい、折れ線グラフにはならない、こりゃ困った、というところで力尽きてしまった。(下図参照)

beetles.pngその1

それからすぐに不幸があって松本へ飛び立ったので、今日、pChartに関して久しぶりに触ってみた。

結論から書こう。

解決した。

結局のところ、drawLineGraph()関数がうまく機能していないのが理由なので、pChartディレクトリの“pChart.class”ファイルを直接弄ってみることにした。

1429行目に、以下のコードがある。

function drawLineGraph($Data,$DataDescription,$SerieName="")
 {
  /* Validate the Data and DataDescription array */
  $this->validateDataDescription("drawLineGraph",$DataDescription);
  $this->validateData("drawLineGraph",$Data);

  $GraphID = 0;
  foreach ( $DataDescription["Values"] as $Key2 => $ColName )
   {
    $ID = 0;
    foreach ( $DataDescription["Description"] as $keyI => $ValueI )
     { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }

     if ( $SerieName == "" || $SerieName == $ColName )
      {
       $XPos  = $this->GArea_X1 + $this->GAreaXOffset;
       $XLast = -1;
       foreach ( $Data as $Key => $Values )
        {
         if ( isset($Data[$Key][$ColName]))
          {
           $Value = $Data[$Key][$ColName];
           $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);

           /* Save point into the image map if option activated */
           if ( $this->BuildMap )
            $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Line");

           if (!is_numeric($Value)) { $XLast = -1; }
           if ( $XLast != -1 )
            $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);

           $XLast = $XPos;
           $YLast = $YPos;
           if (!is_numeric($Value)) { $XLast = -1; }
          }
         $XPos = $XPos + $this->DivisionWidth;
        }
       $GraphID++;
      }
    }
  }

このコードのうち、1450行目の

$Value = $Data[$Key][$ColName];

で、値が欠落していると$Valueが空の値になってしまうため、1457行目の

if (!is_numeric($Value)) { $XLast = -1; }

にひっかかってしまい、その結果1459行目のdrawLine()関数が働かず、折れ線グラフにならないワケである。

ということは、値が欠落している場合(つまり$Value ==""の場合)は1451~1465行目までの処理を行わない代わりに、$XPos(X座標の位置)をストックしておき、値が出現した場合にそのストックを開放してdrawLine()関数を実行してやれば折れ線グラフが描画されるはずである

したがって、コードを以下のように改変した。

function drawLineGraph($Data,$DataDescription,$SerieName="")
{
  /* Validate the Data and DataDescription array */
  $this->validateDataDescription("drawLineGraph",$DataDescription);
  $this->validateData("drawLineGraph",$Data);

  $GraphID = 0;
  foreach($DataDescription["Values"] as $Key2 => $ColName)
  {
    $ID = 0;
    foreach($DataDescription["Description"] as $keyI => $ValueI)
    {
      if($keyI == $ColName){
        $ColorID = $ID;
      }
      $ID++;
    }

    if($SerieName == "" || $SerieName == $ColName){
      $XPos  = $this->GArea_X1 + $this->GAreaXOffset;
      $XLast = -1;
/* added by N */  $noValueCount = 0;
      foreach($Data as $Key => $Values)
      {
        if(isset($Data[$Key][$ColName])){
          $Value = $Data[$Key][$ColName];
/* added by N */  if($Value === ""){
/* added by N */    ++$noValueCount;
/* added by N */  }else{
/* added by N */    if($Key != 0){
/* added by N */      $XPos = $XPos + $this->DivisionWidth * ($noValueCount + 1);
/* added by N */    }
            $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);

            /* Save point into the image map if option activated */
            if($this->BuildMap ){
              $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Line");
            }

            if(!is_numeric($Value)){
              $XLast = -1;
            }
            if($XLast != -1){
              $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);
            }

            $XLast = $XPos;
            $YLast = $YPos;

            if(!is_numeric($Value)){
              $XLast = -1;
            }
/* added by N */      $noValueCount = 0;
/* added by N */  }
        }
// deleted by N  $XPos == $XPos + $this->DivisionWidth;
      }
      $GraphID++;
    }
  }
}

“added by N”と書かれている場所が、今回改変した場所である。

この改変した“pChart.class”ファイルを元に、以前作成したbeetles.phpファイルを実行して生成されたグラフが以下のものである。

beetles.pngその2

途中の値が欠落していても、バッチリプロットが直線で結ばれた折れ線グラフが出来上がった。

やればできるねえ、ボク。

ネット上でいくらググってみてもこれの解決法は載ってなかったので(そもそも値の欠落しているデータをグラフ化しようという人が単にいないのか?)、これは自画自賛してもよいんでないかい?

同じような改変をすれば、折れ線グラフだけでなくベジェ曲線を用いた曲線グラフにも応用が利きそう。

でも、今日はこれで満足じゃ。

気持ちよく寝れそうだ。