SNAP Library , Developer Reference  2013-01-07 14:03:36
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
gnuplot.cpp
Go to the documentation of this file.
00001 #include "stdafx.h"
00002 #include "gnuplot.h"
00003 
00005 // GNU-Plot-Chart
00006 /*#ifdef GLib_WIN
00007   TStr TGnuPlot::GnuPlotPath = "\\Dev\\GLib\\gnuplot\\bin\\";
00008 #else
00009   TStr TGnuPlot::GnuPlotPath = "/usr/bin/";
00010 #endif*/
00011 
00012 // Determines the gnuplot version and the tics command syntax.
00013 // Gnuplot changed the syntax with version 4.2:
00014 // - before 4.2: set ticscale 2 1
00015 // - 4.2 and later: set tics 2
00016 int TGnuPlot::GetTics42() {
00017 #ifdef GLib_WIN
00018   return -1;
00019 #else   
00020   FILE* p;
00021   char Buf[1024];
00022   char Version[1024];
00023   size_t n;
00024 
00025   // get gnuplot version
00026   p = popen("gnuplot -V","r");
00027   if (p == NULL) {
00028     return -1;
00029   }
00030   n = fread(Buf, 1, 100, p);
00031   if (n <= 0) {
00032     return -1;
00033   }
00034   Buf[n] = '\0';
00035   pclose(p);
00036 
00037   // printf("Buf %d .%s.\n", n, Buf);
00038   n = sscanf(Buf, "gnuplot %s", Version);
00039   if (n <= 0) {
00040     return -1;
00041   }
00042   // printf("Version %d .%s.\n", n, Version);
00043   if ((strlen(Version) < 3) || (Version[1] != '.')) {
00044     return -1;
00045   }
00046 
00047   // test version < 4.2
00048   if ((Version[0] < '4') || ((Version[0] == '4') && (Version[2] < '2'))) {
00049     // printf("TGnuPlot::GetTics42 0\n");
00050     return 0;
00051   }
00052   // printf("TGnuPlot::GetTics42 1\n");
00053   return 1;
00054 #endif
00055 }
00056 
00057 int TGnuPlot::Tics42 = TGnuPlot::GetTics42();
00058 
00059 TStr TGnuPlot::DefPlotFNm = "GnuPlot.plt";
00060 TStr TGnuPlot::DefDataFNm = "GnuPlot.tab";
00061 
00062 TGnuPlot::TGpSeries::TGpSeries(const TGnuPlot::TGpSeries& Gps) :
00063   SeriesTy(Gps.SeriesTy), XYValV(Gps.XYValV), ZValV(Gps.ZValV),
00064   Label(Gps.Label), WithStyle(Gps.WithStyle), DataFNm(Gps.DataFNm),
00065   XCol(Gps.XCol), YCol(Gps.YCol), ZCol(Gps.ZCol) {
00066 }
00067 
00068 TGnuPlot::TGpSeries& TGnuPlot::TGpSeries::operator = (const TGnuPlot::TGpSeries& Gps) {
00069   if(this != &Gps) {
00070     SeriesTy = Gps.SeriesTy;
00071     XYValV = Gps.XYValV;  ZValV = Gps.ZValV;
00072     Label = Gps.Label;
00073     DataFNm = Gps.DataFNm;
00074     WithStyle = Gps.WithStyle;
00075     XCol = Gps.XCol;  YCol = Gps.YCol;  ZCol = Gps.ZCol;
00076   }
00077   return *this;
00078 }
00079 
00080 bool TGnuPlot::TGpSeries::operator < (const TGpSeries& Gps) const {
00081   return (XYValV < Gps.XYValV) || ((XYValV == Gps.XYValV) && (Label < Gps.Label));
00082 }
00083 
00084 TGnuPlot::TGnuPlot(const TStr& FileNm, const TStr& PlotTitle, const bool& Grid) :
00085  DataFNm(FileNm+".tab"), PlotFNm(FileNm+".plt"), Title(PlotTitle), LblX(), LblY(), ScaleTy(gpsAuto),
00086  YRange(0, 0), XRange(0, 0), SetGrid(Grid), SetPause(true),
00087  SeriesV(), MoreCmds() {
00088   IAssert(! FileNm.Empty());
00089 }
00090 
00091 TGnuPlot::TGnuPlot(const TStr& DataFileNm, const TStr& PlotFileNm, const TStr& PlotTitle, const bool& Grid) :
00092   DataFNm(DataFileNm.Empty() ? DefDataFNm : DataFileNm),
00093   PlotFNm(PlotFileNm.Empty() ? DefPlotFNm : PlotFileNm),
00094   Title(PlotTitle), LblX(), LblY(), ScaleTy(gpsAuto),
00095   YRange(0, 0), XRange(0, 0), SetGrid(Grid), SetPause(true), SeriesV(), MoreCmds() {
00096 }
00097 
00098 TGnuPlot::TGnuPlot(const TGnuPlot& GnuPlot) : DataFNm(GnuPlot.DataFNm), PlotFNm(GnuPlot.PlotFNm),
00099   Title(GnuPlot.Title), LblX(GnuPlot.LblX), LblY(GnuPlot.LblY), ScaleTy(GnuPlot.ScaleTy), YRange(GnuPlot.YRange),
00100   XRange(GnuPlot.XRange), SetGrid(GnuPlot.SetGrid), SetPause(GnuPlot.SetPause), SeriesV(GnuPlot.SeriesV),
00101   MoreCmds(GnuPlot.MoreCmds) {
00102 }
00103 
00104 TGnuPlot& TGnuPlot::operator = (const TGnuPlot& GnuPlot) {
00105   if (this != &GnuPlot) {
00106     DataFNm = GnuPlot.DataFNm;
00107     PlotFNm = GnuPlot.PlotFNm;
00108     Title = GnuPlot.Title;
00109     LblX = GnuPlot.LblX;
00110     LblY = GnuPlot.LblY;
00111     ScaleTy = GnuPlot.ScaleTy;
00112     YRange = GnuPlot.YRange;
00113     XRange = GnuPlot.XRange;
00114     SetGrid = GnuPlot.SetGrid;
00115     SetPause = GnuPlot.SetPause;
00116     SeriesV = GnuPlot.SeriesV;
00117     MoreCmds = GnuPlot.MoreCmds;
00118   }
00119   return *this;
00120 }
00121 
00122 TStr TGnuPlot::GetSeriesPlotStr(const int& SeriesId) {
00123   TChA PlotStr;
00124   TGpSeries& Series = SeriesV[SeriesId];
00125   if (SeriesId != 0) PlotStr += ",\\\n\t";
00126   if (Series.XCol >= 0) {
00127     PlotStr += "\"" + Series.DataFNm + "\" using " + TInt::GetStr(Series.XCol);
00128     if (Series.YCol != 0) { PlotStr += ":" + TInt::GetStr(Series.YCol); }
00129     if (Series.ZCol != 0) { PlotStr += ":" + TInt::GetStr(Series.ZCol); }
00130     else if (Series.SeriesTy==gpwFilledCurves) { PlotStr += ":(0)"; } // filled curves requres 3rd column
00131   } else {
00132     // function
00133     //IAssertR(Series.DataFNm.SearchCh('=') != -1, TStr::Fmt("Expression %s is not a function", Series.DataFNm.CStr()));
00134     PlotStr += Series.DataFNm;
00135   }
00136   PlotStr += " title \"" + Series.Label + "\"";
00137   // hard coded line style
00138   if (Series.WithStyle.Empty()) {
00139     if (Series.SeriesTy == gpwLines) Series.WithStyle = "lw 1";
00140     //if (Series.SeriesTy == gpwPoints) Series.WithStyle = "pt 6 ps 1 lw 1"; // circles
00141     //if (Series.SeriesTy == gpwLinesPoints) Series.WithStyle = "pt 6 ps 1 lw 1"; // circles
00142     if (Series.SeriesTy == gpwBoxes) Series.WithStyle = "fill solid 0.3";
00143   }
00144   PlotStr += " with " + GetSeriesTyStr(Series.SeriesTy) + " " + Series.WithStyle;
00145   return PlotStr;
00146 }
00147 
00148 //GP.AddFunc("2*x**-2+4", gpwLines, "2*x^-2+4");
00149 int TGnuPlot::AddFunc(const TStr& FuncStr, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00150   const int Id = SeriesV.Len();
00151   TGpSeries Plot;
00152   Plot.SeriesTy = SeriesTy;
00153   Plot.Label = Label;
00154   if (! FuncStr.Empty()) { Plot.DataFNm = TStr::Fmt("f%d(x)=%s, f%d(x)", Id, FuncStr.CStr(), Id); }
00155   else { Plot.DataFNm = TStr::Fmt("f%d(x)", Id); }
00156   Plot.XCol = -1;
00157   Plot.WithStyle = Style;
00158   SeriesV.Add(Plot);
00159   return Id;
00160 }
00161 
00162 int TGnuPlot::AddPlot(const TStr& DataFNm, const int& ColY,
00163                       const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00164   return AddPlot(DataFNm, 0, ColY, SeriesTy, Label, Style);
00165 }
00166 
00167 int TGnuPlot::AddPlot(const TStr& DataFNm, const int& ColX, const int& ColY,
00168                       const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00169   IAssert(ColY > 0);  IAssert(ColX >= 0);
00170   TGpSeries Plot;
00171   Plot.SeriesTy = SeriesTy;
00172   Plot.Label = Label;
00173   Plot.DataFNm = DataFNm;  Plot.DataFNm.ChangeStrAll("\\", "\\\\");
00174   Plot.XCol = ColX;  Plot.YCol = ColY;  Plot.ZCol = 0;
00175   Plot.WithStyle = Style;
00176   SeriesV.Add(Plot);
00177   return SeriesV.Len() - 1;
00178 }
00179 
00180 int TGnuPlot::AddPlot(const TIntV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00181   TFltKdV XYValV(YValV.Len(), 0);
00182   for (int i = 0; i < YValV.Len(); i++) {
00183     XYValV.Add(TFltKd(TFlt(i+1), TFlt(YValV[i])));
00184   }
00185   return AddPlot(XYValV, SeriesTy, Label, Style);
00186 }
00187 
00188 int TGnuPlot::AddPlot(const TFltV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00189   TFltKdV XYValV(YValV.Len(), 0);
00190   for (int i = 0; i < YValV.Len(); i++) {
00191     XYValV.Add(TFltKd(TFlt(i+1), TFlt(YValV[i])));
00192   }
00193   return AddPlot(XYValV, SeriesTy, Label, Style);
00194 }
00195 
00196 int TGnuPlot::AddPlot(const TFltV& XValV, const TFltV& YValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00197   IAssert(XValV.Len() == YValV.Len());
00198   TFltKdV XYValV(XValV.Len(), 0);
00199   for (int i = 0; i < YValV.Len(); i++) {
00200     XYValV.Add(TFltKd(TFlt(XValV[i]), TFlt(YValV[i])));
00201   }
00202   return AddPlot(XYValV, SeriesTy, Label, Style);
00203 }
00204 
00205 int TGnuPlot::AddPlot(const TIntPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00206   TFltKdV XYFltValV(XYValV.Len(), 0);
00207   for (int i = 0; i < XYValV.Len(); i++) {
00208     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Val1), TFlt(XYValV[i].Val2)));
00209   }
00210   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00211 }
00212 
00213 int TGnuPlot::AddPlot(const TFltPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00214   TFltKdV XYFltValV(XYValV.Len(), 0);
00215   for (int i = 0; i < XYValV.Len(); i++) {
00216     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00217   }
00218   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00219 }
00220 
00221 int TGnuPlot::AddPlot(const TIntKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00222   TFltKdV XYFltValV(XYValV.Len(), 0);
00223   for (int i = 0; i < XYValV.Len(); i++) {
00224     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Key), TFlt(XYValV[i].Dat)));
00225   }
00226   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00227 }
00228 
00229 int TGnuPlot::AddPlot(const TIntFltKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00230   TFltKdV XYFltValV(XYValV.Len(), 0);
00231   for (int i = 0; i < XYValV.Len(); i++) {
00232     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Key), TFlt(XYValV[i].Dat)));
00233   }
00234   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00235 }
00236 
00237 int TGnuPlot::AddPlot(const TIntFltPrV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00238   TFltKdV XYFltValV(XYValV.Len(), 0);
00239   for (int i = 0; i < XYValV.Len(); i++) {
00240     XYFltValV.Add(TFltKd(TFlt(XYValV[i].Val1), TFlt(XYValV[i].Val2)));
00241   }
00242   return AddPlot(XYFltValV, SeriesTy, Label, Style);
00243 }
00244 
00245 int TGnuPlot::AddPlot(const TFltKdV& XYValV, const TGpSeriesTy& SeriesTy, const TStr& Label, const TStr& Style) {
00246   if (XYValV.Empty()) {
00247     printf("***AddPlot: empty plot (%s) %s\n", DataFNm.CStr(), Title.CStr());
00248     return -1;
00249   }
00250   TGpSeries Plot;
00251   Plot.SeriesTy = SeriesTy;
00252   Plot.Label = Label;
00253   Plot.XYValV = XYValV;
00254   Plot.WithStyle = Style;
00255   SeriesV.Add(Plot);
00256   return SeriesV.Len() - 1;
00257 }
00258 
00259 int TGnuPlot::AddErrBar(const TFltTrV& XYDValV, const TStr& Label) {
00260   TFltKdV XYFltValV(XYDValV.Len(), 0);
00261   TFltV DeltaV(XYDValV.Len(), 0);
00262   for (int i = 0; i < XYDValV.Len(); i++) {
00263     XYFltValV.Add(TFltKd(XYDValV[i].Val1, XYDValV[i].Val2));
00264     DeltaV.Add(XYDValV[i].Val3);
00265   }
00266   return AddErrBar(XYFltValV, DeltaV, Label);
00267 }
00268 
00269 int TGnuPlot::AddErrBar(const TFltTrV& XYDValV, const TStr& DatLabel, const TStr& ErrLabel) {
00270   TFltKdV XYFltValV(XYDValV.Len(), 0);
00271   TFltV DeltaV(XYDValV.Len(), 0);
00272   for (int i = 0; i < XYDValV.Len(); i++) {
00273     XYFltValV.Add(TFltKd(XYDValV[i].Val1, XYDValV[i].Val2));
00274     DeltaV.Add(XYDValV[i].Val3);
00275   }
00276   const int PlotId = AddPlot(XYFltValV, gpwLinesPoints, DatLabel);
00277   AddErrBar(XYFltValV, DeltaV, ErrLabel);
00278   return PlotId;
00279 }
00280 
00281 int TGnuPlot::AddErrBar(const TFltV& YValV, const TFltV& DeltaYV, const TStr& Label) {
00282   IAssert(YValV.Len() == DeltaYV.Len());
00283   TFltKdV XYFltValV(YValV.Len(), 0);
00284   for (int i = 0; i < YValV.Len(); i++) {
00285     XYFltValV.Add(TFltKd(TFlt(i+1), YValV[i]));
00286   }
00287   return AddErrBar(XYFltValV, DeltaYV, Label);
00288 }
00289 
00290 int TGnuPlot::AddErrBar(const TFltV& XValV, const TFltV& YValV, const TFltV& DeltaYV, const TStr& Label) {
00291   IAssert(XValV.Len() == YValV.Len());
00292   IAssert(XValV.Len() == DeltaYV.Len());
00293   TFltKdV XYFltValV(XValV.Len(), 0);
00294   for (int i = 0; i < XValV.Len(); i++) {
00295     XYFltValV.Add(TFltKd(XValV[i], YValV[i]));
00296   }
00297   return AddErrBar(XYFltValV, DeltaYV, Label);
00298 }
00299 
00300 int TGnuPlot::AddErrBar(const TFltPrV& XYValV, const TFltV& DeltaYV, const TStr& Label) {
00301   TFltKdV XYFltValV(XYValV.Len(), 0);
00302   for (int i = 0; i < XYValV.Len(); i++) {
00303     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00304   }
00305   return AddErrBar(XYFltValV, DeltaYV, Label);
00306 }
00307 
00308 int TGnuPlot::AddErrBar(const TFltPrV& XYValV, const TFltV& DeltaV, const TStr& DatLabel, const TStr& ErrLabel) {
00309   TFltKdV XYFltValV(XYValV.Len(), 0);
00310   for (int i = 0; i < XYValV.Len(); i++) {
00311     XYFltValV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2));
00312   }
00313   const int PlotId = AddPlot(XYFltValV, gpwLinesPoints, DatLabel);
00314   AddErrBar(XYFltValV, DeltaV, ErrLabel);
00315   return PlotId;
00316 }
00317 
00318 int TGnuPlot::AddErrBar(const TFltKdV& XYValV, const TFltV& DeltaYV, const TStr& Label) {
00319   if (XYValV.Empty()) {
00320     printf("***AddErrBar: empty plot (%s) %s\n", DataFNm.CStr(), Title.CStr());
00321     return -1;
00322   }
00323   IAssert(XYValV.Len() == DeltaYV.Len());
00324   TGpSeries Plot;
00325   Plot.SeriesTy = gpwErrBars;
00326   Plot.Label = Label;
00327   Plot.XYValV = XYValV;
00328   Plot.ZValV = DeltaYV;
00329   SeriesV.Add(Plot);
00330   return SeriesV.Len() - 1;
00331 }
00332 
00333 int TGnuPlot::AddLinFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00334   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00335   const TGpSeries& Plot = SeriesV[PlotId];
00336   if(Plot.XYValV.Empty()) return -1;
00337   const TFltKdV& XY = Plot.XYValV;
00338   double A, B, R2, SigA, SigB, Chi2;
00339   // linear fit
00340   TFltPrV XYPr;
00341   int s;
00342   for (s = 0; s < XY.Len(); s++) {
00343     XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat));
00344   }
00345   TSpecFunc::LinearFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00346   TStr StyleStr=Style;
00347   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00348   const int FitId = AddFunc(TStr::Fmt("%f+%f*x", A, B),
00349     SeriesTy, TStr::Fmt("%.4g + %.4g x  R^2:%.2g", A, B, R2), StyleStr);
00350   return FitId;
00351   /*SeriesV.Add();
00352   TGpSeries& NewPlot = SeriesV.Last();
00353   TFltKdV& EstXY = NewPlot.XYValV;
00354   for (s = 0; s < XY.Len(); s++) {
00355     EstXY.Add(TFltKd(XY[s].Key, A + B*XYPr[s].Val1));
00356   }
00357   NewPlot.Label = TStr::Fmt("%.4g + %.4g x  R^2:%.2g", A, B, R2);
00358   NewPlot.SeriesTy = SeriesTy;
00359   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00360   else { NewPlot.WithStyle = Style; }
00361   return SeriesV.Len() - 1;*/
00362 }
00363 
00364 int TGnuPlot::AddPwrFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00365   const int PlotId1 = AddPwrFit3(PlotId, SeriesTy);
00366   AddPwrFit2(PlotId, SeriesTy, 5.0);
00367   return PlotId1;
00368 }
00369 
00370 // linear fit on log-log scales{%
00371 int TGnuPlot::AddPwrFit1(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00372   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00373   const TGpSeries& Plot = SeriesV[PlotId];
00374   if(Plot.XYValV.Empty()) return -1;
00375   const TFltKdV& XY = Plot.XYValV;
00376   double A, B, R2, SigA, SigB, Chi2, MinY = TFlt::Mx, MinX = TFlt::Mx;
00377   // power fit
00378   TFltPrV XYPr;
00379   int s;
00380   for (s = 0; s < XY.Len(); s++) {
00381     if (XY[s].Key > 0) {
00382       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat)); 
00383       MinX = TMath::Mn(MinX, XY[s].Key());
00384       MinY = TMath::Mn(MinY, XY[s].Dat());
00385     }
00386   }
00387   MinY = TMath::Mn(1.0, MinY);
00388   TSpecFunc::PowerFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00389   TStr StyleStr=Style;
00390   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00391   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", A, B),
00392     SeriesTy, TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2), StyleStr);
00393   return FitId;
00394   /*SeriesV.Add();
00395   TGpSeries& NewPlot = SeriesV.Last();
00396   const int FitId = SeriesV.Len() - 1;
00397   NewPlot.DataFNm = ;
00398   TFltKdV& EstXY = NewPlot.XYValV;
00399   for (s = 0; s < XYPr.Len(); s++) {
00400     const double YVal = A*pow(XYPr[s].Val1(), B);
00401     if (YVal < MinY) continue;
00402     EstXY.Add(TFltKd(XYPr[s].Val1, YVal));
00403   }
00404   NewPlot.Label = ;
00405   NewPlot.SeriesTy = SeriesTy;
00406   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00407   else { NewPlot.WithStyle = Style; }
00408   //if (MinX < 5.0) MinX = 5.0;
00409   //AddPwrFit2(PlotId, SeriesTy, MinX);*/
00410 }
00411 
00412 // MLE power-coefficient
00413 int TGnuPlot::AddPwrFit2(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style) {
00414   const TGpSeries& Plot = SeriesV[PlotId];
00415   if(Plot.XYValV.Empty()) return -1;
00416   const TFltKdV& XY = Plot.XYValV;
00417   // power fit
00418   TFltPrV XYPr;
00419   double MinY = TFlt::Mx;
00420   for (int s = 0; s < XY.Len(); s++) {
00421     if (XY[s].Key > 0.0) {
00422       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat));
00423       MinY = TMath::Mn(MinY, XY[s].Dat());
00424     }
00425   }
00426   if (XYPr.Empty()) return -1;
00427   MinY = TMath::Mn(1.0, MinY);
00428   // determine the sign of power coefficient
00429   double CoefSign = 0.0;
00430   { double A, B, R2, SigA, SigB, Chi2;
00431   TSpecFunc::PowerFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00432   CoefSign = B > 0.0 ? +1.0 : -1.0; }
00433   const double PowerCf = CoefSign * TSpecFunc::GetPowerCoef(XYPr, MinX);
00434   int Mid = (int) exp(log((double)XYPr.Len())/2.0);
00435   if (Mid >= XYPr.Len()) { Mid = XYPr.Len()-1; }
00436   const double MidX = XYPr[Mid].Val1();
00437   const double MidY = XYPr[Mid].Val2();
00438   const double B = MidY / pow(MidX, PowerCf);
00439   TStr StyleStr=Style;
00440   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00441   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", B, PowerCf),
00442     SeriesTy, TStr::Fmt("MLE = x^{%.4g}", PowerCf), StyleStr);
00443   return FitId;
00444   /*SeriesV.Add();
00445   TGpSeries& NewPlot = SeriesV.Last();
00446   TFltKdV& XYFit = NewPlot.XYValV;
00447   XYFit.Gen(XYPr.Len(), 0);
00448   for (int s = 0; s < XYPr.Len(); s++) {
00449     const double XVal = XYPr[s].Val1;
00450     const double YVal = B * pow(XYPr[s].Val1(), PowerCf);
00451     if (YVal < MinY || XVal < MinX) continue;
00452     XYFit.Add(TFltKd(XVal, YVal));
00453   }
00454   NewPlot.Label = TStr::Fmt("PowerFit: %g", PowerCf);
00455   NewPlot.SeriesTy = SeriesTy;
00456   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00457   else { NewPlot.WithStyle = Style; }
00458   return SeriesV.Len() - 1;*/
00459 }
00460 
00461 int TGnuPlot::AddPwrFit3(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style) {
00462   double Intercept, Slope, R2;
00463   return AddPwrFit3(PlotId, SeriesTy, MinX, Style, Intercept, Slope, R2);
00464 }
00465 
00466 // some kind of least squares power-law fitting that cutts the tail until the fit is good
00467 int TGnuPlot::AddPwrFit3(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& MinX, const TStr& Style, double& Intercept, double& Slope, double& R2) {
00468   if (PlotId < 0 || PlotId >= SeriesV.Len()) return -1;
00469   const TGpSeries& Plot = SeriesV[PlotId];
00470   if(Plot.XYValV.Empty()) return -1;
00471   double A, B, SigA, SigB, Chi2, MinY=TFlt::Mx;
00472   const TFltKdV& XY = Plot.XYValV;
00473   //SeriesV.Add();
00474   //TGpSeries& NewPlot = SeriesV.Last();
00475   //TFltKdV& EstXY = NewPlot.XYValV;
00476   TFltPrV FitXY, NewFitXY;
00477   for (int s = 0; s < XY.Len(); s++) {
00478     if (XY[s].Key > 0 && XY[s].Key >= MinX) {
00479       FitXY.Add(TFltPr(XY[s].Key, XY[s].Dat)); 
00480       MinY = TMath::Mn(MinY, XY[s].Dat());
00481     }
00482   }
00483   MinY = TMath::Mn(1.0, MinY);
00484   // power fit (if tail is too fat, cut everything where
00485   // extrapolation sets the value < MinY
00486   while (true) {
00487     TSpecFunc::PowerFit(FitXY, A, B, SigA, SigB, Chi2, R2);
00488     NewFitXY.Clr(false);
00489     //EstXY.Clr(false);
00490     for (int s = 0; s < FitXY.Len(); s++) {
00491       const double YVal = A*pow(FitXY[s].Val1(), B);
00492       if (YVal < MinY) continue;
00493       //EstXY.Add(TFltKd(FitXY[s].Val1, YVal));
00494       NewFitXY.Add(TFltPr(FitXY[s].Val1, FitXY[s].Val2));
00495     }
00496     if (NewFitXY.Len() < 10 || FitXY.Last().Val1 < 1.2 * NewFitXY.Last().Val1) { break; }
00497     else { FitXY.Swap(NewFitXY); }
00498   }
00499   TStr StyleStr=Style;
00500   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00501   const int FitId = AddFunc(TStr::Fmt("%f*x**%f", A, B),
00502     SeriesTy, TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2), StyleStr);
00503   return FitId;
00504   /*NewPlot.Label = TStr::Fmt("%.1g * x^{%.4g}  R^2:%.2g", A, B, R2);
00505   Intercept = A;
00506   Slope = B;
00507   NewPlot.SeriesTy = SeriesTy;
00508   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00509   else { NewPlot.WithStyle = Style; }
00510   return SeriesV.Len() - 1;*/
00511 }
00512 
00513 int TGnuPlot::AddLogFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const TStr& Style) {
00514   const TGpSeries& Plot = SeriesV[PlotId];
00515   if(Plot.XYValV.Empty()) return -1;
00516   const TFltKdV& XY = Plot.XYValV;
00517   double A, B, R2, SigA, SigB, Chi2;
00518   // power fit
00519   TFltPrV XYPr;
00520   int s;
00521   for (s = 0; s < XY.Len(); s++) {
00522     if (XY[s].Key > 0) {
00523       XYPr.Add(TFltPr(XY[s].Key, XY[s].Dat)); } 
00524   }
00525   TSpecFunc::LogFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00526   TStr StyleStr=Style;
00527   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00528   const int FitId = AddFunc(TStr::Fmt("%f+%f*log(x)", A, B),
00529     SeriesTy, TStr::Fmt("%.4g + %.4g log(x)  R^2:%.2g", A, B, R2), StyleStr);
00530   return FitId;
00531   /*SeriesV.Add();
00532   TGpSeries& NewPlot = SeriesV.Last();
00533   TFltKdV& EstXY = NewPlot.XYValV;
00534   for (s = 0; s < XYPr.Len(); s++) {
00535     EstXY.Add(TFltKd(XYPr[s].Val1, A+B*log((double)XYPr[s].Val1)));
00536   }
00537   NewPlot.Label = TStr::Fmt("%.4g + %.4g log(x)  R^2:%.2g", A, B, R2);
00538   NewPlot.SeriesTy = SeriesTy;
00539   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00540   else { NewPlot.WithStyle = Style; }
00541   return SeriesV.Len() - 1;*/
00542 }
00543 
00544 int TGnuPlot::AddExpFit(const int& PlotId, const TGpSeriesTy& SeriesTy, const double& FitXOffset, const TStr& Style) {
00545   const TGpSeries& Plot = SeriesV[PlotId];
00546   if(Plot.XYValV.Empty()) return -1;
00547   const TFltKdV& XY = Plot.XYValV;
00548   double A, B, R2, SigA, SigB, Chi2;
00549   // power fit
00550   TFltPrV XYPr;
00551   int s;
00552   for (s = 0; s < XY.Len(); s++) {
00553     if (XY[s].Key-FitXOffset > 0) {
00554       XYPr.Add(TFltPr(XY[s].Key-FitXOffset, XY[s].Dat)); } 
00555   }
00556   TSpecFunc::ExpFit(XYPr, A, B, SigA, SigB, Chi2, R2);
00557   TStr Label, StyleStr=Style;
00558   if (FitXOffset == 0) { Label = TStr::Fmt("%.4g exp(%.4g x)  R^2:%.2g", A, B, R2); }
00559   else { Label = TStr::Fmt("%.4g exp(%.4g x - %g)  R^2:%.2g", A, B, FitXOffset, R2); }
00560   if (StyleStr.Empty()) { StyleStr = "linewidth 3"; }
00561   const int FitId = AddFunc(TStr::Fmt("%f*exp(%f*x-%f)", A, B, FitXOffset),
00562     SeriesTy, Label, StyleStr);
00563   return FitId;
00564   /*SeriesV.Add();
00565   TGpSeries& NewPlot = SeriesV.Last();
00566   TFltKdV& EstXY = NewPlot.XYValV;
00567   for (s = 0; s < XYPr.Len(); s++) {
00568     EstXY.Add(TFltKd(XYPr[s].Val1+FitXOffset, A*exp(B*XYPr[s].Val1)));
00569   }
00570   NewPlot.SeriesTy = SeriesTy;
00571   if (Style.Empty()) { NewPlot.WithStyle = "linewidth 3"; }
00572   else { NewPlot.WithStyle = Style; }
00573   return SeriesV.Len() - 1;*/
00574 }
00575 
00576 void TGnuPlot::SavePng(const TStr& FNm, const int& SizeX, const int& SizeY, const TStr& Comment, const TStr& Terminal) {
00577   if (Terminal.Empty()) {
00578     //#ifdef GLib_WIN
00579     AddCmd(TStr::Fmt("set terminal png small size %d,%d", SizeX, SizeY));
00580     AddCmd(TStr::Fmt("set output '%s'", FNm.CStr()));
00587   } else {
00588     AddCmd(Terminal);
00589     AddCmd(TStr::Fmt("set output '%s'", FNm.CStr()));
00590   }
00591   Pause(false);
00592   CreatePlotFile(Comment.Empty()? Title : Comment);
00593   RunGnuPlot();
00594   MoreCmds.DelLast();
00595   MoreCmds.DelLast();
00596 }
00597 
00598 void TGnuPlot::SaveEps(const TStr& FNm, const int& FontSz, const TStr& Comment) {
00599   AddCmd(TStr::Fmt("set terminal postscript enhanced eps %d color", FontSz));
00600   AddCmd(TStr::Fmt("set output '%s'", FNm.CStr()));
00601   Pause(false);
00602   CreatePlotFile(Comment.Empty()? Title : Comment);
00603   RunGnuPlot();
00604   MoreCmds.DelLast();
00605   MoreCmds.DelLast();
00606 }
00607 
00608 void TGnuPlot::MakeExpBins(const TFltPrV& XYValV, TFltPrV& ExpXYValV, const double& BinFactor, const double& MinYVal) {
00609   TFltKdV KdV(XYValV.Len(), 0), OutV;
00610   for (int i = 0; i < XYValV.Len(); i++) {
00611     KdV.Add(TFltKd(XYValV[i].Val1, XYValV[i].Val2)); }
00612   KdV.Sort();
00613   TGnuPlot::MakeExpBins(KdV, OutV, BinFactor, MinYVal);
00614   ExpXYValV.Gen(OutV.Len(), 0);
00615   for (int i = 0; i < OutV.Len(); i++) {
00616     ExpXYValV.Add(TFltPr(OutV[i].Key, OutV[i].Dat)); }
00617 }
00618 
00619 void TGnuPlot::MakeExpBins(const TFltKdV& XYValV, TFltKdV& ExpXYValV, const double& BinFactor, const double& MinYVal) {
00620   if (XYValV.Empty()) { ExpXYValV.Clr(false); return; }
00621   IAssert(! XYValV.Empty());
00622   IAssert(XYValV.IsSorted());
00623   const TFlt MxX = XYValV.Last().Key;
00624   // find buckets
00625   TFltV BucketEndV; BucketEndV.Add(1);
00626   double PrevBPos = 1, BPos = 1;
00627   while (BPos <= MxX) {
00628     PrevBPos = (uint) floor(BPos);
00629     BPos *= BinFactor;
00630     if (floor(BPos) == PrevBPos) {
00631       BPos = PrevBPos + 1; }
00632     BucketEndV.Add(floor(BPos));
00633   }
00634   //printf("buckets:\n"); for (int i = 0; i < BucketEndV.Len(); i++) { printf("\t%g\n", BucketEndV[i]);}
00635   ExpXYValV.Gen(BucketEndV.Len(), 0);
00636   int CurB = 0;
00637   double AvgPos=0, Cnt=0, AvgVal=0;
00638   for (int v = 0; v < XYValV.Len(); v++) {
00639     if (XYValV[v].Key() == 0.0) { continue; }
00640     AvgPos += XYValV[v].Key ;//* XYValV[v].Dat;  // x
00641     AvgVal += XYValV[v].Dat;  // y
00642     Cnt++;
00643     if (v+1 == XYValV.Len() || XYValV[v+1].Key > BucketEndV[CurB]) {
00644       if (Cnt != 0) {
00645         //AvgPos /= AvgVal;
00646         //AvgVal /= (BucketEndV[CurB]-BucketEndV[CurB-1]);
00647         AvgPos /= (double) Cnt;
00648         AvgVal /= (double) Cnt;
00649         if (AvgVal < MinYVal) { AvgVal = MinYVal; }
00650         ExpXYValV.Add(TFltKd(AvgPos, AvgVal));
00651         //printf("b: %6.2f\t%6.2f\n", AvgPos, AvgVal);
00652         AvgPos = 0;  AvgVal = 0;  Cnt = 0;
00653       }
00654       CurB++;
00655     }
00656   }
00657 }
00658 
00659 void TGnuPlot::LoadTs(const TStr& FNm, TStrV& ColNmV, TVec<TFltKdV>& ColV) {
00660   PSs Ss = TSs::LoadTxt(ssfTabSep, FNm);
00661   int row = 0;
00662   ColNmV.Clr();
00663   while (Ss->At(0, row)[0] == '#') { row++; }
00664   for (int c = 1; c < Ss->GetXLen(row); c+=2) {
00665     ColNmV.Add(Ss->At(c, row));
00666   }
00667   row++;
00668   ColV.Gen(ColNmV.Len(), ColNmV.Len());
00669   for (; row < Ss->GetYLen(); row++) {
00670     for (int c = 0; c < Ss->GetXLen(row); c+=2) {
00671       if (Ss->At(c,row).Empty()) break;
00672       ColV[c/2].Add(TFltKd(Ss->At(c,row).GetFlt(), Ss->At(c+1,row).GetFlt()));
00673     }
00674   }
00675 }
00676 
00677 TStr TGnuPlot::GetScaleStr(const TGpScaleTy& ScaleTy) {
00678   switch(ScaleTy){
00679     case gpsNoAuto: return TStr("set noautoscale");
00680     case gpsAuto: return TStr("set autoscale");
00681     case gpsLog: return TStr("set logscale");
00682     case gpsLog2X: return TStr("set logscale x 2");
00683     case gpsLog2Y: return TStr("set logscale y 2");
00684     case gpsLog2XY: return TStr("set logscale xy 2");
00685     case gpsLog10X: return TStr("set logscale x 10");
00686     case gpsLog10Y: return TStr("set logscale y 10");
00687     case gpsLog10XY: return TStr("set logscale xy 10");
00688     default: Fail;
00689   }
00690   return TStr();
00691 }
00692 
00693 TStr TGnuPlot::GetSeriesTyStr(const TGpSeriesTy& SeriesTy) {
00694   switch(SeriesTy) {
00695     case gpwLines: return TStr("lines");
00696     case gpwPoints: return TStr("points");
00697     case gpwLinesPoints: return TStr("linespoints");
00698     case gpwImpulses: return TStr("impulses");
00699     case gpwDots: return TStr("dots");
00700     case gpwSteps: return TStr("steps");
00701     case gpwFSteps: return TStr("fsteps");
00702     case gpwHiSteps: return TStr("histeps");
00703     case gpwBoxes: return TStr("boxes");
00704     case gpwErrBars: return TStr("errorbars");
00705     case gpwFilledCurves: return TStr("filledcurves");
00706     default: Fail;
00707   }
00708   return TStr();
00709 }
00710 
00711 void TGnuPlot::SaveTs(const TIntKdV& KdV, const TStr& FNm, const TStr& HeadLn) {
00712   FILE *F = fopen(FNm.CStr(), "wt");
00713   EAssert(F);
00714   if (! HeadLn.Empty()) fprintf(F, "# %s\n", HeadLn.CStr());
00715   for (int i = 0; i < KdV.Len(); i++) {
00716     fprintf(F, "%d\t%d\n", KdV[i].Key(), KdV[i].Dat()); }
00717   fclose(F);
00718 }
00719 
00720 
00721 void TGnuPlot::SaveTs(const TIntFltKdV& KdV, const TStr& FNm, const TStr& HeadLn) {
00722   FILE *F = fopen(FNm.CStr(), "wt");
00723   EAssert(F);
00724   if (! HeadLn.Empty()) fprintf(F, "# %s\n", HeadLn.CStr());
00725   for (int i = 0; i < KdV.Len(); i++)
00726     fprintf(F, "%d\t%g\n", KdV[i].Key(), KdV[i].Dat());
00727   fclose(F);
00728 }
00729 
00730 void TGnuPlot::Test() {
00731   TFltV DeltaY;
00732   TFltPrV ValV1, ValV2, ValV3;
00733   for (int i = 1; i < 30; i++) {
00734     ValV1.Add(TFltPr(i, pow(double(i), 1.2)));
00735     DeltaY.Add(5*TInt::Rnd.GetUniDev());
00736     ValV2.Add(TFltPr(i, 5*i-1));
00737   }
00738   for (int i = -10; i < 20; i++) {
00739     ValV3.Add(TFltPr(i, 2*i + 2 + TInt::Rnd.GetUniDev()));
00740   }
00741   TGnuPlot GnuPlot("testDat", "TestPlot", true);
00742   GnuPlot.SetXYLabel("X", "Y");
00743   const int id2 = GnuPlot.AddPlot(ValV2, gpwPoints, "y=5*x-1");
00744   const int id3 = GnuPlot.AddPlot(ValV3, gpwPoints, "y=2*x+2");
00745   GnuPlot.AddErrBar(ValV1, DeltaY, "y=x^2", "Error bar");
00746   GnuPlot.AddLinFit(id2, gpwLines);
00747   GnuPlot.AddLinFit(id3, gpwLines);
00748   GnuPlot.Plot();
00749   GnuPlot.SavePng("testPlot.png");
00750 }
00751 
00752 int TGnuPlot::IsSameXCol(const int& CurId, const int& PrevId) const {
00753   //if (SerId < 1) { return -1; }
00754   if (SeriesV[CurId].XYValV.Len() != SeriesV[PrevId].XYValV.Len()) { return -1; }
00755   for (int x = 0; x < SeriesV[CurId].XYValV.Len(); x++) {
00756     if (SeriesV[CurId].XYValV[x] != SeriesV[PrevId].XYValV[x]) { return -1; }
00757   }
00758   IAssert(SeriesV[PrevId].XCol > 0);
00759   return SeriesV[PrevId].XCol;
00760 }
00761 
00762 void TGnuPlot::CreatePlotFile(const TStr& Comment) {
00763   time_t ltime;  time(&ltime);
00764   char* TimeStr = ctime(&ltime);  TimeStr[strlen(TimeStr) - 1] = 0;
00765   // rearrange columns so that longest are on the left
00766   //SeriesV.Sort(false);
00767   TIntV SerIdV(SeriesV.Len(), 0);
00768   for (int i = 0; i < SeriesV.Len(); i++) { SerIdV.Add(i); }
00769   SerIdV.SortCmp(TGpSeriesCmp(SeriesV));
00770   // set columns
00771   int ColCnt = 1;
00772   bool SaveData = false;
00773   for (int s = 0; s < SeriesV.Len(); s++) {
00774     TGpSeries& Plt = SeriesV[SerIdV[s]];
00775     if (Plt.XYValV.Empty()) { continue; }
00776     Plt.DataFNm = DataFNm;
00777     // plots use same X column
00778     const int PrevCol = s > 0 ? IsSameXCol(SerIdV[s], SerIdV[s-1]) : -1;
00779     if (PrevCol != -1) { Plt.XCol = PrevCol; }
00780     else { Plt.XCol = ColCnt;  ColCnt++; }
00781     Plt.YCol = ColCnt;  ColCnt++;
00782     if (! Plt.ZValV.Empty()) { Plt.ZCol = ColCnt;  ColCnt++; }
00783     if (! Plt.XYValV.Empty()) { SaveData=true; }
00784   }
00785   // save data file (skip duplicate X columns)
00786   if (SaveData) {
00787     FILE *F = fopen(DataFNm.CStr(), "wt");
00788     EAssertR(F != NULL, TStr("Can not open data file ")+DataFNm);
00789     fprintf(F, "#\n");
00790     fprintf(F, "# %s (%s)\n", Comment.CStr(), TimeStr);
00791     fprintf(F, "#\n");
00792     // column names
00793     for (int i = 0; i < SerIdV.Len(); i++) {
00794       const TGpSeries& Ser = SeriesV[SerIdV[i]];
00795       if (Ser.XYValV.Empty()) { continue; }
00796       if (i == 0) { fprintf(F, "# "); } else { fprintf(F, "\t"); }
00797       if (Ser.SaveXVals()) {
00798         if (! LblX.Empty()) { fprintf(F, "%s\t", LblX.CStr()); }
00799         else { fprintf(F, "XVals\t"); }
00800       }
00801       if (Ser.Label.Empty()) { fprintf(F, "%s", LblY.CStr()); }
00802       else { fprintf(F, "%s", SeriesV[SerIdV[i]].Label.CStr()); }
00803       if (Ser.ZCol > 0) fprintf(F, "\tDeltaY");
00804     }
00805     fprintf(F, "\n");
00806     // data
00807     for (int row = 0; row < SeriesV[SerIdV[0]].XYValV.Len(); row++) {
00808       for (int i = 0; i < SeriesV.Len(); i++) {
00809         const TGpSeries& Ser = SeriesV[SerIdV[i]];
00810         if (row < Ser.XYValV.Len()) {
00811           if (i > 0) { fprintf(F, "\t"); }
00812           if (Ser.SaveXVals()) { fprintf(F, "%g\t%g", Ser.XYValV[row].Key(), Ser.XYValV[row].Dat()); }
00813           else { fprintf(F, "%g", Ser.XYValV[row].Dat()); }
00814           if (! Ser.ZValV.Empty()) { fprintf(F, "\t%g", Ser.ZValV[row]()); }
00815         }
00816       }
00817       fprintf(F, "\n");
00818     }
00819     fclose(F);
00820   }
00821   // save plot file
00822   FILE *F = fopen(PlotFNm.CStr(), "wt");
00823   EAssertR(F != 0, TStr("Can not open plot file ")+PlotFNm);
00824   TStr CurDir = TDir::GetCurDir();
00825   CurDir.ChangeStrAll("\\", "\\\\");
00826   fprintf(F, "#\n");
00827   fprintf(F, "# %s (%s)\n", Comment.CStr(), TimeStr);
00828   fprintf(F, "#\n\n");
00829   if (! Title.Empty()) fprintf(F, "set title \"%s\"\n", Title.CStr());
00830   fprintf(F, "set key bottom right\n");
00831   fprintf(F, "%s\n", GetScaleStr(ScaleTy).CStr());
00832   if (ScaleTy==gpsLog || ScaleTy==gpsLog10X || ScaleTy==gpsLog10XY) {
00833     fprintf(F, "set format x \"10^{%%L}\"\n");
00834     fprintf(F, "set mxtics 10\n"); }
00835   if (ScaleTy==gpsLog || ScaleTy==gpsLog10Y || ScaleTy==gpsLog10XY) {
00836     fprintf(F, "set format y \"10^{%%L}\"\n");
00837     fprintf(F, "set mytics 10\n"); }
00838   if (ScaleTy==gpsLog2X || ScaleTy==gpsLog2XY) { fprintf(F, "set format x \"2^{%%L}\"\n"); }
00839   if (ScaleTy==gpsLog2Y || ScaleTy==gpsLog2XY) { fprintf(F, "set format y \"2^{%%L}\"\n"); }
00840   if (SetGrid) fprintf(F, "set grid\n");
00841   if (XRange.Val1 != XRange.Val2) fprintf(F, "set xrange [%g:%g]\n", XRange.Val1(), XRange.Val2());
00842   if (YRange.Val1 != YRange.Val2) fprintf(F, "set yrange [%g:%g]\n", YRange.Val1(), YRange.Val2());
00843   if (! LblX.Empty()) fprintf(F, "set xlabel \"%s\"\n", LblX.CStr());
00844   if (! LblY.Empty()) fprintf(F, "set ylabel \"%s\"\n", LblY.CStr());
00845   if (Tics42) {
00846     fprintf(F, "set tics scale 2\n"); // New in version 4.2
00847   } else {
00848     fprintf(F, "set ticscale 2 1\n"); // Old (deprecated)
00849   }
00850   // custom commands
00851   for (int i = 0; i < MoreCmds.Len(); i++) {
00852     fprintf(F, "%s\n", MoreCmds[i].CStr()); }
00853   // plot
00854   if (! SeriesV.Empty()) {
00855     fprintf(F, "plot \t");
00856     for (int i = 0; i < SeriesV.Len(); i++) {
00857       fprintf(F, "%s", GetSeriesPlotStr(i).CStr()); }
00858     fprintf(F, "\n");
00859   }
00860   if (SetPause) fprintf(F, "pause -1 \"Hit return to exit. %s\"\n", PlotFNm.CStr());
00861   fclose(F);
00862 }
00863 
00864 void TGnuPlot::RunGnuPlot() const {
00865   TStr GpFNm, GpPath;
00866   #if defined(GLib_WIN)
00867     GpFNm = "wgnuplot.exe";
00868     GpPath = "C:\\gnuplot\\";
00869   #elif defined(GLib_CYGWIN)
00870     GpFNm = "gnuplot.exe";
00871     GpPath = "/usr/bin/";
00872   #else
00873     GpFNm = "gnuplot";
00874     GpPath = "/usr/bin/";
00875   #endif
00876   if (system(TStr::Fmt("%s %s", GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00877   #if defined(GLib_WIN)
00878   if (system(TStr::Fmt(".\\%s %s", GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00879   #else
00880   if (system(TStr::Fmt("./%s %s", GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00881   #endif
00882   if (system(TStr::Fmt("%s%s %s", GpPath.CStr(), GpFNm.CStr(), PlotFNm.CStr()).CStr())==0) { return; }
00883   //FailR(TStr::Fmt("Cat not find GnuPlot (%s) for plot %s. Set the PATH.", GpFNm.CStr(), PlotFNm.CStr()).CStr());
00884   //ErrNotify(TStr::Fmt("Cat not find GnuPlot (%s) for plot %s. Set the PATH.", GpFNm.CStr(), PlotFNm.CStr()).CStr());
00885   fprintf(stderr, "[%s:%d] Cat not find GnuPlot (%s) for plot %s. Set the PATH.\n", __FILE__, __LINE__, GpFNm.CStr(), PlotFNm.CStr());
00886 }