. */ /* */ /* ----------------------------------------------------------------------- */ /* */ /* (C) Copyright 2007-2008 */ /* Andrew Que */ /* �|> */ /*=========================================================================*/ /** * X/Y plot * *
* Used for creating graphs of X/Y data and includes functions for * drawing mean average and linear regression. Functions include: *
* Used to create a plot of X/Y data *
* Examples of use:
*
* $Plot = new XY_PlotClass( $Image ); // <- Initilize
* $Plot->AddData( 1 , 5 ); // <- Add some data
* $Plot->AddData( 3 , 2 );
* $Plot->AddData( 4 , 4 );
* $Plot->SetColor( $Black ); // <- Line color
* $Plot->RenderWithLines(); // <- Draw lines into $Image
*
* @package XY_Plot
*/
class XY_PlotClass
{
/**#@+ @ignore */
protected $Image;
protected $Window;
protected $X_Max = -1;
protected $X_Min = -1;
protected $Y_Min = 0;
protected $Y_Max = 100;
protected $Color = 0;
protected $LinearRegressionColor = 0;
protected $LinearRegressionThickness = 4;
protected $LinearAverageColor = 0;
protected $Data = array();
protected $WindowedData = array();
protected $RenderMethod = "Points";
protected $Slope;
protected $Correlation;
protected $Y_Intercept;
protected $Average;
protected $MaxX_Distance = 0;
protected $CircleSize = 5;
protected $AverageWidth = 1;
protected $IsDataCalculated = false;
protected $Y_MajorDivisionExtention = 0;
protected $Y_MajorDivisionScale = 1;
protected $Y_MajorDivisionColor;
protected $Y_MajorDivisionTextColor;
protected $Y_MajorTextCallback = null;
protected $Y_MajorTextFontSize = 2;
protected $Y_MinorDivisionScale = 1;
protected $Y_MinorDivisionColor;
protected $X_MajorDivisionExtention = 0;
protected $X_MajorDivisionScale = 1;
protected $X_MajorDivisionColor;
protected $X_MajorDivisionTextColor;
protected $X_MajorTextCallback = null;
protected $X_MajorTextFontSize = 2;
protected $X_MajorCustomStart = null;
protected $X_MajorCustomIncrement = null;
protected $X_MajorCustomEnd = null;
protected $X_MinorDivisionScale = 1;
protected $X_MinorDivisionColor;
protected $X_MinorTextFontSize = 2;
protected $X_MinorCustomStart = null;
protected $X_MinorCustomIncrement = null;
protected $X_MinorCustomEnd = null;
/**#@-*/
/**
* Constructor
* @param $Image The image to use for the plot
*/
public function __construct( $Image )
{
$this->Image = $Image;
// Assume graph uses entire window
$this->Window =
new Window(
0 , 0 ,
imagesx( $this->Image ) , imagesy( $this->Image ) );
}
/**
* Set the width of the mean average plot
*
* Set the width of the mean average plot line
* @param $Value New width
*/
public function SetAverageWidth( $Value )
{
$this->AverageWidth = $Value;
}
/**
* Get mean average width
*
* Return mean average width
* @return mean average width
*/
public function GetAverageWidth()
{
return $this->AverageWidth;
}
/**
* Set the max and max X-span
*
* The values for X-min and X-max further narrow down the data added
* to the plot. This specifies a range of X values that will be on the
* the chart.
* @param $X_Min The lowest X-value to include in chart
* @param $X_Max The highest X-value to include in chart
*/
public function SetX_Span( $X_Min , $X_Max )
{
$this->X_Max = $X_Max;
$this->X_Min = $X_Min;
$IsDataCalculated = false;
}
/**
* Limit Y-axis range
*
* Set the range for Y values. Values above and below the min and
* max values will be clipped.
* @param $Y_Min The lowest Y-value to include in chart
* @param $Y_Max The highest Y-value to include in chart
*/
public function SetY_Span( $Y_Min , $Y_Max )
{
$this->Y_Min = $Y_Min;
$this->Y_Max = $Y_Max;
}
/**
* Resize the viewing window
* @param $x left edge
* @param $y top edge
* @param $xx right edge
* @param $yy bottom edge
*/
public function SizeWindow( $x , $y , $xx , $yy )
{
$this->Window->Resize( $x , $y , $xx , $yy );
}
/**
* Set the color of the line plot
*
* This is the color of the line created by RenderWithLines().
* @param $Color Color of the line
*/
public function SetColor( $Color )
{
$this->Color = $Color;
}
/**
* Set color of the linear regression line
*
* This is the color of the line created by RenderLinearRegression().
* @param $Color Color of the line
*/
public function SetLinearRegressionColor( $Color )
{
$this->LinearRegressionColor = $Color;
}
/**
* Set color of the average line
*
* This is the color of the line created by RenderMeanPlot().
* @param $Color Color of the line
*/
public function SetAverageColor( $Color )
{
$this->LinearAverageColor = $Color;
}
/**
* Flush all data
*
* This will remove add data points from the plot. Useful for adding more
* then one plot to an image.
*/
public function ResetData()
{
$this->Data = array();
$IsDataCalculated = false;
}
/**
* Add a data point
*
* This called for every data point to be part of the chart.
* @param $x X-cord of data point
* @param $y Y value of point at X
*/
public function AddData( $x , $y )
{
$this->Data[ "$x" ] = (float)$y;
$IsDataCalculated = false;
}
/**
* Max gab between x values
*
* Set the maximum gap between x values before a line no longer
* connects them. Useful when areas of data are missing. Set to
* 0 to disable (default).
* @param $Distance Max distance between x values
*/
public function SetMaxX_Distance( $Distance )
{
$this->MaxX_Distance = $Distance;
}
/**
* Get the max gab between x balues
*/
public function GetMaxX_Distance( $Distance )
{
return $this->MaxX_Distance;
}
/**
* Linear regression line thickness
*
* Set thickness of linear regression line. Default is 4 pixels.
* @param $Value Thickness
*/
public function SetLinearRegressionThickness( $Value )
{
$this->LinearRegressionThickness = $Value;
}
/**
* Get Linear regression line thickness
*
* Return thickness of linear regression line.
* @return Thickness
*/
public function GetLinearRegressionThickness()
{
return $this->LinearRegressionThickness;
}
/**
* Set circle size for data points
*
* The circle size is a parameter for the RenderPoints()
* method. The size is the dimeter of the circle used to denote a point
* on the chart. Default size is 5 pixels.
* @param $Size Dimeter of circle
*/
public function SetCircleSize( $Size )
{
$this->CircleSize = $Size;
}
/**
* Return the lowest Y data scale
*/
public function GetY_Min()
{
return $this->Y_Min;
}
/**
* Return the highest Y data scale
*/
public function GetY_Max()
{
return $this->Y_Max;
}
/**
* Return the lowest X data scale
*/
public function GetX_Min()
{
return $this->X_Min;
}
/**
* Return the highest x data scale
*/
public function GetX_Max()
{
return $this->X_Max;
}
/**
* Computed slope
*
*
* Return the slope computer through linear regression. Requires a call * to CalculateLinearRegression() before containing * valid data. *
* This is the m part of the standard line function y = mx + b * @return Slope of linear regression line */ public function GetSlope() { return $this->Slope; } /** * Computed Y-intercept * *
* Returns the Y-intercept computed through linear regression. Requires * a call to CalculateLinearRegression() before containing * valid data. *
* This is the b part of the standard line function y = mx + b * @return Y-intercept */ public function GetY_Intercept() { return $this->Y_Intercept; } /** * Correlation coefficient * * Returns the correlation coefficient computed through linear regression. Requires * a call to CalculateLinearRegression() before containing * valid data. * @return Correlation coefficient */ public function GetCorrelation() { return $this->Correlation; } /** * Mean average * * Return the mean average of data within X span. Requires a call * to CalculateMeanAverage before containing valid data. * @return Mean average */ public function GetAverage() { return $this->Average; } //------------------------------------------------------------------------ /** * Build an array narrowed in on the x-frame */ private function BuildWindowArray() { // Have we built this array already? if ( ! $IsDataCalculated ) { // Sort data ksort( $this->Data ); // Clear array $this->WindowedData = array(); // For all samples foreach ( $this->Data as $x => $y ) { // Within sample window? if ( ( $x < $this->X_Min ) || ( $x > $this->X_Max ) ) continue; // Add to windowed data $this->WindowedData[] = array( "x" => $x , "y" => $y ); } // Data is now calculated $IsDataCalculated = true; } return $this->WindowedData; } /** * Scale a Y data point into the Y window scale * * This function will translate the value in $y to a verticle * pixel location in the image window. This function can be useful * for drawing grid lines. * @param $y The Y-value to translate * @return translated Y-value */ public function ScaleY( $y ) { // Compute delta Y $Y_Delta = $this->Y_Max - $this->Y_Min; // Strip minimum value $y -= $this->Y_Min; // Scale data if ( $Y_Delta != 0 ) $y = ( $y * $this->Window->GetHeigth() ) / $Y_Delta; else $y = 0; // Adjust for window height $y = $this->Window->GetHeigth() - $y; return $y; } /** * Scale a X data point into the X window scale * * This function will translate the value in $x to a horizontal * pixel location in the image window. * @since verion 1.2 * @param $x The X-value to translate * @return translated X-value */ public function ScaleX( $x ) { // Scale x $x -= $this->X_Min; $x = $x * $this->Window->GetWidth(); $x /= $this->X_Max - $this->X_Min; $x = round( $x ); return $x; } /** * Calculate the lowest value of Y data * * @return Lowest Y value in data */ public function FindY_Min() { $WindowArray = $this->BuildWindowArray(); $Min = $WindowArray[ 0 ][ "y" ]; // For all data for ( $Index = 0; $Index < count( $WindowArray ); ++$Index ) $Min = Min( $Min , $WindowArray[ $Index ][ "y" ] ); return $Min; } /** * Calculate the highest value of Y data * * @return Highest Y value in data */ public function FindY_Max() { $WindowArray = $this->BuildWindowArray(); $Max = $WindowArray[ 0 ][ "y" ]; // For all data for ( $Index = 0; $Index < count( $WindowArray ); ++$Index ) $Max = Max( $Max , $WindowArray[ $Index ][ "y" ] ); return $Max; } /** * Number of data points * * Find the number of data points in the window * @return Number of data points */ public function FindNumberOfDataPoints() { $WindowArray = $this->BuildWindowArray(); return count( $WindowArray ); } /** * Calculate the lowest value of X data * * @return Lowest X value in data */ public function FindX_Min() { $Min = min( array_keys( $this->Data ) ); return $Min; } /** * Calculate the highest value of X data * @return Highest X value in data */ public function FindX_Max() { $Max = max( array_keys( $this->Data ) ); return $Max; } /** * Automaticlly adjust the min and max values * * Scale Y min/max to fit all the data. This will find the min and * max values of Y and set Y-min and Y-max accordingly. A rounding * paremters can be used to round down/up and min/max values. For * example, a round value of 0.1 will round to the nearest 10th. If * Y-max was .22 and Y-min was .15, the values used with be .3 and .1 * @param $Round Decimal to round to */ public function AutoScaleY_MinMax( $Round ) { // Fetch data $WindowArray = $this->BuildWindowArray(); $First = current( $WindowArray ); $Y_Max = $Y_Min = $First[ "y" ]; // For all data points foreach ( $WindowArray as $Data ) { $Y_Min = Min( $Y_Min , $Data[ "y" ] ); $Y_Max = Max( $Y_Max , $Data[ "y" ] ); } // If rounding if ( $Round > 0 ) { $Round = 1 / $Round; $Y_Min = floor( $Y_Min * $Round ) / $Round; $Y_Max = ceil( $Y_Max * $Round ) / $Round; } // Set this as the new span $this->SetY_Span( $Y_Min , $Y_Max ); } /** * Automaticlly adjust the Y min and max values * * @deprecated Use AutoScaleY_MinMax */ public function AdjustMinMax( $Round ) { $this->AutoScaleY_MinMax( $Round ); } /** * Automaticlly adjust the X min and max values * * Scale X min/max to fit all the data. This will find the min and * max values of X and set X-min and X-max accordingly. A rounding * paremters can be used to round down/up and min/max values. For * example, a round value of 0.1 will round to the nearest 10th. If * X-max was .22 and X-min was .15, the values used with be .3 and .1 * @param $Round Decimal to round to */ public function AutoScaleX_MinMax( $Round = 0 ) { $X_Min = min( array_keys( $this->Data ) ); $X_Max = max( array_keys( $this->Data ) ); // If rounding if ( $Round > 0 ) { $Round = 1 / $Round; $X_Min = floor( $X_Min * $Round ) / $Round; $X_Max = ceil( $X_Max * $Round ) / $Round; } // Set this as the new span $this->SetX_Span( $X_Min , $X_Max ); } /** * Calculate mean average * * Calculate the mean average of data inside the plot * @return Average */ public function CalculateMeanAverage() { // Fetch data $WindowArray = $this->BuildWindowArray(); $Count = $n = count( $WindowArray ); // Do all sumations $Average = 0.0; for ( $Index = 0; $Index < $Count; ++$Index ) $Average += $WindowArray[ $Index ][ "y" ]; $Average /= $Count; $this->Average = $Average; } /** * Calculate slope and y-intercept of least square linear regression * * This function is needed if the data from the linear regression * calculation is needed but the linear regression plot hasn't been drawn. * After this function is called, GetSlope and GetY_Intercept * will return valid information. */ public function CalculateLinearRegression() { $DeltaX = $this->X_Max - $this->X_Min; // Fetch data $WindowArray = $this->BuildWindowArray(); $Count = $n = count( $WindowArray ); // No data? if ( $Count == 0 ) { $this->Slope = $m = 0; $this->Y_Intercept = $b = 0; return; } // Do all sumations $SumX = $SumY = $SumXY = $SumXX = $SumYY = 0.0; for ( $Index = 0; $Index < $Count; ++$Index ) { $x = $WindowArray[ $Index ][ "x" ] - $this->X_Min; $y = $WindowArray[ $Index ][ "y" ]; $SumX += $x; // � x $SumY += $y; // � y $SumXY += $x * $y; // � xy $SumXX += $x * $x; // � x^2 $SumYY += $y * $y; // � y^2 } $SumX_SumX = $SumX * $SumX; // ( �x )^2 $SumY_SumY = $SumY * $SumY; // ( �y )^2 // Slope: // n �xy - �x �y // m = ------------------- // n �x^2 - ( �x )^2 // $Numerator = ( $n * $SumXY ) - ( $SumX * $SumY ); $Denominator = ( $n * $SumXX ) - $SumX_SumX; if ( $Denominator ) $m = $Numerator / $Denominator; else $m = 0; // Y-intercept: // �y - m �x // b = ----------- // n // $b = ( $SumY - ( $m * $SumX ) ) / $n; // Correlation coefficient // n �xy - �x �y // r = --------------------------------------------- // �[ n �x^2 - ( �x )^2 ][ n �y^2 - ( �y )^2 ] // $Numerator = ( $n * $SumXY ) - ( $SumX * $SumY ); $AccumulatorX = ( $n * $SumXX ) - $SumX_SumX; $AccumulatorY = ( $n * $SumYY ) - $SumY_SumY; $Denominator = sqrt( $AccumulatorX * $AccumulatorY ); if ( $Denominator ) $r = $Numerator / $Denominator; else $r = 0; // Save information $this->Slope = $m; $this->Y_Intercept = $b; $this->Correlation = $r; } //------------------------------------------------------------------------ /** * Draw points for each data point given * * This creates a point plot in the image specified during creation of * the class. Each point is of the size specified by SetCircleSize * and of the color specified by SetColor */ public function RenderPoints() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); $Height = $this->Window->GetHeigth(); // Delta Y $Y_Delta = $this->Y_Max - $this->Y_Min; // Delta X $DeltaX = $this->X_Max - $this->X_Min; // Get data points $WindowArray = $this->BuildWindowArray(); // Number of data points $IndexMax = count( $WindowArray ) ; // For each point for ( $Index = 0; $Index < $IndexMax; ++$Index ) { // Scale x $x = $this->ScaleX( $WindowArray[ $Index ][ "x" ] ); // Scale y $y = $this->ScaleY( $WindowArray[ $Index ][ "y" ] ); // Draw point ClippedFilledCircle( $this->Image , $MarginLeft + $x , $MarginTop + $y , $this->CircleSize , $this->Color , $MarginLeft , $MarginTop , $MarginRight , $MarginBottom ); } } /** * Draw lines from point to point * * This creates a line plot in the image specified during creation of * the class. Lines will connect all the points in the graph, sorted by * their x-values. A gap in the chart will be left if the distance * between two points is over the values specified with SetMaxX_Distance. * The color of the lines is specified with SetColor */ public function RenderWithLines() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Delta Y $Y_Delta = $this->Y_Max - $this->Y_Min; // Delta X $DeltaX = $this->X_Max - $this->X_Min; // Get data points $WindowArray = $this->BuildWindowArray(); // Number of data points $IndexMax = count( $WindowArray ) ; $LastY = null; $LastX = 0; $LastRawX = null; // For each point for ( $Index = 0; $Index < $IndexMax; ++$Index ) { // Scale x $x = $this->ScaleX( $WindowArray[ $Index ][ "x" ] ); // Scale y $y = $this->ScaleY( $WindowArray[ $Index ][ "y" ] ); // Delta X between this sample and last $X_Span = $WindowArray[ $Index ][ "x" ] - $LastRawX; // Is this distance too great? if ( ( $LastY === null ) || ( ( $this->MaxX_Distance != 0 ) && ( $X_Span > $this->MaxX_Distance ) ) ) { $LastX = $x; $LastY = $y; $LastRawX = $WindowArray[ $Index ][ "x" ]; // Skip plotting this line continue; } // Locations of line $PointX = $MarginLeft + $LastX; $PointY = $MarginTop + $LastY; $PointXX = $MarginLeft + $x; $PointYY = $MarginTop + $y; // Draw clipped line DrawClippedLine( $this->Image , $PointX , $PointY , $PointXX , $PointYY , $MarginLeft , $MarginTop , $MarginRight , $MarginBottom , $this->Color ); // Set last coordinates to current $LastX = $x; $LastY = $y; $LastRawX = $WindowArray[ $Index ][ "x" ]; } } /** * Draw linear regression plot * * This function will compute and draw a line representing the mean * square linear regression of the data within the window. */ public function RenderLinearRegression() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Calculate linear regression data $this->CalculateLinearRegression(); $DeltaX = $this->X_Max - $this->X_Min; $m = $this->Slope; $b = $this->Y_Intercept; // Standard line function is y = mx + b $y = $this->ScaleY( $b , false ); $yy = $this->ScaleY( ( $m * $DeltaX ) + $b , false ); $x = $MarginLeft; $y = $MarginTop + $y + $Index; $xx = $MarginRight; $yy = $MarginTop + $yy + $Index; // Draw line for ( $Index = 0; $Index < $this->LinearRegressionThickness; ++$Index ) { $Y_Offset = floor( $Index - ( $this->LinearRegressionThickness / 2 ) ); DrawClippedLine( $this->Image , $x , $y + $Y_Offset , $xx , $yy + $Y_Offset , $MarginLeft , $MarginTop , $MarginRight , $MarginBottom , $this->LinearRegressionColor ); } } /** * Draw mean average line * * This creates a line denoting the mean average in the image specified * during creation of the class. */ public function RenderMeanPlot() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); // Calculate average $this->CalculateMeanAverage(); // Standard line function is y = mx + b $y = $this->ScaleY( $this->Average ); // Draw average for ( $Index = 0; $Index < $this->AverageWidth; ++$Index ) imageline( $this->Image , $MarginLeft , $MarginTop + $y + $Index , $MarginRight , $MarginTop + $y + $Index , $this->LinearAverageColor ); } //------------------------------------------------------------------------ // Grids //------------------------------------------------------------------------ /** * Font size for verticle major divisions * * This sets the size of the font (PHP's internal fonts for GD) used * for verticle lables * @param $Value new font size must be between 1 and 5 * @since verion 1.2 */ function SetY_MajorTextFontSize( $Value ) { assert( $Value >= 1 ); assert( $Value <= 5 ); $this->Y_MajorTextFontSize = $Value; } /** * Get font size for verticle divisions * * Return the font size for verticle divisison * @return font size for verticle divisions * @since verion 1.2 */ function GetY_MajorTextFontSize() { return $this->Y_MajorTextFontSize; } /** * Major verticle division extention * * Number of pixels past the margin to extend major verticle divisions * Default is 0. * @param $Value Pixel to extend * @since verion 1.2 */ function SetY_MajorDivisionExtention( $Value ) { $this->Y_MajorDivisionExtention = $Value; } /** * Major verticle division extention * * Current number of pixels past the margin to extend major verticle * divisions * @return verticle division extention * @since verion 1.2 */ function GetY_MajorDivisionExtention() { return $this->Y_MajorDivisionExtention; } /** * Major verticle scale * * These are the increments in which the major verticle scale * is labled. For example, a value of 50 would place divides every * 50 units. * @param $Value Scale * @since verion 1.2 */ function SetY_MajorDivisionScale( $Value ) { $this->Y_MajorDivisionScale = $Value; } /** * Get major verticle scale * * Return increments in which the major verticle scale * is labled. * @return increments of scale * @since verion 1.2 */ function GetY_MajorDivisionScale() { return $this->Y_MajorDivisionScale; } /** * Color of major verticle divisions * * Set the color of major verticle divisions * @param $Value Allocated color in the image * @since verion 1.2 */ function SetY_MajorDivisionColor( $Value ) { $this->Y_MajorDivisionColor = $Value; } /** * Get color of major verticle divisions * * Return the color of major verticle divisions * @return color * @since verion 1.2 */ function GetY_MajorDivisionColor() { return $this->Y_MajorDivisionColor; } /** * Color of major verticle division lables * * Set color of major verticle divisions lables * @param $Value Allocated color in the image * @since verion 1.2 */ function SetY_MajorDivisionTextColor( $Value ) { $this->Y_MajorDivisionTextColor = $Value; } /** * Get color of major verticle division lables * * Return the current color of text lables for verticle division lables * @return color * @since verion 1.2 */ function GetY_MajorDivisionTextColor() { return $this->Y_MajorDivisionTextColor; } /** * Text callback for verticle division lables * *
* Assigns a custom callback for creating a string for verticle * lables. The callback function is passed 3 parameters: a value, * x location and y location. The callback function can do one of two * things. *
* The callback function may return a string with the value properly
* formatted.
*
* function FormatCallback( $Value )
* {
* return "$" . number_format( $Value , 2 );
* }
*
*
* This function is an example of a simple callback, formatting the * number as a dollor amount. *
* The other option is to make place custom text at the location
*
* function FormatCallback( $Value , $x , $y )
* {
* // Price for this division
* imagestring(
* $Image ,
* $FontSize ,
* $x + $CenterBias , $y ,
* $String ,
* $ColorMap[ "Black" ] );
*
* return "";
* }
*
*
* This example (which is not functional) shows how such a function might * look. The parameters of $x and $y are the location of the point at * which the text is to be placed. By returning nothing, XY Plot will * print nothing to the chart. * @param $Value callback function * @since verion 1.2 */ function SetY_MajorTextCallback( $Value ) { $this->Y_MajorTextCallback = $Value; } /** * Get text callback for verticle division lables * * Return the callback function for verticle division lables * @return function name * @since verion 1.2 */ function GetY_MajorTextCallback() { return $this->Y_MajorTextCallback; } /** * Major verticle divisions * * Draw major verticle (top to bottom) divisions and add text lables * @since verion 1.2 */ function DrawY_MajorDivisions() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Round off start and end of horizontal divisions $Round = 1.0 / $this->Y_MajorDivisionScale; $Y_MinStart = floor( $this->Y_Min * $Round ) / $Round; $Y_MaxStart = ceil( $this->Y_Max * $Round ) / $Round; $Y_Position = $Y_MaxStart; // While more divisions remain to be drawn while ( $Y_Position >= $Y_MinStart ) { // Get vertical location of line $y = round( $this->ScaleY( $Y_Position , false ) ); $y += $MarginTop; // Is this within the margins? if ( ( $y < $MarginTop ) || ( $y > $MarginBottom ) ) { $Y_Position -= $this->Y_MajorDivisionScale; continue; } $x = $MarginRight + $this->Y_MajorDivisionExtention; // Division line imageline( $this->Image , $MarginLeft , $y , $x , $y , $this->Y_MajorDivisionColor ); $Callback = $this->Y_MajorTextCallback; // Lable for division if ( $Callback ) $String = $Callback( $Y_Position , $x , $y ); else $String = number_format( $Y_Position , 0 ); // If there is a string to print if ( $String != "" ) { $CenterBias = ImageFontHeight( $this->Y_MajorTextFontSize ); $CenterBias /= 2; $CenterBias = -round( $CenterBias ); // Price for this division imagestring( $this->Image , $this->Y_MajorTextFontSize , $x + 4 , $y + $CenterBias , $String , $this->Y_MajorDivisionTextColor ); } // Next... $Y_Position -= $this->Y_MajorDivisionScale; } } /** * Minor verticle scale * * These are the increments in which the minor verticle scale * is labled. For example, a value of 50 would place divides every * 50 units. * @param $Value Scale * @since verion 1.2 */ function SetY_MinorDivisionScale( $Value ) { $this->Y_MinorDivisionScale = $Value; } /** * Get minor verticle scale * * Return increments in which the minor verticle scale * is labled. * @return increments of scale * @since verion 1.2 */ function GetY_MinorDivisionScale() { return $this->Y_MinorDivisionScale; } /** * Color of minor verticle divisions * * Set the color of minor verticle divisions * @param $Value Allocated color in the image * @since verion 1.2 */ function SetY_MinorDivisionColor( $Value ) { $this->Y_MinorDivisionColor = $Value; } /** * Get color of minor verticle divisions * * Return the color of minor verticle divisions * @return color * @since verion 1.2 */ function GetY_MinorDivisionColor() { return $this->Y_MinorDivisionColor; } /** * Minor verticle divisions * * Draw minor verticle (top to bottom) divisions * @since verion 1.2 */ function DrawY_MinorDivisions() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Round off start and end of horizontal divisions $Round = 1.0 / $this->Y_MinorDivisionScale; $Y_MinStart = floor( $this->Y_Min * $Round ) / $Round; $Y_MaxStart = ceil( $this->Y_Max * $Round ) / $Round; $Y_Position = $Y_MaxStart; // While more divisions remain to be drawn while ( $Y_Position >= $Y_MinStart ) { // Get vertical location of line $y = round( $this->ScaleY( $Y_Position , false ) ); $y += $MarginTop; // Is this within the margins? if ( ( $y < $MarginTop ) || ( $y > $MarginBottom ) ) { $Y_Position -= $this->Y_MinorDivisionScale; continue; } $x = $MarginRight + $this->Y_MinorDivisionExtention; // Division line imageline( $this->Image , $MarginLeft , $y , $x , $y , $this->Y_MinorDivisionColor ); // Next... $Y_Position -= $this->Y_MinorDivisionScale; } } /** * Custom major horizontal start value * * This is the value from which to start the grid lines. * Set to null to disable (default). * @param $Value Value to start from * @since verion 1.2 */ function SetX_MajorCustomStart( $Value ) { $this->X_MajorCustomStart = $Value; } /** * Return custom start value * @return Custom start value * @since verion 1.2 */ function GetX_MajorCustomStart() { return $this->X_MajorCustomStart; } /** * Custom major horizontal division increment function * * The custom increment function must take a value and return * the next value. This function is useful if the graph is not * split up linearly, such as with logarithmic divisions or divisions * by month. * @param $Value A custom increment function * @since verion 1.2 */ function SetX_MajorCustomIncrement( $Value ) { $this->X_MajorCustomIncrement = $Value; } /** * Get custom major horizontal division increment function * * @return major horizontal division increment function * @since verion 1.2 */ function GetX_MajorCustomIncrement() { return $this->X_MajorCustomIncrement; } /** * Custom major horizontal division end value * * A value at which to stop making division marks. This can be useful * if the division lines stop before the end of the chat * @param $Value X value at which to stop * @since verion 1.2 */ function SetX_MajorCustomEnd( $Value ) { $this->X_MajorCustomEnd = $Value; } /** * Get custom major horizontal division end value * @return custom major horizontal division end value * @since verion 1.2 */ function GetX_MajorCustomEnd() { return $this->X_MajorCustomEnd; } /** * Font size for horizontal major divisions * * This sets the size of the font (PHP's internal fonts for GD) used * for horizontal lables * @param $Value new font size (must be between 1 and 5) * @since verion 1.2 */ function SetX_MajorTextFontSize( $Value ) { assert( $Value >= 1 ); assert( $Value <= 5 ); $this->X_MajorTextFontSize = $Value; } /** * Get font size for horizontal divisions * * Return the font size for horizontal divisison * @return font size for horizontal divisions * @since verion 1.2 */ function GetX_MajorTextFontSize() { return $this->X_MajorTextFontSize; } /** * Major horizontal division extention * * Number of pixels past the margin to extend major horizontal divisions * Default is 0. * @param $Value Pixel to extend * @since verion 1.2 */ function SetX_MajorDivisionExtention( $Value ) { $this->X_MajorDivisionExtention = $Value; } /** * Major horizontal division extention * * Current number of pixels past the margin to extend major horizontal * divisions * @return horizontal division extention * @since verion 1.2 */ function GetX_MajorDivisionExtention() { return $this->X_MajorDivisionExtention; } /** * Major horizontal scale * * These are the increments in which the major horizontal scale * is labled. For example, a value of 50 would place divides every * 50 units. * @param $Value Scale * @since verion 1.2 */ function SetX_MajorDivisionScale( $Value ) { $this->X_MajorDivisionScale = $Value; } /** * Get major horizontal scale * * Return increments in which the major horizontal scale * is labled. * @return increments of scale * @since verion 1.2 */ function GetX_MajorDivisionScale() { return $this->X_MajorDivisionScale; } /** * Color of horizontal divisions * * Set the color of major horizontal divisions * @param $Value Allocated color in the image * @since verion 1.2 */ function SetX_MajorDivisionColor( $Value ) { $this->X_MajorDivisionColor = $Value; } /** * Get color of major horitontal divisions * * Return the color of major horitontal divisions * @return color * @since verion 1.2 */ function GetX_MajorDivisionColor() { return $this->X_MajorDivisionColor; } /** * Color of major horitontal division lables * * Set color of major horitontal divisions lables * @param $Value Allocated color in the image * @since verion 1.2 */ function SetX_MajorDivisionTextColor( $Value ) { $this->X_MajorDivisionTextColor = $Value; } /** * Get color of major horitontal division lables * * Return the current color of text lables for horitontal division lables * @return color * @since verion 1.2 */ function GetX_MajorDivisionTextColor() { return $this->X_MajorDivisionTextColor; } /** * Text callback for horitontal division lables * *
* Assigns a custom callback for creating a string for verticle * lables. The callback function is passed 3 parameters: a value, * x location and y location. The callback function can do one of two * things. *
* The callback function may return a string with the value properly
* formatted.
*
* function FormatCallback( $Value )
* {
* return "$" . number_format( $Value , 2 );
* }
*
*
* This function is an example of a simple callback, formatting the * number as a dollor amount. *
* The other option is to make place custom text at the location
*
* function FormatCallback( $Value , $x , $y )
* {
* // Price for this division
* imagestring(
* $Image ,
* $FontSize ,
* $x + $CenterBias , $y ,
* $String ,
* $ColorMap[ "Black" ] );
*
* return "";
* }
*
*
* This example (which is not functional) shows how such a function might * look. The parameters of $x and $y are the location of the point at * which the text is to be placed. By returning nothing, XY Plot will * print nothing to the chart. * @param $Value callback function * @since verion 1.2 */ function SetX_MajorTextCallback( $Value ) { $this->X_MajorTextCallback = $Value; } /** * Get text callback for horitontal division lables * * Return the callback function for horitontal division lables * @return function name * @since verion 1.2 */ function GetX_MajorTextCallback() { return $this->X_MajorTextCallback; } /** * Major horizontal divisions * * Draw major horizontal (left to right) divisions and add text lables * @since verion 1.2 */ function DrawX_MajorDivisions() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Round off start and end of horizontal divisions $Round = 1.0 / $this->X_MajorDivisionScale; // Start if ( $this->X_MajorCustomStart === null ) $X_Position = $X_MinStart = floor( $this->X_Min * $Round ) / $Round; else $X_Position = $this->X_MajorCustomStart; // End if ( $this->X_MajorCustomEnd === null ) $X_MaxStart = ceil( $this->X_Max * $Round ) / $Round; else $X_MaxStart = $this->X_MajorCustomEnd; $IncFunction = $this->X_MajorCustomIncrement; // While more divisions remain to be drawn while ( $X_Position <= $X_MaxStart ) { // Get vertical location of line $x = round( $this->ScaleX( $X_Position , false ) ); $x += $MarginLeft; // Is this within the margins? if ( ( $x < $MarginLeft ) || ( $x > $MarginRight ) ) { if ( $IncFunction === null ) $X_Position += $this->X_MajorDivisionScale; else $X_Position = $IncFunction( $X_Position ); continue; } $y = $MarginBottom + $this->X_MajorDivisionExtention; // Division line imageline( $this->Image , $x , $MarginTop , $x , $y , $this->X_MajorDivisionColor ); $Callback = $this->X_MajorTextCallback; // Lable for division if ( $Callback ) $String = $Callback( $X_Position , $x , $y ); else $String = number_format( $X_Position , 0 ); if ( $String != "" ) { // Center the text $CenterBias = strlen( $String ); $CenterBias *= ImageFontWidth( $this->X_MajorTextFontSize ); $CenterBias /= 2; $CenterBias = -round( $CenterBias ); // Price for this division imagestring( $this->Image , $this->X_MajorTextFontSize , $x + $CenterBias , $y , $String , $this->X_MajorDivisionTextColor ); } // Next... if ( $IncFunction === null ) $X_Position += $this->X_MajorDivisionScale; else $X_Position = $IncFunction( $X_Position ); } } /** * Custom Minor horizontal start value * * This is the value from which to start the grid lines. * Set to null to disable (default). * @param $Value Value to start from * @since verion 1.2 */ function SetX_MinorCustomStart( $Value ) { $this->X_MinorCustomStart = $Value; } /** * Return custom start value * @return Custom start value * @since verion 1.2 */ function GetX_MinorCustomStart() { return $this->X_MinorCustomStart; } /** * Custom Minor horizontal division increment function * * The custom increment function must take a value and return * the next value. This function is useful if the graph is not * split up linearly, such as with logarithmic divisions or divisions * by month. * @param $Value A custom increment function * @since verion 1.2 */ function SetX_MinorCustomIncrement( $Value ) { $this->X_MinorCustomIncrement = $Value; } /** * Get custom Minor horizontal division increment function * * @return Minor horizontal division increment function * @since verion 1.2 */ function GetX_MinorCustomIncrement() { return $this->X_MinorCustomIncrement; } /** * Custom Minor horizontal division end value * * A value at which to stop making division marks. This can be useful * if the division lines stop before the end of the chat * @param $Value X value at which to stop * @since verion 1.2 */ function SetX_MinorCustomEnd( $Value ) { $this->X_MinorCustomEnd = $Value; } /** * Get custom Minor horizontal division end value * @return custom Minor horizontal division end value * @since verion 1.2 */ function GetX_MinorCustomEnd() { return $this->X_MinorCustomEnd; } /** * Minor horizontal scale * * These are the increments in which the minor horizontal scale * is labled. For example, a value of 50 would place divides every * 50 units. * @param $Value Scale * @since verion 1.2 */ function SetX_MinorDivisionScale( $Value ) { $this->X_MinorDivisionScale = $Value; } /** * Get minor horizontal scale * * Return increments in which the minor horizontal scale * is labled. * @return increments of scale * @since verion 1.2 */ function GetX_MinorDivisionScale() { return $this->X_MinorDivisionScale; } /** * Color of horizontal divisions * * Set the color of minor horizontal divisions * @param $Value Allocated color in the image * @since verion 1.2 */ function SetX_MinorDivisionColor( $Value ) { $this->X_MinorDivisionColor = $Value; } /** * Get color of minor horitontal divisions * * Return the color of minor horitontal divisions * @return color * @since verion 1.2 */ function GetX_MinorDivisionColor() { return $this->X_MinorDivisionColor; } /** * Minor horizontal divisions * * Draw minor horizontal (left to right) divisions * @since verion 1.2 */ function DrawX_MinorDivisions() { // Margins $MarginLeft = $this->Window->GetX(); $MarginTop = $this->Window->GetY(); $MarginRight = $this->Window->GetXX(); $MarginBottom = $this->Window->GetYY(); // Round off start and end of horizontal divisions $Round = 1.0 / $this->X_MinorDivisionScale; // Start if ( $this->X_MinorCustomStart === null ) $X_Position = $X_MinStart = floor( $this->X_Min * $Round ) / $Round; else $X_Position = $this->X_MinorCustomStart; // End if ( $this->X_MinorCustomEnd === null ) $X_MaxStart = ceil( $this->X_Max * $Round ) / $Round; else $X_MaxStart = $this->X_MinorCustomEnd; $IncFunction = $this->X_MinorCustomIncrement; // While more divisions remain to be drawn while ( $X_Position <= $X_MaxStart ) { // Get vertical location of line $x = round( $this->ScaleX( $X_Position , false ) ); $x += $MarginLeft; // Is this within the margins? if ( ( $x < $MarginLeft ) || ( $x > $MarginRight ) ) { if ( $IncFunction === null ) $X_Position += $this->X_MinorDivisionScale; else $X_Position = $IncFunction( $X_Position ); continue; } $y = $MarginBottom + $this->X_MinorDivisionExtention; // Division line imageline( $this->Image , $x , $MarginTop , $x , $y , $this->X_MinorDivisionColor ); // Next... if ( $IncFunction === null ) $X_Position += $this->X_MinorDivisionScale; else $X_Position = $IncFunction( $X_Position ); } } } // Hardware: the parts of a computer that can be kicked. ~Jeff Pesis ?>