SNAP Library, User Reference  2012-10-15 15:06:59
SNAP, a general purpose network analysis and graph mining library
 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 }