- Timestamp:
- Apr 14, 2019, 2:31:40 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/client/modules/Elezioni/grafici/jpgraph_utils.inc.php
r265 r267 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 1777 2009-08-23 17:34:36Z ljp $7 8 // Copyright (c) Asial Corporation. 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 1091 2009-01-18 22:57:40Z ljp $ 7 // 8 // Copyright (c) Aditus Consulting. 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 __construct($aFunc,$aXFunc='') {21 22 23 } 24 19 20 function FuncGenerator($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); 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 ''; 45 120 } 46 121 } … … 76 151 77 152 static function UseWeekFormat($aFlg) { 78 153 self::$iUseWeeks = $aFlg; 79 154 } 80 155 81 156 static function doYearly($aType,$aMinor=false) { 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 105 106 107 108 $y=self::$startyear; 109 110 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 111 for($k=0; $k < 1; ++$k ) { 112 113 114 115 116 117 118 119 120 121 $y=self::$startyear; 122 123 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 124 for($k=0; $k < 4; ++$k ) { 125 126 127 128 129 130 131 132 133 157 $i=0; $j=0; 158 $m = self::$startmonth; 159 $y = self::$startyear; 160 161 if( self::$startday == 1 ) { 162 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 163 } 164 ++$m; 165 166 167 switch( $aType ) { 168 case DSUTILS_YEAR1: 169 for($y=self::$startyear; $y <= self::$endyear; ++$y ) { 170 if( $aMinor ) { 171 while( $m <= 12 ) { 172 if( !($y == self::$endyear && $m > self::$endmonth) ) { 173 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 174 } 175 ++$m; 176 } 177 $m=1; 178 } 179 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 180 } 181 break; 182 case DSUTILS_YEAR2: 183 $y=self::$startyear; 184 while( $y <= self::$endyear ) { 185 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 186 for($k=0; $k < 1; ++$k ) { 187 ++$y; 188 if( $aMinor ) { 189 self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); 190 } 191 } 192 ++$y; 193 } 194 break; 195 case DSUTILS_YEAR5: 196 $y=self::$startyear; 197 while( $y <= self::$endyear ) { 198 self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); 199 for($k=0; $k < 4; ++$k ) { 200 ++$y; 201 if( $aMinor ) { 202 self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); 203 } 204 } 205 ++$y; 206 } 207 break; 208 } 134 209 } 135 210 136 211 static function doDaily($aType,$aMinor=false) { 137 138 139 140 141 142 143 144 145 146 $t = mktime(0,0,0,$m,$d,$y); 147 148 149 150 151 152 153 154 self::$minTickPositions[$j++] = strtotime('+12 hours',$t); 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 212 $m = self::$startmonth; 213 $y = self::$startyear; 214 $d = self::$startday; 215 $h = self::$starthour; 216 $i=0;$j=0; 217 218 if( $h == 0 ) { 219 self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); 220 } 221 $t = mktime(0,0,0,$m,$d,$y); 222 223 switch($aType) { 224 case DSUTILS_DAY1: 225 while( $t <= self::$iMax ) { 226 $t = strtotime('+1 day',$t); 227 self::$tickPositions[$i++] = $t; 228 if( $aMinor ) { 229 self::$minTickPositions[$j++] = strtotime('+12 hours',$t); 230 } 231 } 232 break; 233 case DSUTILS_DAY2: 234 while( $t <= self::$iMax ) { 235 $t = strtotime('+1 day',$t); 236 if( $aMinor ) { 237 self::$minTickPositions[$j++] = $t; 238 } 239 $t = strtotime('+1 day',$t); 240 self::$tickPositions[$i++] = $t; 241 } 242 break; 243 case DSUTILS_DAY4: 244 while( $t <= self::$iMax ) { 245 for($k=0; $k < 3; ++$k ) { 246 $t = strtotime('+1 day',$t); 247 if( $aMinor ) { 248 self::$minTickPositions[$j++] = $t; 249 } 250 } 251 $t = strtotime('+1 day',$t); 252 self::$tickPositions[$i++] = $t; 253 } 254 break; 255 } 181 256 } 182 257 183 258 static function doWeekly($aType,$aMinor=false) { 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 259 $hpd = 3600*24; 260 $hpw = 3600*24*7; 261 // Find out week number of min date 262 $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); 263 $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; 264 $daynumber = date('w',self::$iMin); 265 if( $daynumber == 0 ) $daynumber = 7; 266 $m = self::$startmonth; 267 $y = self::$startyear; 268 $d = self::$startday; 269 $i=0;$j=0; 270 // The assumption is that the weeks start on Monday. If the first day 271 // is later in the week then the first week tick has to be on the following 272 // week. 273 if( $daynumber == 1 ) { 274 self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); 275 $t = mktime(0,0,0,$m,$d,$y) + $hpw; 276 } 277 else { 278 $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber); 279 } 280 281 switch($aType) { 282 case DSUTILS_WEEK1: 283 $cnt=0; 284 break; 285 case DSUTILS_WEEK2: 286 $cnt=1; 287 break; 288 case DSUTILS_WEEK4: 289 $cnt=3; 290 break; 291 } 292 while( $t <= self::$iMax ) { 293 self::$tickPositions[$i++] = $t; 294 for($k=0; $k < $cnt; ++$k ) { 295 $t += $hpw; 296 if( $aMinor ) { 297 self::$minTickPositions[$j++] = $t; 298 } 299 } 300 $t += $hpw; 301 } 227 302 } 228 303 229 304 static function doMonthly($aType,$aMinor=false) { 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 256 case DSUTILS_MONTH1: 257 258 259 260 if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) 261 262 263 264 // Major at month 265 266 267 268 269 case DSUTILS_MONTH2: 270 271 272 273 274 275 // Major at every second month 276 277 278 279 280 281 case DSUTILS_MONTH3: 282 283 284 285 286 // Major at every third month 287 288 289 290 291 292 case DSUTILS_MONTH6: 293 294 295 296 297 // Major at every third month 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 } 316 317 305 $monthcount=0; 306 $m = self::$startmonth; 307 $y = self::$startyear; 308 $i=0; $j=0; 309 310 // Skip the first month label if it is before the startdate 311 if( self::$startday == 1 ) { 312 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 313 $monthcount=1; 314 } 315 if( $aType == 1 ) { 316 if( self::$startday < 15 ) { 317 self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); 318 } 319 } 320 ++$m; 321 322 // Loop through all the years included in the scale 323 for($y=self::$startyear; $y <= self::$endyear; ++$y ) { 324 // Loop through all the months. There are three cases to consider: 325 // 1. We are in the first year and must start with the startmonth 326 // 2. We are in the end year and we must stop at last month of the scale 327 // 3. A year in between where we run through all the 12 months 328 $stopmonth = $y == self::$endyear ? self::$endmonth : 12; 329 while( $m <= $stopmonth ) { 330 switch( $aType ) { 331 case DSUTILS_MONTH1: 332 // Set minor tick at the middle of the month 333 if( $aMinor ) { 334 if( $m <= $stopmonth ) { 335 if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) 336 self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); 337 } 338 } 339 // Major at month 340 // Get timestamp of first hour of first day in each month 341 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 342 343 break; 344 case DSUTILS_MONTH2: 345 if( $aMinor ) { 346 // Set minor tick at start of each month 347 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 348 } 349 350 // Major at every second month 351 // Get timestamp of first hour of first day in each month 352 if( $monthcount % 2 == 0 ) { 353 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 354 } 355 break; 356 case DSUTILS_MONTH3: 357 if( $aMinor ) { 358 // Set minor tick at start of each month 359 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 360 } 361 // Major at every third month 362 // Get timestamp of first hour of first day in each month 363 if( $monthcount % 3 == 0 ) { 364 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 365 } 366 break; 367 case DSUTILS_MONTH6: 368 if( $aMinor ) { 369 // Set minor tick at start of each month 370 self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); 371 } 372 // Major at every third month 373 // Get timestamp of first hour of first day in each month 374 if( $monthcount % 6 == 0 ) { 375 self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); 376 } 377 break; 378 } 379 ++$m; 380 ++$monthcount; 381 } 382 $m=1; 383 } 384 385 // For the case where all dates are within the same month 386 // we want to make sure we have at least two ticks on the scale 387 // since the scale want work properly otherwise 388 if(self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType==1 ) { 389 self::$tickPositions[$i++] = mktime(0 ,0 ,0, self::$startmonth + 1, 1, self::$startyear); 390 } 391 392 return array(self::$tickPositions,self::$minTickPositions); 318 393 } 319 394 320 395 static function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) { 321 322 396 $n = count($aData); 397 return self::GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints); 323 398 } 324 399 325 400 static function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) { 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 } 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 } 362 441 } 363 442 364 443 static function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) { 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 } 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 402 482 } 403 483 … … 406 486 //============================================================================= 407 487 Class ReadFileData { 488 408 489 //---------------------------------------------------------------------------- 409 490 // Desciption: 410 // Read numeric data from a file. 411 // Each value should be separated by either a new line or by a specified 491 // Read numeric data from a file. 492 // Each value should be separated by either a new line or by a specified 412 493 // separator character (default is ','). 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 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 415 496 // file will be discarded. 416 497 // 417 // Returns: 498 // Returns: 418 499 // The number of data values read on success, FALSE on failure 419 500 //---------------------------------------------------------------------------- 420 501 static function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { 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 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 } 594 525 } 595 526 596 define('__LR_EPSILON', 1.0e-8);597 //=============================================================================598 // Class LinearRegression599 //=============================================================================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 685 527 ?>
Note:
See TracChangeset
for help on using the changeset viewer.