array(), 1 => array()); /** * The names of the axes * @var array */ private $axis = array(0 => 'X Axis', 1 => 'Y Axis'); // ################################################################### /** * Does the actual graphing and returns a byte stream of a PNG image * * @return string Byte stream */ public function graph() { // calculates the standard deviation of the two piles to determine the x and y intervals $xint = $this->_standardDeviation($this->piles[0]); $yint = $this->_standardDeviation($this->piles[1]); $xmin = min($this->piles[0]); $xmin = ($xmin - $xint < 0 ? 0 : $xmin - $xint); $xmax = max($this->piles[0]) + $xint; $ymin = min($this->piles[1]); $ymin = ($ymin - $yint < 0 ? 0 : $ymin - $yint); $ymax = max($this->piles[1]) + $yint; $colors = $this->_primeColors(); $this->_paintCanvas(); // draw the axes $originx = self::PADDING + imagefontwidth(1) + self::SPACING + imagefontwidth(3) + self::PADDING; $originy = $this->dimensions['height'] - (self::PADDING + imagefontheight(1) + self::SPACING + imagefontheight(3) + self::SPACING); $endx = $this->dimensions['width'] - self::PADDING - 150 - self::PADDING; $endy = 40; $length = $endx - $originx; $height = $originy - $endy; imageline($this->image, $originx, $originy, $endx, $originy, $colors['grey']); imageline($this->image, $originx, $originy, $originx, $endy, $colors['grey']); imageline($this->image, $endx, $originy, $endx, $endy, $colors['grey']); // label the axes imagestring($this->image, 3, $length / 2, $this->dimensions['height'] - self::SPACING - imagefontheight(3), $this->axis[0], $colors['black']); imagestringup($this->image, 3, self::SPACING, $height / 2 + $endy, $this->axis[1], $colors['black']); // score the axes $count = 0; for ($i = $originx; $i <= $endx; $i += ($length / $xint)) { imageline($this->image, $i - self::SPACING, $originy + self::SPACING, $i + self::SPACING, $originy - self::SPACING, $colors['grey']); imagestring($this->image, 1, $i, $originy + self::PADDING, round($count), $colors['black']); $count += $xint; } $count = 0; for ($i = $originy; $i >= $endy; $i -= ($height / $yint)) { imageline($this->image, $originx, $i, $endx, $i, $colors['grey']); imagestring($this->image, 1, self::SPACING + self::PADDING, $i, round($count), $colors['black']); $count += $yint; } header("Content-Type: image/png"); imagepng($this->image); } // ################################################################### /** * Adds a "line" with a given name and a set of datapoints in the form * array(x, y) * * @param string The line's name * @param array Array of array(x,y) as data points */ public function addDataSet($name, $points) { $this->_addPoints($points); $this->_sortPoints($points); $this->dataset[] = array($name, $points, $this->_fetchColor()); } // ################################################################### /** * This does the same thing as addDataSet(), except the client code * can specify the color in the form of array(R, G, B) * * @param string The line's name * @param array Array of array(x,y) as data points * @param array A color in the form of 3 RGB points */ public function addDataSetColor($name, $points, $color) { $this->_addPoints($points); $this->_sortPoints($points); $this->dataset[] = array($name, $points, imagecolorallocate($this->image, $color[0], $color[1], $color[2])); } // ################################################################### /** * Adds a set of points to the piles and ensures that they are all valid * * @param array Points to add */ private function _addPoints($points) { $xpairs = array(); foreach ($points AS $point) { if (isset($xpairs["$point[0]"])) { trigger_error('You cannot have more than one of the same x-values for a given data set'); } $xpairs["$point[0]"] = $point[0]; $this->piles[0][] = $point[0]; $this->piles[1][] = $point[1]; } } // ################################################################### /** * Sorts an array of points using quick sort so they're in x-increasing * order * * @param array Array of points */ private function _sortPoints(&$points) { $this->_quickSortPoints($points, 0, sizeof($points) - 1); } // ################################################################### /** * Quicksort function for sorting function * * @param array Array of points * @param integer Lower bound * @param integer Upper bound */ private function _quickSortPoints(&$points, $low, $high) { if (($high - $low) > 1) { $partition = $this->_partitionPoints($points, $low, $high); $this->_quickSortPoints($points, $low, $partition); $this->_quickSortPoints($points, $partition + 1, $high); } } // ################################################################### /** * Quicksort partitioner: returns the index of the pivot element where * all x-coords on the left side of pivot are less than or equal to * pivot, and all x-coords are higher to the right * * @param array Array of points * @param integer Lower bound * @param integer Upper bound * * @return integer Pivot index */ private function _partitionPoints(&$points, $low, $high) { $pivot = $low; for ($unsorted = $low + 1; $unsorted <= $high; $unsorted++) { if ($points[$unsorted][0] < $points[$pivot][0]) { $temp = $points[$pivot]; $points[$pivot] = $points[$unsorted]; $points[$unsorted] = $points[$pivot + 1]; $points[$pivot + 1] = $temp; $pivot++; } } return $pivot; } // ################################################################### /** * Returns the unbiased statistical standard deviation of an array of * values * * @param array Array of values * * @return float Standard deviation (unbiased) */ private function _standardDeviation($vals) { $average = $this->_arrayAverage($vals); $popVariance = array(); foreach ($vals AS $val) { $popVariance[] = pow($val - $average, 2); } return sqrt($this->_arrayAverage($popVariance)); } // ################################################################### /** * Returns the stastical mean of an array of values * * @param array Array of values * * @return float Statistical mean */ private function _arrayAverage($vals) { return array_sum($vals) / count($vals); } // ################################################################### /** * Sets the titles of the two axes * * @param string X-axis name * @param string Y-axis name */ public function setAxes($xaxis, $yaxis) { $this->axis[0] = $xaxis; $this->axis[1] = $yaxis; } } /*=====================================================================* || ################################################################### || # $HeadURL$ || # $Id$ || ################################################################### \*=====================================================================*/ ?>