2 /*=======================================================================
3 // File: JPGRAPH_LOG.PHP
4 // Description: Log scale plot extension for JpGraph
6 // Author: Johan Persson (johanp@aditus.nu)
7 // Ver: $Id: jpgraph_log.php,v 1.1 2006/07/07 13:37:14 powles Exp $
9 // Copyright (c) Aditus Consulting. All rights reserved.
10 //========================================================================
14 DEFINE('LOGLABELS_PLAIN',0);
15 DEFINE('LOGLABELS_MAGNITUDE',1);
17 //===================================================
19 // Description: Logarithmic scale between world and screen
20 //===================================================
21 class LogScale
extends LinearScale
{
25 // Log scale is specified using the log of min and max
26 function __construct($min,$max,$type="y") {
27 parent
::__construct($min,$max,$type);
28 $this->ticks
= new LogTicks();
35 // Translate between world and screen
36 function Translate($a) {
37 if( !is_numeric($a) ) {
38 if( $a != '' && $a != '-' && $a != 'x' )
39 JpGraphError
::RaiseL(11001);
40 //('Your data contains non-numeric values.');
44 JpGraphError
::RaiseL(11002);
45 //("Negative data values can not be used in a log scale.");
50 return ceil($this->off +
($a*1.0 - $this->scale
[0]) * $this->scale_factor
);
53 // Relative translate (don't include offset) usefull when we just want
54 // to know the relative position (in pixels) on the axis
55 function RelTranslate($a) {
56 if( !is_numeric($a) ) {
57 if( $a != '' && $a != '-' && $a != 'x' )
58 JpGraphError
::RaiseL(11001);
59 //('Your data contains non-numeric values.');
64 return round(($a*1.0 - $this->scale
[0]) * $this->scale_factor
);
67 // Use bcpow() for increased precision
68 function GetMinVal() {
69 if( function_exists("bcpow") )
70 return round(bcpow(10,$this->scale
[0],15),14);
72 return round(pow(10,$this->scale
[0]),14);
75 function GetMaxVal() {
76 if( function_exists("bcpow") )
77 return round(bcpow(10,$this->scale
[1],15),14);
79 return round(pow(10,$this->scale
[1]),14);
82 // Logarithmic autoscaling is much simplier since we just
83 // set the min and max to logs of the min and max values.
84 // Note that for log autoscale the "maxstep" the fourth argument
85 // isn't used. This is just included to give the method the same
86 // signature as the linear counterpart.
87 function AutoScale(&$img,$min,$max,$dummy, $dummy2 = true) {
91 JpGraphError
::RaiseL(11004);
92 //('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.');
94 $smin = floor(log10($min));
95 $smax = ceil(log10($max));
96 $this->Update($img,$smin,$smax);
102 //===================================================
105 //===================================================
106 class LogTicks
extends Ticks
{
107 var $label_logtype=LOGLABELS_MAGNITUDE
;
110 function __construct() {
111 parent
::__construct();
115 function IsSpecified() {
119 function SetLabelLogType($aType) {
120 $this->label_logtype
= $aType;
123 // For log scale it's meaningless to speak about a major step
124 // We just return -1 to make the framework happy (specifically
126 function GetMajor() {
130 function SetTextLabelStart($aStart) {
131 JpGraphError
::RaiseL(11005);
132 //('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.');
135 function SetXLabelOffset($dummy) {
136 // For log scales we dont care about XLabel offset
139 // Draw ticks on image "img" using scale "scale". The axis absolute
140 // position in the image is specified in pos, i.e. for an x-axis
141 // it specifies the absolute y-coord and for Y-ticks it specified the
142 // absolute x-position.
143 function Stroke(&$img,&$scale,$pos) {
144 $start = $scale->GetMinVal();
145 $limit = $scale->GetMaxVal();
146 $nextMajor = 10*$start;
147 $step = $nextMajor / 10.0;
150 $img->SetLineWeight($this->weight
);
152 if( $scale->type
== "y" ) {
153 // member direction specified if the ticks should be on
154 // left or right side.
155 $a=$pos +
$this->direction
*$this->GetMinTickAbsSize();
156 $a2=$pos +
$this->direction
*$this->GetMajTickAbsSize();
159 $this->maj_ticks_pos
[0]=$scale->Translate($start);
160 $this->maj_ticklabels_pos
[0]=$scale->Translate($start);
161 if( $this->supress_first
)
162 $this->maj_ticks_label
[0]="";
164 if( $this->label_formfunc
!= '' ) {
165 $f = $this->label_formfunc
;
166 $this->maj_ticks_label
[0]=call_user_func($f,$start);
168 elseif( $this->label_logtype
== LOGLABELS_PLAIN
)
169 $this->maj_ticks_label
[0]=$start;
171 $this->maj_ticks_label
[0]='10^'.round(log10($start));
174 for($y=$start; $y<=$limit; $y+
=$step,++
$count ) {
175 $ys=$scale->Translate($y);
176 $this->ticks_pos
[]=$ys;
177 $this->ticklabels_pos
[]=$ys;
178 if( $count %
10 == 0 ) {
179 if( !$this->supress_tickmarks
) {
180 if( $this->majcolor
!="" ) {
181 $img->PushColor($this->majcolor
);
182 $img->Line($pos,$ys,$a2,$ys);
186 $img->Line($pos,$ys,$a2,$ys);
189 $this->maj_ticks_pos
[$i]=$ys;
190 $this->maj_ticklabels_pos
[$i]=$ys;
192 if( $this->label_formfunc
!= '' ) {
193 $f = $this->label_formfunc
;
194 $this->maj_ticks_label
[$i]=call_user_func($f,$nextMajor);
196 elseif( $this->label_logtype
== 0 )
197 $this->maj_ticks_label
[$i]=$nextMajor;
199 $this->maj_ticks_label
[$i]='10^'.round(log10($nextMajor));
206 if( !$this->supress_tickmarks
&& !$this->supress_minor_tickmarks
) {
207 if( $this->mincolor
!="" ) $img->PushColor($this->mincolor
);
208 $img->Line($pos,$ys,$a,$ys);
209 if( $this->mincolor
!="" ) $img->PopColor();
215 $a=$pos - $this->direction
*$this->GetMinTickAbsSize();
216 $a2=$pos - $this->direction
*$this->GetMajTickAbsSize();
218 $this->maj_ticks_pos
[0]=$scale->Translate($start);
219 $this->maj_ticklabels_pos
[0]=$scale->Translate($start);
220 if( $this->supress_first
)
221 $this->maj_ticks_label
[0]="";
223 if( $this->label_formfunc
!= '' ) {
224 $f = $this->label_formfunc
;
225 $this->maj_ticks_label
[0]=call_user_func($f,$start);
227 elseif( $this->label_logtype
== 0 )
228 $this->maj_ticks_label
[0]=$start;
230 $this->maj_ticks_label
[0]='10^'.round(log10($start));
233 for($x=$start; $x<=$limit; $x+
=$step,++
$count ) {
234 $xs=$scale->Translate($x);
235 $this->ticks_pos
[]=$xs;
236 $this->ticklabels_pos
[]=$xs;
237 if( $count %
10 == 0 ) {
238 if( !$this->supress_tickmarks
) {
239 $img->Line($xs,$pos,$xs,$a2);
241 $this->maj_ticks_pos
[$i]=$xs;
242 $this->maj_ticklabels_pos
[$i]=$xs;
244 if( $this->label_formfunc
!= '' ) {
245 $f = $this->label_formfunc
;
246 $this->maj_ticks_label
[$i]=call_user_func($f,$nextMajor);
248 elseif( $this->label_logtype
== 0 )
249 $this->maj_ticks_label
[$i]=$nextMajor;
251 $this->maj_ticks_label
[$i]='10^'.round(log10($nextMajor));
258 if( !$this->supress_tickmarks
&& !$this->supress_minor_tickmarks
) {
259 $img->Line($xs,$pos,$xs,$a);