2019-07-17 20:08:50 +00:00
< ? php
/*=======================================================================
2019-07-17 20:31:04 +00:00
// File: JPGRAPH_LOG.PHP
// Description: Log scale plot extension for JpGraph
// Created: 2001-01-08
// Ver: $Id: jpgraph_log.php 1106 2009-02-22 20:16:35Z ljp $
//
// Copyright (c) Aditus Consulting. All rights reserved.
//========================================================================
*/
2019-07-17 20:08:50 +00:00
DEFINE ( 'LOGLABELS_PLAIN' , 0 );
DEFINE ( 'LOGLABELS_MAGNITUDE' , 1 );
//===================================================
// CLASS LogScale
// Description: Logarithmic scale between world and screen
//===================================================
class LogScale extends LinearScale {
2019-07-17 20:31:04 +00:00
//---------------
// CONSTRUCTOR
2019-07-17 20:08:50 +00:00
// Log scale is specified using the log of min and max
2019-07-17 20:31:04 +00:00
function __construct ( $min , $max , $type = " y " ) {
parent :: __construct ( $min , $max , $type );
$this -> ticks = new LogTicks ();
$this -> name = 'log' ;
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
//----------------
// PUBLIC METHODS
2019-07-17 20:08:50 +00:00
// Translate between world and screen
function Translate ( $a ) {
2019-07-17 20:31:04 +00:00
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 );
2019-07-17 20:08:50 +00:00
}
// Relative translate (don't include offset) usefull when we just want
2019-07-17 20:31:04 +00:00
// to know the relative position (in pixels) on the axis
2019-07-17 20:08:50 +00:00
function RelTranslate ( $a ) {
2019-07-17 20:31:04 +00:00
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 );
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
2019-07-17 20:08:50 +00:00
// Use bcpow() for increased precision
function GetMinVal () {
2019-07-17 20:31:04 +00:00
if ( function_exists ( " bcpow " ) ) {
return round ( bcpow ( 10 , $this -> scale [ 0 ], 15 ), 14 );
}
else {
return round ( pow ( 10 , $this -> scale [ 0 ]), 14 );
}
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
2019-07-17 20:08:50 +00:00
function GetMaxVal () {
2019-07-17 20:31:04 +00:00
if ( function_exists ( " bcpow " ) ) {
return round ( bcpow ( 10 , $this -> scale [ 1 ], 15 ), 14 );
}
else {
return round ( pow ( 10 , $this -> scale [ 1 ]), 14 );
}
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
2019-07-17 20:08:50 +00:00
// 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 , $maxsteps , $majend = true ) {
2019-07-17 20:31:04 +00:00
if ( $min == 0 ) $min = 1 ;
2019-07-17 20:08:50 +00:00
2019-07-17 20:31:04 +00:00
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.');
}
if ( is_numeric ( $this -> autoscale_min ) ) {
$smin = round ( $this -> autoscale_min );
$smax = ceil ( log10 ( $max ));
if ( $min >= $max ) {
JpGraphError :: RaiseL ( 25071 ); //('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
}
}
else {
$smin = floor ( log10 ( $min ));
if ( is_numeric ( $this -> autoscale_max ) ) {
$smax = round ( $this -> autoscale_max );
if ( $smin >= $smax ) {
JpGraphError :: RaiseL ( 25072 ); //('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
}
}
else
$smax = ceil ( log10 ( $max ));
}
$this -> Update ( $img , $smin , $smax );
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
//---------------
// PRIVATE METHODS
2019-07-17 20:08:50 +00:00
} // Class
//===================================================
// CLASS LogTicks
2019-07-17 20:31:04 +00:00
// Description:
2019-07-17 20:08:50 +00:00
//===================================================
class LogTicks extends Ticks {
private $label_logtype = LOGLABELS_MAGNITUDE ;
private $ticklabels_pos = array ();
2019-07-17 20:31:04 +00:00
//---------------
// CONSTRUCTOR
2019-07-17 20:08:50 +00:00
function LogTicks () {
}
2019-07-17 20:31:04 +00:00
//---------------
// PUBLIC METHODS
2019-07-17 20:08:50 +00:00
function IsSpecified () {
2019-07-17 20:31:04 +00:00
return true ;
2019-07-17 20:08:50 +00:00
}
function SetLabelLogType ( $aType ) {
2019-07-17 20:31:04 +00:00
$this -> label_logtype = $aType ;
2019-07-17 20:08:50 +00:00
}
2019-07-17 20:31:04 +00:00
2019-07-17 20:08:50 +00:00
// 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 () {
2019-07-17 20:31:04 +00:00
return - 1 ;
2019-07-17 20:08:50 +00:00
}
function SetTextLabelStart ( $aStart ) {
2019-07-17 20:31:04 +00:00
JpGraphError :: RaiseL ( 11005 );
//('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.');
2019-07-17 20:08:50 +00:00
}
function SetXLabelOffset ( $dummy ) {
2019-07-17 20:31:04 +00:00
// For log scales we dont care about XLabel offset
2019-07-17 20:08:50 +00:00
}
// 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 ) {
2019-07-17 20:31:04 +00:00
$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 ;
2019-07-17 20:08:50 +00:00
2019-07-17 20:31:04 +00:00
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 ;
2019-07-17 20:08:50 +00:00
2019-07-17 20:31:04 +00:00
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 ;
2019-07-17 20:08:50 +00:00
}
} // Class
/* EOF */
?>