I have created a graph using Jpgraph (http://www.jpgraph.com).
Jpgraph has a spline class which smooths out the lines on the line graph. However it does not work as I expected. As you can see, the highest peak of the line goes above the actual markings (the red squares). Friday 10pm is 2.0 however it appears to be higher than that around 6am friday.
A poorly laptop touchpad drawn example of what I would have expected is below :)
I have managed to track down the class to jpgraph_regstat.php. Any idea how to make the center of the peak the actual markings?
//------------------------------------------------------------------------
// CLASS Spline
// Create a new data array from an existing data array but with more points.
// The new points are interpolated using a cubic spline algorithm
//------------------------------------------------------------------------
class Spline {
// 3:rd degree polynom approximation
private $xdata,$ydata; // Data vectors
private $y2; // 2:nd derivate of ydata
private $n=0;
function __construct($xdata,$ydata) {
$this->y2 = array();
$this->xdata = $xdata;
$this->ydata = $ydata;
$n = count($ydata);
$this->n = $n;
if( $this->n !== count($xdata) ) {
JpGraphError::RaiseL(19001);
//('Spline: Number of X and Y coordinates must be the same');
}
// Natural spline 2:derivate == 0 at endpoints
$this->y2[0] = 0.0;
$this->y2[$n-1] = 0.0;
$delta[0] = 0.0;
// Calculate 2:nd derivate
for($i=1; $i < $n-1; ++$i) {
$d = ($xdata[$i+1]-$xdata[$i-1]);
if( $d == 0 ) {
JpGraphError::RaiseL(19002);
//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.');
}
$s = ($xdata[$i]-$xdata[$i-1])/$d;
$p = $s*$this->y2[$i-1]+2.0;
$this->y2[$i] = ($s-1.0)/$p;
$delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) -
($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]);
$delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p;
}
// Backward substitution
for( $j=$n-2; $j >= 0; --$j ) {
$this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j];
}
}
// Return the two new data vectors
function Get($num=50) {
$n = $this->n ;
$step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1);
$xnew=array();
$ynew=array();
$xnew[0] = $this->xdata[0];
$ynew[0] = $this->ydata[0];
for( $j=1; $j < $num; ++$j ) {
$xnew[$j] = $xnew[0]+$j*$step;
$ynew[$j] = $this->Interpolate($xnew[$j]);
}
return array($xnew,$ynew);
}
// Return a single interpolated Y-value from an x value
function Interpolate($xpoint) {
$max = $this->n-1;
$min = 0;
// Binary search to find interval
while( $max-$min > 1 ) {
$k = ($max+$min) / 2;
if( $this->xdata[$k] > $xpoint )
$max=$k;
else
$min=$k;
}
// Each interval is interpolated by a 3:degree polynom function
$h = $this->xdata[$max]-$this->xdata[$min];
if( $h == 0 ) {
JpGraphError::RaiseL(19002);
//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.');
}
$a = ($this->xdata[$max]-$xpoint)/$h;
$b = ($xpoint-$this->xdata[$min])/$h;
return $a*$this->ydata[$min]+$b*$this->ydata[$max]+
(($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0;
}
}
Code example using spline can be found here (http://jpgraph.net/download/manuals/chunkhtml/example_src/splineex1.html)