| <?php |
| /*======================================================================= |
| // File: JPGRAPH_LOG.PHP |
| // Description: Log scale plot extension for JpGraph |
| // Created: 2001-01-08 |
| // Author: Johan Persson (johanp@aditus.nu) |
| // Ver: $Id$ |
| // |
| // 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::RaiseL(11001); |
| //('Your data contains non-numeric values.'); |
| return 1; |
| } |
| if( $a < 0 ) { |
| JpGraphError::RaiseL(11002); |
| //("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::RaiseL(11001); |
| //('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::RaiseL(11004); |
| //('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::RaiseL(11005); |
| //('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 */ |
| ?> |