UltraScan III
us_distrib_plot.cpp
Go to the documentation of this file.
1 
3 #include "us_distrib_plot.h"
4 #include "us_settings.h"
5 #include "us_gui_settings.h"
6 #include "us_gui_util.h"
7 #include "us_math2.h"
8 
9 #include <qwt_legend.h>
10 
11 US_DistribPlot::US_DistribPlot( QVector< double >& divfracs,
12  QVector< double >& divsedcs, const double tconc )
13  : US_WidgetsDialog( 0, 0 ), bfracs( divfracs ), dsedcs( divsedcs )
14 {
15 
16  setWindowTitle( tr( "van Holde - Weischet Distribution Plot" ) );
17  setPalette( US_GuiSettings::frameColor() );
18 
19  QGridLayout* main = new QGridLayout( this );
20  main->setSpacing ( 2 );
21  main->setContentsMargins( 2, 2, 2, 2 );
22 
23  tot_conc = tconc;
24  plotType = DISTR;
25  plotTypeH = COMBO;
26  divsCount = bfracs.size();
27  nSensit = 20;
28  nSmooth = 100;
30 DbgLv(1) << "DisPl: divsCount" << divsCount;
31 DbgLv(1) << "DisPl: isedsSize " << dsedcs.size() << divsedcs.size();
32 DbgLv(1) << "DisPl: fra0 fran" << bfracs[0] << bfracs[divsCount-1];
33 DbgLv(1) << "DisPl: sed0 sedn" << dsedcs[0] << dsedcs[divsCount-1];
34 DbgLv(1) << "DisPl: sed1 sed-" << dsedcs[1] << dsedcs[divsCount-2];
35 DbgLv(1) << "DisPl: sed2 sed-" << dsedcs[2] << dsedcs[divsCount-3];
36 //DbgLv(1) << "DisPl: ised0 isedn" << divsedcs[0] << divsedcs[divsCount-1];
37 
38  int row = 0;
39 
40  // Plot Rows
41  QBoxLayout* plot = new US_Plot( data_plot,
42  tr( "Sedimentation Coefficient Distribution" ),
43  tr( "Sedimentation Coefficient" ),
44  tr( "Boundary Fraction" ) );
45 
46  data_plot->setCanvasBackground( Qt::black );
47  data_plot->setMinimumSize( 600, 500 );
48  data_plot->setAxisScale( QwtPlot::yLeft, 0.0, 100.0, 20.0 );
49  //data_plot->setAxisScale( QwtPlot::xBottom, 0.0, 6.9, 1.0 );
50  data_plot->setAxisAutoScale( QwtPlot::xBottom );
51 
52  QwtPlotGrid* grid = us_grid( data_plot );
53  grid->enableXMin( true );
54  grid->enableYMin( true );
55  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
56  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
57  US_PlotPicker* pick = new US_PlotPicker( data_plot );
58  pick->setTrackerPen( QColor( Qt::white ) );
59 
60  main->addLayout( plot, row, 0, 15, 4 );
61  row += 15;
62 
63  // Control Row 1
64  pb_plot_type = us_pushbutton( tr( "Histogram" ) );
65  pb_help = us_pushbutton( tr( "Help" ) );
66  pb_close = us_pushbutton( tr( "Close" ) );
67  main->addWidget( pb_plot_type, row, 0, 1, 1 );
68  main->addWidget( pb_help, row, 1, 1, 1 );
69  main->addWidget( pb_close, row++, 2, 1, 1 );
70 
71  // Control Row 2
72  pb_histogram = us_pushbutton( tr( "Hide Histogram" ) );
73  lb_sensitivity = us_label( tr( "Sensitivity:" ) );
74  ct_sensitivity = us_counter( 2, 10, 100, 1 );
75  pb_histogram-> setEnabled( false );
76  ct_sensitivity->setEnabled( false );
77  ct_sensitivity->setStep( 1.0 );
78  ct_sensitivity->setValue( nSensit );
79  main->addWidget( pb_histogram, row, 0, 1, 1 );
80  main->addWidget( lb_sensitivity, row, 1, 1, 1 );
81  main->addWidget( ct_sensitivity, row++, 2, 1, 1, Qt::AlignLeft );
82 
83  // Control Row 3
84  pb_envelope = us_pushbutton( tr( "Hide Envelope" ) );
85  lb_smoothing = us_label( tr( "Smoothing:" ) );
86  ct_smoothing = us_counter( 2, 10, 100, 1 );
87  pb_envelope-> setEnabled( false );
88  ct_smoothing->setEnabled( false );
89  ct_smoothing->setStep( 1.0 );
90  ct_smoothing->setValue( nSmooth );
91  main->addWidget( pb_envelope, row, 0, 1, 1 );
92  main->addWidget( lb_smoothing, row, 1, 1, 1 );
93  main->addWidget( ct_smoothing, row++, 2, 1, 1, Qt::AlignLeft );
94 
95  show_plot();
96 
97  connect( pb_plot_type, SIGNAL( clicked() ),
98  this, SLOT ( type_plot() ) );
99  connect( pb_help, SIGNAL( clicked() ),
100  this, SLOT ( help() ) );
101  connect( pb_close, SIGNAL( clicked() ),
102  this, SLOT ( save_and_close() ) );
103  connect( pb_histogram, SIGNAL( clicked() ),
104  this, SLOT ( hide_histo() ) );
105  connect( pb_envelope, SIGNAL( clicked() ),
106  this, SLOT ( hide_envel() ) );
107  connect( ct_sensitivity, SIGNAL( valueChanged( double ) ),
108  this, SLOT ( change_sensit( double ) ) );
109  connect( ct_smoothing, SIGNAL( valueChanged( double ) ),
110  this, SLOT ( change_smooth( double ) ) );
111 }
112 
113 // Generate distribution,histogram plots and save the SVG files
114 void US_DistribPlot::save_plots( QString& plot1File, QString& plot2File )
115 {
116  // Set up, generate distribution plot and save it to a file
117  data_plot->detachItems();
118  QwtPlotGrid* grid = us_grid( data_plot );
119  grid->enableXMin( true );
120  grid->enableYMin( true );
121  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
122  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
123  plotType = DISTR;
124 
125  plot_distrib();
126 
127  US_GuiUtil::save_plot( plot1File, data_plot );
128 
129  // Set up, generate combined histogram plot and save it to a file
130  data_plot->detachItems();
131  grid = us_grid( data_plot );
132  grid->enableXMin( true );
133  grid->enableYMin( true );
134  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
135  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
136  plotType = COMBO;
137 
138  plot_combined();
139 
140  US_GuiUtil::save_plot( plot2File, data_plot );
141 
142  QString runID = plot1File.section( "/", -2, -2 );
143 
144  if ( runID == "tmp" ) return;
145 
146  // Also save the envelope data with present parameters
147  QString dat2File = US_Settings::resultDir() + "/" + runID + "/"
148  + plot1File.section( "/", -1, -1 ).section( ".", 0, 1 )
149  + ".s-c-envelope.csv";
150 
151  save_data_file( dat2File );
152 }
153 
154 // clear plot and execute appropriate new plot
156 {
157 
158  data_plot->detachItems();
159 
160  QwtPlotGrid* grid = us_grid( data_plot );
161  grid->enableXMin( true );
162  grid->enableYMin( true );
163  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
164  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
165 
166 
167  if ( plotType == DISTR )
168  {
169  data_plot->setTitle( tr( "G(s) Distribution" ) );
170  plot_distrib();
171  }
172 
173  else if ( plotType == COMBO )
174  {
175  data_plot->setTitle( tr( "g(s) Distribution" ) );
176  plot_combined();
177  }
178 
179  else if ( plotType == HISTO || plotType == NONE )
180  {
181  data_plot->setTitle( tr( "g(s) Distribution" ) );
182  plot_histogram();
183  }
184 
185  else if ( plotType == ENVEL )
186  {
187  data_plot->setTitle( tr( "g(s) Distribution" ) );
188  plot_envelope();
189  }
190 
191 }
192 
193 // change type of plot to distribution or histogram and replot
195 {
196  if ( plotType == DISTR )
197  { // change to histogram plot
199  pb_plot_type->setText( tr( "Distribution" ) );
200  pb_histogram ->setEnabled( true );
201  pb_envelope ->setEnabled( true );
202  ct_sensitivity->setEnabled( true );
203  ct_smoothing ->setEnabled( true );
204  }
205 
206  else
207  { // change to distribution plot
208  plotType = DISTR;
209  pb_plot_type->setText( tr( "Histogram" ) );
210  pb_histogram ->setEnabled( false );
211  pb_envelope ->setEnabled( false );
212  ct_sensitivity->setEnabled( false );
213  ct_smoothing ->setEnabled( false );
214  }
215 
216  show_plot();
217 }
218 
219 // flip-flop between hide/show histogram and replot
221 {
222  bool isHis = ( plotType == HISTO || plotType == COMBO );
223  bool isEnv = ( plotType == ENVEL || plotType == COMBO );
224 
225  if ( isHis )
226  { // turn off histogram
227  plotType = isEnv ? ENVEL : NONE;
228  pb_histogram->setText( tr( "Show Histogram" ) );
229  }
230 
231  else
232  { // turn on histogram
233  plotType = isEnv ? COMBO : HISTO;
234  pb_histogram->setText( tr( "Hide Histogram" ) );
235  }
236 
238 
239  show_plot();
240 }
241 
242 // flip-flop between hide/show envelope and replot
244 {
245  bool isHis = ( plotType == HISTO || plotType == COMBO );
246  bool isEnv = ( plotType == ENVEL || plotType == COMBO );
247 
248  if ( isEnv )
249  { // turn off envelope
250  plotType = isHis ? HISTO : NONE;
251  pb_envelope->setText( tr( "Show Envelope" ) );
252  }
253 
254  else
255  { // turn on envelope
256  plotType = isHis ? COMBO : ENVEL;
257  pb_envelope->setText( tr( "Hide Envelope" ) );
258  }
259 
261 
262  show_plot();
263 }
264 
265 // get changed sensitivity value and replot
266 void US_DistribPlot::change_sensit( double value )
267 {
268  nSensit = (int)value;
269 
270  show_plot();
271 }
272 
273 // get changed smoothing value and replot
274 void US_DistribPlot::change_smooth( double value )
275 {
276  nSmooth = (int)value;
277 
278  show_plot();
279 }
280 
281 // plot distribution points
283 {
284  // Set up the axes
285  data_plot->setAxisTitle( QwtPlot::yLeft,
286  tr( "Boundary Fraction" ) );
287  data_plot->setAxisTitle( QwtPlot::xBottom,
288  tr( "Sedimentation Coefficient" ) );
289  data_plot->setAxisScale( QwtPlot::yLeft, 0.0, 100.0, 20.0 );
290 
291  // create the x,y arrays of sedcoeffs,boundfracs
292 
293  double* xx = dsedcs.data();
294  double* yy = bfracs.data();
295  double maxx = 0.0;
296  double minx = 100.0;
297 // double xinc = 1.0;
298  double rngx = 100.0;
299 
300  for ( int jj = 0; jj < divsCount; jj++ )
301  {
302  maxx = max( maxx, xx[ jj ] );
303  minx = min( minx, xx[ jj ] );
304  }
305 
306  rngx = maxx - minx;
307  minx = minx - rngx * 0.1;
308  maxx = maxx + rngx * 0.1;
309 // xinc = ( rngx < 15.0 ) ? xinc : ( xinc * 5.0 );
310 // xinc = ( rngx > 1.0 ) ? xinc : ( xinc * 0.2 );
311 // data_plot->setAxisScale( QwtPlot::xBottom, minx, maxx, xinc );
312  data_plot->setAxisAutoScale( QwtPlot::xBottom );
313 
314  // first draw the yellow line through points
315  dcurve = us_curve( data_plot, tr( "Distrib Line" ) );
316  dcurve->setPen( QPen( QBrush( Qt::yellow ), 1.0 ) );
317  dcurve->setData( xx, yy, divsCount );
318 
319  // then draw the symbols at each point
320  dcurve = us_curve( data_plot, tr( "Distrib Points" ) );
321  QwtSymbol sym;
322  sym.setStyle( QwtSymbol::Ellipse );
323  sym.setPen ( QPen( Qt::blue ) );
324  sym.setBrush( QBrush( Qt::white ) );
325  sym.setSize ( 8 );
326  dcurve->setStyle( QwtPlotCurve::NoCurve );
327  dcurve->setSymbol( sym );
328  dcurve->setData ( xx, yy, divsCount );
329 
330  data_plot->replot();
331 }
332 
333 // plot histogram
335 {
336  QVector< double > xvec;
337  QVector< double > yvec;
338  double minx = dsedcs[ 0 ];
339  double maxx = minx;;
340 // double xinc = 1.0;
341  double xval;
342  double rngx;
343  int npoints;
344 
345  // Set up the axes
346  data_plot->setAxisTitle( QwtPlot::yLeft,
347  tr( "Relative Concentration" ) );
348  data_plot->setAxisTitle( QwtPlot::xBottom,
349  tr( "Sedimentation Coefficient" ) );
350 
351  // Get scale from envelope data
352  npoints = envel_data( xvec, yvec );
353  double* xx = xvec.data();
354  double* yy = yvec.data();
355  double esum = 0.0;
356 
357  for ( int jj = 0; jj < npoints; jj++ )
358  esum += yy[ jj ];
359 
360  double yscl = tot_conc / esum;
361 
362  // Calculate histogram data
363  npoints = histo_data( xvec, yvec );
364  xx = xvec.data();
365  yy = yvec.data();
366 
367  for ( int jj = 0; jj < divsCount; jj++ )
368  {
369  xval = dsedcs.at( jj );
370  minx = qMin( minx, xval );
371  maxx = qMax( maxx, xval );
372  }
373 
374  rngx = maxx - minx;
375  minx = minx - rngx * 0.10;
376  maxx = maxx + rngx * 0.10;
377 // xinc = ( rngx < 15.0 ) ? xinc : ( xinc * 5.0 );
378 // xinc = ( rngx > 1.0 ) ? xinc : ( xinc * 0.2 );
379 // data_plot->setAxisScale( QwtPlot::xBottom, minx, maxx, xinc );
380  data_plot->setAxisAutoScale( QwtPlot::yLeft );
381  data_plot->setAxisAutoScale( QwtPlot::xBottom );
382 
383 #if 0
384  double hsum = 0.0;
385  for ( int jj = 0; jj < npoints; jj++ )
386  hsum += yy[ jj ];
387  yscl = tot_conc / hsum;
388 #endif
389 DbgLv(2) << "HISTO_DAT:" << npoints;
390 for(int jj=0;jj<npoints;jj++) DbgLv(2) << jj << xx[jj] << yy[jj];
391  // Scale Y points so envelope integration equals total concentration
392  for ( int jj = 0; jj < npoints; jj++ )
393  yy[ jj ] *= yscl;
394 
395  // Draw curve of histogram sticks
396  hcurve = us_curve( data_plot, tr( "Histogram Bar" ) );
397  hcurve->setPen( QPen( QBrush( Qt::red ), 5.0 ) );
398  hcurve->setStyle( QwtPlotCurve::Sticks );
399  hcurve->setData( xx, yy, npoints );
400 
401 
402  if ( plotType == HISTO || plotType == NONE )
403  {
404  data_plot->replot();
405  }
406 }
407 
408 // plot envelope
410 {
411  QVector< double > xvec;
412  QVector< double > yvec;
413  double* xx;
414  double* yy;
415  double minx = dsedcs[ 0 ];
416  double maxx = minx;
417 // double xinc = 1.0;
418  double xval;
419  double rngx;
420  int npoints;
421 
422  for ( int jj = 0; jj < divsCount; jj++ )
423  {
424  xval = dsedcs.at( jj );
425  minx = qMin( minx, xval );
426  maxx = qMax( maxx, xval );
427  }
428 
429  rngx = maxx - minx;
430  minx = minx - rngx * 0.10;
431  maxx = maxx + rngx * 0.10;
432 
433  if ( plotType == ENVEL )
434  { // if envelope only, must set up axes (otherwise handled by histo)
435  data_plot->setAxisTitle( QwtPlot::yLeft,
436  tr( "Relative Concentration" ) );
437  data_plot->setAxisTitle( QwtPlot::xBottom,
438  tr( "Sedimentation Coefficient" ) );
439 
440  // calculate histogram data in order to use its maximum Y
441  npoints = histo_data( xvec, yvec );
442  xx = xvec.data();
443  yy = yvec.data();
444 // xinc = ( rngx < 15.0 ) ? xinc : ( xinc * 5.0 );
445 // xinc = ( rngx > 1.0 ) ? xinc : ( xinc * 0.2 );
446 // data_plot->setAxisScale( QwtPlot::xBottom, minx, maxx, xinc );
447  data_plot->setAxisAutoScale( QwtPlot::yLeft );
448  data_plot->setAxisAutoScale( QwtPlot::xBottom );
449  }
450 
451  // Calculate envelope data
452  npoints = envel_data( xvec, yvec );
453  xx = xvec.data();
454  yy = yvec.data();
455 
456  // Scale Y points so integration equals total concentration
457  double esum = 0.0;
458 
459  for ( int jj = 0; jj < npoints; jj++ )
460  esum += yy[ jj ];
461 
462  double yscl = tot_conc / esum;
463 
464  for ( int jj = 0; jj < npoints; jj++ )
465  yy[ jj ] *= yscl;
466 
467  // Draw a cyan line through points
468  ecurve = us_curve( data_plot, tr( "Envelope Line" ) );
469  ecurve->setPen( QPen( QBrush( Qt::cyan ), 3.0 ) );
470  ecurve->setData( xx, yy, npoints );
471 
472  data_plot->replot();
473 }
474 
475 // plot combined histogram and envelope
477 {
478  plot_histogram();
479  plot_envelope();
480 }
481 
482 // generate histogram data
483 int US_DistribPlot::histo_data( QVector< double >& xvec,
484  QVector< double >& yvec )
485 {
486  int steps;
487  int stoff = 0;
488  double max_cept = 1.0e-6;
489  double min_cept = 1.0e+6;
490  double sed_bin = dsedcs.at( 0 );
491  double div_scl = (double)nSensit * (double)divsCount * 0.01;
492  double max_step;
493  double sed_lo;
494  double sed_hi;
495  double sedc;
496 
497  for ( int jj = 0; jj < divsCount; jj++ )
498  { // get min,max intercept sedimentation coefficients
499  max_cept = max( max_cept, dsedcs.at( jj ) );
500  min_cept = min( min_cept, dsedcs.at( jj ) );
501  }
502 
503  // calculate values based on range and sensitivity
504  sed_bin = ( max_cept - min_cept ) / div_scl;
505  max_step = max_cept * 4.0 / 3.0;
506  steps = (int)( max_step / sed_bin );
507  stoff = (int)( min_cept / sed_bin ) - 1;
508  stoff = qMax( stoff, 0 );
509  steps -= stoff;
510 
511  xvec.fill( 0.0, steps );
512  yvec.fill( 0.0, steps );
513  double* sval = xvec.data(); // sedcoeff array
514  double* bink = yvec.data(); // bin count array
515 
516  for ( int jj = 0; jj < steps; jj++ )
517  { // accumulate histogram values
518  int kbin = 0;
519  sed_lo = sed_bin * (double)( jj + stoff ); // low bin sedcoeff
520  sed_hi = sed_lo + sed_bin; // high bin sedcoeff
521  sval[ jj ] = ( sed_lo + sed_hi ) * 0.5; // mid bin sedcoeff
522 
523  for ( int kk = 0; kk < divsCount; kk++ )
524  { // accumulate count of sedcoeff values in current bin
525  sedc = dsedcs.at( kk );
526 
527  if ( sedc >= sed_lo && sedc < sed_hi )
528  kbin++;
529  }
530 
531  bink[ jj ] = (double)kbin; // current bin count
532  }
533 
534  return steps; // return arrays' size
535 }
536 
537 // Generate envelope data
538 int US_DistribPlot::envel_data( QVector< double >& xvec,
539  QVector< double >& yvec )
540 {
541  int steps;
542  int array = 300;
543  double max_cept = 1.0e-6;
544  double min_cept = 1.0e+6;
545  double sed_bin = dsedcs.at( 0 );
546  double his_sum = 0.0;
547  double env_sum = 0.0;
548  double div_scl = (double)nSensit * (double)divsCount * 0.01;
549  double max_step;
550  double sigma;
551  double sed_lo;
552  double sed_hi;
553  double sedc;
554 
555  for ( int jj = 0; jj < divsCount; jj++ )
556  { // get min,max intercept sedimentation coefficients
557  max_cept = max( max_cept, dsedcs.at( jj ) );
558  min_cept = min( min_cept, dsedcs.at( jj ) );
559  }
560 
561  // calculate values based on range and sensitivity
562  sed_bin = ( max_cept - min_cept ) / div_scl;
563  max_step = max_cept * 4.0 / 3.0;
564  steps = (int)( max_step / sed_bin );
565 DbgLv(2) << "ED: steps" << steps << "sed_bin" << sed_bin;
566 
567  if ( array <= steps )
568  { // insure envelope array size bigger than histogram array size
569  array = steps + 1;
570  }
571 
572  xvec.fill( 0.0, array );
573  yvec.fill( 0.0, array );
574  double bink = 0.0;
575  double sval = 0.0;
576  double pisqr = sqrt( M_PI * 2.0 );
577  double* xval = xvec.data();
578  double* yval = yvec.data();
579  double scale = max_step / (double)array;
580 DbgLv(2) << "ED: max_step array scale" << max_step << array << scale;
581 
582  for ( int jj = 0; jj < array; jj++ )
583  { // initialize envelope values
584  xval[ jj ] = scale * (double)( jj );
585  yval[ jj ] = 0.0;
586  }
587 
588  sigma = sed_bin * 0.02 * (double)nSmooth;
589 DbgLv(2) << "ED: sed_bin sigma" << sed_bin << sigma;
590 
591  for ( int jj = 0; jj < steps; jj++ )
592  { // calculate histogram values and envelope values based on them
593  int kbin = 0;
594  sed_lo = sed_bin * (double)( jj );
595  sed_hi = sed_lo + sed_bin;
596  sval = ( sed_lo + sed_hi ) * 0.5;
597 
598  for ( int kk = 0; kk < divsCount; kk++ )
599  { // count sedcoeffs within current step range
600  sedc = dsedcs.at( kk );
601 
602  if ( sedc >= sed_lo && sedc < sed_hi )
603  kbin++;
604  }
605 
606  bink = (double)kbin;
607  his_sum += ( bink * sed_bin ); // bump histogram sum
608 
609  if ( kbin > 0 )
610  { // if non-empty bin, update envelope Y values
611  for ( int kk = 0; kk < array; kk++ )
612  {
613  double xdif = ( xval[ kk ] - sval ) / sigma;
614  yval[ kk ] += ( ( bink / ( sigma * pisqr ) )
615  * exp( -( xdif * xdif ) / 2.0 ) );
616 DbgLv(2) << "ED: kk" << kk << "xdif bink yval" << xdif << bink << yval[kk];
617  }
618  }
619 DbgLv(2) << "ED: jj" << jj << "sval his_sum" << sval << his_sum;
620  }
621 
622  for ( int kk = 0; kk < array; kk++ )
623  { // accumulate the envelope values sum
624  env_sum += yval[ kk ];
625  }
626 
627  env_sum *= scale; // sum times X increment
628  scale = his_sum / env_sum; // normalizing scale factor
629 DbgLv(2) << "ED: hsum esum scale " << his_sum << env_sum << scale;
630 
631  for ( int kk = 0; kk < array; kk++ )
632  { // normalize Y values
633  yval[ kk ] *= scale;
634  }
635 
636  return array; // return arrays' size
637 }
638 
639 // Save plots and data to temporary files and close
641 {
642  QString basename = US_Settings::tmpDir() + "/vHW.temp.";
643  QString tplot1File = basename + "s-c-distrib.svg";
644  QString tplot2File = basename + "s-c-histo.svg";
645  QString tdata2File = basename + "s-c-envelope.csv";
646 
647  save_plots( tplot1File, tplot2File );
648  save_data_file( tdata2File );
649 
650  close();
651 }
652 
653 // Save envelope data file
654 void US_DistribPlot::save_data_file( QString data2File )
655 {
656  QVector< double > hseds;
657  QVector< double > hfrqs;
658  QVector< double > eseds;
659  QVector< double > efrqs;
660 
661  int nhpts = histo_data( hseds, hfrqs );
662  int nepts = envel_data( eseds, efrqs );
663 DbgLv(1) << "SaveDat: file" << data2File << "nhpts nepts" << nhpts << nepts;
664 
665  QFile datf( data2File );
666 
667  if ( ! datf.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
668  return;
669 
670  QTextStream ts( &datf );
671 
672  ts << tr( "\"S-value(Envelope)\",\"Frequency(E)\","
673  "\"S-value(Histogram)\",\"Frequency(H)\","
674  "\"TotalConcentration\"\n" );
675 
676  for ( int ii = 0; ii < nepts; ii++ )
677  {
678  QString line;
679  if ( ii < nhpts )
680  line = QString().sprintf(
681  "\"%.6f\",\"%.6f\",\"%.6f\",\"%9.2f\",\"%9.2f\"\n",
682  eseds[ ii ], efrqs[ ii ], hseds[ ii ], hfrqs[ ii ],
683  tot_conc );
684  else
685  line = QString().sprintf(
686  "\"%.6f\",\"%.6f\",\"\",\"\",\"\"\n",
687  eseds[ ii ], efrqs[ ii ] );
688 
689  line.replace( " ", "" );
690  ts << line;
691  }
692 DbgLv(1) << "SaveDat: file written";
693 
694  datf.close();
695 }
696