Package PyFoam :: Package Applications :: Module SamplePlot
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.SamplePlot

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/SamplePlot.py 8488 2013-11-03T14:38:32.775063Z bgschaid  $ 
  2  """ 
  3  Application class that implements pyFoamSamplePlot.py 
  4  """ 
  5   
  6  import sys,string 
  7  from os import path 
  8  from optparse import OptionGroup 
  9   
 10  from .PyFoamApplication import PyFoamApplication 
 11  from PyFoam.RunDictionary.SampleDirectory import SampleDirectory 
 12  from PyFoam.Basics.SpreadsheetData import WrongDataSize 
 13   
 14  from PyFoam.Error import error,warning 
 15   
 16  from .PlotHelpers import cleanFilename 
 17   
 18  from PyFoam.ThirdParty.six import print_ 
 19   
20 -class SamplePlot(PyFoamApplication):
21 - def __init__(self,args=None):
22 description="""\ 23 Reads data from the sample-dictionary and generates appropriate 24 gnuplot-commands. As an option the data can be written to a CSV-file. 25 """ 26 27 PyFoamApplication.__init__(self, 28 args=args, 29 description=description, 30 usage="%prog [options] <casedir>", 31 nr=1, 32 changeVersion=False, 33 interspersed=True)
34 35 modeChoices=["separate","timesInOne","fieldsInOne","linesInOne","complete"] 36
37 - def addOptions(self):
38 data=OptionGroup(self.parser, 39 "Data", 40 "Select the data to plot") 41 self.parser.add_option_group(data) 42 43 data.add_option("--line", 44 action="append", 45 default=None, 46 dest="line", 47 help="Thesample line from which data is plotted (can be used more than once)") 48 data.add_option("--field", 49 action="append", 50 default=None, 51 dest="field", 52 help="The fields that are plotted (can be used more than once). If none are specified all found fields are used") 53 data.add_option("--pattern-for-line", 54 action="store", 55 default=None, 56 dest="linePattern", 57 help="Usually the name of the line is automatically determined from the file name by taking the first part. If this regular expression is specified then it is used: the first group in the pattern will be the line name") 58 data.add_option("--default-value-names", 59 action="store", 60 default=None, 61 dest="valueNames", 62 help="Usually the names of the values automatically determined from the file. If they are specified (as a comma separated list of names) then these names are used and all the files MUST have these values") 63 data.add_option("--no-extension-needed", 64 action="store_false", 65 default=True, 66 dest="needsExtension", 67 help="The files do not have an extension") 68 data.add_option("--is-distribution", 69 action="store_true", 70 default=False, 71 dest="isDistribution", 72 help="The files in the directory are distributions. This sets the names of the lines and fields accordingly") 73 data.add_option("--postfix-for-field-names", 74 action="append", 75 default=[], 76 dest="fieldPostfix", 77 help="Possible postfix for field names of the form 'name_postfix'. Note that this should not be a possible field name") 78 data.add_option("--prefix-for-field-names", 79 action="append", 80 default=[], 81 dest="fieldPrefix", 82 help="Possible prefix for field names of the form 'prefix_name'. Note that this should not be a possible field name") 83 data.add_option("--directory-name", 84 action="store", 85 default="samples", 86 dest="dirName", 87 help="Alternate name for the directory with the samples (Default: %default)") 88 data.add_option("--preferred-component", 89 action="store", 90 type="int", 91 default=None, 92 dest="component", 93 help="The component that should be used for vectors. Otherwise the absolute value is used") 94 data.add_option("--reference-directory", 95 action="store", 96 default=None, 97 dest="reference", 98 help="A reference directory. If fitting sample data is found there it is plotted alongside the regular data") 99 data.add_option("--reference-case", 100 action="store", 101 default=None, 102 dest="referenceCase", 103 help="A reference case where a directory with the same name is looked for. Mutual exclusive with --reference-directory") 104 105 scale=OptionGroup(self.parser, 106 "Scale", 107 "Scale the data before comparing (not used during plotting)") 108 self.parser.add_option_group(scale) 109 scale.add_option("--scale-data", 110 action="store", 111 type="float", 112 default=1, 113 dest="scaleData", 114 help="Scale the data by this factor. Default: %default") 115 scale.add_option("--offset-data", 116 action="store", 117 type="float", 118 default=0, 119 dest="offsetData", 120 help="Offset the data by this factor. Default: %default") 121 scale.add_option("--scale-x-axis", 122 action="store", 123 type="float", 124 default=1, 125 dest="scaleXAxis", 126 help="Scale the x-axis by this factor. Default: %default") 127 scale.add_option("--offset-x-axis", 128 action="store", 129 type="float", 130 default=0, 131 dest="offsetXAxis", 132 help="Offset the x-axis by this factor. Default: %default") 133 134 scale.add_option("--scale-reference-data", 135 action="store", 136 type="float", 137 default=1, 138 dest="scaleReferenceData", 139 help="Scale the reference data by this factor. Default: %default") 140 scale.add_option("--offset-reference-data", 141 action="store", 142 type="float", 143 default=0, 144 dest="offsetReferenceData", 145 help="Offset the reference data by this factor. Default: %default") 146 scale.add_option("--scale-reference-x-axis", 147 action="store", 148 type="float", 149 default=1, 150 dest="scaleReferenceXAxis", 151 help="Scale the reference x-axis by this factor. Default: %default") 152 scale.add_option("--offset-reference-x-axis", 153 action="store", 154 type="float", 155 default=0, 156 dest="offsetReferenceXAxis", 157 help="Offset the reference x-axis by this factor. Default: %default") 158 159 time=OptionGroup(self.parser, 160 "Time", 161 "Select the times to plot") 162 self.parser.add_option_group(time) 163 164 time.add_option("--time", 165 action="append", 166 default=None, 167 dest="time", 168 help="The times that are plotted (can be used more than once). If none are specified all found times are used") 169 time.add_option("--min-time", 170 action="store", 171 type="float", 172 default=None, 173 dest="minTime", 174 help="The smallest time that should be used") 175 time.add_option("--max-time", 176 action="store", 177 type="float", 178 default=None, 179 dest="maxTime", 180 help="The biggest time that should be used") 181 time.add_option("--fuzzy-time", 182 action="store_true", 183 default=False, 184 dest="fuzzyTime", 185 help="Try to find the next timestep if the time doesn't match exactly") 186 time.add_option("--latest-time", 187 action="store_true", 188 default=False, 189 dest="latestTime", 190 help="Take the latest time from the data") 191 time.add_option("--reference-time", 192 action="store", 193 default=None, 194 dest="referenceTime", 195 help="Take this time from the reference data (instead of using the same time as the regular data)") 196 time.add_option("--tolerant-reference-time", 197 action="store_true", 198 default=False, 199 dest="tolerantReferenceTime", 200 help="Take the reference-time that is nearest to the selected time") 201 202 output=OptionGroup(self.parser, 203 "Appearance", 204 "How it should be plotted") 205 self.parser.add_option_group(output) 206 207 output.add_option("--mode", 208 type="choice", 209 default="separate", 210 dest="mode", 211 action="store", 212 choices=self.modeChoices, 213 help="What kind of plots are generated: a) separate for every time, line and field b) all times of a field in one plot c) all fields of a time in one plot d) all lines in one plot e) everything in one plot (Names: "+string.join(self.modeChoices,", ")+") Default: %default") 214 output.add_option("--unscaled", 215 action="store_false", 216 dest="scaled", 217 default=True, 218 help="Don't scale a value to the same range for all plots") 219 output.add_option("--scale-all", 220 action="store_true", 221 dest="scaleAll", 222 default=False, 223 help="Use the same scale for all fields (else use one scale for each field)") 224 output.add_option("--scale-domain", 225 action="store_true", 226 dest="scaleDomain", 227 default=False, 228 help="Automatically scale the x-domain to the same length for all plots") 229 output.add_option("--domain-minimum", 230 action="store", 231 type="float", 232 dest="domainMin", 233 default=None, 234 help="Use this value as the minimum for the x-domain for all plots") 235 output.add_option("--domain-maximum", 236 action="store", 237 type="float", 238 dest="domainMax", 239 default=None, 240 help="Use this value as the maximum for the x-domain for all plots") 241 output.add_option("--gnuplot-file", 242 action="store", 243 dest="gnuplotFile", 244 default=None, 245 help="Write the necessary gnuplot commands to this file. Else they are written to the standard output") 246 output.add_option("--picture-destination", 247 action="store", 248 dest="pictureDest", 249 default=None, 250 help="Directory the pictures should be stored to") 251 output.add_option("--name-prefix", 252 action="store", 253 dest="namePrefix", 254 default=None, 255 help="Prefix to the picture-name") 256 output.add_option("--csv-file", 257 action="store", 258 dest="csvFile", 259 default=None, 260 help="Write the data to a CSV-file instead of the gnuplot-commands") 261 output.add_option("--excel-file", 262 action="store", 263 dest="excelFile", 264 default=None, 265 help="Write the data to a Excel-file instead of the gnuplot-commands") 266 output.add_option("--pandas-data", 267 action="store_true", 268 dest="pandasData", 269 default=False, 270 help="Pass the raw data in pandas-format") 271 output.add_option("--numpy-data", 272 action="store_true", 273 dest="numpyData", 274 default=False, 275 help="Pass the raw data in numpy-format") 276 277 data.add_option("--info", 278 action="store_true", 279 dest="info", 280 default=False, 281 help="Print info about the sampled data and exit") 282 output.add_option("--style", 283 action="store", 284 default="lines", 285 dest="style", 286 help="Gnuplot-style for the data (Default: %default)") 287 output.add_option("--clean-filename", 288 action="store_true", 289 dest="cleanFilename", 290 default=False, 291 help="Clean filenames so that they can be used in HTML or Latex-documents") 292 output.add_option("--reference-prefix", 293 action="store", 294 dest="refprefix", 295 default="Reference", 296 help="Prefix that gets added to the reference lines. Default: %default") 297 output.add_option("--resample-reference", 298 action="store_true", 299 dest="resampleReference", 300 default=False, 301 help="Resample the reference value to the current x-axis (for CSV or Excel-output)") 302 output.add_option("--extend-data", 303 action="store_true", 304 dest="extendData", 305 default=False, 306 help="Extend the data range if it differs (for CSV or Excel-files)") 307 output.add_option("--silent", 308 action="store_true", 309 dest="silent", 310 default=False, 311 help="Don't write to screen (with the silent and the compare-options)") 312 313 numerics=OptionGroup(self.parser, 314 "Quantify", 315 "Metrics of the data and numerical comparisons") 316 self.parser.add_option_group(numerics) 317 numerics.add_option("--metrics", 318 action="store_true", 319 dest="metrics", 320 default=None, 321 help="Print the metrics of the data sets") 322 numerics.add_option("--compare", 323 action="store_true", 324 dest="compare", 325 default=None, 326 help="Compare all data sets that are also in the reference data") 327 numerics.add_option("--common-range-compare", 328 action="store_true", 329 dest="commonRange", 330 default=None, 331 help="When comparing two datasets only use the common time range") 332 numerics.add_option("--index-tolerant-compare", 333 action="store_true", 334 dest="indexTolerant", 335 default=None, 336 help="Compare two data sets even if they have different indizes") 337 numerics.add_option("--use-reference-for-comparison", 338 action="store_false", 339 dest="compareOnOriginal", 340 default=True, 341 help="Use the reference-data as the basis for the numerical comparison. Otherwise the original data will be used")
342
343 - def run(self):
344 if self.opts.isDistribution: 345 if self.opts.valueNames or self.opts.linePattern: 346 self.error("The option --is-distribution can not be used with --pattern-for-line or --default-value-names") 347 self.opts.valueNames="normalized,raw" 348 self.opts.linePattern=".+istribution_(.+)" 349 self.opts.needsExtension=False 350 351 # remove trailing slashif present 352 if self.opts.dirName[-1]==path.sep: 353 self.opts.dirName=self.opts.dirName[:-1] 354 355 usedDirName=self.opts.dirName.replace("/","_") 356 357 samples=SampleDirectory(self.parser.getArgs()[0], 358 dirName=self.opts.dirName, 359 postfixes=self.opts.fieldPostfix, 360 prefixes=self.opts.fieldPrefix, 361 valueNames=self.opts.valueNames.split(","), 362 linePattern=self.opts.linePattern, 363 needsExtension=self.opts.needsExtension) 364 reference=None 365 if self.opts.reference and self.opts.referenceCase: 366 self.error("Options --reference-directory and --reference-case are mutual exclusive") 367 if (self.opts.csvFile or self.opts.excelFile or self.opts.pandasData or self.opts.numpyData) and (self.opts.compare or self.opts.metrics): 368 self.error("Options --csv-file/--excel-file/--pandas-data/--numpy-data and --compare/--metrics are mutual exclusive") 369 370 if self.opts.reference: 371 reference=SampleDirectory(self.parser.getArgs()[0], 372 dirName=self.opts.reference, 373 postfixes=self.opts.fieldPostfix, 374 prefixes=self.opts.fieldPrefix) 375 elif self.opts.referenceCase: 376 reference=SampleDirectory(self.opts.referenceCase, 377 dirName=self.opts.dirName, 378 postfixes=self.opts.fieldPostfix, 379 prefixes=self.opts.fieldPrefix) 380 381 if reference: 382 if path.samefile(reference.dir,samples.dir): 383 self.error("Used sample directory",samples.dir, 384 "and reference directory",reference.dir, 385 "are the same") 386 387 lines=samples.lines() 388 times=samples.times 389 390 if self.opts.info: 391 if not self.opts.silent: 392 print_("Times : ",samples.times) 393 print_("Lines : ",samples.lines()) 394 print_("Fields: ",list(samples.values())) 395 396 self.setData({'times' : samples.times, 397 'lines' : samples.lines(), 398 'values' : list(samples.values())}) 399 400 if reference: 401 if not self.opts.silent: 402 print_("\nReference Data:") 403 print_("Times : ",reference.times) 404 print_("Lines : ",reference.lines()) 405 print_("Fields: ",list(reference.values())) 406 self.setData({'reference':{'times' : samples.times, 407 'lines' : samples.lines(), 408 'values' : list(samples.values())}}) 409 410 return 0 411 412 if self.opts.line==None: 413 # error("At least one line has to be specified. Found were",samples.lines()) 414 self.opts.line=lines 415 else: 416 for l in self.opts.line: 417 if l not in lines: 418 error("The line",l,"does not exist in",lines) 419 420 if self.opts.latestTime: 421 if self.opts.time: 422 self.opts.time.append(samples.times[-1]) 423 else: 424 self.opts.time=[samples.times[-1]] 425 426 if self.opts.maxTime or self.opts.minTime: 427 if self.opts.time: 428 error("Times",self.opts.time,"and range [",self.opts.minTime,",",self.opts.maxTime,"] set: contradiction") 429 self.opts.time=[] 430 if self.opts.maxTime==None: 431 self.opts.maxTime= 1e20 432 if self.opts.minTime==None: 433 self.opts.minTime=-1e20 434 435 for t in times: 436 if float(t)<=self.opts.maxTime and float(t)>=self.opts.minTime: 437 self.opts.time.append(t) 438 439 if len(self.opts.time)==0: 440 error("No times in range [",self.opts.minTime,",",self.opts.maxTime,"] found: ",times) 441 elif self.opts.time: 442 iTimes=self.opts.time 443 self.opts.time=[] 444 for t in iTimes: 445 if t in samples.times: 446 self.opts.time.append(t) 447 elif self.opts.fuzzyTime: 448 tf=float(t) 449 use=None 450 dist=1e20 451 for ts in samples.times: 452 if abs(tf-float(ts))<dist: 453 use=ts 454 dist=abs(tf-float(ts)) 455 if use and use not in self.opts.time: 456 self.opts.time.append(use) 457 else: 458 pass 459 # self.warning("Time",t,"not found in the sample-times. Use option --fuzzy") 460 if self.opts.tolerantReferenceTime: 461 if self.opts.referenceTime: 462 self.error("--tolerant-reference-time and --reference-time can't be used at the same time") 463 refTimes={} 464 for t in self.opts.time: 465 dist=1e20 466 for rt in reference.times: 467 if abs(float(t)-float(rt))<dist: 468 refTimes[t]=rt 469 dist=abs(float(t)-float(rt)) 470 471 plots=[] 472 oPlots=[] 473 rPlots=[] 474 475 if self.opts.mode=="separate": 476 if self.opts.time==None: 477 self.opts.time=samples.times 478 if self.opts.field==None: 479 self.opts.field=list(samples.values()) 480 if self.opts.line==None: 481 self.opts.line=samples.lines() 482 for t in self.opts.time: 483 for f in self.opts.field: 484 for l in self.opts.line: 485 plot=samples.getData(line=[l], 486 value=[f], 487 time=[t], 488 scale=(self.opts.scaleXAxis, 489 self.opts.scaleData), 490 offset=(self.opts.offsetXAxis, 491 self.opts.offsetData)) 492 oPlots.append(plot[:]) 493 if reference: 494 rT=[t] 495 if self.opts.referenceTime: 496 rT=[self.opts.referenceTime] 497 elif self.opts.tolerantReferenceTime: 498 rT=[refTimes[t]] 499 p=reference.getData(line=[l], 500 value=[f], 501 time=rT, 502 note=self.opts.refprefix+" ", 503 scale=(self.opts.scaleReferenceXAxis, 504 self.opts.scaleReferenceData), 505 offset=(self.opts.offsetReferenceXAxis, 506 self.opts.offsetReferenceData)) 507 rPlots.append(p) 508 plot+=p 509 plots.append(plot) 510 511 elif self.opts.mode=="timesInOne": 512 if self.opts.field==None: 513 self.opts.field=list(samples.values()) 514 if self.opts.line==None: 515 self.opts.line=samples.lines() 516 for f in self.opts.field: 517 for l in self.opts.line: 518 plot=samples.getData(line=[l], 519 value=[f], 520 time=self.opts.time) 521 oPlots.append(plot[:]) 522 523 if reference: 524 rT=self.opts.time 525 if self.opts.referenceTime: 526 rT=[self.opts.referenceTime] 527 elif self.opts.tolerantReferenceTime: 528 rT=[refTimes[t]] 529 p=reference.getData(line=[l], 530 value=[f], 531 time=rT, 532 note=self.opts.refprefix+" ") 533 rPlots.append(p) 534 plot+=p 535 536 plots.append(plot) 537 538 elif self.opts.mode=="fieldsInOne": 539 if self.opts.scaled and not self.opts.scaleAll: 540 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value") 541 self.opts.scaleAll=True 542 543 if self.opts.time==None: 544 self.opts.time=samples.times 545 if self.opts.line==None: 546 self.opts.line=samples.lines() 547 for t in self.opts.time: 548 for l in self.opts.line: 549 plot=samples.getData(line=[l], 550 value=self.opts.field, 551 time=[t]) 552 oPlots.append(plot[:]) 553 if reference: 554 rT=t 555 if self.opts.referenceTime: 556 rT=self.opts.referenceTime 557 elif self.opts.tolerantReferenceTime: 558 rT=refTimes[t] 559 p=reference.getData(line=[l], 560 value=self.opts.field, 561 time=[rT], 562 note=self.opts.refprefix+" ") 563 rPlots.append(p) 564 plot+=p 565 566 plots.append(plot) 567 568 elif self.opts.mode=="linesInOne": 569 if self.opts.field==None: 570 self.opts.field=list(samples.values()) 571 if self.opts.time==None: 572 self.opts.time=samples.times 573 for f in self.opts.field: 574 for t in self.opts.time: 575 plot=samples.getData(line=self.opts.line, 576 value=[f], 577 time=[t]) 578 oPlots.append(plot[:]) 579 580 if reference: 581 rT=t 582 if self.opts.referenceTime: 583 rT=self.opts.referenceTime 584 elif self.opts.tolerantReferenceTime: 585 rT=refTimes[t] 586 p=reference.getData(line=self.opts.line, 587 value=[f], 588 time=[rT], 589 note=self.opts.refprefix+" ") 590 rPlots.append(p) 591 plot+=p 592 593 plots.append(plot) 594 595 elif self.opts.mode=="complete": 596 if self.opts.scaled and not self.opts.scaleAll: 597 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value") 598 self.opts.scaleAll=True 599 600 plot=samples.getData(line=self.opts.line, 601 value=self.opts.field, 602 time=self.opts.time) 603 oPlots.append(plot[:]) 604 if reference: 605 rT=self.opts.time 606 if self.opts.referenceTime: 607 rT=[self.opts.referenceTime] 608 elif self.opts.tolerantReferenceTime: 609 rT=[refTimes[t]] 610 p=reference.getData(line=self.opts.line, 611 value=self.opts.field, 612 time=rT, 613 note=self.opts.refprefix+" ") 614 plot+=p 615 rPlots.append(p) 616 617 plots.append(plot) 618 619 xMin,xMax=None,None 620 if self.opts.scaleDomain: 621 if self.opts.domainMin or self.opts.domainMax: 622 self.error("--scale-domain used. Can't use --domain-minimum or --domain-maximum") 623 xMin,xMax=1e40,-1e40 624 for p in plots: 625 for d in p: 626 mi,mx=d.domain() 627 xMin=min(xMin,mi) 628 xMax=max(xMax,mx) 629 else: 630 xMin,xMax=self.opts.domainMin,self.opts.domainMax 631 632 if self.opts.scaled: 633 if self.opts.scaleAll: 634 vRange=None 635 else: 636 vRanges={} 637 638 for p in plots: 639 for d in p: 640 mi,ma=d.range(component=self.opts.component) 641 nm=d.name 642 if not self.opts.scaleAll: 643 if nm in vRanges: 644 vRange=vRanges[nm] 645 else: 646 vRange=None 647 648 if vRange==None: 649 vRange=mi,ma 650 else: 651 vRange=min(vRange[0],mi),max(vRange[1],ma) 652 if not self.opts.scaleAll: 653 vRanges[nm]=vRange 654 655 result="set term png\n" 656 657 plots=[p for p in plots if len(p)>0] 658 659 if len(plots)<1: 660 self.error("No plots produced. Nothing done") 661 662 for p in plots: 663 if len(p)<1: 664 continue 665 666 name="" 667 668 if self.opts.namePrefix: 669 name+=self.opts.namePrefix+"_" 670 name+=usedDirName 671 title=None 672 tIndex=times.index(p[0].time()) 673 674 # name+="_"+string.join(self.opts.line,"_") 675 676 if self.opts.mode=="separate": 677 name+="_%s" % (p[0].line()) 678 name+="_%s_%04d" % (p[0].name,tIndex) 679 title="%s at t=%f on %s" % (p[0].name,float(p[0].time()),p[0].line()) 680 elif self.opts.mode=="timesInOne": 681 name+="_%s" % (p[0].line()) 682 if self.opts.time!=None: 683 name+="_"+"_".join(["t="+t for t in self.opts.time]) 684 name+="_%s" % p[0].name 685 title="%s on %s" % (p[0].name,p[0].line()) 686 elif self.opts.mode=="fieldsInOne": 687 name+="_%s" % (p[0].line()) 688 if self.opts.field!=None: 689 name+="_"+string.join(self.opts.field,"_") 690 if self.opts.time!=None: 691 name+="_"+"_".join(["t="+t for t in self.opts.time]) 692 name+="_%04d" % tIndex 693 title="t=%f on %s" % (float(p[0].time()),p[0].line()) 694 elif self.opts.mode=="linesInOne": 695 name+="_%s" % (p[0].name) 696 if self.opts.line!=None: 697 name+="_"+string.join(self.opts.line,"_") 698 name+="_t=%f" % float(p[0].time()) 699 title="%s at t=%f" % (p[0].name,float(p[0].time())) 700 elif self.opts.mode=="complete": 701 pass 702 703 name+=".png" 704 if self.opts.pictureDest: 705 name=path.join(self.opts.pictureDest,name) 706 707 if self.opts.cleanFilename: 708 name=cleanFilename(name) 709 710 result+='set output "%s"\n' % name 711 if title!=None: 712 result+='set title "%s"\n' % title.replace("_","\\_") 713 714 result+="plot " 715 if self.opts.scaled: 716 if not self.opts.scaleAll: 717 vRange=vRanges[p[0].name] 718 719 # only scale if extremas are sufficiently different 720 if abs(vRange[0]-vRange[1])>1e-5*max(abs(vRange[0]),abs(vRange[1])) and max(abs(vRange[0]),abs(vRange[1]))>1e-10: 721 yRange="[%g:%g] " % vRange 722 else: 723 yRange="[]" 724 else: 725 yRange="[]" 726 727 if xMin or xMax: 728 xRange="[" 729 if xMin: 730 xRange+=str(xMin) 731 xRange+=":" 732 if xMax: 733 xRange+=str(xMax) 734 xRange+="]" 735 else: 736 xRange="[]" 737 738 if self.opts.scaled or xMin or xMax: 739 result+=xRange+yRange 740 741 first=True 742 743 for d in p: 744 if first: 745 first=False 746 else: 747 result+=", " 748 749 colSpec=d.index+1 750 if d.isVector(): 751 if self.opts.component!=None: 752 colSpec=d.index+1+self.opts.component 753 else: 754 colSpec="(sqrt($%d**2+$%d**2+$%d**2))" % (d.index+1,d.index+2,d.index+3) 755 756 # result+='"%s" using 1:%s ' % (d.file,colSpec) 757 758 def makeCol(spec,sc,off): 759 if type(spec)==str: 760 pre="" 761 else: 762 pre="$" 763 spec=str(spec) 764 if sc==1: 765 if off==0: 766 return spec 767 else: 768 return "(%s%s+%f)" % (pre,spec,off) 769 else: 770 if off==0: 771 return "(%s%s*%f)" % (pre,spec,sc) 772 else: 773 return "(%s%s*%f+%f)" % (pre,spec,sc,off)
774 775 result+='"%s" using %s:%s ' % (d.file, 776 makeCol(1,d.scale[0],d.offset[0]), 777 makeCol(colSpec,d.scale[1],d.offset[1])) 778 779 title=d.note 780 if self.opts.mode=="separate": 781 title+="" 782 elif self.opts.mode=="timesInOne": 783 title+="t=%f" % float(d.time()) 784 elif self.opts.mode=="fieldsInOne": 785 title+="%s" % d.name 786 elif self.opts.mode=="linesInOne": 787 title+="t=%f" % float(d.time()) 788 elif self.opts.mode=="complete": 789 title+="%s at t=%f" % (d.name,float(d.time())) 790 791 if len(self.opts.line)>1: 792 title+=" on %s" % d.line() 793 794 if title=="": 795 result+="notitle " 796 else: 797 result+='title "%s" ' % title.replace("_","\\_") 798 799 result+="with %s " % self.opts.style 800 801 result+="\n" 802 803 if self.opts.csvFile or self.opts.excelFile or self.opts.pandasData or self.opts.numpyData: 804 tmp=sum(plots,[]) 805 c=tmp[0]() 806 for p in tmp[1:]: 807 try: 808 c+=p() 809 except WrongDataSize: 810 if self.opts.resampleReference: 811 sp=p() 812 for n in sp.names()[1:]: 813 data=c.resample(sp, 814 n, 815 extendData=self.opts.extendData) 816 try: 817 c.append(n,data) 818 except ValueError: 819 c.append(self.opts.refprefix+" "+n,data) 820 else: 821 self.warning("Try the --resample-option") 822 raise 823 824 if self.opts.csvFile: 825 c.writeCSV(self.opts.csvFile) 826 if self.opts.excelFile: 827 c.getData().to_excel(self.opts.excelFile) 828 if self.opts.pandasData: 829 self.setData({"series":c.getSeries(), 830 "dataFrame":c.getData()}) 831 if self.opts.numpyData: 832 self.setData({"data":c.data.copy()}) 833 834 elif self.opts.compare or self.opts.metrics: 835 statData={} 836 if self.opts.compare: 837 statData["compare"]={} 838 if self.opts.metrics: 839 statData["metrics"]={} 840 for p in self.opts.line: 841 if self.opts.compare: 842 statData["compare"][p]={} 843 if self.opts.metrics: 844 statData["metrics"][p]={} 845 846 oPlots=[item for sublist in oPlots for item in sublist] 847 rPlots=[item for sublist in rPlots for item in sublist] 848 if len(rPlots)!=len(oPlots) and self.opts.compare: 849 self.error("Number of original data sets",len(oPlots), 850 "is not equal to the reference data sets", 851 len(rPlots)) 852 if len(rPlots)==0 and self.opts.metrics: 853 rPlots=[None]*len(oPlots) 854 855 for o,r in zip(oPlots,rPlots): 856 data=o(scaleData=self.opts.scaleData, 857 offsetData=self.opts.offsetData, 858 scaleX=self.opts.scaleXAxis, 859 offsetX=self.opts.offsetXAxis) 860 if self.opts.compare: 861 if o.name!=r.name or (o.index!=r.index and not self.opts.indexTolerant): 862 self.error("Data from original",o.name,o.index, 863 "and reference",r.name,r.index, 864 "do not match. Try --index-tolerant-compare if you're sure that the data is right") 865 ref=r(scaleData=self.opts.scaleReferenceData, 866 offsetData=self.opts.offsetReferenceData, 867 scaleX=self.opts.scaleReferenceXAxis, 868 offsetX=self.opts.offsetReferenceXAxis) 869 else: 870 ref=None 871 for i,n in enumerate(data.names()): 872 if i==0: 873 continue 874 indexName=o.name 875 if n.split(" ")[-1]!=indexName: 876 indexName=n.split(" ")[-1] 877 878 if self.opts.metrics: 879 if not self.opts.silent: 880 print_("Metrics for",indexName,"(Path:",o.file,")") 881 result=data.metrics(data.names()[i], 882 minTime=self.opts.minTime, 883 maxTime=self.opts.maxTime) 884 statData["metrics"][o.line()][indexName]=result 885 if not self.opts.silent: 886 print_(" Min :",result["min"]) 887 print_(" Max :",result["max"]) 888 print_(" Average :",result["average"]) 889 print_(" Weighted average :",result["wAverage"]) 890 if not self.opts.compare: 891 print_("Data size:",data.size()) 892 print_(" Time Range :",result["tMin"],result["tMax"]) 893 if self.opts.compare: 894 oname=data.names()[i] 895 if self.opts.referenceTime or self.opts.tolerantReferenceTime: 896 oname=ref.names()[i] 897 if not self.opts.silent: 898 print_("Comparing",indexName,"with name",oname,"(Path:",r.file,")",end="") 899 if self.opts.compareOnOriginal: 900 if not self.opts.silent: 901 print_("on original data points") 902 result=data.compare(ref, 903 data.names()[i], 904 otherName=oname,common=self.opts.commonRange, 905 minTime=self.opts.minTime, 906 maxTime=self.opts.maxTime) 907 else: 908 if not self.opts.silent: 909 print_("on reference data points") 910 result=ref.compare(data, 911 oname, 912 otherName=data.names()[i], 913 common=self.opts.commonRange, 914 minTime=self.opts.minTime, 915 maxTime=self.opts.maxTime) 916 statData["compare"][o.line()][indexName]=result 917 if not self.opts.silent: 918 print_(" Max difference :",result["max"],"(at",result["maxPos"],")") 919 print_(" Average difference :",result["average"]) 920 print_(" Weighted average :",result["wAverage"]) 921 print_("Data size:",data.size(),"Reference:",ref.size()) 922 if not self.opts.metrics: 923 print_(" Time Range :",result["tMin"],result["tMax"]) 924 if not self.opts.silent: 925 print_() 926 927 self.setData(statData) 928 else: 929 dest=sys.stdout 930 if self.opts.gnuplotFile: 931 dest=open(self.opts.gnuplotFile,"w") 932 933 dest.write(result)
934 935 # Should work with Python3 and Python2 936