- Timestamp:
- Apr 13, 2019, 8:05:15 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/client/modules/Elezioni/grafici/jpgraph_utils.inc.php
r2 r265 1 1 <?php 2 2 /*======================================================================= 3 // File:JPGRAPH_UTILS.INC4 // Description: Collection of non-essential "nice to have" utilities 5 // Created:2005-11-206 // Ver: $Id: jpgraph_utils.inc.php 1091 2009-01-18 22:57:40Z ljp $7 //8 // Copyright (c) Aditus Consulting. All rights reserved.9 //========================================================================10 */3 // File: JPGRAPH_UTILS.INC 4 // Description: Collection of non-essential "nice to have" utilities 5 // Created: 2005-11-20 6 // Ver: $Id: jpgraph_utils.inc.php 1777 2009-08-23 17:34:36Z ljp $ 7 // 8 // Copyright (c) Asial Corporation. All rights reserved. 9 //======================================================================== 10 */ 11 11 12 12 //=================================================== 13 13 // CLASS FuncGenerator 14 // Description: Utility class to help generate data for function plots. 14 // Description: Utility class to help generate data for function plots. 15 15 // The class supports both parametric and regular functions. 16 16 //=================================================== 17 17 class FuncGenerator { 18 18 private $iFunc='',$iXFunc='',$iMin,$iMax,$iStepSize; 19 20 function FuncGenerator($aFunc,$aXFunc='') {21 22 23 } 24 19 20 function __construct($aFunc,$aXFunc='') { 21 $this->iFunc = $aFunc; 22 $this->iXFunc = $aXFunc; 23 } 24 25 25 function E($aXMin,$aXMax,$aSteps=50) { 26 $this->iMin = $aXMin; 27 $this->iMax = $aXMax; 28 $this->iStepSize = ($aXMax-$aXMin)/$aSteps; 29 30 if( $this->iXFunc != '' ) 31 $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; 32 elseif( $this->iFunc != '' ) 33 $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; 34 else 35 JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); 36 37 @eval($t); 38 39 // If there is an error in the function specifcation this is the only 40 // way we can discover that. 41 if( empty($xa) || empty($ya) ) 42 JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); 43 44 return array($xa,$ya); 45 } 46 } 47 48 //============================================================================= 49 // CLASS SymChar 50 // Description: Code values for some commonly used characters that 51 // normally isn't available directly on the keyboard, for example 52 // mathematical and greek symbols. 53 //============================================================================= 54 class SymChar { 55 static function Get($aSymb,$aCapital=FALSE) { 56 $iSymbols = array( 57 /* Greek */ 58 array('alpha','03B1','0391'), 59 array('beta','03B2','0392'), 60 array('gamma','03B3','0393'), 61 array('delta','03B4','0394'), 62 array('epsilon','03B5','0395'), 63 array('zeta','03B6','0396'), 64 array('ny','03B7','0397'), 65 array('eta','03B8','0398'), 66 array('theta','03B8','0398'), 67 array('iota','03B9','0399'), 68 array('kappa','03BA','039A'), 69 array('lambda','03BB','039B'), 70 array('mu','03BC','039C'), 71 array('nu','03BD','039D'), 72 array('xi','03BE','039E'), 73 array('omicron','03BF','039F'), 74 array('pi','03C0','03A0'), 75 array('rho','03C1','03A1'), 76 array('sigma','03C3','03A3'), 77 array('tau','03C4','03A4'), 78 array('upsilon','03C5','03A5'), 79 array('phi','03C6','03A6'), 80 array('chi','03C7','03A7'), 81 array('psi','03C8','03A8'), 82 array('omega','03C9','03A9'), 83 /* Money */ 84 array('euro','20AC'), 85 array('yen','00A5'), 86 array('pound','20A4'), 87 /* Math */ 88 array('approx','2248'), 89 array('neq','2260'), 90 array('not','2310'), 91 array('def','2261'), 92 array('inf','221E'), 93 array('sqrt','221A'), 94 array('int','222B'), 95 /* Misc */ 96 array('copy','00A9'), 97 array('para','00A7'), 98 array('tm','2122'), /* Trademark symbol */ 99 array('rtm','00AE') /* Registered trademark */ 100 101 ); 102 103 $n = count($iSymbols); 104 $i=0; 105 $found = false; 106 $aSymb = strtolower($aSymb); 107 while( $i < $n && !$found ) { 108 $found = $aSymb === $iSymbols[$i++][0]; 109 } 110 if( $found ) { 111 $ca = $iSymbols[--$i]; 112 if( $aCapital && count($ca)==3 ) 113 $s = $ca[2]; 114 else 115 $s = $ca[1]; 116 return sprintf('&#%04d;',hexdec($s)); 117 } 118 else 119 return ''; 26 $this->iMin = $aXMin; 27 $this->iMax = $aXMax; 28 $this->iStepSize = ($aXMax-$aXMin)/$aSteps; 29 30 if( $this->iXFunc != '' ) 31 $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; 32 elseif( $this->iFunc != '' ) 33 $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; 34 else 35 JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); 36 37 @eval($t); 38 39 // If there is an error in the function specifcation this is the only 40 // way we can discover that. 41 if( empty($xa) || empty($ya) ) 42 JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); 43 44 return array($xa,$ya); 120 45 } 121 46 } … … 151 76 152 77 static function UseWeekFormat($aFlg) { 153 78 self::$iUseWeeks = $aFlg; 154 79 } 155 80 156 81 static function doYearly($aType,$aMinor=false) { 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 180 181 182 183 $y=self::$startyear; 184 185 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 186 for($k=0; $k < 1; ++$k ) { 187 188 189 190 191 192 193 194 195 196 $y=self::$startyear; 197 198 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 199 for($k=0; $k < 4; ++$k ) { 200 201 202 203 204 205 206 207 208 82 $i=0; $j=0; 83 $m = self::$startmonth; 84 $y = self::$startyear; 85 86 if( self::$startday == 1 ) { 87 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 88 } 89 ++$m; 90 91 92 switch( $aType ) { 93 case DSUTILS_YEAR1: 94 for($y=self::$startyear; $y <= self::$endyear; ++$y ) { 95 if( $aMinor ) { 96 while( $m <= 12 ) { 97 if( !($y == self::$endyear && $m > self::$endmonth) ) { 98 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 99 } 100 ++$m; 101 } 102 $m=1; 103 } 104 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 105 } 106 break; 107 case DSUTILS_YEAR2: 108 $y=self::$startyear; 109 while( $y <= self::$endyear ) { 110 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 111 for($k=0; $k < 1; ++$k ) { 112 ++$y; 113 if( $aMinor ) { 114 self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); 115 } 116 } 117 ++$y; 118 } 119 break; 120 case DSUTILS_YEAR5: 121 $y=self::$startyear; 122 while( $y <= self::$endyear ) { 123 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 124 for($k=0; $k < 4; ++$k ) { 125 ++$y; 126 if( $aMinor ) { 127 self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); 128 } 129 } 130 ++$y; 131 } 132 break; 133 } 209 134 } 210 135 211 136 static function doDaily($aType,$aMinor=false) { 212 213 214 215 216 217 218 219 220 221 $t = mktime(0,0,0,$m,$d,$y); 222 223 224 225 226 227 228 229 self::$minTickPositions[$j++] = strtotime('+12 hours',$t); 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 137 $m = self::$startmonth; 138 $y = self::$startyear; 139 $d = self::$startday; 140 $h = self::$starthour; 141 $i=0;$j=0; 142 143 if( $h == 0 ) { 144 self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); 145 } 146 $t = mktime(0,0,0,$m,$d,$y); 147 148 switch($aType) { 149 case DSUTILS_DAY1: 150 while( $t <= self::$iMax ) { 151 $t = strtotime('+1 day',$t); 152 self::$tickPositions[$i++] = $t; 153 if( $aMinor ) { 154 self::$minTickPositions[$j++] = strtotime('+12 hours',$t); 155 } 156 } 157 break; 158 case DSUTILS_DAY2: 159 while( $t <= self::$iMax ) { 160 $t = strtotime('+1 day',$t); 161 if( $aMinor ) { 162 self::$minTickPositions[$j++] = $t; 163 } 164 $t = strtotime('+1 day',$t); 165 self::$tickPositions[$i++] = $t; 166 } 167 break; 168 case DSUTILS_DAY4: 169 while( $t <= self::$iMax ) { 170 for($k=0; $k < 3; ++$k ) { 171 $t = strtotime('+1 day',$t); 172 if( $aMinor ) { 173 self::$minTickPositions[$j++] = $t; 174 } 175 } 176 $t = strtotime('+1 day',$t); 177 self::$tickPositions[$i++] = $t; 178 } 179 break; 180 } 256 181 } 257 182 258 183 static function doWeekly($aType,$aMinor=false) { 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 184 $hpd = 3600*24; 185 $hpw = 3600*24*7; 186 // Find out week number of min date 187 $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); 188 $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; 189 $daynumber = date('w',self::$iMin); 190 if( $daynumber == 0 ) $daynumber = 7; 191 $m = self::$startmonth; 192 $y = self::$startyear; 193 $d = self::$startday; 194 $i=0;$j=0; 195 // The assumption is that the weeks start on Monday. If the first day 196 // is later in the week then the first week tick has to be on the following 197 // week. 198 if( $daynumber == 1 ) { 199 self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); 200 $t = mktime(0,0,0,$m,$d,$y) + $hpw; 201 } 202 else { 203 $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber); 204 } 205 206 switch($aType) { 207 case DSUTILS_WEEK1: 208 $cnt=0; 209 break; 210 case DSUTILS_WEEK2: 211 $cnt=1; 212 break; 213 case DSUTILS_WEEK4: 214 $cnt=3; 215 break; 216 } 217 while( $t <= self::$iMax ) { 218 self::$tickPositions[$i++] = $t; 219 for($k=0; $k < $cnt; ++$k ) { 220 $t += $hpw; 221 if( $aMinor ) { 222 self::$minTickPositions[$j++] = $t; 223 } 224 } 225 $t += $hpw; 226 } 302 227 } 303 228 304 229 static function doMonthly($aType,$aMinor=false) { 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 case DSUTILS_MONTH1: 332 333 334 335 if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) 336 337 338 339 // Major at month 340 341 342 343 344 case DSUTILS_MONTH2: 345 346 347 348 349 350 // Major at every second month 351 352 353 354 355 356 case DSUTILS_MONTH3: 357 358 359 360 361 // Major at every third month 362 363 364 365 366 367 case DSUTILS_MONTH6: 368 369 370 371 372 // Major at every third month 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 } 391 392 230 $monthcount=0; 231 $m = self::$startmonth; 232 $y = self::$startyear; 233 $i=0; $j=0; 234 235 // Skip the first month label if it is before the startdate 236 if( self::$startday == 1 ) { 237 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 238 $monthcount=1; 239 } 240 if( $aType == 1 ) { 241 if( self::$startday < 15 ) { 242 self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); 243 } 244 } 245 ++$m; 246 247 // Loop through all the years included in the scale 248 for($y=self::$startyear; $y <= self::$endyear; ++$y ) { 249 // Loop through all the months. There are three cases to consider: 250 // 1. We are in the first year and must start with the startmonth 251 // 2. We are in the end year and we must stop at last month of the scale 252 // 3. A year in between where we run through all the 12 months 253 $stopmonth = $y == self::$endyear ? self::$endmonth : 12; 254 while( $m <= $stopmonth ) { 255 switch( $aType ) { 256 case DSUTILS_MONTH1: 257 // Set minor tick at the middle of the month 258 if( $aMinor ) { 259 if( $m <= $stopmonth ) { 260 if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) 261 self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); 262 } 263 } 264 // Major at month 265 // Get timestamp of first hour of first day in each month 266 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 267 268 break; 269 case DSUTILS_MONTH2: 270 if( $aMinor ) { 271 // Set minor tick at start of each month 272 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 273 } 274 275 // Major at every second month 276 // Get timestamp of first hour of first day in each month 277 if( $monthcount % 2 == 0 ) { 278 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 279 } 280 break; 281 case DSUTILS_MONTH3: 282 if( $aMinor ) { 283 // Set minor tick at start of each month 284 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 285 } 286 // Major at every third month 287 // Get timestamp of first hour of first day in each month 288 if( $monthcount % 3 == 0 ) { 289 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 290 } 291 break; 292 case DSUTILS_MONTH6: 293 if( $aMinor ) { 294 // Set minor tick at start of each month 295 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 296 } 297 // Major at every third month 298 // Get timestamp of first hour of first day in each month 299 if( $monthcount % 6 == 0 ) { 300 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 301 } 302 break; 303 } 304 ++$m; 305 ++$monthcount; 306 } 307 $m=1; 308 } 309 310 // For the case where all dates are within the same month 311 // we want to make sure we have at least two ticks on the scale 312 // since the scale want work properly otherwise 313 if(self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType==1 ) { 314 self::$tickPositions[$i++] = mktime(0 ,0 ,0, self::$startmonth + 1, 1, self::$startyear); 315 } 316 317 return array(self::$tickPositions,self::$minTickPositions); 393 318 } 394 319 395 320 static function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) { 396 397 321 $n = count($aData); 322 return self::GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints); 398 323 } 399 324 400 325 static function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) { 401 $diff = $aMax - $aMin; 402 $spd = 3600*24; 403 $spw = $spd*7; 404 $spm = $spd*30; 405 $spy = $spd*352; 406 407 if( self::$iUseWeeks ) 408 $w = 'W'; 409 else 410 $w = 'd M'; 411 412 // Decision table for suitable scales 413 // First value: Main decision point 414 // Second value: Array of formatting depending on divisor for wanted max number of ticks. <divisor><formatting><format-string>,.. 415 $tt = array( 416 array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')), 417 array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M', 418 7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)), 419 array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M', 420 7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w, 421 30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')), 422 array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y', 423 180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y'))); 424 425 $ntt = count($tt); 426 $nd = floor($diff/$spd); 427 for($i=0; $i < $ntt; ++$i ) { 428 if( $diff <= $tt[$i][0] || $i==$ntt-1) { 429 $t = $tt[$i][1]; 430 $n = count($t)/3; 431 for( $j=0; $j < $n; ++$j ) { 432 if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) { 433 $type = $t[3*$j+1]; 434 $fs = $t[3*$j+2]; 435 list($tickPositions,$minTickPositions) = self::GetTicksFromMinMax($aMin,$aMax,$type,$aMinor); 436 return array($fs,$tickPositions,$minTickPositions,$type); 437 } 438 } 439 } 440 } 326 $diff = $aMax - $aMin; 327 $spd = 3600*24; 328 $spw = $spd*7; 329 $spm = $spd*30; 330 $spy = $spd*352; 331 332 if( self::$iUseWeeks ) 333 $w = 'W'; 334 else 335 $w = 'd M'; 336 337 // Decision table for suitable scales 338 // First value: Main decision point 339 // Second value: Array of formatting depending on divisor for wanted max number of ticks. <divisor><formatting><format-string>,.. 340 $tt = array( 341 array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')), 342 array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)), 343 array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w,30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')), 344 array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y',180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y'))); 345 346 $ntt = count($tt); 347 $nd = floor($diff/$spd); 348 for($i=0; $i < $ntt; ++$i ) { 349 if( $diff <= $tt[$i][0] || $i==$ntt-1) { 350 $t = $tt[$i][1]; 351 $n = count($t)/3; 352 for( $j=0; $j < $n; ++$j ) { 353 if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) { 354 $type = $t[3*$j+1]; 355 $fs = $t[3*$j+2]; 356 list($tickPositions,$minTickPositions) = self::GetTicksFromMinMax($aMin,$aMax,$type,$aMinor); 357 return array($fs,$tickPositions,$minTickPositions,$type); 358 } 359 } 360 } 361 } 441 362 } 442 363 443 364 static function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) { 444 self::$starthour = date('G',$aMin); 445 self::$startmonth = date('n',$aMin); 446 self::$startday = date('j',$aMin); 447 self::$startyear = date('Y',$aMin); 448 self::$endmonth = date('n',$aMax); 449 self::$endyear = date('Y',$aMax); 450 self::$endday = date('j',$aMax); 451 self::$iMin = $aMin; 452 self::$iMax = $aMax; 453 454 if( $aType <= DSUTILS_MONTH6 ) { 455 self::doMonthly($aType,$aMinor); 456 } 457 elseif( $aType <= DSUTILS_WEEK4 ) { 458 self::doWeekly($aType,$aMinor); 459 } 460 elseif( $aType <= DSUTILS_DAY4 ) { 461 self::doDaily($aType,$aMinor); 462 } 463 elseif( $aType <= DSUTILS_YEAR5 ) { 464 self::doYearly($aType,$aMinor); 465 } 466 else { 467 JpGraphError::RaiseL(24003); 468 } 469 // put a label at the very left data pos 470 if( $aEndPoints ) { 471 $tickPositions[$i++] = $aData[0]; 472 } 473 474 // put a label at the very right data pos 475 if( $aEndPoints ) { 476 $tickPositions[$i] = $aData[$n-1]; 477 } 478 479 return array(self::$tickPositions,self::$minTickPositions); 480 } 481 365 self::$starthour = date('G',$aMin); 366 self::$startmonth = date('n',$aMin); 367 self::$startday = date('j',$aMin); 368 self::$startyear = date('Y',$aMin); 369 self::$endmonth = date('n',$aMax); 370 self::$endyear = date('Y',$aMax); 371 self::$endday = date('j',$aMax); 372 self::$iMin = $aMin; 373 self::$iMax = $aMax; 374 375 if( $aType <= DSUTILS_MONTH6 ) { 376 self::doMonthly($aType,$aMinor); 377 } 378 elseif( $aType <= DSUTILS_WEEK4 ) { 379 self::doWeekly($aType,$aMinor); 380 } 381 elseif( $aType <= DSUTILS_DAY4 ) { 382 self::doDaily($aType,$aMinor); 383 } 384 elseif( $aType <= DSUTILS_YEAR5 ) { 385 self::doYearly($aType,$aMinor); 386 } 387 else { 388 JpGraphError::RaiseL(24003); 389 } 390 // put a label at the very left data pos 391 if( $aEndPoints ) { 392 $tickPositions[$i++] = $aData[0]; 393 } 394 395 // put a label at the very right data pos 396 if( $aEndPoints ) { 397 $tickPositions[$i] = $aData[$n-1]; 398 } 399 400 return array(self::$tickPositions,self::$minTickPositions); 401 } 482 402 } 483 403 … … 486 406 //============================================================================= 487 407 Class ReadFileData { 488 489 408 //---------------------------------------------------------------------------- 490 409 // Desciption: 491 // Read numeric data from a file. 492 // Each value should be separated by either a new line or by a specified 410 // Read numeric data from a file. 411 // Each value should be separated by either a new line or by a specified 493 412 // separator character (default is ','). 494 // Before returning the data each value is converted to a proper float 495 // value. The routine is robust in the sense that non numeric data in the 413 // Before returning the data each value is converted to a proper float 414 // value. The routine is robust in the sense that non numeric data in the 496 415 // file will be discarded. 497 416 // 498 // Returns: 417 // Returns: 499 418 // The number of data values read on success, FALSE on failure 500 419 //---------------------------------------------------------------------------- 501 420 static function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { 502 $rh = fopen($aFile,'r'); 503 if( $rh === false ) 504 return false; 505 $tmp = array(); 506 $lineofdata = fgetcsv($rh, 1000, ','); 507 while ( $lineofdata !== FALSE) { 508 $tmp = array_merge($tmp,$lineofdata); 509 $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); 510 } 511 fclose($rh); 512 513 // Now make sure that all data is numeric. By default 514 // all data is read as strings 515 $n = count($tmp); 516 $aData = array(); 517 $cnt=0; 518 for($i=0; $i < $n; ++$i) { 519 if( $tmp[$i] !== "" ) { 520 $aData[$cnt++] = floatval($tmp[$i]); 521 } 522 } 523 return $cnt; 524 } 421 $rh = @fopen($aFile,'r'); 422 if( $rh === false ) { 423 return false; 424 } 425 $tmp = array(); 426 $lineofdata = fgetcsv($rh, 1000, ','); 427 while ( $lineofdata !== FALSE) { 428 $tmp = array_merge($tmp,$lineofdata); 429 $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); 430 } 431 fclose($rh); 432 433 // Now make sure that all data is numeric. By default 434 // all data is read as strings 435 $n = count($tmp); 436 $aData = array(); 437 $cnt=0; 438 for($i=0; $i < $n; ++$i) { 439 if( $tmp[$i] !== "" ) { 440 $aData[$cnt++] = floatval($tmp[$i]); 441 } 442 } 443 return $cnt; 444 } 445 446 //---------------------------------------------------------------------------- 447 // Desciption: 448 // Read numeric data from a file. 449 // Each value should be separated by either a new line or by a specified 450 // separator character (default is ','). 451 // Before returning the data each value is converted to a proper float 452 // value. The routine is robust in the sense that non numeric data in the 453 // file will be discarded. 454 // 455 // Options: 456 // 'separator' => ',', 457 // 'enclosure' => '"', 458 // 'readlength' => 1024, 459 // 'ignore_first' => false, 460 // 'first_as_key' => false 461 // 'escape' => '\', # PHP >= 5.3 only 462 // 463 // Returns: 464 // The number of lines read on success, FALSE on failure 465 //---------------------------------------------------------------------------- 466 static function FromCSV2($aFile, &$aData, $aOptions = array()) { 467 $aDefaults = array( 468 'separator' => ',', 469 'enclosure' => chr(34), 470 'escape' => chr(92), 471 'readlength' => 1024, 472 'ignore_first' => false, 473 'first_as_key' => false 474 ); 475 476 $aOptions = array_merge( 477 $aDefaults, is_array($aOptions) ? $aOptions : array()); 478 479 if( $aOptions['first_as_key'] ) { 480 $aOptions['ignore_first'] = true; 481 } 482 483 $rh = @fopen($aFile, 'r'); 484 485 if( $rh === false ) { 486 return false; 487 } 488 489 $aData = array(); 490 $aLine = fgetcsv($rh, 491 $aOptions['readlength'], 492 $aOptions['separator'], 493 $aOptions['enclosure'] 494 /*, $aOptions['escape'] # PHP >= 5.3 only */ 495 ); 496 497 // Use numeric array keys for the columns by default 498 // If specified use first lines values as assoc keys instead 499 $keys = array_keys($aLine); 500 if( $aOptions['first_as_key'] ) { 501 $keys = array_values($aLine); 502 } 503 504 $num_lines = 0; 505 $num_cols = count($aLine); 506 507 while ($aLine !== false) { 508 if( is_array($aLine) && count($aLine) != $num_cols ) { 509 JpGraphError::RaiseL(24004); 510 // 'ReadCSV2: Column count mismatch in %s line %d' 511 } 512 513 // fgetcsv returns NULL for empty lines 514 if( !is_null($aLine) ) { 515 $num_lines++; 516 517 if( !($aOptions['ignore_first'] && $num_lines == 1) && is_numeric($aLine[0]) ) { 518 for( $i = 0; $i < $num_cols; $i++ ) { 519 $aData[ $keys[$i] ][] = floatval($aLine[$i]); 520 } 521 } 522 } 523 524 $aLine = fgetcsv($rh, 525 $aOptions['readlength'], 526 $aOptions['separator'], 527 $aOptions['enclosure'] 528 /*, $aOptions['escape'] # PHP >= 5.3 only*/ 529 ); 530 } 531 532 fclose($rh); 533 534 if( $aOptions['ignore_first'] ) { 535 $num_lines--; 536 } 537 538 return $num_lines; 539 } 540 541 // Read data from two columns in a plain text file 542 static function From2Col($aFile, $aCol1, $aCol2, $aSepChar=' ') { 543 $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); 544 if( $lines === false ) { 545 return false; 546 } 547 $s = '/[\s]+/'; 548 if( $aSepChar == ',' ) { 549 $s = '/[\s]*,[\s]*/'; 550 } 551 elseif( $aSepChar == ';' ) { 552 $s = '/[\s]*;[\s]*/'; 553 } 554 foreach( $lines as $line => $datarow ) { 555 $split = preg_split($s,$datarow); 556 $aCol1[] = floatval(trim($split[0])); 557 $aCol2[] = floatval(trim($split[1])); 558 } 559 560 return count($lines); 561 } 562 563 // Read data from one columns in a plain text file 564 static function From1Col($aFile, $aCol1) { 565 $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); 566 if( $lines === false ) { 567 return false; 568 } 569 foreach( $lines as $line => $datarow ) { 570 $aCol1[] = floatval(trim($datarow)); 571 } 572 573 return count($lines); 574 } 575 576 static function FromMatrix($aFile,$aSepChar=' ') { 577 $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); 578 if( $lines === false ) { 579 return false; 580 } 581 $mat = array(); 582 $reg = '/'.$aSepChar.'/'; 583 foreach( $lines as $line => $datarow ) { 584 $row = preg_split($reg,trim($datarow)); 585 foreach ($row as $key => $cell ) { 586 $row[$key] = floatval(trim($cell)); 587 } 588 $mat[] = $row; 589 } 590 return $mat; 591 } 592 593 525 594 } 526 595 596 define('__LR_EPSILON', 1.0e-8); 597 //============================================================================= 598 // Class LinearRegression 599 //============================================================================= 600 class LinearRegression { 601 private $ix=array(),$iy=array(); 602 private $ib=0, $ia=0; 603 private $icalculated=false; 604 public $iDet=0, $iCorr=0, $iStdErr=0; 605 606 public function __construct($aDataX,$aDataY) { 607 if( count($aDataX) !== count($aDataY) ) { 608 JpGraph::Raise('LinearRegression: X and Y data array must be of equal length.'); 609 } 610 $this->ix = $aDataX; 611 $this->iy = $aDataY; 612 } 613 614 public function Calc() { 615 616 $this->icalculated = true; 617 618 $n = count($this->ix); 619 $sx2 = 0 ; 620 $sy2 = 0 ; 621 $sxy = 0 ; 622 $sx = 0 ; 623 $sy = 0 ; 624 625 for( $i=0; $i < $n; ++$i ) { 626 $sx2 += $this->ix[$i] * $this->ix[$i]; 627 $sy2 += $this->iy[$i] * $this->iy[$i]; 628 $sxy += $this->ix[$i] * $this->iy[$i]; 629 $sx += $this->ix[$i]; 630 $sy += $this->iy[$i]; 631 } 632 633 if( $n*$sx2 - $sx*$sx > __LR_EPSILON ) { 634 $this->ib = ($n*$sxy - $sx*$sy) / ( $n*$sx2 - $sx*$sx ); 635 $this->ia = ( $sy - $this->ib*$sx ) / $n; 636 637 $sx = $this->ib * ( $sxy - $sx*$sy/$n ); 638 $sy2 = $sy2 - $sy*$sy/$n; 639 $sy = $sy2 - $sx; 640 641 $this->iDet = $sx / $sy2; 642 $this->iCorr = sqrt($this->iDet); 643 if( $n > 2 ) { 644 $this->iStdErr = sqrt( $sy / ($n-2) ); 645 } 646 else { 647 $this->iStdErr = NAN ; 648 } 649 } 650 else { 651 $this->ib = 0; 652 $this->ia = 0; 653 } 654 655 } 656 657 public function GetAB() { 658 if( $this->icalculated == false ) 659 $this->Calc(); 660 return array($this->ia, $this->ib); 661 } 662 663 public function GetStat() { 664 if( $this->icalculated == false ) 665 $this->Calc(); 666 return array($this->iStdErr, $this->iCorr, $this->iDet); 667 } 668 669 public function GetY($aMinX, $aMaxX, $aStep=1) { 670 if( $this->icalculated == false ) 671 $this->Calc(); 672 673 $yy = array(); 674 $i = 0; 675 for( $x=$aMinX; $x <= $aMaxX; $x += $aStep ) { 676 $xx[$i ] = $x; 677 $yy[$i++] = $this->ia + $this->ib * $x; 678 } 679 680 return array($xx,$yy); 681 } 682 683 } 684 527 685 ?>
Note:
See TracChangeset
for help on using the changeset viewer.