2006-07-01 03:48:56 +02:00
< ? php
/*=======================================================================
// File: JPGRAPH_LOG.PHP
// Description: Log scale plot extension for JpGraph
// Created: 2001-01-08
// Author: Johan Persson (johanp@aditus.nu)
// Ver: $Id: jpgraph_log.php 56 2005-06-06 20:14:44Z ljp $
//
// Copyright (c) Aditus Consulting. All rights reserved.
//========================================================================
*/
DEFINE ( 'LOGLABELS_PLAIN' , 0 );
DEFINE ( 'LOGLABELS_MAGNITUDE' , 1 );
//===================================================
// CLASS LogScale
// Description: Logarithmic scale between world and screen
//===================================================
class LogScale extends LinearScale {
//---------------
// CONSTRUCTOR
// Log scale is specified using the log of min and max
function LogScale ( $min , $max , $type = " y " ) {
$this -> LinearScale ( $min , $max , $type );
$this -> ticks = new LogTicks ();
$this -> name = 'log' ;
}
//----------------
// PUBLIC METHODS
// Translate between world and screen
function Translate ( $a ) {
if ( ! is_numeric ( $a ) ) {
if ( $a != '' && $a != '-' && $a != 'x' )
JpGraphError :: Raise ( 'Your data contains non-numeric values.' );
return 1 ;
}
if ( $a < 0 ) {
JpGraphError :: Raise ( " Negative data values can not be used in a log scale. " );
exit ( 1 );
}
if ( $a == 0 ) $a = 1 ;
$a = log10 ( $a );
return ceil ( $this -> off + ( $a * 1.0 - $this -> scale [ 0 ]) * $this -> scale_factor );
}
// Relative translate (don't include offset) usefull when we just want
// to know the relative position (in pixels) on the axis
function RelTranslate ( $a ) {
if ( ! is_numeric ( $a ) ) {
if ( $a != '' && $a != '-' && $a != 'x' )
JpGraphError :: Raise ( 'Your data contains non-numeric values.' );
return 1 ;
}
if ( $a == 0 ) $a = 1 ;
$a = log10 ( $a );
return round (( $a * 1.0 - $this -> scale [ 0 ]) * $this -> scale_factor );
}
// Use bcpow() for increased precision
function GetMinVal () {
if ( function_exists ( " bcpow " ) )
return round ( bcpow ( 10 , $this -> scale [ 0 ], 15 ), 14 );
else
return round ( pow ( 10 , $this -> scale [ 0 ]), 14 );
}
function GetMaxVal () {
if ( function_exists ( " bcpow " ) )
return round ( bcpow ( 10 , $this -> scale [ 1 ], 15 ), 14 );
else
return round ( pow ( 10 , $this -> scale [ 1 ]), 14 );
}
// Logarithmic autoscaling is much simplier since we just
// set the min and max to logs of the min and max values.
// Note that for log autoscale the "maxstep" the fourth argument
// isn't used. This is just included to give the method the same
// signature as the linear counterpart.
function AutoScale ( & $img , $min , $max , $dummy ) {
if ( $min == 0 ) $min = 1 ;
if ( $max <= 0 ) {
JpGraphError :: Raise ( 'Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.' );
}
$smin = floor ( log10 ( $min ));
$smax = ceil ( log10 ( $max ));
$this -> Update ( $img , $smin , $smax );
}
//---------------
// PRIVATE METHODS
} // Class
//===================================================
// CLASS LogTicks
// Description:
//===================================================
class LogTicks extends Ticks {
var $label_logtype = LOGLABELS_MAGNITUDE ;
//---------------
// CONSTRUCTOR
function LogTicks () {
}
//---------------
// PUBLIC METHODS
function IsSpecified () {
return true ;
}
function SetLabelLogType ( $aType ) {
$this -> label_logtype = $aType ;
}
// For log scale it's meaningless to speak about a major step
// We just return -1 to make the framework happy (specifically
// StrokeLabels() )
function GetMajor () {
return - 1 ;
}
function SetTextLabelStart ( $aStart ) {
JpGraphError :: Raise ( 'Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.' );
}
function SetXLabelOffset ( $dummy ) {
// For log scales we dont care about XLabel offset
}
// Draw ticks on image "img" using scale "scale". The axis absolute
// position in the image is specified in pos, i.e. for an x-axis
// it specifies the absolute y-coord and for Y-ticks it specified the
// absolute x-position.
function Stroke ( & $img , & $scale , $pos ) {
$start = $scale -> GetMinVal ();
$limit = $scale -> GetMaxVal ();
$nextMajor = 10 * $start ;
$step = $nextMajor / 10.0 ;
$img -> SetLineWeight ( $this -> weight );
if ( $scale -> type == " y " ) {
// member direction specified if the ticks should be on
// left or right side.
$a = $pos + $this -> direction * $this -> GetMinTickAbsSize ();
$a2 = $pos + $this -> direction * $this -> GetMajTickAbsSize ();
$count = 1 ;
$this -> maj_ticks_pos [ 0 ] = $scale -> Translate ( $start );
$this -> maj_ticklabels_pos [ 0 ] = $scale -> Translate ( $start );
if ( $this -> supress_first )
$this -> maj_ticks_label [ 0 ] = " " ;
else {
if ( $this -> label_formfunc != '' ) {
$f = $this -> label_formfunc ;
$this -> maj_ticks_label [ 0 ] = call_user_func ( $f , $start );
}
elseif ( $this -> label_logtype == LOGLABELS_PLAIN )
$this -> maj_ticks_label [ 0 ] = $start ;
else
$this -> maj_ticks_label [ 0 ] = '10^' . round ( log10 ( $start ));
}
$i = 1 ;
for ( $y = $start ; $y <= $limit ; $y += $step , ++ $count ) {
$ys = $scale -> Translate ( $y );
$this -> ticks_pos [] = $ys ;
$this -> ticklabels_pos [] = $ys ;
if ( $count % 10 == 0 ) {
if ( ! $this -> supress_tickmarks ) {
if ( $this -> majcolor != " " ) {
$img -> PushColor ( $this -> majcolor );
$img -> Line ( $pos , $ys , $a2 , $ys );
$img -> PopColor ();
}
else
$img -> Line ( $pos , $ys , $a2 , $ys );
}
$this -> maj_ticks_pos [ $i ] = $ys ;
$this -> maj_ticklabels_pos [ $i ] = $ys ;
if ( $this -> label_formfunc != '' ) {
$f = $this -> label_formfunc ;
$this -> maj_ticks_label [ $i ] = call_user_func ( $f , $nextMajor );
}
elseif ( $this -> label_logtype == 0 )
$this -> maj_ticks_label [ $i ] = $nextMajor ;
else
$this -> maj_ticks_label [ $i ] = '10^' . round ( log10 ( $nextMajor ));
++ $i ;
$nextMajor *= 10 ;
$step *= 10 ;
$count = 1 ;
}
else {
if ( ! $this -> supress_tickmarks && ! $this -> supress_minor_tickmarks ) {
if ( $this -> mincolor != " " ) $img -> PushColor ( $this -> mincolor );
$img -> Line ( $pos , $ys , $a , $ys );
if ( $this -> mincolor != " " ) $img -> PopColor ();
}
}
}
}
else {
$a = $pos - $this -> direction * $this -> GetMinTickAbsSize ();
$a2 = $pos - $this -> direction * $this -> GetMajTickAbsSize ();
$count = 1 ;
$this -> maj_ticks_pos [ 0 ] = $scale -> Translate ( $start );
$this -> maj_ticklabels_pos [ 0 ] = $scale -> Translate ( $start );
if ( $this -> supress_first )
$this -> maj_ticks_label [ 0 ] = " " ;
else {
if ( $this -> label_formfunc != '' ) {
$f = $this -> label_formfunc ;
$this -> maj_ticks_label [ 0 ] = call_user_func ( $f , $start );
}
elseif ( $this -> label_logtype == 0 )
$this -> maj_ticks_label [ 0 ] = $start ;
else
$this -> maj_ticks_label [ 0 ] = '10^' . round ( log10 ( $start ));
}
$i = 1 ;
for ( $x = $start ; $x <= $limit ; $x += $step , ++ $count ) {
$xs = $scale -> Translate ( $x );
$this -> ticks_pos [] = $xs ;
$this -> ticklabels_pos [] = $xs ;
if ( $count % 10 == 0 ) {
if ( ! $this -> supress_tickmarks ) {
$img -> Line ( $xs , $pos , $xs , $a2 );
}
$this -> maj_ticks_pos [ $i ] = $xs ;
$this -> maj_ticklabels_pos [ $i ] = $xs ;
if ( $this -> label_formfunc != '' ) {
$f = $this -> label_formfunc ;
$this -> maj_ticks_label [ $i ] = call_user_func ( $f , $nextMajor );
}
elseif ( $this -> label_logtype == 0 )
$this -> maj_ticks_label [ $i ] = $nextMajor ;
else
$this -> maj_ticks_label [ $i ] = '10^' . round ( log10 ( $nextMajor ));
++ $i ;
$nextMajor *= 10 ;
$step *= 10 ;
$count = 1 ;
}
else {
if ( ! $this -> supress_tickmarks && ! $this -> supress_minor_tickmarks ) {
$img -> Line ( $xs , $pos , $xs , $a );
}
}
}
}
return true ;
}
} // Class
/* EOF */
?>